Coverage Report

Created: 2025-06-12 06:27

/src/libtorrent/src/torrent.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
3
Copyright (c) 2003-2022, Arvid Norberg
4
Copyright (c) 2003, Daniel Wallin
5
Copyright (c) 2004, Magnus Jonsson
6
Copyright (c) 2008, Andrew Resch
7
Copyright (c) 2015, Mikhail Titov
8
Copyright (c) 2015-2020, Steven Siloti
9
Copyright (c) 2016-2020, Alden Torres
10
Copyright (c) 2016-2017, Andrei Kurushin
11
Copyright (c) 2016, Jonathan McDougall
12
Copyright (c) 2016-2018, Pavel Pimenov
13
Copyright (c) 2017, 2020, AllSeeingEyeTolledEweSew
14
Copyright (c) 2017, Falcosc
15
Copyright (c) 2017, ximply
16
Copyright (c) 2018, Fernando Rodriguez
17
Copyright (c) 2018, airium
18
Copyright (c) 2018, d-komarov
19
Copyright (c) 2020, Paul-Louis Ageneau
20
Copyright (c) 2021, AdvenT
21
Copyright (c) 2021, Joris CARRIER
22
Copyright (c) 2021, thrnz
23
Copyright (c) 2024, Elyas EL IDRISSI
24
All rights reserved.
25
26
Redistribution and use in source and binary forms, with or without
27
modification, are permitted provided that the following conditions
28
are met:
29
30
    * Redistributions of source code must retain the above copyright
31
      notice, this list of conditions and the following disclaimer.
32
    * Redistributions in binary form must reproduce the above copyright
33
      notice, this list of conditions and the following disclaimer in
34
      the documentation and/or other materials provided with the distribution.
35
    * Neither the name of the author nor the names of its
36
      contributors may be used to endorse or promote products derived
37
      from this software without specific prior written permission.
38
39
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
40
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
42
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
43
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
44
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
45
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
46
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
47
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
48
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
49
POSSIBILITY OF SUCH DAMAGE.
50
51
*/
52
53
#include "libtorrent/config.hpp"
54
55
#include <cstdarg> // for va_list
56
#include <ctime>
57
#include <algorithm>
58
#include <set>
59
#include <map>
60
#include <vector>
61
#include <cctype>
62
#include <numeric>
63
#include <limits> // for numeric_limits
64
#include <cstdio> // for snprintf
65
#include <functional>
66
67
#include "libtorrent/torrent.hpp"
68
#include "libtorrent/torrent_handle.hpp"
69
#include "libtorrent/announce_entry.hpp"
70
#include "libtorrent/torrent_info.hpp"
71
#include "libtorrent/tracker_manager.hpp"
72
#include "libtorrent/parse_url.hpp"
73
#include "libtorrent/bencode.hpp"
74
#include "libtorrent/hasher.hpp"
75
#include "libtorrent/entry.hpp"
76
#include "libtorrent/peer.hpp"
77
#include "libtorrent/peer_connection.hpp"
78
#include "libtorrent/bt_peer_connection.hpp"
79
#include "libtorrent/web_peer_connection.hpp"
80
#include "libtorrent/http_seed_connection.hpp"
81
#include "libtorrent/peer_connection_handle.hpp"
82
#include "libtorrent/peer_id.hpp"
83
#include "libtorrent/identify_client.hpp"
84
#include "libtorrent/alert_types.hpp"
85
#include "libtorrent/extensions.hpp"
86
#include "libtorrent/aux_/session_interface.hpp"
87
#include "libtorrent/aux_/instantiate_connection.hpp"
88
#include "libtorrent/assert.hpp"
89
#include "libtorrent/kademlia/dht_tracker.hpp"
90
#include "libtorrent/peer_info.hpp"
91
#include "libtorrent/http_connection.hpp"
92
#include "libtorrent/random.hpp"
93
#include "libtorrent/peer_class.hpp" // for peer_class
94
#include "libtorrent/socket_io.hpp" // for read_*_endpoint
95
#include "libtorrent/ip_filter.hpp"
96
#include "libtorrent/request_blocks.hpp"
97
#include "libtorrent/performance_counters.hpp" // for counters
98
#include "libtorrent/aux_/resolver_interface.hpp"
99
#include "libtorrent/aux_/alloca.hpp"
100
#include "libtorrent/resolve_links.hpp"
101
#include "libtorrent/aux_/file_progress.hpp"
102
#include "libtorrent/aux_/has_block.hpp"
103
#include "libtorrent/aux_/alert_manager.hpp"
104
#include "libtorrent/disk_interface.hpp"
105
#include "libtorrent/aux_/ip_helpers.hpp" // for is_ip_address
106
#include "libtorrent/download_priority.hpp"
107
#include "libtorrent/hex.hpp" // to_hex
108
#include "libtorrent/aux_/range.hpp"
109
#include "libtorrent/aux_/merkle.hpp"
110
#include "libtorrent/mmap_disk_io.hpp" // for hasher_thread_divisor
111
#include "libtorrent/aux_/numeric_cast.hpp"
112
#include "libtorrent/aux_/path.hpp"
113
#include "libtorrent/aux_/generate_peer_id.hpp"
114
#include "libtorrent/aux_/announce_entry.hpp"
115
#include "libtorrent/ssl.hpp"
116
#include "libtorrent/aux_/apply_pad_files.hpp"
117
118
#ifdef TORRENT_SSL_PEERS
119
#include "libtorrent/ssl_stream.hpp"
120
#endif // TORRENT_SSL_PEERS
121
122
#ifndef TORRENT_DISABLE_LOGGING
123
#include "libtorrent/aux_/session_impl.hpp" // for tracker_logger
124
#endif
125
126
#include "libtorrent/aux_/torrent_impl.hpp"
127
128
using namespace std::placeholders;
129
130
namespace libtorrent {
131
namespace {
132
133
bool is_downloading_state(int const st)
134
2.72k
{
135
2.72k
  switch (st)
136
2.72k
  {
137
65
    case torrent_status::checking_files:
138
1.99k
    case torrent_status::checking_resume_data:
139
1.99k
      return false;
140
0
    case torrent_status::downloading_metadata:
141
466
    case torrent_status::downloading:
142
728
    case torrent_status::finished:
143
728
    case torrent_status::seeding:
144
728
      return true;
145
0
    default:
146
      // unexpected state
147
0
      TORRENT_ASSERT_FAIL_VAL(st);
148
0
      return false;
149
2.72k
  }
150
2.72k
}
151
} // anonymous namespace
152
153
  constexpr web_seed_flag_t torrent::ephemeral;
154
  constexpr web_seed_flag_t torrent::no_local_ips;
155
156
  web_seed_t::web_seed_t(web_seed_entry const& wse)
157
0
    : web_seed_entry(wse)
158
0
  {
159
0
    peer_info.web_seed = true;
160
0
  }
161
162
  web_seed_t::web_seed_t(std::string const& url_, web_seed_entry::type_t type_
163
    , std::string const& auth_
164
    , web_seed_entry::headers_t const& extra_headers_)
165
0
    : web_seed_entry(url_, type_, auth_, extra_headers_)
166
0
  {
167
0
    peer_info.web_seed = true;
168
0
  }
169
170
  torrent_hot_members::torrent_hot_members(aux::session_interface& ses
171
    , add_torrent_params const& p, bool const session_paused)
172
1.88k
    : m_ses(ses)
173
1.88k
    , m_complete(0xffffff)
174
1.88k
    , m_upload_mode(p.flags & torrent_flags::upload_mode)
175
1.88k
    , m_connections_initialized(false)
176
1.88k
    , m_abort(false)
177
1.88k
    , m_paused(p.flags & torrent_flags::paused)
178
1.88k
    , m_session_paused(session_paused)
179
#ifndef TORRENT_DISABLE_SHARE_MODE
180
1.88k
    , m_share_mode(p.flags & torrent_flags::share_mode)
181
#endif
182
1.88k
    , m_have_all(false)
183
1.88k
    , m_graceful_pause_mode(false)
184
1.88k
    , m_state_subscription(p.flags & torrent_flags::update_subscribe)
185
1.88k
    , m_max_connections(0xffffff)
186
1.88k
    , m_state(torrent_status::checking_resume_data)
187
1.88k
  {}
188
189
  torrent::torrent(
190
    aux::session_interface& ses
191
    , bool const session_paused
192
    , add_torrent_params&& p)
193
1.88k
    : torrent_hot_members(ses, p, session_paused)
194
1.88k
    , m_total_uploaded(p.total_uploaded)
195
1.88k
    , m_total_downloaded(p.total_downloaded)
196
1.88k
    , m_tracker_timer(ses.get_context())
197
1.88k
    , m_inactivity_timer(ses.get_context())
198
1.88k
    , m_trackerid(p.trackerid)
199
1.88k
    , m_save_path(complete(p.save_path))
200
1.88k
    , m_stats_counters(ses.stats_counters())
201
1.88k
    , m_added_time(p.added_time ? p.added_time : aux::posix_time())
202
1.88k
    , m_completed_time(p.completed_time)
203
1.88k
    , m_last_seen_complete(p.last_seen_complete)
204
1.88k
    , m_swarm_last_seen_complete(p.last_seen_complete)
205
1.88k
    , m_info_hash(p.info_hashes)
206
1.88k
    , m_error_file(torrent_status::error_file_none)
207
1.88k
    , m_sequence_number(-1)
208
1.88k
    , m_peer_id(aux::generate_peer_id(settings()))
209
1.88k
    , m_announce_to_trackers(!(p.flags & torrent_flags::paused))
210
1.88k
    , m_announce_to_lsd(!(p.flags & torrent_flags::paused))
211
1.88k
    , m_has_incoming(false)
212
1.88k
    , m_files_checked(false)
213
1.88k
    , m_storage_mode(p.storage_mode)
214
1.88k
    , m_announcing(false)
215
1.88k
    , m_added(false)
216
1.88k
    , m_sequential_download(p.flags & torrent_flags::sequential_download)
217
1.88k
    , m_auto_sequential(false)
218
1.88k
    , m_seed_mode(false)
219
#ifndef TORRENT_DISABLE_SUPERSEEDING
220
1.88k
    , m_super_seeding(p.flags & torrent_flags::super_seeding)
221
#endif
222
1.88k
    , m_stop_when_ready(p.flags & torrent_flags::stop_when_ready)
223
1.88k
    , m_enable_dht(!bool(p.flags & torrent_flags::disable_dht))
224
1.88k
    , m_enable_lsd(!bool(p.flags & torrent_flags::disable_lsd))
225
1.88k
    , m_i2p(bool(p.flags & torrent_flags::i2p_torrent))
226
1.88k
    , m_max_uploads((1 << 24) - 1)
227
1.88k
    , m_num_uploads(0)
228
1.88k
    , m_enable_pex(!bool(p.flags & torrent_flags::disable_pex))
229
1.88k
    , m_apply_ip_filter(p.flags & torrent_flags::apply_ip_filter)
230
1.88k
    , m_pending_active_change(false)
231
1.88k
    , m_v2_piece_layers_validated(false)
232
1.88k
    , m_connect_boost_counter(static_cast<std::uint8_t>(settings().get_int(settings_pack::torrent_connect_boost)))
233
1.88k
    , m_incomplete(0xffffff)
234
1.88k
    , m_announce_to_dht(!(p.flags & torrent_flags::paused))
235
1.88k
    , m_ssl_torrent(false)
236
1.88k
    , m_deleted(false)
237
1.88k
    , m_last_download(aux::from_time_t(p.last_download))
238
1.88k
    , m_last_upload(aux::from_time_t(p.last_upload))
239
1.88k
    , m_userdata(p.userdata)
240
1.88k
    , m_auto_managed(p.flags & torrent_flags::auto_managed)
241
1.88k
    , m_current_gauge_state(static_cast<std::uint32_t>(no_gauge_state))
242
1.88k
    , m_moving_storage(false)
243
1.88k
    , m_inactive(false)
244
1.88k
    , m_downloaded(0xffffff)
245
1.88k
    , m_progress_ppm(0)
246
1.88k
    , m_torrent_initialized(false)
247
1.88k
    , m_outstanding_file_priority(false)
248
1.88k
    , m_complete_sent(false)
249
1.88k
  {
250
1.88k
    if (p.flags & torrent_flags::need_save_resume)
251
862
    {
252
862
      m_need_save_resume_data |= torrent_handle::only_if_modified
253
862
        | torrent_handle::if_metadata_changed;
254
862
    }
255
256
    // we cannot log in the constructor, because it relies on shared_from_this
257
    // being initialized, which happens after the constructor returns.
258
259
#if TORRENT_USE_UNC_PATHS
260
    m_save_path = canonicalize_path(m_save_path);
261
#endif
262
263
1.88k
    if (!m_apply_ip_filter)
264
1.27k
    {
265
1.27k
      inc_stats_counter(counters::non_filter_torrents);
266
1.27k
    }
267
268
1.88k
    if (!m_torrent_file)
269
1.88k
      m_torrent_file = (p.ti ? p.ti : std::make_shared<torrent_info>(m_info_hash));
270
271
1.88k
#if TORRENT_USE_I2P
272
1.88k
    if (m_torrent_file->is_i2p())
273
0
      m_i2p = true;
274
1.88k
#endif
275
276
1.88k
    if (m_torrent_file->is_valid())
277
1.88k
    {
278
1.88k
      error_code ec = initialize_merkle_trees();
279
1.88k
      if (ec) throw system_error(ec);
280
1.88k
      m_size_on_disk = aux::size_on_disk(m_torrent_file->files());
281
1.88k
    }
282
283
    // --- WEB SEEDS ---
284
285
    // if override web seed flag is set, don't load any web seeds from the
286
    // torrent file.
287
1.88k
    std::vector<web_seed_t> ws;
288
1.88k
    if (!(p.flags & torrent_flags::override_web_seeds))
289
1.01k
    {
290
1.01k
      for (auto const& e : m_torrent_file->web_seeds())
291
0
        ws.emplace_back(e);
292
1.01k
    }
293
294
    // add web seeds from add_torrent_params
295
1.88k
    bool const multi_file = m_torrent_file->is_valid()
296
1.88k
        && m_torrent_file->num_files() > 1;
297
298
1.88k
    for (auto const& u : p.url_seeds)
299
0
    {
300
0
      ws.emplace_back(web_seed_t(u, web_seed_entry::url_seed));
301
302
      // correct URLs to end with a "/" for multi-file torrents
303
0
      if (multi_file)
304
0
        ensure_trailing_slash(ws.back().url);
305
0
      if (!m_torrent_file->is_valid())
306
0
        m_torrent_file->add_url_seed(ws.back().url);
307
0
    }
308
309
1.88k
    for (auto const& e : p.http_seeds)
310
0
    {
311
0
      ws.emplace_back(e, web_seed_entry::http_seed);
312
0
      if (!m_torrent_file->is_valid())
313
0
        m_torrent_file->add_http_seed(e);
314
0
    }
315
316
1.88k
    aux::random_shuffle(ws);
317
1.88k
    for (auto& w : ws) m_web_seeds.emplace_back(std::move(w));
318
319
    // --- TRACKERS ---
320
321
    // if override trackers flag is set, don't load trackers from torrent file
322
1.88k
    if (!(p.flags & torrent_flags::override_trackers))
323
1.07k
    {
324
1.07k
      m_trackers.clear();
325
1.07k
      for (auto const& ae : m_torrent_file->trackers())
326
0
        m_trackers.emplace_back(ae);
327
1.07k
    }
328
329
1.88k
    int tier = 0;
330
1.88k
    auto tier_iter = p.tracker_tiers.begin();
331
1.88k
    for (auto const& url : p.trackers)
332
0
    {
333
0
      aux::announce_entry e(url);
334
0
      if (tier_iter != p.tracker_tiers.end())
335
0
        tier = *tier_iter++;
336
337
0
      e.fail_limit = 0;
338
0
      e.source = announce_entry::source_magnet_link;
339
0
      e.tier = std::uint8_t(tier);
340
0
      if (!find_tracker(e.url))
341
0
      {
342
0
        if (e.url.empty()) continue;
343
0
        m_trackers.push_back(e);
344
        // add the tracker to the m_torrent_file here so that the trackers
345
        // will be preserved via create_torrent() when passing in just the
346
        // torrent_info object.
347
0
        if (!m_torrent_file->is_valid())
348
0
          m_torrent_file->add_tracker(e.url, e.tier, announce_entry::tracker_source(e.source));
349
0
      }
350
0
    }
351
352
1.88k
    std::sort(m_trackers.begin(), m_trackers.end()
353
1.88k
      , [] (aux::announce_entry const& lhs, aux::announce_entry const& rhs)
354
1.88k
      { return lhs.tier < rhs.tier; });
355
356
1.88k
    if (settings().get_bool(settings_pack::prefer_udp_trackers))
357
1.88k
      prioritize_udp_trackers();
358
359
1.88k
    if (m_torrent_file->is_valid())
360
1.88k
    {
361
      // setting file- or piece priorities for seed mode makes no sense. If a
362
      // torrent ends up in seed mode by accident, it can be very confusing,
363
      // so assume the seed mode flag is not intended and don't enable it in
364
      // that case. Also, if the resume data says we're missing a piece, we
365
      // can't be in seed-mode.
366
1.88k
      m_seed_mode = (p.flags & torrent_flags::seed_mode)
367
1.88k
        && std::find(p.file_priorities.begin(), p.file_priorities.end(), dont_download) == p.file_priorities.end()
368
1.88k
        && std::find(p.piece_priorities.begin(), p.piece_priorities.end(), dont_download) == p.piece_priorities.end()
369
1.88k
        && std::find(p.have_pieces.begin(), p.have_pieces.end(), false) == p.have_pieces.end();
370
371
1.88k
      m_connections_initialized = true;
372
1.88k
    }
373
0
    else
374
0
    {
375
0
      if (!p.name.empty()) m_name.reset(new std::string(p.name));
376
0
    }
377
378
1.88k
    TORRENT_ASSERT(is_single_thread());
379
1.88k
    m_file_priority.assign(p.file_priorities.begin(), p.file_priorities.end());
380
381
1.88k
    if (m_seed_mode)
382
333
    {
383
333
      m_verified.resize(m_torrent_file->num_pieces(), false);
384
333
      m_verifying.resize(m_torrent_file->num_pieces(), false);
385
333
    }
386
387
1.88k
    m_total_uploaded = p.total_uploaded;
388
1.88k
    m_total_downloaded = p.total_downloaded;
389
390
    // the number of seconds this torrent has spent in started, finished and
391
    // seeding state so far, respectively.
392
1.88k
    m_active_time = seconds(p.active_time);
393
1.88k
    m_finished_time = seconds(p.finished_time);
394
1.88k
    m_seeding_time = seconds(p.seeding_time);
395
396
1.88k
    if (m_completed_time != 0 && m_completed_time < m_added_time)
397
0
      m_completed_time = m_added_time;
398
399
    // --- V2 HASHES ---
400
401
1.88k
    if (m_torrent_file->is_valid() && m_torrent_file->info_hashes().has_v2())
402
1.88k
    {
403
1.88k
      if (!p.merkle_trees.empty())
404
802
        load_merkle_trees(
405
802
          std::move(p.merkle_trees)
406
802
          , std::move(p.merkle_tree_mask)
407
802
          , std::move(p.verified_leaf_hashes));
408
409
      // we really don't want to store extra copies of the trees
410
1.88k
      TORRENT_ASSERT(p.merkle_trees.empty());
411
1.88k
    }
412
413
1.88k
    if (valid_metadata())
414
1.88k
    {
415
1.88k
      inc_stats_counter(counters::num_total_pieces_added
416
1.88k
        , m_torrent_file->num_pieces());
417
1.88k
    }
418
419
    // TODO: 3 we could probably get away with just saving a few fields here
420
1.88k
    m_add_torrent_params = std::make_unique<add_torrent_params>(std::move(p));
421
1.88k
  }
422
423
  void torrent::load_merkle_trees(
424
    aux::vector<std::vector<sha256_hash>, file_index_t> trees_import
425
    , aux::vector<std::vector<bool>, file_index_t> mask
426
    , aux::vector<std::vector<bool>, file_index_t> verified)
427
802
  {
428
802
    auto const& fs = m_torrent_file->orig_files();
429
430
802
    std::vector<bool> const empty_verified;
431
1.60k
    for (file_index_t i{0}; i < fs.end_file(); ++i)
432
802
    {
433
802
      if (fs.pad_file_at(i) || fs.file_size(i) == 0)
434
0
        continue;
435
436
802
      if (i >= trees_import.end_index()) break;
437
802
      std::vector<bool> const& verified_bitmask = (i >= verified.end_index()) ? empty_verified : verified[i];
438
802
      if (i < mask.end_index() && !mask[i].empty())
439
742
      {
440
742
        mask[i].resize(m_merkle_trees[i].size(), false);
441
742
        m_merkle_trees[i].load_sparse_tree(trees_import[i], mask[i], verified_bitmask);
442
742
      }
443
60
      else
444
60
      {
445
60
        m_merkle_trees[i].load_tree(trees_import[i], verified_bitmask);
446
60
      }
447
802
    }
448
802
  }
449
450
  void torrent::inc_stats_counter(int c, int value)
451
9.64k
  { m_ses.stats_counters().inc_stats_counter(c, value); }
452
453
  int torrent::current_stats_state() const
454
15.3k
  {
455
15.3k
    if (m_abort || !m_added)
456
13.4k
      return counters::num_checking_torrents + no_gauge_state;
457
458
1.89k
    if (has_error()) return counters::num_error_torrents;
459
1.89k
    if (m_paused || m_graceful_pause_mode)
460
830
    {
461
830
      if (!is_auto_managed()) return counters::num_stopped_torrents;
462
178
      if (is_seed()) return counters::num_queued_seeding_torrents;
463
131
      return counters::num_queued_download_torrents;
464
178
    }
465
1.06k
    if (state() == torrent_status::checking_files
466
1.06k
#if TORRENT_ABI_VERSION == 1
467
1.06k
      || state() == torrent_status::queued_for_checking
468
1.06k
#endif
469
1.06k
      )
470
121
      return counters::num_checking_torrents;
471
944
    else if (is_seed()) return counters::num_seeding_torrents;
472
752
    else if (is_upload_only()) return counters::num_upload_only_torrents;
473
490
    return counters::num_downloading_torrents;
474
1.06k
  }
475
476
  void torrent::update_gauge()
477
15.3k
  {
478
15.3k
    int const new_gauge_state = current_stats_state() - counters::num_checking_torrents;
479
15.3k
    TORRENT_ASSERT(new_gauge_state >= 0);
480
15.3k
    TORRENT_ASSERT(new_gauge_state <= no_gauge_state);
481
482
15.3k
    if (new_gauge_state == int(m_current_gauge_state)) return;
483
484
3.76k
    if (m_current_gauge_state != no_gauge_state)
485
1.88k
      inc_stats_counter(m_current_gauge_state + counters::num_checking_torrents, -1);
486
3.76k
    if (new_gauge_state != no_gauge_state)
487
1.88k
      inc_stats_counter(new_gauge_state + counters::num_checking_torrents, 1);
488
489
3.76k
    TORRENT_ASSERT(new_gauge_state >= 0);
490
3.76k
    TORRENT_ASSERT(new_gauge_state <= no_gauge_state);
491
3.76k
    m_current_gauge_state = static_cast<std::uint32_t>(new_gauge_state);
492
3.76k
  }
493
494
  void torrent::leave_seed_mode(seed_mode_t const checking)
495
0
  {
496
0
    if (!m_seed_mode) return;
497
498
0
    if (checking == seed_mode_t::check_files)
499
0
    {
500
      // this means the user promised we had all the
501
      // files, but it turned out we didn't. This is
502
      // an error.
503
504
      // TODO: 2 post alert
505
506
#ifndef TORRENT_DISABLE_LOGGING
507
      debug_log("*** FAILED SEED MODE, rechecking");
508
#endif
509
0
    }
510
511
#ifndef TORRENT_DISABLE_LOGGING
512
    debug_log("*** LEAVING SEED MODE (%s)"
513
      , checking == seed_mode_t::skip_checking ? "as seed" : "as non-seed");
514
#endif
515
0
    m_seed_mode = false;
516
    // seed is false if we turned out not
517
    // to be a seed after all
518
0
    if (checking == seed_mode_t::check_files
519
0
      && state() != torrent_status::checking_resume_data)
520
0
    {
521
0
      m_have_all = false;
522
0
      set_state(torrent_status::downloading);
523
0
      force_recheck();
524
0
    }
525
0
    m_num_verified = 0;
526
0
    m_verified.clear();
527
0
    m_verifying.clear();
528
529
0
    set_need_save_resume(torrent_handle::if_state_changed);
530
0
  }
531
532
  void torrent::verified(piece_index_t const piece)
533
0
  {
534
0
    TORRENT_ASSERT(!m_verified.get_bit(piece));
535
0
    ++m_num_verified;
536
0
    m_verified.set_bit(piece);
537
0
    set_need_save_resume(torrent_handle::if_download_progress);
538
0
  }
539
540
  void torrent::start()
541
1.88k
  {
542
1.88k
    TORRENT_ASSERT(is_single_thread());
543
1.88k
    TORRENT_ASSERT(m_was_started == false);
544
1.88k
#if TORRENT_USE_ASSERTS
545
1.88k
    m_was_started = true;
546
1.88k
#endif
547
548
    // Some of these calls may log to the torrent debug log, which requires a
549
    // call to get_handle(), which requires the torrent object to be fully
550
    // constructed, as it relies on get_shared_from_this()
551
1.88k
    if (m_add_torrent_params)
552
1.88k
    {
553
1.88k
#if TORRENT_ABI_VERSION == 1
554
1.88k
      if (m_add_torrent_params->internal_resume_data_error
555
1.88k
        && m_ses.alerts().should_post<fastresume_rejected_alert>())
556
0
      {
557
0
        m_ses.alerts().emplace_alert<fastresume_rejected_alert>(get_handle()
558
0
          , m_add_torrent_params->internal_resume_data_error, ""
559
0
          , operation_t::unknown);
560
0
      }
561
1.88k
#endif
562
563
1.88k
      add_torrent_params const& p = *m_add_torrent_params;
564
565
1.88k
      set_max_uploads(p.max_uploads, false);
566
1.88k
      set_max_connections(p.max_connections, false);
567
1.88k
      set_limit_impl(p.upload_limit, peer_connection::upload_channel, false);
568
1.88k
      set_limit_impl(p.download_limit, peer_connection::download_channel, false);
569
570
1.88k
      for (auto const& peer : p.peers)
571
0
      {
572
0
        add_peer(peer, peer_info::resume_data);
573
0
      }
574
575
1.88k
      if (!p.peers.empty())
576
0
      {
577
0
        do_connect_boost();
578
0
      }
579
580
#ifndef TORRENT_DISABLE_LOGGING
581
      if (should_log() && !p.peers.empty())
582
      {
583
        std::string str;
584
        for (auto const& peer : p.peers)
585
        {
586
          str += peer.address().to_string();
587
          str += ' ';
588
        }
589
        debug_log("add_torrent add_peer() [ %s] connect-candidates: %d"
590
          , str.c_str(), m_peer_list
591
          ? m_peer_list->num_connect_candidates() : -1);
592
      }
593
#endif
594
1.88k
    }
595
596
#ifndef TORRENT_DISABLE_LOGGING
597
    if (should_log())
598
    {
599
      debug_log("creating torrent: %s max-uploads: %d max-connections: %d "
600
        "upload-limit: %d download-limit: %d flags: %s%s%s%s%s%s%s%s%s%s%s "
601
        "save-path: %s"
602
        , torrent_file().name().c_str()
603
        , int(m_max_uploads)
604
        , int(m_max_connections)
605
        , upload_limit()
606
        , download_limit()
607
        , m_seed_mode ? "seed-mode " : ""
608
        , m_upload_mode ? "upload-mode " : ""
609
#ifndef TORRENT_DISABLE_SHARE_MODE
610
        , m_share_mode ? "share-mode " : ""
611
#else
612
        , ""
613
#endif
614
        , m_apply_ip_filter ? "apply-ip-filter " : ""
615
        , m_paused ? "paused " : ""
616
        , m_auto_managed ? "auto-managed " : ""
617
        , m_state_subscription ? "update-subscribe " : ""
618
#ifndef TORRENT_DISABLE_SUPERSEEDING
619
        , m_super_seeding ? "super-seeding " : ""
620
#else
621
        , ""
622
#endif
623
        , m_sequential_download ? "sequential-download " : ""
624
        , (m_add_torrent_params && m_add_torrent_params->flags & torrent_flags::override_trackers)
625
          ? "override-trackers "  : ""
626
        , (m_add_torrent_params && m_add_torrent_params->flags & torrent_flags::override_web_seeds)
627
          ? "override-web-seeds " : ""
628
        , m_save_path.c_str()
629
        );
630
    }
631
#endif
632
633
1.88k
    update_gauge();
634
635
1.88k
    update_want_peers();
636
1.88k
    update_want_scrape();
637
1.88k
    update_want_tick();
638
1.88k
    update_state_list();
639
640
1.88k
    if (m_torrent_file->is_valid())
641
1.88k
    {
642
1.88k
      init();
643
1.88k
    }
644
0
    else
645
0
    {
646
      // we need to start announcing since we don't have any
647
      // metadata. To receive peers to ask for it.
648
0
      set_state(torrent_status::downloading_metadata);
649
0
      start_announcing();
650
0
    }
651
652
#if TORRENT_USE_INVARIANT_CHECKS
653
    check_invariant();
654
#endif
655
1.88k
  }
656
657
  void torrent::set_apply_ip_filter(bool b)
658
0
  {
659
0
    if (b == m_apply_ip_filter) return;
660
0
    if (b)
661
0
    {
662
0
      inc_stats_counter(counters::non_filter_torrents, -1);
663
0
    }
664
0
    else
665
0
    {
666
0
      inc_stats_counter(counters::non_filter_torrents);
667
0
    }
668
669
0
    set_need_save_resume(torrent_handle::if_config_changed);
670
671
0
    m_apply_ip_filter = b;
672
0
    ip_filter_updated();
673
0
    state_updated();
674
0
  }
675
676
  void torrent::set_ip_filter(std::shared_ptr<const ip_filter> ipf)
677
1.88k
  {
678
1.88k
    m_ip_filter = std::move(ipf);
679
1.88k
    if (!m_apply_ip_filter) return;
680
608
    ip_filter_updated();
681
608
  }
682
683
#ifndef TORRENT_DISABLE_DHT
684
  bool torrent::should_announce_dht() const
685
0
  {
686
0
    TORRENT_ASSERT(is_single_thread());
687
0
    if (!m_enable_dht) return false;
688
0
    if (!m_ses.announce_dht()) return false;
689
690
0
#if TORRENT_USE_I2P
691
    // i2p torrents don't announced on the DHT
692
    // unless we allow mixed swarms
693
0
    if (is_i2p() && !settings().get_bool(settings_pack::allow_i2p_mixed))
694
0
      return false;
695
0
#endif
696
697
0
    if (!m_ses.dht()) return false;
698
0
    if (m_torrent_file->is_valid() && !m_files_checked) return false;
699
0
    if (!m_announce_to_dht) return false;
700
0
    if (m_paused) return false;
701
702
    // don't announce private torrents
703
0
    if (m_torrent_file->is_valid() && m_torrent_file->priv()) return false;
704
0
    if (m_trackers.empty()) return true;
705
0
    if (!settings().get_bool(settings_pack::use_dht_as_fallback)) return true;
706
707
0
    return std::none_of(m_trackers.begin(), m_trackers.end()
708
0
      , [](aux::announce_entry const& tr) { return bool(tr.verified); });
709
0
  }
710
711
#endif
712
713
  torrent::~torrent()
714
1.88k
  {
715
    // TODO: 3 assert there are no outstanding async operations on this
716
    // torrent
717
718
1.88k
#if TORRENT_USE_ASSERTS
719
16.9k
    for (torrent_list_index_t i{}; i != m_links.end_index(); ++i)
720
15.0k
    {
721
15.0k
      if (!m_links[i].in_list()) continue;
722
0
      m_links[i].unlink(m_ses.torrent_list(i), i);
723
0
    }
724
1.88k
#endif
725
726
    // The invariant can't be maintained here, since the torrent
727
    // is being destructed, all weak references to it have been
728
    // reset, which means that all its peers already have an
729
    // invalidated torrent pointer (so it cannot be verified to be correct)
730
731
    // i.e. the invariant can only be maintained if all connections have
732
    // been closed by the time the torrent is destructed. And they are
733
    // supposed to be closed. So we can still do the invariant check.
734
735
    // however, the torrent object may be destructed from the main
736
    // thread when shutting down, if the disk cache has references to it.
737
    // this means that the invariant check that this is called from the
738
    // network thread cannot be maintained
739
740
1.88k
    TORRENT_ASSERT(m_peer_class == peer_class_t{0});
741
1.88k
    TORRENT_ASSERT(m_connections.empty());
742
    // just in case, make sure the session accounting is kept right
743
1.88k
    for (auto p : m_connections)
744
0
      m_ses.close_connection(p);
745
1.88k
  }
746
747
  void torrent::read_piece(piece_index_t const piece)
748
0
  {
749
0
    error_code ec;
750
0
    if (m_abort || m_deleted)
751
0
    {
752
0
      ec.assign(boost::system::errc::operation_canceled, generic_category());
753
0
    }
754
0
    else if (!valid_metadata())
755
0
    {
756
0
      ec.assign(errors::no_metadata, libtorrent_category());
757
0
    }
758
0
    else if (!user_have_piece(piece))
759
0
    {
760
0
      ec.assign(errors::invalid_piece_index, libtorrent_category());
761
0
    }
762
763
0
    if (ec)
764
0
    {
765
0
      m_ses.alerts().emplace_alert<read_piece_alert>(get_handle(), piece, ec);
766
0
      return;
767
0
    }
768
769
0
    const int piece_size = m_torrent_file->piece_size(piece);
770
0
    const int blocks_in_piece = (piece_size + block_size() - 1) / block_size();
771
772
0
    TORRENT_ASSERT(blocks_in_piece > 0);
773
0
    TORRENT_ASSERT(piece_size > 0);
774
775
0
    if (blocks_in_piece == 0)
776
0
    {
777
      // this shouldn't actually happen
778
0
      boost::shared_array<char> buf;
779
0
      m_ses.alerts().emplace_alert<read_piece_alert>(
780
0
        get_handle(), piece, buf, 0);
781
0
      return;
782
0
    }
783
784
0
    std::shared_ptr<read_piece_struct> rp = std::make_shared<read_piece_struct>();
785
0
    rp->piece_data.reset(new (std::nothrow) char[std::size_t(piece_size)]);
786
0
    if (!rp->piece_data)
787
0
    {
788
0
      m_ses.alerts().emplace_alert<read_piece_alert>(
789
0
        get_handle(), piece, error_code(boost::system::errc::not_enough_memory, generic_category()));
790
0
      return;
791
0
    }
792
0
    rp->blocks_left = blocks_in_piece;
793
0
    rp->fail = false;
794
795
0
    disk_job_flags_t flags{};
796
0
    auto const read_mode = settings().get_int(settings_pack::disk_io_read_mode);
797
0
    if (read_mode == settings_pack::disable_os_cache)
798
0
      flags |= disk_interface::volatile_read;
799
800
0
    peer_request r;
801
0
    r.piece = piece;
802
0
    r.start = 0;
803
0
    auto self = shared_from_this();
804
0
    for (int i = 0; i < blocks_in_piece; ++i, r.start += block_size())
805
0
    {
806
0
      r.length = std::min(piece_size - r.start, block_size());
807
0
      m_ses.disk_thread().async_read(m_storage, r
808
0
        , [self, r, rp](disk_buffer_holder block, storage_error const& se) mutable
809
0
        { self->on_disk_read_complete(std::move(block), se, r, rp); }
810
0
        , flags);
811
0
    }
812
0
    m_ses.deferred_submit_jobs();
813
0
  }
814
815
#ifndef TORRENT_DISABLE_SHARE_MODE
816
  void torrent::send_share_mode()
817
0
  {
818
0
#ifndef TORRENT_DISABLE_EXTENSIONS
819
0
    for (auto const pc : m_connections)
820
0
    {
821
0
      TORRENT_INCREMENT(m_iterating_connections);
822
0
      if (pc->type() != connection_type::bittorrent) continue;
823
0
      auto* p = static_cast<bt_peer_connection*>(pc);
824
0
      p->write_share_mode();
825
0
    }
826
0
#endif
827
0
  }
828
#endif // TORRENT_DISABLE_SHARE_MODE
829
830
  void torrent::send_upload_only()
831
553
  {
832
553
#ifndef TORRENT_DISABLE_EXTENSIONS
833
834
553
#ifndef TORRENT_DISABLE_SHARE_MODE
835
553
    if (share_mode()) return;
836
237
#endif
837
237
#ifndef TORRENT_DISABLE_SUPERSEEDING
838
237
    if (super_seeding()) return;
839
192
#endif
840
841
    // if we send upload-only, the other end is very likely to disconnect
842
    // us, at least if it's a seed. If we don't want to close redundant
843
    // connections, don't sent upload-only
844
192
    if (!settings().get_bool(settings_pack::close_redundant_connections)) return;
845
846
    // if we're super seeding, we don't want to make peers
847
    // think that we only have a single piece and is upload
848
    // only, since they might disconnect immediately when
849
    // they have downloaded a single piece, although we'll
850
    // make another piece available
851
192
    bool const upload_only_enabled = is_upload_only()
852
192
#ifndef TORRENT_DISABLE_SUPERSEEDING
853
192
      && !super_seeding()
854
192
#endif
855
192
      ;
856
857
192
    for (auto p : m_connections)
858
0
    {
859
0
      TORRENT_INCREMENT(m_iterating_connections);
860
861
0
      p->send_not_interested();
862
0
      p->send_upload_only(upload_only_enabled);
863
0
    }
864
192
#endif // TORRENT_DISABLE_EXTENSIONS
865
192
  }
866
867
  torrent_flags_t torrent::flags() const
868
3
  {
869
3
    torrent_flags_t ret = torrent_flags_t{};
870
3
    if (m_seed_mode)
871
0
      ret |= torrent_flags::seed_mode;
872
3
    if (m_upload_mode)
873
0
      ret |= torrent_flags::upload_mode;
874
3
#ifndef TORRENT_DISABLE_SHARE_MODE
875
3
    if (m_share_mode)
876
0
      ret |= torrent_flags::share_mode;
877
3
#endif
878
3
    if (m_apply_ip_filter)
879
3
      ret |= torrent_flags::apply_ip_filter;
880
3
    if (is_torrent_paused())
881
0
      ret |= torrent_flags::paused;
882
3
    if (m_auto_managed)
883
3
      ret |= torrent_flags::auto_managed;
884
3
#ifndef TORRENT_DISABLE_SUPERSEEDING
885
3
    if (m_super_seeding)
886
0
      ret |= torrent_flags::super_seeding;
887
3
#endif
888
3
    if (m_sequential_download)
889
0
      ret |= torrent_flags::sequential_download;
890
3
    if (m_stop_when_ready)
891
0
      ret |= torrent_flags::stop_when_ready;
892
3
    if (!m_enable_dht)
893
0
      ret |= torrent_flags::disable_dht;
894
3
    if (!m_enable_lsd)
895
0
      ret |= torrent_flags::disable_lsd;
896
3
    if (!m_enable_pex)
897
0
      ret |= torrent_flags::disable_pex;
898
3
    if (m_i2p)
899
0
      ret |= torrent_flags::i2p_torrent;
900
3
    return ret;
901
3
  }
902
903
  void torrent::set_flags(torrent_flags_t const flags
904
    , torrent_flags_t const mask)
905
0
  {
906
0
    if (mask & torrent_flags::i2p_torrent)
907
0
    {
908
0
      m_i2p = bool(flags & torrent_flags::i2p_torrent);
909
0
    }
910
0
    if ((mask & torrent_flags::seed_mode)
911
0
      && !(flags & torrent_flags::seed_mode))
912
0
    {
913
0
      leave_seed_mode(seed_mode_t::check_files);
914
0
    }
915
0
    if (mask & torrent_flags::upload_mode)
916
0
      set_upload_mode(bool(flags & torrent_flags::upload_mode));
917
0
#ifndef TORRENT_DISABLE_SHARE_MODE
918
0
    if (mask & torrent_flags::share_mode)
919
0
      set_share_mode(bool(flags & torrent_flags::share_mode));
920
0
#endif
921
0
    if (mask & torrent_flags::apply_ip_filter)
922
0
      set_apply_ip_filter(bool(flags & torrent_flags::apply_ip_filter));
923
0
    if (mask & torrent_flags::paused)
924
0
    {
925
0
      if (flags & torrent_flags::paused)
926
0
        pause(torrent_handle::graceful_pause);
927
0
      else
928
0
        resume();
929
0
    }
930
0
    if (mask & torrent_flags::auto_managed)
931
0
      auto_managed(bool(flags & torrent_flags::auto_managed));
932
0
#ifndef TORRENT_DISABLE_SUPERSEEDING
933
0
    if (mask & torrent_flags::super_seeding)
934
0
      set_super_seeding(bool(flags & torrent_flags::super_seeding));
935
0
#endif
936
0
    if (mask & torrent_flags::sequential_download)
937
0
      set_sequential_download(bool(flags & torrent_flags::sequential_download));
938
0
    if (mask & torrent_flags::stop_when_ready)
939
0
      stop_when_ready(bool(flags & torrent_flags::stop_when_ready));
940
0
    if (mask & torrent_flags::disable_dht)
941
0
    {
942
0
      bool const new_value = !bool(flags & torrent_flags::disable_dht);
943
0
      if (m_enable_dht != new_value) set_need_save_resume(torrent_handle::if_config_changed);
944
0
      m_enable_dht = new_value;
945
0
    }
946
0
    if (mask & torrent_flags::disable_lsd)
947
0
    {
948
0
      bool const new_value = !bool(flags & torrent_flags::disable_lsd);
949
0
      if (m_enable_dht != new_value) set_need_save_resume(torrent_handle::if_config_changed);
950
0
      m_enable_lsd = new_value;
951
0
    }
952
0
    if (mask & torrent_flags::disable_pex)
953
0
    {
954
0
      bool const new_value = !bool(flags & torrent_flags::disable_pex);
955
0
      if (m_enable_dht != new_value) set_need_save_resume(torrent_handle::if_config_changed);
956
0
      m_enable_pex = new_value;
957
0
    }
958
0
  }
959
960
#ifndef TORRENT_DISABLE_SHARE_MODE
961
  void torrent::set_share_mode(bool s)
962
0
  {
963
0
    if (s == m_share_mode) return;
964
965
0
    m_share_mode = s;
966
0
    set_need_save_resume(torrent_handle::if_config_changed);
967
#ifndef TORRENT_DISABLE_LOGGING
968
    debug_log("*** set-share-mode: %d", s);
969
#endif
970
0
    if (m_share_mode)
971
0
    {
972
0
      std::size_t const num_files = valid_metadata()
973
0
        ? std::size_t(m_torrent_file->num_files())
974
0
        : m_file_priority.size();
975
      // in share mode, all pieces have their priorities initialized to
976
      // dont_download
977
0
      prioritize_files(aux::vector<download_priority_t, file_index_t>(num_files, dont_download));
978
0
    }
979
0
  }
980
#endif // TORRENT_DISABLE_SHARE_MODE
981
982
  void torrent::set_upload_mode(bool b)
983
0
  {
984
0
    if (b == m_upload_mode) return;
985
986
0
    m_upload_mode = b;
987
#ifndef TORRENT_DISABLE_LOGGING
988
    debug_log("*** set-upload-mode: %d", b);
989
#endif
990
991
0
    set_need_save_resume(torrent_handle::if_state_changed);
992
0
    update_gauge();
993
0
    state_updated();
994
0
    send_upload_only();
995
996
0
    if (m_upload_mode)
997
0
    {
998
      // clear request queues of all peers
999
0
      for (auto p : m_connections)
1000
0
      {
1001
0
        TORRENT_INCREMENT(m_iterating_connections);
1002
        // we may want to disconnect other upload-only peers
1003
0
        if (p->upload_only())
1004
0
          p->update_interest();
1005
0
        p->cancel_all_requests();
1006
0
      }
1007
      // this is used to try leaving upload only mode periodically
1008
0
      m_upload_mode_time = aux::time_now32();
1009
0
    }
1010
0
    else if (m_peer_list)
1011
0
    {
1012
      // reset last_connected, to force fast reconnect after leaving upload mode
1013
0
      for (auto pe : *m_peer_list)
1014
0
      {
1015
0
        pe->last_connected = 0;
1016
0
      }
1017
1018
      // send_block_requests on all peers
1019
0
      for (auto p : m_connections)
1020
0
      {
1021
0
        TORRENT_INCREMENT(m_iterating_connections);
1022
        // we may be interested now, or no longer interested
1023
0
        p->update_interest();
1024
0
        p->send_block_requests();
1025
0
      }
1026
0
    }
1027
0
  }
1028
1029
  void torrent::need_peer_list()
1030
640
  {
1031
640
    if (m_peer_list) return;
1032
1
    m_peer_list = std::make_unique<peer_list>(m_ses.get_peer_allocator());
1033
1
  }
1034
1035
  void torrent::handle_exception()
1036
0
  {
1037
0
    try
1038
0
    {
1039
0
      throw;
1040
0
    }
1041
0
    catch (system_error const& err)
1042
0
    {
1043
#ifndef TORRENT_DISABLE_LOGGING
1044
      if (should_log())
1045
      {
1046
        debug_log("torrent exception: (%d) %s: %s"
1047
          , err.code().value(), err.code().message().c_str()
1048
          , err.what());
1049
      }
1050
#endif
1051
0
      set_error(err.code(), torrent_status::error_file_exception);
1052
0
    }
1053
0
    catch (std::exception const& err)
1054
0
    {
1055
0
      TORRENT_UNUSED(err);
1056
0
      set_error(error_code(), torrent_status::error_file_exception);
1057
#ifndef TORRENT_DISABLE_LOGGING
1058
      if (should_log())
1059
      {
1060
        debug_log("torrent exception: %s", err.what());
1061
      }
1062
#endif
1063
0
    }
1064
0
    catch (...)
1065
0
    {
1066
0
      set_error(error_code(), torrent_status::error_file_exception);
1067
#ifndef TORRENT_DISABLE_LOGGING
1068
      if (should_log())
1069
      {
1070
        debug_log("torrent exception: unknown");
1071
      }
1072
#endif
1073
0
    }
1074
0
  }
1075
1076
  void torrent::handle_disk_error(string_view job_name
1077
    , storage_error const& error
1078
    , peer_connection* c
1079
    , disk_class rw)
1080
0
  {
1081
0
    TORRENT_UNUSED(job_name);
1082
0
    TORRENT_ASSERT(is_single_thread());
1083
0
    TORRENT_ASSERT(error);
1084
1085
#ifndef TORRENT_DISABLE_LOGGING
1086
    if (should_log())
1087
    {
1088
      debug_log("disk error: (%d) %s [%*s : %s] in file: %s"
1089
        , error.ec.value(), error.ec.message().c_str()
1090
        , int(job_name.size()), job_name.data()
1091
        , operation_name(error.operation)
1092
        , resolve_filename(error.file()).c_str());
1093
    }
1094
#endif
1095
1096
0
    if (error.ec == boost::system::errc::not_enough_memory)
1097
0
    {
1098
0
      if (alerts().should_post<file_error_alert>())
1099
0
        alerts().emplace_alert<file_error_alert>(error.ec
1100
0
          , resolve_filename(error.file()), error.operation, get_handle());
1101
0
      if (c) c->disconnect(errors::no_memory, error.operation);
1102
0
      return;
1103
0
    }
1104
1105
0
    if (error.ec == boost::asio::error::operation_aborted) return;
1106
1107
    // notify the user of the error
1108
0
    if (alerts().should_post<file_error_alert>())
1109
0
      alerts().emplace_alert<file_error_alert>(error.ec
1110
0
        , resolve_filename(error.file()), error.operation, get_handle());
1111
1112
    // if a write operation failed, and future writes are likely to
1113
    // fail, while reads may succeed, just set the torrent to upload mode
1114
    // if we make an incorrect assumption here, it's not the end of the
1115
    // world, if we ever issue a read request and it fails as well, we
1116
    // won't get in here and we'll actually end up pausing the torrent
1117
0
    if (rw == disk_class::write
1118
0
      && (error.ec == boost::system::errc::read_only_file_system
1119
0
      || error.ec == boost::system::errc::permission_denied
1120
0
      || error.ec == boost::system::errc::operation_not_permitted
1121
0
      || error.ec == boost::system::errc::no_space_on_device
1122
0
      || error.ec == boost::system::errc::file_too_large))
1123
0
    {
1124
      // if we failed to write, stop downloading and just
1125
      // keep seeding.
1126
      // TODO: 1 make this depend on the error and on the filesystem the
1127
      // files are being downloaded to. If the error is no_space_left_on_device
1128
      // and the filesystem doesn't support sparse files, only zero the priorities
1129
      // of the pieces that are at the tails of all files, leaving everything
1130
      // up to the highest written piece in each file
1131
0
      set_upload_mode(true);
1132
0
      return;
1133
0
    }
1134
1135
    // put the torrent in an error-state
1136
0
    set_error(error.ec, error.file());
1137
1138
    // if the error appears to be more serious than a full disk, just pause the torrent
1139
0
    pause();
1140
0
  }
1141
1142
  void torrent::handle_inconsistent_hashes(piece_index_t const piece)
1143
0
  {
1144
0
    auto const file_slices = torrent_file().map_block(piece, 0, 0);
1145
0
    file_index_t const file = file_slices.empty() ? torrent_status::error_file_none : file_slices[0].file_index;
1146
0
    set_error(errors::torrent_inconsistent_hashes, file);
1147
    // if this is a hybrid torrent, we may have marked some more pieces
1148
    // as "have" but not yet validated them against the v2 hashes. At
1149
    // this point, just assume we have no pieces
1150
0
    m_picker.reset();
1151
0
    m_hash_picker.reset();
1152
0
    m_file_progress.clear();
1153
0
    m_have_all = false;
1154
0
    update_gauge();
1155
0
    pause();
1156
0
  }
1157
1158
0
  void torrent::on_piece_fail_sync(piece_index_t const piece, piece_block) try
1159
0
  {
1160
0
    if (m_abort) return;
1161
1162
    // the user may have called force_recheck, which clears
1163
    // the piece picker
1164
0
    if (has_picker())
1165
0
    {
1166
      // unlock the piece and restore it, as if no block was
1167
      // ever downloaded for it.
1168
0
      m_picker->restore_piece(piece);
1169
0
    }
1170
1171
0
    update_gauge();
1172
    // some peers that previously was no longer interesting may
1173
    // now have become interesting, since we lack this one piece now.
1174
0
    for (auto i = begin(); i != end();)
1175
0
    {
1176
0
      peer_connection* p = *i;
1177
      // update_interest may disconnect the peer and
1178
      // invalidate the iterator
1179
0
      ++i;
1180
      // no need to do anything with peers that
1181
      // already are interested. Gaining a piece may
1182
      // only make uninteresting peers interesting again.
1183
0
      if (p->is_interesting()) continue;
1184
0
      p->update_interest();
1185
0
      if (!m_abort)
1186
0
      {
1187
0
        if (request_a_block(*this, *p))
1188
0
          inc_stats_counter(counters::hash_fail_piece_picks);
1189
0
        p->send_block_requests();
1190
0
      }
1191
0
    }
1192
0
  }
1193
0
  catch (...) { handle_exception(); }
1194
1195
  void torrent::on_disk_read_complete(disk_buffer_holder buffer
1196
    , storage_error const& se
1197
0
    , peer_request const&  r, std::shared_ptr<read_piece_struct> rp) try
1198
0
  {
1199
    // hold a reference until this function returns
1200
0
    TORRENT_ASSERT(is_single_thread());
1201
1202
0
    --rp->blocks_left;
1203
0
    if (se)
1204
0
    {
1205
0
      rp->fail = true;
1206
0
      rp->error = se.ec;
1207
0
      handle_disk_error("read", se);
1208
0
    }
1209
0
    else
1210
0
    {
1211
0
      std::memcpy(rp->piece_data.get() + r.start, buffer.data(), aux::numeric_cast<std::size_t>(r.length));
1212
0
    }
1213
1214
0
    if (rp->blocks_left == 0)
1215
0
    {
1216
0
      int size = m_torrent_file->piece_size(r.piece);
1217
0
      if (rp->fail)
1218
0
      {
1219
0
        m_ses.alerts().emplace_alert<read_piece_alert>(
1220
0
          get_handle(), r.piece, rp->error);
1221
0
      }
1222
0
      else
1223
0
      {
1224
0
        m_ses.alerts().emplace_alert<read_piece_alert>(
1225
0
          get_handle(), r.piece, rp->piece_data, size);
1226
0
      }
1227
0
    }
1228
0
  }
1229
0
  catch (...) { handle_exception(); }
1230
1231
  storage_mode_t torrent::storage_mode() const
1232
0
  { return storage_mode_t(m_storage_mode); }
1233
1234
  void torrent::clear_peers()
1235
0
  {
1236
0
    disconnect_all(error_code(), operation_t::unknown);
1237
0
    if (m_peer_list) m_peer_list->clear();
1238
0
  }
1239
1240
  void torrent::need_picker()
1241
8.42k
  {
1242
8.42k
    if (m_picker) return;
1243
1244
1.57k
    TORRENT_ASSERT(valid_metadata());
1245
1.57k
    TORRENT_ASSERT(m_connections_initialized);
1246
1247
1.57k
    INVARIANT_CHECK;
1248
1249
    // if we have all pieces we should not have a picker
1250
    // unless we're in suggest mode
1251
1.57k
    TORRENT_ASSERT(!m_have_all
1252
1.57k
      || settings().get_int(settings_pack::suggest_mode)
1253
1.57k
      == settings_pack::suggest_read_cache);
1254
1255
1.57k
    auto pp = std::make_unique<piece_picker>(m_torrent_file->total_size()
1256
1.57k
      , m_torrent_file->piece_length());
1257
1258
1.57k
    if (m_have_all) pp->we_have_all();
1259
1260
    // initialize the file progress too
1261
1.57k
    if (m_file_progress.empty())
1262
1.57k
      m_file_progress.init(*pp, m_torrent_file->files());
1263
1264
1.57k
    m_picker = std::move(pp);
1265
1266
1.57k
    update_gauge();
1267
1268
1.57k
    for (auto const p : m_connections)
1269
0
    {
1270
0
      TORRENT_INCREMENT(m_iterating_connections);
1271
0
      if (p->is_disconnecting()) continue;
1272
0
      peer_has(p->get_bitfield(), p);
1273
0
    }
1274
1.57k
  }
1275
1276
  void torrent::need_hash_picker()
1277
1.02k
  {
1278
1.02k
    if (m_hash_picker) return;
1279
1280
1
    TORRENT_ASSERT(valid_metadata());
1281
1
    TORRENT_ASSERT(m_connections_initialized);
1282
1283
    //INVARIANT_CHECK;
1284
1285
1
    m_hash_picker.reset(new hash_picker(m_torrent_file->orig_files()
1286
1
      , m_merkle_trees));
1287
1
  }
1288
1289
  struct piece_refcount
1290
  {
1291
    piece_refcount(piece_picker& p, piece_index_t piece)
1292
0
      : m_picker(p)
1293
0
      , m_piece(piece)
1294
0
    {
1295
0
      m_picker.inc_refcount(m_piece, nullptr);
1296
0
    }
1297
1298
    piece_refcount(piece_refcount const&) = delete;
1299
    piece_refcount& operator=(piece_refcount const&) = delete;
1300
1301
0
    void disarm() { m_armed = false; }
1302
1303
    ~piece_refcount()
1304
0
    {
1305
0
      if (m_armed)
1306
0
        m_picker.dec_refcount(m_piece, nullptr);
1307
0
    }
1308
1309
  private:
1310
    piece_picker& m_picker;
1311
    piece_index_t m_piece;
1312
    bool m_armed = true;
1313
  };
1314
1315
  void torrent::add_piece_async(piece_index_t const piece
1316
    , std::vector<char> data, add_piece_flags_t const flags)
1317
0
  {
1318
0
    TORRENT_ASSERT(is_single_thread());
1319
1320
    // make sure the piece index is correct
1321
0
    if (piece >= torrent_file().end_piece())
1322
0
      return;
1323
1324
    // make sure the piece size is correct
1325
0
    if (data.size() != std::size_t(m_torrent_file->piece_size(piece)))
1326
0
      return;
1327
1328
0
    add_piece(piece, data.data(), flags);
1329
0
  }
1330
1331
  // TODO: 3 there's some duplication between this function and
1332
  // peer_connection::incoming_piece(). is there a way to merge something?
1333
  void torrent::add_piece(piece_index_t const piece, char const* data
1334
    , add_piece_flags_t const flags)
1335
0
  {
1336
0
    TORRENT_ASSERT(is_single_thread());
1337
1338
    // make sure the piece index is correct
1339
0
    if (piece >= torrent_file().end_piece())
1340
0
      return;
1341
1342
0
    int const piece_size = m_torrent_file->piece_size(piece);
1343
0
    int const blocks_in_piece = (piece_size + block_size() - 1) / block_size();
1344
1345
0
    if (m_deleted) return;
1346
1347
    // avoid crash trying to access the picker when there is none
1348
0
    if (m_have_all && !has_picker()) return;
1349
1350
    // we don't support clobbering the piece picker while checking the
1351
    // files. We may end up having the same piece multiple times
1352
0
    TORRENT_ASSERT_PRECOND(state() != torrent_status::checking_files
1353
0
      && state() != torrent_status::checking_resume_data);
1354
0
    if (state() == torrent_status::checking_files
1355
0
      || state() == torrent_status::checking_resume_data)
1356
0
      return;
1357
1358
0
    need_picker();
1359
1360
0
    if (picker().have_piece(piece)
1361
0
      && !(flags & torrent_handle::overwrite_existing))
1362
0
      return;
1363
1364
0
    peer_request p;
1365
0
    p.piece = piece;
1366
0
    p.start = 0;
1367
0
    piece_refcount refcount{picker(), piece};
1368
0
    auto self = shared_from_this();
1369
0
    for (int i = 0; i < blocks_in_piece; ++i, p.start += block_size())
1370
0
    {
1371
0
      piece_block const block(piece, i);
1372
1373
0
      bool const finished = picker().is_finished(block);
1374
1375
      // if this block is already finished, only resume if we have the
1376
      // flag set to overwrite existing data.
1377
0
      if (!(flags & torrent_handle::overwrite_existing) && finished)
1378
0
        continue;
1379
1380
0
      bool const downloaded = picker().is_downloaded(block);
1381
1382
      // however, if the block is downloaded by not written to disk yet,
1383
      // we can't (easily) replace it. We would have to synchronize with
1384
      // the disk in a clear_piece() call. Instead, just ignore such
1385
      // blocks.
1386
0
      if (downloaded && !finished)
1387
0
        continue;
1388
1389
0
      p.length = std::min(piece_size - p.start, block_size());
1390
1391
0
      m_stats_counters.inc_stats_counter(counters::queued_write_bytes, p.length);
1392
1393
0
      disk_job_flags_t dflags{};
1394
1395
0
      auto const write_mode = settings().get_int(settings_pack::disk_io_write_mode);
1396
0
      if (write_mode == settings_pack::disable_os_cache)
1397
0
        dflags |= disk_interface::flush_piece | disk_interface::volatile_read;
1398
1399
0
      m_ses.disk_thread().async_write(m_storage, p, data + p.start, nullptr
1400
0
        , [self, p](storage_error const& error) { self->on_disk_write_complete(error, p); }
1401
0
        , dflags);
1402
1403
0
      bool const was_finished = picker().is_piece_finished(p.piece);
1404
0
      bool const multi = picker().num_peers(block) > 1;
1405
1406
0
      picker().mark_as_downloading(block, nullptr);
1407
0
      picker().mark_as_writing(block, nullptr);
1408
1409
0
      if (multi) cancel_block(block);
1410
1411
      // did we just finish the piece?
1412
      // this means all blocks are either written
1413
      // to disk or are in the disk write cache
1414
0
      if (picker().is_piece_finished(p.piece) && !was_finished)
1415
0
      {
1416
0
        verify_piece(p.piece);
1417
0
      }
1418
0
    }
1419
0
    m_ses.deferred_submit_jobs();
1420
    // if we don't have a picker anymore, we don't need to (and shouldn't)
1421
    // decrement the refcount
1422
0
    if (!m_picker)
1423
0
      refcount.disarm();
1424
0
  }
1425
1426
  void torrent::on_disk_write_complete(storage_error const& error
1427
0
    , peer_request const& p) try
1428
0
  {
1429
0
    TORRENT_ASSERT(is_single_thread());
1430
1431
0
    m_stats_counters.inc_stats_counter(counters::queued_write_bytes, -p.length);
1432
1433
//    std::fprintf(stderr, "torrent::on_disk_write_complete ret:%d piece:%d block:%d\n"
1434
//      , j->ret, j->piece, j->offset/0x4000);
1435
1436
0
    INVARIANT_CHECK;
1437
0
    if (m_abort) return;
1438
0
    piece_block const block_finished(p.piece, p.start / block_size());
1439
1440
0
    if (error)
1441
0
    {
1442
0
      handle_disk_error("write", error);
1443
0
      return;
1444
0
    }
1445
1446
0
    if (!has_picker()) return;
1447
1448
    // if we already have this block, just ignore it.
1449
    // this can happen if the same block is passed in through
1450
    // add_piece() multiple times
1451
0
    if (picker().is_finished(block_finished)) return;
1452
1453
0
    picker().mark_as_finished(block_finished, nullptr);
1454
0
    maybe_done_flushing();
1455
1456
0
    if (alerts().should_post<block_finished_alert>())
1457
0
    {
1458
0
      alerts().emplace_alert<block_finished_alert>(get_handle(),
1459
0
        tcp::endpoint(), peer_id(), block_finished.block_index
1460
0
        , block_finished.piece_index);
1461
0
    }
1462
0
  }
1463
0
  catch (...) { handle_exception(); }
1464
1465
  peer_request torrent::to_req(piece_block const& p) const
1466
188
  {
1467
188
    int const block_offset = p.block_index * block_size();
1468
188
    int const block = std::min(torrent_file().piece_size(
1469
188
      p.piece_index) - block_offset, block_size());
1470
188
    TORRENT_ASSERT(block > 0);
1471
188
    TORRENT_ASSERT(block <= block_size());
1472
1473
188
    peer_request r;
1474
188
    r.piece = p.piece_index;
1475
188
    r.start = block_offset;
1476
188
    r.length = block;
1477
188
    return r;
1478
188
  }
1479
1480
  std::string torrent::name() const
1481
28.8k
  {
1482
28.8k
    if (valid_metadata()) return m_torrent_file->name();
1483
0
    if (m_name) return *m_name;
1484
0
    return "";
1485
0
  }
1486
1487
#ifndef TORRENT_DISABLE_EXTENSIONS
1488
1489
  void torrent::add_extension(std::shared_ptr<torrent_plugin> ext)
1490
5.64k
  {
1491
5.64k
    m_extensions.push_back(std::move(ext));
1492
5.64k
    auto& ext_ref = m_extensions.back();
1493
1494
5.64k
    for (auto p : m_connections)
1495
0
    {
1496
0
      TORRENT_INCREMENT(m_iterating_connections);
1497
0
      std::shared_ptr<peer_plugin> pp(ext_ref->new_connection(peer_connection_handle(p->self())));
1498
0
      if (pp) p->add_extension(std::move(pp));
1499
0
    }
1500
1501
    // if files are checked for this torrent, call the extension
1502
    // to let it initialize itself
1503
5.64k
    if (m_connections_initialized)
1504
5.64k
      ext_ref->on_files_checked();
1505
5.64k
  }
1506
1507
  void torrent::remove_extension(std::shared_ptr<torrent_plugin> ext)
1508
0
  {
1509
0
    auto const i = std::find(m_extensions.begin(), m_extensions.end(), ext);
1510
0
    if (i == m_extensions.end()) return;
1511
0
    m_extensions.erase(i);
1512
0
  }
1513
1514
  void torrent::add_extension_fun(std::function<std::shared_ptr<torrent_plugin>(torrent_handle const&, client_data_t)> const& ext
1515
    , client_data_t userdata)
1516
0
  {
1517
0
    std::shared_ptr<torrent_plugin> tp(ext(get_handle(), userdata));
1518
0
    if (!tp) return;
1519
1520
0
    add_extension(std::move(tp));
1521
0
  }
1522
1523
#endif
1524
1525
#ifdef TORRENT_SSL_PEERS
1526
  bool torrent::verify_peer_cert(bool const preverified, ssl::verify_context& ctx)
1527
0
  {
1528
    // if the cert wasn't signed by the correct CA, fail the verification
1529
0
    if (!preverified) return false;
1530
1531
0
    std::string expected = m_torrent_file->name();
1532
#ifndef TORRENT_DISABLE_LOGGING
1533
    std::string names;
1534
    bool match = false;
1535
#endif
1536
1537
0
#ifdef TORRENT_USE_OPENSSL
1538
0
#ifdef __clang__
1539
0
#pragma clang diagnostic push
1540
0
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
1541
0
#pragma clang diagnostic ignored "-Wused-but-marked-unused"
1542
0
#pragma clang diagnostic ignored "-Wold-style-cast"
1543
0
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
1544
0
#endif
1545
    // we're only interested in checking the certificate at the end of the chain.
1546
    // any certificate that isn't the leaf (i.e. the one presented by the peer)
1547
    // should be accepted automatically, given preverified is true. The leaf certificate
1548
    // need to be verified to make sure its DN matches the info-hash
1549
0
    int depth = X509_STORE_CTX_get_error_depth(ctx.native_handle());
1550
0
    if (depth > 0) return true;
1551
1552
0
    X509* cert = X509_STORE_CTX_get_current_cert(ctx.native_handle());
1553
1554
    // Go through the alternate names in the certificate looking for matching DNS entries
1555
0
    auto* gens = static_cast<GENERAL_NAMES*>(
1556
0
      X509_get_ext_d2i(cert, NID_subject_alt_name, nullptr, nullptr));
1557
1558
0
    for (int i = 0; i < sk_GENERAL_NAME_num(gens); ++i)
1559
0
    {
1560
0
      GENERAL_NAME* gen = sk_GENERAL_NAME_value(gens, i);
1561
0
      if (gen->type != GEN_DNS) continue;
1562
0
      ASN1_IA5STRING* domain = gen->d.dNSName;
1563
0
      if (domain->type != V_ASN1_IA5STRING || !domain->data || !domain->length) continue;
1564
0
      auto const* torrent_name = reinterpret_cast<char const*>(domain->data);
1565
0
      auto const name_length = aux::numeric_cast<std::size_t>(domain->length);
1566
1567
#ifndef TORRENT_DISABLE_LOGGING
1568
      if (i > 1) names += " | n: ";
1569
      names.append(torrent_name, name_length);
1570
#endif
1571
0
      if (std::strncmp(torrent_name, "*", name_length) == 0
1572
0
        || std::strncmp(torrent_name, expected.c_str(), name_length) == 0)
1573
0
      {
1574
#ifndef TORRENT_DISABLE_LOGGING
1575
        match = true;
1576
        // if we're logging, keep looping over all names,
1577
        // for completeness of the log
1578
        continue;
1579
#else
1580
0
        return true;
1581
0
#endif
1582
0
      }
1583
0
    }
1584
1585
    // no match in the alternate names, so try the common names. We should only
1586
    // use the "most specific" common name, which is the last one in the list.
1587
0
    X509_NAME* name = X509_get_subject_name(cert);
1588
0
    int i = -1;
1589
0
    ASN1_STRING* common_name = nullptr;
1590
0
    while ((i = X509_NAME_get_index_by_NID(name, NID_commonName, i)) >= 0)
1591
0
    {
1592
0
      X509_NAME_ENTRY* name_entry = X509_NAME_get_entry(name, i);
1593
0
      common_name = X509_NAME_ENTRY_get_data(name_entry);
1594
0
    }
1595
0
    if (common_name && common_name->data && common_name->length)
1596
0
    {
1597
0
      auto const* torrent_name = reinterpret_cast<char const*>(common_name->data);
1598
0
      auto const name_length = aux::numeric_cast<std::size_t>(common_name->length);
1599
1600
#ifndef TORRENT_DISABLE_LOGGING
1601
      if (!names.empty()) names += " | n: ";
1602
      names.append(torrent_name, name_length);
1603
#endif
1604
0
      if (std::strncmp(torrent_name, "*", name_length) == 0
1605
0
        || std::strncmp(torrent_name, expected.c_str(), name_length) == 0)
1606
0
      {
1607
0
#ifdef TORRENT_DISABLE_LOGGING
1608
0
        return true;
1609
#else
1610
        match = true;
1611
#endif
1612
1613
0
      }
1614
0
    }
1615
0
#ifdef __clang__
1616
0
#pragma clang diagnostic pop
1617
0
#endif
1618
1619
#elif defined TORRENT_USE_GNUTLS
1620
    gnutls_x509_crt_t cert = ctx.native_handle();
1621
1622
    // We don't use gnutls_x509_crt_check_hostname()
1623
    // as it doesn't handle wildcards the way we need here
1624
1625
    char buf[256];
1626
    unsigned int seq = 0;
1627
    while(true) {
1628
      size_t len = sizeof(buf);
1629
      int ret = gnutls_x509_crt_get_subject_alt_name(cert, seq, buf, &len, nullptr);
1630
      if(ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE) break;
1631
      if(ret == GNUTLS_E_SUCCESS)
1632
      {
1633
#ifndef TORRENT_DISABLE_LOGGING
1634
        if (!names.empty()) names += " | n: ";
1635
        names.append(buf, len);
1636
#endif
1637
        if (std::strncmp(buf, "*", len) == 0
1638
          || std::strncmp(buf, expected.c_str(), len) == 0)
1639
        {
1640
#ifndef TORRENT_DISABLE_LOGGING
1641
          match = true;
1642
          continue;
1643
#else
1644
          return true;
1645
#endif
1646
        }
1647
      }
1648
      ++seq;
1649
    }
1650
1651
    // no match in the alternate names, so try the common name
1652
    size_t len = sizeof(buf);
1653
    int ret = gnutls_x509_crt_get_dn_by_oid(cert, GNUTLS_OID_X520_COMMON_NAME, 0, 0, buf, &len);
1654
    if(ret == GNUTLS_E_SUCCESS)
1655
    {
1656
#ifndef TORRENT_DISABLE_LOGGING
1657
      if (!names.empty()) names += " | n: ";
1658
      names.append(buf, len);
1659
#endif
1660
      if (std::strncmp(buf, "*", len) == 0
1661
        || std::strncmp(buf, expected.c_str(), len) == 0)
1662
      {
1663
#ifdef TORRENT_DISABLE_LOGGING
1664
        return true;
1665
#else
1666
        match = true;
1667
#endif
1668
      }
1669
    }
1670
#endif // TORRENT_USE_GNUTLS
1671
1672
#ifndef TORRENT_DISABLE_LOGGING
1673
    debug_log("<== incoming SSL CONNECTION [ n: %s | match: %s ]"
1674
      , names.c_str(), match?"yes":"no");
1675
    return match;
1676
#else
1677
0
    return false;
1678
0
#endif
1679
0
  }
1680
1681
  void torrent::init_ssl(string_view cert)
1682
0
  {
1683
    // create the SSL context for this torrent. We need to
1684
    // inject the root certificate, and no other, to
1685
    // verify other peers against
1686
0
    std::unique_ptr<ssl::context> ctx(std::make_unique<ssl::context>(ssl::context::tls));
1687
1688
0
    ctx->set_options(ssl::context::default_workarounds
1689
0
      | ssl::context::no_sslv2
1690
0
      | ssl::context::no_sslv3
1691
0
      | ssl::context::single_dh_use);
1692
1693
0
    error_code ec;
1694
0
    ctx->set_verify_mode(ssl::context::verify_peer
1695
0
      | ssl::context::verify_fail_if_no_peer_cert
1696
0
      | ssl::context::verify_client_once, ec);
1697
0
    if (ec)
1698
0
    {
1699
0
      set_error(ec, torrent_status::error_file_ssl_ctx);
1700
0
      pause();
1701
0
      return;
1702
0
    }
1703
1704
    // the verification function verifies the distinguished name
1705
    // of a peer certificate to make sure it matches the info-hash
1706
    // of the torrent, or that it's a "star-cert"
1707
0
    ctx->set_verify_callback(
1708
0
        std::bind(&torrent::verify_peer_cert, this, _1, _2)
1709
0
        , ec);
1710
0
    if (ec)
1711
0
    {
1712
0
      set_error(ec, torrent_status::error_file_ssl_ctx);
1713
0
      pause();
1714
0
      return;
1715
0
    }
1716
1717
    // set the root certificate as trust
1718
0
    ssl::set_trust_certificate(ctx->native_handle(), cert, ec);
1719
0
    if (ec)
1720
0
    {
1721
0
      set_error(ec, torrent_status::error_file_ssl_ctx);
1722
0
      pause();
1723
0
      return;
1724
0
    }
1725
1726
#if 0
1727
    char filename[100];
1728
    std::snprintf(filename, sizeof(filename), "/tmp/%u.pem", random());
1729
    FILE* f = fopen(filename, "w+");
1730
    fwrite(cert.c_str(), cert.size(), 1, f);
1731
    fclose(f);
1732
    ctx->load_verify_file(filename);
1733
#endif
1734
1735
    // if all went well, set the torrent ssl context to this one
1736
0
    m_ssl_ctx = std::move(ctx);
1737
    // tell the client we need a cert for this torrent
1738
0
    alerts().emplace_alert<torrent_need_cert_alert>(get_handle());
1739
0
  }
1740
#endif // TORRENT_SSL_PEERS
1741
1742
  void torrent::construct_storage()
1743
1.88k
  {
1744
1.88k
    storage_params params{
1745
1.88k
      m_torrent_file->orig_files(),
1746
1.88k
      &m_torrent_file->orig_files() != &m_torrent_file->files()
1747
1.88k
        ? &m_torrent_file->files() : nullptr,
1748
1.88k
      m_save_path,
1749
1.88k
      static_cast<storage_mode_t>(m_storage_mode),
1750
1.88k
      m_file_priority,
1751
1.88k
      m_info_hash.get_best()
1752
1.88k
    };
1753
1754
    // the shared_from_this() will create an intentional
1755
    // cycle of ownership, se the hpp file for description.
1756
1.88k
    m_storage = m_ses.disk_thread().new_torrent(params, shared_from_this());
1757
1.88k
  }
1758
1759
  peer_connection* torrent::find_lowest_ranking_peer() const
1760
0
  {
1761
0
    auto lowest_rank = end();
1762
0
    for (auto i = begin(); i != end(); ++i)
1763
0
    {
1764
      // disconnecting peers don't count
1765
0
      if ((*i)->is_disconnecting()) continue;
1766
0
      if (lowest_rank == end() || (*lowest_rank)->peer_rank() > (*i)->peer_rank())
1767
0
        lowest_rank = i;
1768
0
    }
1769
1770
0
    if (lowest_rank == end()) return nullptr;
1771
0
    return *lowest_rank;
1772
0
  }
1773
1774
  // this may not be called from a constructor because of the call to
1775
  // shared_from_this(). It's either called when we start() the torrent, or at a
1776
  // later time if it's a magnet link, once the metadata is downloaded
1777
  void torrent::init()
1778
1.88k
  {
1779
1.88k
    INVARIANT_CHECK;
1780
1781
1.88k
    TORRENT_ASSERT(is_single_thread());
1782
1783
#ifndef TORRENT_DISABLE_LOGGING
1784
    debug_log("init torrent: %s", torrent_file().name().c_str());
1785
#endif
1786
1787
1.88k
    TORRENT_ASSERT(valid_metadata());
1788
1.88k
    TORRENT_ASSERT(m_torrent_file->num_files() > 0);
1789
1.88k
    TORRENT_ASSERT(m_torrent_file->total_size() >= 0);
1790
1791
1.88k
    if (int(m_file_priority.size()) > m_torrent_file->num_files())
1792
84
      m_file_priority.resize(m_torrent_file->num_files());
1793
1.79k
    else if (m_add_torrent_params->flags & torrent_flags::default_dont_download)
1794
398
      m_file_priority.resize(m_torrent_file->num_files(), dont_download);
1795
1796
1.88k
    auto cert = m_torrent_file->ssl_cert();
1797
1.88k
    if (!cert.empty())
1798
0
    {
1799
0
      m_ssl_torrent = true;
1800
0
#ifdef TORRENT_SSL_PEERS
1801
0
      init_ssl(cert);
1802
0
#endif
1803
0
    }
1804
1805
1.88k
    if (m_torrent_file->num_pieces() > piece_picker::max_pieces)
1806
0
    {
1807
0
      set_error(errors::too_many_pieces_in_torrent, torrent_status::error_file_none);
1808
0
      pause();
1809
0
      return;
1810
0
    }
1811
1812
1.88k
    if (m_torrent_file->num_pieces() == 0)
1813
0
    {
1814
0
      set_error(errors::torrent_invalid_length, torrent_status::error_file_none);
1815
0
      pause();
1816
0
      return;
1817
0
    }
1818
1819
1.88k
    int const blocks_per_piece
1820
1.88k
      = (m_torrent_file->piece_length() + default_block_size - 1) / default_block_size;
1821
1.88k
    if (blocks_per_piece > piece_picker::max_blocks_per_piece)
1822
0
    {
1823
0
      set_error(errors::invalid_piece_size, torrent_status::error_file_none);
1824
0
      pause();
1825
0
      return;
1826
0
    }
1827
1828
    // --- MAPPED FILES ---
1829
1.88k
    file_storage const& fs = m_torrent_file->files();
1830
1.88k
    if (m_add_torrent_params)
1831
1.88k
    {
1832
1.88k
      for (auto const& f : m_add_torrent_params->renamed_files)
1833
0
      {
1834
0
        if (f.first < file_index_t(0) || f.first >= fs.end_file()) continue;
1835
0
        m_torrent_file->rename_file(file_index_t(f.first), f.second);
1836
0
      }
1837
1.88k
    }
1838
1839
1.88k
    construct_storage();
1840
1841
1.88k
#ifndef TORRENT_DISABLE_SHARE_MODE
1842
1.88k
    if (m_share_mode && valid_metadata())
1843
643
    {
1844
      // in share mode, all pieces have their priorities initialized to 0
1845
643
      m_file_priority.clear();
1846
643
      m_file_priority.resize(m_torrent_file->num_files(), dont_download);
1847
643
    }
1848
1.88k
#endif
1849
1850
    // it's important to initialize the peers early, because this is what will
1851
    // fix up their have-bitmasks to have the correct size
1852
    // TODO: 2 add a unit test where we don't have metadata, connect to a peer
1853
    // that sends a bitfield that's too large, then we get the metadata
1854
1.88k
    if (!m_connections_initialized)
1855
0
    {
1856
0
      m_connections_initialized = true;
1857
      // all peer connections have to initialize themselves now that the metadata
1858
      // is available
1859
      // copy the peer list since peers may disconnect and invalidate
1860
      // m_connections as we initialize them
1861
0
      for (auto c : m_connections)
1862
0
      {
1863
0
        auto pc = c->self();
1864
0
        if (pc->is_disconnecting()) continue;
1865
0
        pc->on_metadata_impl();
1866
0
        if (pc->is_disconnecting()) continue;
1867
0
        pc->init();
1868
0
      }
1869
0
    }
1870
1871
    // in case file priorities were passed in via the add_torrent_params
1872
    // and also in the case of share mode, we need to update the priorities
1873
    // this has to be applied before piece priority
1874
1.88k
    if (!m_file_priority.empty())
1875
1.02k
    {
1876
      // m_file_priority was loaded from the resume data, this doesn't
1877
      // alter any state that needs to be saved in the resume data
1878
1.02k
      auto const ns = m_need_save_resume_data;
1879
1.02k
      update_piece_priorities(m_file_priority);
1880
1.02k
      m_need_save_resume_data = ns;
1881
1.02k
    }
1882
1883
1.88k
    if (m_add_torrent_params)
1884
1.88k
    {
1885
1.88k
      piece_index_t idx(0);
1886
1.88k
      if (m_add_torrent_params->piece_priorities.size() > std::size_t(m_torrent_file->num_pieces()))
1887
98
        m_add_torrent_params->piece_priorities.resize(std::size_t(m_torrent_file->num_pieces()));
1888
1889
1.88k
      for (auto prio : m_add_torrent_params->piece_priorities)
1890
1.54k
      {
1891
1.54k
        if (has_picker() || prio != default_priority)
1892
1.54k
        {
1893
1.54k
          need_picker();
1894
1.54k
          m_picker->set_piece_priority(idx, prio);
1895
1.54k
        }
1896
1.54k
        ++idx;
1897
1.54k
      }
1898
1.88k
      update_gauge();
1899
1.88k
    }
1900
1901
1.88k
    if (m_seed_mode)
1902
333
    {
1903
333
      m_have_all = true;
1904
333
      update_gauge();
1905
333
      update_state_list();
1906
333
      update_want_tick();
1907
333
    }
1908
1.54k
    else
1909
1.54k
    {
1910
1.54k
      need_picker();
1911
1912
1.54k
      TORRENT_ASSERT(block_size() > 0);
1913
1914
1.54k
      m_padding_bytes = 0;
1915
1.54k
      std::vector<piece_index_t> have_pieces;
1916
1917
1.54k
      aux::apply_pad_files(fs, [&](piece_index_t const piece, int const bytes)
1918
1.54k
      {
1919
0
        m_padding_bytes += bytes;
1920
0
        if (bytes == fs.piece_size(piece))
1921
0
          have_pieces.push_back(piece);
1922
0
        m_picker->set_pad_bytes(piece, bytes);
1923
0
      });
1924
1925
1.54k
      for (auto i : have_pieces)
1926
0
      {
1927
        // we may have this piece already, if we picked it up from
1928
        // resume data.
1929
0
        if (m_picker->have_piece(i)) continue;
1930
//        picker().piece_passed(i);
1931
//        TORRENT_ASSERT(picker().have_piece(i));
1932
0
        we_have(i);
1933
0
      }
1934
1.54k
    }
1935
1936
1.88k
    set_state(torrent_status::checking_resume_data);
1937
1938
1.88k
    aux::vector<std::string, file_index_t> links;
1939
1.88k
#ifndef TORRENT_DISABLE_MUTABLE_TORRENTS
1940
1.88k
    if (!m_torrent_file->similar_torrents().empty()
1941
1.88k
      || !m_torrent_file->collections().empty())
1942
0
    {
1943
0
      resolve_links res(m_torrent_file);
1944
1945
0
      for (auto const& ih : m_torrent_file->similar_torrents())
1946
0
      {
1947
0
        std::shared_ptr<torrent> t = m_ses.find_torrent(info_hash_t(ih)).lock();
1948
0
        if (!t) continue;
1949
1950
        // Only attempt to reuse files from torrents that are seeding.
1951
        // TODO: this could be optimized by looking up which files are
1952
        // complete and just look at those
1953
0
        if (!t->is_seed()) continue;
1954
1955
0
        res.match(t->get_torrent_file(), t->save_path());
1956
0
      }
1957
0
      for (auto const& c : m_torrent_file->collections())
1958
0
      {
1959
0
        std::vector<std::shared_ptr<torrent>> ts = m_ses.find_collection(c);
1960
1961
0
        for (auto const& t : ts)
1962
0
        {
1963
          // Only attempt to reuse files from torrents that are seeding.
1964
          // TODO: this could be optimized by looking up which files are
1965
          // complete and just look at those
1966
0
          if (!t->is_seed()) continue;
1967
1968
0
          res.match(t->get_torrent_file(), t->save_path());
1969
0
        }
1970
0
      }
1971
1972
0
      std::vector<resolve_links::link_t> const& l = res.get_links();
1973
0
      if (!l.empty())
1974
0
      {
1975
0
        links.resize(m_torrent_file->files().num_files());
1976
0
        for (auto const& i : l)
1977
0
        {
1978
0
          if (!i.ti) continue;
1979
0
          links[i.file_idx] = combine_path(i.save_path
1980
0
            , i.ti->files().file_path(i.file_idx));
1981
0
        }
1982
0
      }
1983
0
    }
1984
1.88k
#endif // TORRENT_DISABLE_MUTABLE_TORRENTS
1985
1986
1.88k
#if TORRENT_USE_ASSERTS
1987
1.88k
    TORRENT_ASSERT(m_outstanding_check_files == false);
1988
1.88k
    m_outstanding_check_files = true;
1989
1.88k
#endif
1990
1991
1.88k
    if (!m_add_torrent_params || !(m_add_torrent_params->flags & torrent_flags::no_verify_files))
1992
806
    {
1993
806
      m_ses.disk_thread().async_check_files(
1994
806
        m_storage, m_add_torrent_params ? m_add_torrent_params.get() : nullptr
1995
806
        , std::move(links), [self = shared_from_this()](status_t st, storage_error const& error)
1996
806
        { self->on_resume_data_checked(st, error); });
1997
#ifndef TORRENT_DISABLE_LOGGING
1998
      debug_log("init, async_check_files");
1999
#endif
2000
806
      m_ses.deferred_submit_jobs();
2001
806
    }
2002
1.07k
    else
2003
1.07k
    {
2004
1.07k
      on_resume_data_checked(status_t::no_error, storage_error{});
2005
1.07k
    }
2006
2007
1.88k
    update_want_peers();
2008
1.88k
    update_want_tick();
2009
2010
    // this will remove the piece picker, if we're done with it
2011
1.88k
    maybe_done_flushing();
2012
2013
1.88k
    m_torrent_initialized = true;
2014
1.88k
  }
2015
2016
  bt_peer_connection* torrent::find_introducer(tcp::endpoint const& ep) const
2017
0
  {
2018
0
#ifndef TORRENT_DISABLE_EXTENSIONS
2019
0
    for (auto pe : m_connections)
2020
0
    {
2021
0
      TORRENT_INCREMENT(m_iterating_connections);
2022
0
      if (pe->type() != connection_type::bittorrent) continue;
2023
0
      auto* p = static_cast<bt_peer_connection*>(pe);
2024
0
      if (!p->supports_holepunch()) continue;
2025
0
      if (p->was_introduced_by(ep)) return p;
2026
0
    }
2027
#else
2028
    TORRENT_UNUSED(ep);
2029
#endif
2030
0
    return nullptr;
2031
0
  }
2032
2033
  bt_peer_connection* torrent::find_peer(tcp::endpoint const& ep) const
2034
0
  {
2035
0
    for (auto p : m_connections)
2036
0
    {
2037
0
      TORRENT_INCREMENT(m_iterating_connections);
2038
0
      if (p->type() != connection_type::bittorrent) continue;
2039
0
      if (p->remote() == ep) return static_cast<bt_peer_connection*>(p);
2040
0
    }
2041
0
    return nullptr;
2042
0
  }
2043
2044
  peer_connection* torrent::find_peer(peer_id const& pid)
2045
282
  {
2046
282
    for (auto p : m_connections)
2047
282
    {
2048
282
      if (p->pid() == pid) return p;
2049
282
    }
2050
282
    return nullptr;
2051
282
  }
2052
2053
  bool torrent::is_self_connection(peer_id const& pid) const
2054
282
  {
2055
282
    return m_outgoing_pids.count(pid) > 0;
2056
282
  }
2057
2058
  void torrent::on_resume_data_checked(status_t status
2059
2.95k
    , storage_error const& error) try
2060
2.95k
  {
2061
2.95k
#if TORRENT_USE_ASSERTS
2062
2.95k
    TORRENT_ASSERT(m_outstanding_check_files);
2063
2.95k
    m_outstanding_check_files = false;
2064
2.95k
#endif
2065
2066
    // when applying some of the resume data to the torrent, we will
2067
    // trigger calls that set m_need_save_resume_data, even though we're
2068
    // just applying the state of the resume data we loaded with. We don't
2069
    // want anything in this function to affect the state of
2070
    // m_need_save_resume_data, so we save it in a local variable and reset
2071
    // it at the end of the function.
2072
2.95k
    auto const need_save_resume_data = m_need_save_resume_data;
2073
2074
2.95k
    TORRENT_ASSERT(is_single_thread());
2075
2076
2.95k
    if (m_abort) return;
2077
2078
2.15k
    if ((status & status_t::oversized_file) != status_t{})
2079
0
    {
2080
      // clear the flag
2081
0
      status = status & ~status_t::oversized_file;
2082
0
      if (m_ses.alerts().should_post<oversized_file_alert>())
2083
0
        m_ses.alerts().emplace_alert<oversized_file_alert>(get_handle());
2084
0
    }
2085
2086
2.15k
    if (status == status_t::fatal_disk_error)
2087
0
    {
2088
0
      TORRENT_ASSERT(m_outstanding_check_files == false);
2089
0
      handle_disk_error("check_resume_data", error);
2090
0
      auto_managed(false);
2091
0
      pause();
2092
0
    }
2093
2094
2.15k
    state_updated();
2095
2096
2.15k
    if (m_add_torrent_params)
2097
1.07k
    {
2098
      // --- PEERS ---
2099
2100
1.07k
      for (auto const& p : m_add_torrent_params->peers)
2101
0
      {
2102
0
        add_peer(p , peer_info::resume_data);
2103
0
      }
2104
2105
#ifndef TORRENT_DISABLE_LOGGING
2106
      if (should_log() && !m_add_torrent_params->peers.empty())
2107
      {
2108
        std::string str;
2109
        for (auto const& peer : m_add_torrent_params->peers)
2110
        {
2111
          str += peer.address().to_string();
2112
          str += ' ';
2113
        }
2114
        debug_log("resume-checked add_peer() [ %s] connect-candidates: %d"
2115
          , str.c_str(), m_peer_list
2116
          ? m_peer_list->num_connect_candidates() : -1);
2117
      }
2118
#endif
2119
2120
1.07k
      for (auto const& p : m_add_torrent_params->banned_peers)
2121
0
      {
2122
0
        torrent_peer* peer = add_peer(p, peer_info::resume_data);
2123
0
        if (peer) ban_peer(peer);
2124
0
      }
2125
2126
1.07k
      if (!m_add_torrent_params->peers.empty()
2127
1.07k
        || !m_add_torrent_params->banned_peers.empty())
2128
0
      {
2129
0
        update_want_peers();
2130
0
      }
2131
2132
#ifndef TORRENT_DISABLE_LOGGING
2133
      if (m_peer_list && m_peer_list->num_peers() > 0)
2134
        debug_log("resume added peers (total peers: %d)"
2135
          , m_peer_list->num_peers());
2136
#endif
2137
1.07k
    }
2138
2139
    // only report this error if the user actually provided resume data
2140
    // (i.e. m_add_torrent_params->have_pieces)
2141
2.15k
    if ((error || status != status_t::no_error)
2142
2.15k
      && m_add_torrent_params
2143
2.15k
      && aux::contains_resume_data(*m_add_torrent_params)
2144
2.15k
      && m_ses.alerts().should_post<fastresume_rejected_alert>())
2145
0
    {
2146
0
      m_ses.alerts().emplace_alert<fastresume_rejected_alert>(get_handle()
2147
0
        , error.ec
2148
0
        , resolve_filename(error.file())
2149
0
        , error.operation);
2150
0
    }
2151
2152
#ifndef TORRENT_DISABLE_LOGGING
2153
    if (should_log())
2154
    {
2155
      if (status != status_t::no_error || error)
2156
      {
2157
        debug_log("fastresume data rejected: ret: %d (%d) op: %s file: %d %s"
2158
          , static_cast<int>(status), error.ec.value()
2159
          , operation_name(error.operation)
2160
          , static_cast<int>(error.file())
2161
          , error.ec.message().c_str());
2162
      }
2163
      else
2164
      {
2165
        debug_log("fastresume data accepted");
2166
      }
2167
    }
2168
#endif
2169
2170
2.15k
    bool should_start_full_check = (status != status_t::no_error);
2171
2172
    // if we got a partial pieces bitfield, it means we were in the middle of
2173
    // checking this torrent. pick it up where we left off
2174
2.15k
    if (status == status_t::no_error
2175
2.15k
      && m_add_torrent_params
2176
2.15k
      && !m_add_torrent_params->have_pieces.empty()
2177
2.15k
      && m_add_torrent_params->have_pieces.size() < m_torrent_file->num_pieces())
2178
156
    {
2179
156
      m_checking_piece = m_num_checked_pieces
2180
156
        = m_add_torrent_params->have_pieces.end_index();
2181
156
      should_start_full_check = true;
2182
156
    }
2183
2184
    // if ret != 0, it means we need a full check. We don't necessarily need
2185
    // that when the resume data check fails. For instance, if the resume data
2186
    // is incorrect, but we don't have any files, we skip the check and initialize
2187
    // the storage to not have anything.
2188
2.15k
    if (status == status_t::no_error)
2189
1.07k
    {
2190
      // there are either no files for this torrent
2191
      // or the resume_data was accepted
2192
2193
1.07k
      if (m_seed_mode)
2194
179
      {
2195
179
        m_have_all = true;
2196
179
        update_gauge();
2197
179
        update_state_list();
2198
2199
179
        if (!error && m_add_torrent_params)
2200
179
        {
2201
179
          int const num_pieces2 = std::min(m_add_torrent_params->verified_pieces.size()
2202
179
            , torrent_file().num_pieces());
2203
179
          for (piece_index_t i = piece_index_t(0);
2204
432
            i < piece_index_t(num_pieces2); ++i)
2205
253
          {
2206
253
            if (!m_add_torrent_params->verified_pieces[i]) continue;
2207
68
            m_verified.set_bit(i);
2208
68
          }
2209
179
        }
2210
179
      }
2211
897
      else if (!error && m_add_torrent_params)
2212
897
      {
2213
        // --- PIECES ---
2214
2215
897
        int const num_pieces = std::min(m_add_torrent_params->have_pieces.size()
2216
897
          , torrent_file().num_pieces());
2217
2.12k
        for (piece_index_t i = piece_index_t(0); i < piece_index_t(num_pieces); ++i)
2218
1.22k
        {
2219
1.22k
          if (!m_add_torrent_params->have_pieces[i]) continue;
2220
663
          need_picker();
2221
663
          m_picker->piece_flushed(i);
2222
663
          inc_stats_counter(counters::num_piece_passed);
2223
663
          update_gauge();
2224
663
          we_have(i, true);
2225
663
        }
2226
2227
        // --- UNFINISHED PIECES ---
2228
2229
897
        int const num_blocks_per_piece = torrent_file().blocks_per_piece();
2230
2231
897
        for (auto const& p : m_add_torrent_params->unfinished_pieces)
2232
1.43k
        {
2233
1.43k
          piece_index_t const piece = p.first;
2234
1.43k
          bitfield const& blocks = p.second;
2235
2236
1.43k
          if (piece < piece_index_t(0) || piece >= torrent_file().end_piece())
2237
647
          {
2238
647
            continue;
2239
647
          }
2240
2241
784
          if (have_piece(piece))
2242
34
            continue;
2243
2244
          // being in seed mode and missing a piece is not compatible.
2245
          // Leave seed mode if that happens
2246
750
          if (m_seed_mode) leave_seed_mode(seed_mode_t::skip_checking);
2247
2248
750
          if (has_picker() && m_picker->have_piece(piece))
2249
0
          {
2250
0
            m_picker->we_dont_have(piece);
2251
0
            update_gauge();
2252
0
          }
2253
2254
750
          need_picker();
2255
2256
750
          const int num_bits = std::min(num_blocks_per_piece, int(blocks.size()));
2257
8.39k
          for (int k = 0; k < num_bits; ++k)
2258
7.64k
          {
2259
7.64k
            if (blocks.get_bit(k))
2260
6.19k
            {
2261
6.19k
              m_picker->mark_as_finished(piece_block(piece, k), nullptr);
2262
6.19k
            }
2263
7.64k
          }
2264
750
          if (m_picker->is_piece_finished(piece))
2265
0
          {
2266
0
            verify_piece(piece);
2267
0
          }
2268
750
        }
2269
897
      }
2270
1.07k
    }
2271
1.07k
    else
2272
1.07k
    {
2273
1.07k
      m_seed_mode = false;
2274
      // either the fastresume data was rejected or there are
2275
      // some files
2276
1.07k
      m_have_all = false;
2277
1.07k
      update_gauge();
2278
1.07k
      update_state_list();
2279
1.07k
    }
2280
2281
2.15k
    if (should_start_full_check)
2282
156
    {
2283
156
      stop_announcing();
2284
156
      set_state(torrent_status::checking_files);
2285
156
      if (should_check_files()) start_checking();
2286
2287
      // start the checking right away (potentially)
2288
156
      m_ses.trigger_auto_manage();
2289
156
    }
2290
1.99k
    else
2291
1.99k
    {
2292
1.99k
      files_checked();
2293
1.99k
    }
2294
2295
    // this will remove the piece picker, if we're done with it
2296
2.15k
    maybe_done_flushing();
2297
2.15k
    TORRENT_ASSERT(m_outstanding_check_files == false);
2298
2.15k
    m_add_torrent_params.reset();
2299
2300
    // restore m_need_save_resume_data to its state when we entered this
2301
    // function.
2302
2.15k
    m_need_save_resume_data = need_save_resume_data;
2303
2.15k
  }
2304
2.95k
  catch (...) { handle_exception(); }
2305
2306
  void torrent::force_recheck()
2307
0
  {
2308
0
    INVARIANT_CHECK;
2309
2310
0
    if (!valid_metadata()) return;
2311
2312
    // if the torrent is already queued to check its files
2313
    // don't do anything
2314
0
    if (should_check_files()
2315
0
      || m_state == torrent_status::checking_resume_data)
2316
0
      return;
2317
2318
0
    clear_error();
2319
2320
0
    disconnect_all(errors::stopping_torrent, operation_t::bittorrent);
2321
0
    stop_announcing();
2322
2323
    // we're checking everything anyway, no point in assuming we are a seed
2324
    // now.
2325
0
    leave_seed_mode(seed_mode_t::skip_checking);
2326
2327
    // forget that we have any pieces
2328
0
    m_have_all = false;
2329
2330
// removing the piece picker will clear the user priorities
2331
// instead, just clear which pieces we have
2332
0
    if (m_picker)
2333
0
    {
2334
0
      m_picker->resize(m_torrent_file->total_size(), m_torrent_file->piece_length());
2335
2336
0
      m_file_progress.clear();
2337
0
      m_file_progress.init(picker(), m_torrent_file->files());
2338
0
    }
2339
2340
    // assume that we don't have anything
2341
0
    m_files_checked = false;
2342
2343
0
    update_gauge();
2344
0
    update_want_tick();
2345
0
    set_state(torrent_status::checking_resume_data);
2346
2347
0
    set_queue_position(last_pos);
2348
2349
0
    TORRENT_ASSERT(m_outstanding_check_files == false);
2350
0
    m_add_torrent_params.reset();
2351
2352
    // this will clear the stat cache, to make us actually query the
2353
    // filesystem for files again
2354
0
    m_ses.disk_thread().async_release_files(m_storage);
2355
2356
0
    m_ses.disk_thread().async_check_files(m_storage, nullptr
2357
0
      , {}, [self = shared_from_this()](status_t st, storage_error const& error)
2358
0
      { self->on_force_recheck(st, error); });
2359
0
    m_ses.deferred_submit_jobs();
2360
0
  }
2361
2362
0
  void torrent::on_force_recheck(status_t status, storage_error const& error) try
2363
0
  {
2364
0
    TORRENT_ASSERT(is_single_thread());
2365
2366
    // hold a reference until this function returns
2367
0
    state_updated();
2368
2369
0
    if (m_abort) return;
2370
2371
0
    if ((status & status_t::oversized_file) != status_t{})
2372
0
    {
2373
      // clear the flag
2374
0
      status = status & ~status_t::oversized_file;
2375
0
      if (m_ses.alerts().should_post<oversized_file_alert>())
2376
0
        m_ses.alerts().emplace_alert<oversized_file_alert>(get_handle());
2377
0
    }
2378
2379
0
    if (error)
2380
0
    {
2381
0
      handle_disk_error("force_recheck", error);
2382
0
      return;
2383
0
    }
2384
0
    if (status == status_t::no_error)
2385
0
    {
2386
      // if there are no files, just start
2387
0
      files_checked();
2388
0
    }
2389
0
    else
2390
0
    {
2391
0
      m_progress_ppm = 0;
2392
0
      m_checking_piece = piece_index_t(0);
2393
0
      m_num_checked_pieces = piece_index_t(0);
2394
2395
0
      set_state(torrent_status::checking_files);
2396
0
      if (m_auto_managed) pause(torrent_handle::graceful_pause);
2397
0
      if (should_check_files()) start_checking();
2398
0
      else m_ses.trigger_auto_manage();
2399
0
    }
2400
0
  }
2401
0
  catch (...) { handle_exception(); }
2402
2403
242
  void torrent::start_checking() try
2404
242
  {
2405
242
    TORRENT_ASSERT(should_check_files());
2406
2407
242
    int num_outstanding = settings().get_int(settings_pack::checking_mem_usage) * block_size()
2408
242
      / m_torrent_file->piece_length();
2409
    // if we only keep a single read operation in-flight at a time, we suffer
2410
    // significant performance degradation. Always keep at least 4 jobs
2411
    // outstanding per hasher thread
2412
242
    int const min_outstanding
2413
242
      = std::max(1, settings().get_int(settings_pack::hashing_threads)) * 2;
2414
242
    if (num_outstanding < min_outstanding) num_outstanding = min_outstanding;
2415
2416
    // subtract the number of pieces we already have outstanding
2417
242
    num_outstanding -= (static_cast<int>(m_checking_piece)
2418
242
      - static_cast<int>(m_num_checked_pieces));
2419
242
    if (num_outstanding <= 0) return;
2420
2421
    // we might already have some outstanding jobs, if we were paused and
2422
    // resumed quickly, before the outstanding jobs completed
2423
242
    if (m_checking_piece >= m_torrent_file->end_piece())
2424
0
    {
2425
#ifndef TORRENT_DISABLE_LOGGING
2426
      debug_log("start_checking, checking_piece >= num_pieces. %d >= %d"
2427
        , static_cast<int>(m_checking_piece), m_torrent_file->num_pieces());
2428
#endif
2429
0
      return;
2430
0
    }
2431
2432
696
    for (int i = 0; i < num_outstanding; ++i)
2433
469
    {
2434
469
      if (has_picker())
2435
428
      {
2436
        // skip pieces we already have
2437
428
        while (m_checking_piece < m_torrent_file->end_piece()
2438
428
          && m_picker->have_piece(m_checking_piece))
2439
0
        {
2440
0
          ++m_checking_piece;
2441
0
          ++m_num_checked_pieces;
2442
0
        }
2443
428
      }
2444
2445
469
      if (m_checking_piece >= m_torrent_file->end_piece()) break;
2446
2447
469
      auto flags = disk_interface::sequential_access | disk_interface::volatile_read;
2448
469
      if (torrent_file().info_hashes().has_v1())
2449
469
        flags |= disk_interface::v1_hash;
2450
469
      aux::vector<sha256_hash> hashes;
2451
469
      if (torrent_file().info_hashes().has_v2())
2452
469
        hashes.resize(torrent_file().orig_files().blocks_in_piece2(m_checking_piece));
2453
2454
469
      span<sha256_hash> v2_span(hashes);
2455
469
      m_ses.disk_thread().async_hash(m_storage, m_checking_piece, v2_span, flags
2456
469
        , [self = shared_from_this(), hashes1 = std::move(hashes)]
2457
469
        (piece_index_t p, sha1_hash const& h, storage_error const& error) mutable
2458
469
        { self->on_piece_hashed(std::move(hashes1), p, h, error); });
2459
469
      ++m_checking_piece;
2460
469
      if (m_checking_piece >= m_torrent_file->end_piece()) break;
2461
469
    }
2462
242
    m_ses.deferred_submit_jobs();
2463
#ifndef TORRENT_DISABLE_LOGGING
2464
    debug_log("start_checking, m_checking_piece: %d"
2465
      , static_cast<int>(m_checking_piece));
2466
#endif
2467
242
  }
2468
242
  catch (...) { handle_exception(); }
2469
2470
  // This is only used for checking of torrents. i.e. force-recheck or initial checking
2471
  // of existing files
2472
  void torrent::on_piece_hashed(aux::vector<sha256_hash> block_hashes
2473
    , piece_index_t const piece, sha1_hash const& piece_hash
2474
469
    , storage_error const& error) try
2475
469
  {
2476
469
    TORRENT_ASSERT(is_single_thread());
2477
469
    INVARIANT_CHECK;
2478
2479
469
    if (m_abort) return;
2480
0
    if (m_deleted) return;
2481
2482
0
    state_updated();
2483
2484
0
    ++m_num_checked_pieces;
2485
2486
0
    if (error)
2487
0
    {
2488
0
      if (error.ec == boost::system::errc::no_such_file_or_directory
2489
0
        || error.ec == boost::asio::error::eof
2490
0
        || error.ec == lt::errors::file_too_short
2491
#ifdef TORRENT_WINDOWS
2492
        || error.ec == error_code(ERROR_HANDLE_EOF, system_category())
2493
#endif
2494
0
        )
2495
0
      {
2496
0
        TORRENT_ASSERT(error.file() >= file_index_t(0));
2497
2498
        // skip this file by updating m_checking_piece to the first piece following it
2499
0
        file_storage const& st = m_torrent_file->files();
2500
0
        std::int64_t file_size = st.file_size(error.file());
2501
0
        piece_index_t last = st.map_file(error.file(), file_size, 0).piece;
2502
0
        if (m_checking_piece < last)
2503
0
        {
2504
0
          int diff = static_cast<int>(last) - static_cast<int>(m_checking_piece);
2505
0
          m_num_checked_pieces = piece_index_t(static_cast<int>(m_num_checked_pieces) + diff);
2506
0
          m_checking_piece = last;
2507
0
        }
2508
0
      }
2509
0
      else
2510
0
      {
2511
0
        m_checking_piece = piece_index_t{0};
2512
0
        m_num_checked_pieces = piece_index_t{0};
2513
0
        if (m_ses.alerts().should_post<file_error_alert>())
2514
0
          m_ses.alerts().emplace_alert<file_error_alert>(error.ec,
2515
0
            resolve_filename(error.file()), error.operation, get_handle());
2516
2517
#ifndef TORRENT_DISABLE_LOGGING
2518
        if (should_log())
2519
        {
2520
          debug_log("on_piece_hashed, fatal disk error: (%d) %s", error.ec.value()
2521
            , error.ec.message().c_str());
2522
        }
2523
#endif
2524
0
        auto_managed(false);
2525
0
        pause();
2526
0
        set_error(error.ec, error.file());
2527
2528
        // recalculate auto-managed torrents sooner
2529
        // in order to start checking the next torrent
2530
0
        m_ses.trigger_auto_manage();
2531
0
        return;
2532
0
      }
2533
0
    }
2534
2535
0
    m_progress_ppm = std::uint32_t(std::int64_t(static_cast<int>(m_num_checked_pieces))
2536
0
      * 1000000 / torrent_file().num_pieces());
2537
2538
0
    boost::tribool hash_passed[2]
2539
0
      = { boost::indeterminate, boost::indeterminate };
2540
2541
0
    if (!settings().get_bool(settings_pack::disable_hash_checks))
2542
0
    {
2543
0
      if (torrent_file().info_hashes().has_v1())
2544
0
        hash_passed[0] = piece_hash == m_torrent_file->hash_for_piece(piece);
2545
2546
      // if the v1 hash failed the check, don't add the v2 hashes to the
2547
      // merkle tree. They are most likely invalid.
2548
0
      if (torrent_file().info_hashes().has_v2() && !bool(hash_passed[0] == false))
2549
0
      {
2550
0
        hash_passed[1] = on_blocks_hashed(piece, block_hashes);
2551
0
      }
2552
0
    }
2553
0
    else
2554
0
    {
2555
0
      hash_passed[0] = hash_passed[1] = true;
2556
0
    }
2557
2558
0
    if ((hash_passed[0] && !hash_passed[1]) || (!hash_passed[0] && hash_passed[1]))
2559
0
    {
2560
0
      handle_inconsistent_hashes(piece);
2561
0
      return;
2562
0
    }
2563
0
    else if (hash_passed[0] || hash_passed[1])
2564
0
    {
2565
0
      if (has_picker() || !m_have_all)
2566
0
      {
2567
0
        need_picker();
2568
0
        m_picker->piece_flushed(piece);
2569
0
        set_need_save_resume(torrent_handle::if_download_progress);
2570
0
        update_gauge();
2571
0
      }
2572
0
      we_have(piece);
2573
0
    }
2574
0
    else if (!error
2575
0
      && boost::indeterminate(hash_passed[0])
2576
0
      && boost::indeterminate(hash_passed[1]))
2577
0
    {
2578
      // The data exists but we don't have the hashes needed to verify
2579
      // it yet. This is a special case because we want to say we have
2580
      // the piece once the hash is verified and not download the data
2581
      // unless the hash check fails. To get this effect we setup the
2582
      // piece's state in the piece picker so that it looks like a piece
2583
      // which is finished but not hash checked.
2584
0
      need_picker();
2585
0
      int const blocks_in_piece = m_picker->blocks_in_piece(piece);
2586
0
      for (int i = 0; i < blocks_in_piece; ++i)
2587
0
        m_picker->mark_as_finished(piece_block(piece, i), nullptr);
2588
0
    }
2589
2590
0
    if (m_checking_piece < m_torrent_file->end_piece() && has_picker())
2591
0
    {
2592
      // skip pieces we already have
2593
0
      while (m_picker->have_piece(m_checking_piece))
2594
0
      {
2595
0
        ++m_checking_piece;
2596
0
        ++m_num_checked_pieces;
2597
0
        if (m_checking_piece >= m_torrent_file->end_piece())
2598
0
        {
2599
          // actually, we already have outstanding jobs for
2600
          // the remaining pieces. We just need to wait for them
2601
          // to finish
2602
0
          break;
2603
0
        }
2604
0
      }
2605
0
    }
2606
2607
0
    if (m_num_checked_pieces < m_torrent_file->end_piece())
2608
0
    {
2609
      // we paused the checking
2610
0
      if (!should_check_files())
2611
0
      {
2612
#ifndef TORRENT_DISABLE_LOGGING
2613
        debug_log("on_piece_hashed, checking paused");
2614
#endif
2615
0
        if (m_checking_piece == m_num_checked_pieces)
2616
0
        {
2617
          // we are paused, and we just completed the last outstanding job.
2618
          // now we can be considered paused
2619
0
          if (alerts().should_post<torrent_paused_alert>())
2620
0
            alerts().emplace_alert<torrent_paused_alert>(get_handle());
2621
0
        }
2622
0
        return;
2623
0
      }
2624
2625
0
      if (m_checking_piece >= m_torrent_file->end_piece())
2626
0
        return;
2627
2628
0
      auto flags = disk_interface::sequential_access | disk_interface::volatile_read;
2629
2630
0
      if (torrent_file().info_hashes().has_v1())
2631
0
        flags |= disk_interface::v1_hash;
2632
0
      if (torrent_file().info_hashes().has_v2())
2633
0
        block_hashes.resize(torrent_file().orig_files().blocks_in_piece2(m_checking_piece));
2634
2635
0
      span<sha256_hash> v2_span(block_hashes);
2636
0
      m_ses.disk_thread().async_hash(m_storage, m_checking_piece, v2_span, flags
2637
0
        , [self = shared_from_this(), hashes = std::move(block_hashes)]
2638
0
        (piece_index_t p, sha1_hash const& h, storage_error const& e)
2639
0
        { self->on_piece_hashed(std::move(hashes), p, h, e); });
2640
0
      ++m_checking_piece;
2641
0
      m_ses.deferred_submit_jobs();
2642
#ifndef TORRENT_DISABLE_LOGGING
2643
      debug_log("on_piece_hashed, m_checking_piece: %d"
2644
        , static_cast<int>(m_checking_piece));
2645
#endif
2646
0
      return;
2647
0
    }
2648
2649
#ifndef TORRENT_DISABLE_LOGGING
2650
    debug_log("on_piece_hashed, completed");
2651
#endif
2652
2653
0
    auto const& pack = settings();
2654
0
    auto get_int_setting = [&pack](int const name) {
2655
0
      int const v = pack.get_int(name);
2656
0
      if (v < 0) return std::numeric_limits<int>::max();
2657
0
      return v;
2658
0
    };
2659
0
    int const limit = std::min({
2660
0
      get_int_setting(settings_pack::active_downloads)
2661
0
      , get_int_setting(settings_pack::active_seeds)
2662
0
      , get_int_setting(settings_pack::active_limit)});
2663
0
    int const num_torrents = m_ses.num_torrents();
2664
0
    if (m_auto_managed && num_torrents > limit)
2665
0
    {
2666
      // if we're auto managed and we've reached one of the limits. Assume
2667
      // we need to be paused until the auto managed logic runs again
2668
      // (which is triggered further down)
2669
0
      set_paused(true);
2670
0
    }
2671
2672
    // we're done checking! (this should cause a call to trigger_auto_manage)
2673
0
    files_checked();
2674
2675
    // reset the checking state
2676
0
    m_checking_piece = piece_index_t(0);
2677
0
    m_num_checked_pieces = piece_index_t(0);
2678
0
  }
2679
469
  catch (...) { handle_exception(); }
2680
2681
#if TORRENT_ABI_VERSION == 1
2682
  void torrent::use_interface(std::string net_interfaces)
2683
0
  {
2684
0
    std::shared_ptr<settings_pack> p = std::make_shared<settings_pack>();
2685
0
    p->set_str(settings_pack::outgoing_interfaces, std::move(net_interfaces));
2686
0
    m_ses.apply_settings_pack(p);
2687
0
  }
2688
#endif
2689
2690
0
  void torrent::on_tracker_announce(error_code const& ec) try
2691
0
  {
2692
0
    COMPLETE_ASYNC("tracker::on_tracker_announce");
2693
0
    TORRENT_ASSERT(is_single_thread());
2694
0
    TORRENT_ASSERT(m_waiting_tracker > 0);
2695
0
    --m_waiting_tracker;
2696
0
    if (ec) return;
2697
0
    if (m_abort) return;
2698
0
    announce_with_tracker();
2699
0
  }
2700
0
  catch (...) { handle_exception(); }
2701
2702
  void torrent::lsd_announce()
2703
334
  {
2704
334
    if (m_abort) return;
2705
334
    if (!m_enable_lsd) return;
2706
2707
    // if the files haven't been checked yet, we're
2708
    // not ready for peers. Except, if we don't have metadata,
2709
    // we need peers to download from
2710
189
    if (!m_files_checked && valid_metadata()) return;
2711
2712
189
    if (!m_announce_to_lsd) return;
2713
2714
    // private torrents are never announced on LSD
2715
189
    if (m_torrent_file->is_valid() && m_torrent_file->priv()) return;
2716
2717
189
#if TORRENT_USE_I2P
2718
    // i2p torrents are also never announced on LSD
2719
    // unless we allow mixed swarms
2720
189
    if (is_i2p() && !settings().get_bool(settings_pack::allow_i2p_mixed))
2721
0
      return;
2722
189
#endif
2723
2724
189
    if (is_paused()) return;
2725
2726
189
    if (!m_ses.has_lsd()) return;
2727
2728
    // TODO: this pattern is repeated in a few places. Factor this into
2729
    // a function and generalize the concept of a torrent having a
2730
    // dedicated listen port
2731
0
#ifdef TORRENT_SSL_PEERS
2732
0
    int port = is_ssl_torrent() ? m_ses.ssl_listen_port() : m_ses.listen_port();
2733
#else
2734
    int port = m_ses.listen_port();
2735
#endif
2736
2737
    // announce with the local discovery service
2738
0
    m_torrent_file->info_hashes().for_each([&](sha1_hash const& ih, protocol_version)
2739
0
    {
2740
0
      m_ses.announce_lsd(ih, port);
2741
0
    });
2742
0
  }
2743
2744
#ifndef TORRENT_DISABLE_DHT
2745
2746
  void torrent::dht_announce()
2747
0
  {
2748
0
    TORRENT_ASSERT(is_single_thread());
2749
0
    if (!m_ses.dht())
2750
0
    {
2751
#ifndef TORRENT_DISABLE_LOGGING
2752
      debug_log("DHT: no dht initialized");
2753
#endif
2754
0
      return;
2755
0
    }
2756
0
    if (!should_announce_dht())
2757
0
    {
2758
#ifndef TORRENT_DISABLE_LOGGING
2759
      if (should_log())
2760
      {
2761
#if TORRENT_USE_I2P
2762
        if (is_i2p() && !settings().get_bool(settings_pack::allow_i2p_mixed))
2763
          debug_log("DHT: i2p torrent (and mixed peers not allowed)");
2764
#endif
2765
        if (!m_ses.announce_dht())
2766
          debug_log("DHT: no listen sockets");
2767
2768
        if (m_torrent_file->is_valid() && !m_files_checked)
2769
          debug_log("DHT: files not checked, skipping DHT announce");
2770
2771
        if (!m_announce_to_dht)
2772
          debug_log("DHT: queueing disabled DHT announce");
2773
2774
        if (m_paused)
2775
          debug_log("DHT: torrent paused, no DHT announce");
2776
2777
        if (!m_enable_dht)
2778
          debug_log("DHT: torrent has DHT disabled flag");
2779
2780
        if (m_torrent_file->is_valid() && m_torrent_file->priv())
2781
          debug_log("DHT: private torrent, no DHT announce");
2782
2783
        if (settings().get_bool(settings_pack::use_dht_as_fallback))
2784
        {
2785
          int const verified_trackers = static_cast<int>(std::count_if(
2786
            m_trackers.begin(), m_trackers.end()
2787
            , [](aux::announce_entry const& t) { return t.verified; }));
2788
2789
          if (verified_trackers > 0)
2790
            debug_log("DHT: only using DHT as fallback, and there are %d working trackers", verified_trackers);
2791
        }
2792
      }
2793
#endif
2794
0
      return;
2795
0
    }
2796
2797
0
    TORRENT_ASSERT(!m_paused);
2798
2799
#ifndef TORRENT_DISABLE_LOGGING
2800
    debug_log("START DHT announce");
2801
    m_dht_start_time = aux::time_now();
2802
#endif
2803
2804
    // if we're a seed, we tell the DHT for better scrape stats
2805
0
    dht::announce_flags_t flags = is_seed() ? dht::announce::seed : dht::announce_flags_t{};
2806
2807
    // If this is an SSL torrent the announce needs to specify an SSL
2808
    // listen port. DHT nodes only operate on non-SSL ports so SSL
2809
    // torrents cannot use implied_port.
2810
    // if we allow incoming uTP connections and don't overwrite
2811
    // the announced port, set the implied_port argument
2812
    // in the announce, this will make the DHT node use
2813
    // our source port in the packet as our listen port, which is
2814
    // likely more accurate when behind a NAT
2815
0
    const auto announce_port = std::uint16_t(settings().get_int(settings_pack::announce_port));
2816
0
    if (is_ssl_torrent())
2817
0
    {
2818
0
      flags |= dht::announce::ssl_torrent;
2819
0
    }
2820
0
    else if (!announce_port && settings().get_bool(settings_pack::enable_incoming_utp))
2821
0
    {
2822
0
      flags |= dht::announce::implied_port;
2823
0
    }
2824
2825
0
    std::weak_ptr<torrent> self(shared_from_this());
2826
0
    m_torrent_file->info_hashes().for_each([&](sha1_hash const& ih, protocol_version v)
2827
0
    {
2828
0
      m_ses.dht()->announce(ih, announce_port, flags
2829
0
        , std::bind(&torrent::on_dht_announce_response_disp, self, v, _1));
2830
0
    });
2831
0
  }
2832
2833
  void torrent::on_dht_announce_response_disp(std::weak_ptr<torrent> const t
2834
    , protocol_version const v, std::vector<tcp::endpoint> const& peers)
2835
0
  {
2836
0
    std::shared_ptr<torrent> tor = t.lock();
2837
0
    if (!tor) return;
2838
0
    tor->on_dht_announce_response(v, peers);
2839
0
  }
2840
2841
  void torrent::on_dht_announce_response(protocol_version const v
2842
0
    , std::vector<tcp::endpoint> const& peers) try
2843
0
  {
2844
0
    TORRENT_ASSERT(is_single_thread());
2845
2846
#ifndef TORRENT_DISABLE_LOGGING
2847
    debug_log("END DHT announce (%d ms) (%d peers)"
2848
      , int(total_milliseconds(clock_type::now() - m_dht_start_time))
2849
      , int(peers.size()));
2850
#endif
2851
2852
0
    if (m_abort) return;
2853
0
    if (peers.empty()) return;
2854
2855
0
    if (m_ses.alerts().should_post<dht_reply_alert>())
2856
0
    {
2857
0
      m_ses.alerts().emplace_alert<dht_reply_alert>(
2858
0
        get_handle(), int(peers.size()));
2859
0
    }
2860
2861
0
#if TORRENT_USE_I2P
2862
0
    if (is_i2p() && !settings().get_bool(settings_pack::allow_i2p_mixed)) return;
2863
0
#endif
2864
2865
0
    if (torrent_file().priv()) return;
2866
2867
0
    for (auto& p : peers)
2868
0
      add_peer(p, peer_info::dht, v == protocol_version::V2 ? pex_lt_v2 : pex_flags_t(0));
2869
2870
#ifndef TORRENT_DISABLE_LOGGING
2871
    if (should_log() && !peers.empty())
2872
    {
2873
      std::string str;
2874
      for (auto const& peer : peers)
2875
      {
2876
        str += peer.address().to_string();
2877
        str += ' ';
2878
      }
2879
      debug_log("DHT add_peer() [ %s] connect-candidates: %d"
2880
        , str.c_str(), m_peer_list
2881
        ? m_peer_list->num_connect_candidates() : -1);
2882
    }
2883
#endif
2884
2885
0
    do_connect_boost();
2886
2887
0
    update_want_peers();
2888
0
  }
2889
0
  catch (...) { handle_exception(); }
2890
2891
#endif
2892
2893
namespace {
2894
  void refresh_endpoint_list(aux::session_interface& ses
2895
    , std::string const& url
2896
    , bool const is_ssl, bool const complete_sent
2897
    , std::vector<aux::announce_endpoint>& aeps)
2898
0
  {
2899
0
#if TORRENT_USE_I2P
2900
0
    if (is_i2p_url(url))
2901
0
    {
2902
0
      if (aeps.size() > 1)
2903
0
      {
2904
0
        aeps.erase(aeps.begin() + 1, aeps.end());
2905
0
      }
2906
0
      else if (aeps.empty())
2907
0
      {
2908
0
        aeps.emplace_back(aux::listen_socket_handle(), complete_sent);
2909
0
      }
2910
0
      return;
2911
0
    }
2912
#else
2913
    TORRENT_UNUSED(url);
2914
#endif
2915
2916
    // update the endpoint list by adding entries for new listen sockets
2917
    // and removing entries for non-existent ones
2918
0
    std::size_t valid_endpoints = 0;
2919
0
    ses.for_each_listen_socket([&](aux::listen_socket_handle const& s) {
2920
0
      if (s.is_ssl() != is_ssl)
2921
0
        return;
2922
0
      for (auto& aep : aeps)
2923
0
      {
2924
0
        if (aep.socket != s) continue;
2925
0
        if (&aeps[valid_endpoints] != &aep) std::swap(aeps[valid_endpoints], aep);
2926
0
        valid_endpoints++;
2927
0
        return;
2928
0
      }
2929
2930
0
      aeps.emplace_back(s, complete_sent);
2931
0
      std::swap(aeps[valid_endpoints], aeps.back());
2932
0
      valid_endpoints++;
2933
0
    });
2934
2935
0
    TORRENT_ASSERT(valid_endpoints <= aeps.size());
2936
0
    aeps.erase(aeps.begin() + int(valid_endpoints), aeps.end());
2937
0
  }
2938
}
2939
2940
  namespace
2941
  {
2942
    struct announce_protocol_state
2943
    {
2944
      // the tier is kept as INT_MAX until we find the first
2945
      // tracker that works, then it's set to that tracker's
2946
      // tier.
2947
      int tier = INT_MAX;
2948
2949
      // have we sent an announce in this tier yet?
2950
      bool sent_announce = false;
2951
2952
      // have we finished sending announces on this listen socket?
2953
      bool done = false;
2954
    };
2955
2956
    struct announce_state
2957
    {
2958
      explicit announce_state(aux::listen_socket_handle s)
2959
0
        : socket(std::move(s)) {}
2960
2961
      aux::listen_socket_handle socket;
2962
2963
      aux::array<announce_protocol_state, num_protocols, protocol_version> state;
2964
    };
2965
  }
2966
2967
  void torrent::announce_with_tracker(event_t e)
2968
668
  {
2969
668
    TORRENT_ASSERT(is_single_thread());
2970
668
    TORRENT_ASSERT(e == event_t::stopped || state() != torrent_status::checking_files);
2971
668
    INVARIANT_CHECK;
2972
2973
668
    if (m_trackers.empty())
2974
668
    {
2975
#ifndef TORRENT_DISABLE_LOGGING
2976
      debug_log("*** announce: no trackers");
2977
#endif
2978
668
      return;
2979
668
    }
2980
2981
0
    if (m_abort) e = event_t::stopped;
2982
2983
    // having stop_tracker_timeout <= 0 means that there is
2984
    // no need to send any request to trackers or trigger any
2985
    // related logic when the event is stopped
2986
0
    if (e == event_t::stopped
2987
0
      && settings().get_int(settings_pack::stop_tracker_timeout) <= 0)
2988
0
    {
2989
#ifndef TORRENT_DISABLE_LOGGING
2990
      debug_log("*** announce: event == stopped && stop_tracker_timeout <= 0");
2991
#endif
2992
0
      return;
2993
0
    }
2994
2995
    // if we're not announcing to trackers, only allow
2996
    // stopping
2997
0
    if (e != event_t::stopped && !m_announce_to_trackers)
2998
0
    {
2999
#ifndef TORRENT_DISABLE_LOGGING
3000
      debug_log("*** announce: event != stopped && !m_announce_to_trackers");
3001
#endif
3002
0
      return;
3003
0
    }
3004
3005
    // if we're not allowing peers, there's no point in announcing
3006
0
    if (e != event_t::stopped && m_paused)
3007
0
    {
3008
#ifndef TORRENT_DISABLE_LOGGING
3009
      debug_log("*** announce: event != stopped && m_paused");
3010
#endif
3011
0
      return;
3012
0
    }
3013
3014
0
    TORRENT_ASSERT(!m_paused || e == event_t::stopped);
3015
3016
0
    if (e == event_t::none && is_finished() && !is_seed())
3017
0
      e = event_t::paused;
3018
3019
0
    tracker_request req;
3020
0
    if (settings().get_bool(settings_pack::apply_ip_filter_to_trackers)
3021
0
      && m_apply_ip_filter)
3022
0
    {
3023
0
      req.filter = m_ip_filter;
3024
0
    }
3025
3026
0
    req.private_torrent = m_torrent_file->priv();
3027
3028
0
    req.pid = m_peer_id;
3029
0
    req.downloaded = m_stat.total_payload_download() - m_total_failed_bytes;
3030
0
    req.uploaded = m_stat.total_payload_upload();
3031
0
    req.corrupt = m_total_failed_bytes;
3032
0
    req.left = value_or(bytes_left(), 16*1024);
3033
0
#ifdef TORRENT_SSL_PEERS
3034
    // if this torrent contains an SSL certificate, make sure
3035
    // any SSL tracker presents a certificate signed by it
3036
0
    req.ssl_ctx = m_ssl_ctx.get();
3037
0
#endif
3038
3039
0
    req.redundant = m_total_redundant_bytes;
3040
    // exclude redundant bytes if we should
3041
0
    if (!settings().get_bool(settings_pack::report_true_downloaded))
3042
0
    {
3043
0
      req.downloaded -= m_total_redundant_bytes;
3044
3045
      // if the torrent is complete we know that all incoming pieces will be
3046
      // marked redundant so add them to the redundant count
3047
      // this is mainly needed to cover the case where a torrent has just completed
3048
      // but still has partially downloaded pieces
3049
      // if the incoming pieces are not accounted for it could cause the downloaded
3050
      // amount to exceed the total size of the torrent which upsets some trackers
3051
0
      if (is_seed())
3052
0
      {
3053
0
        for (auto c : m_connections)
3054
0
        {
3055
0
          TORRENT_INCREMENT(m_iterating_connections);
3056
0
          auto const pbp = c->downloading_piece_progress();
3057
0
          if (pbp.bytes_downloaded > 0)
3058
0
          {
3059
0
            req.downloaded -= pbp.bytes_downloaded;
3060
0
            req.redundant += pbp.bytes_downloaded;
3061
0
          }
3062
0
        }
3063
0
      }
3064
0
    }
3065
0
    if (req.downloaded < 0) req.downloaded = 0;
3066
3067
0
    req.event = e;
3068
3069
    // since sending our IPv4/v6 address to the tracker may be sensitive. Only
3070
    // do that if we're not in anonymous mode and if it's a private torrent
3071
0
    if (!settings().get_bool(settings_pack::anonymous_mode)
3072
0
      && m_torrent_file
3073
0
      && m_torrent_file->priv())
3074
0
    {
3075
0
      m_ses.for_each_listen_socket([&](aux::listen_socket_handle const& s)
3076
0
      {
3077
0
        if (s.is_ssl() != is_ssl_torrent()) return;
3078
0
        tcp::endpoint const ep = s.get_local_endpoint();
3079
0
        if (ep.address().is_unspecified()) return;
3080
0
        if (aux::is_v6(ep))
3081
0
        {
3082
0
          if (!aux::is_local(ep.address()) && !ep.address().is_loopback())
3083
0
            req.ipv6.push_back(ep.address().to_v6());
3084
0
        }
3085
0
        else
3086
0
        {
3087
0
          if (!aux::is_local(ep.address()) && !ep.address().is_loopback())
3088
0
            req.ipv4.push_back(ep.address().to_v4());
3089
0
        }
3090
0
      });
3091
0
    }
3092
3093
    // if we are aborting. we don't want any new peers
3094
0
    req.num_want = (req.event == event_t::stopped)
3095
0
      ? 0 : settings().get_int(settings_pack::num_want);
3096
3097
// some older versions of clang had a bug where it would fire this warning here
3098
0
#ifdef __clang__
3099
0
#pragma clang diagnostic push
3100
0
#pragma clang diagnostic ignored "-Wmissing-braces"
3101
0
#endif
3102
0
    aux::array<bool const, num_protocols, protocol_version> const supports_protocol
3103
0
    { {
3104
0
      m_info_hash.has_v1(),
3105
0
      m_info_hash.has_v2()
3106
0
    } };
3107
0
#ifdef __clang__
3108
0
#pragma clang diagnostic pop
3109
0
#endif
3110
3111
0
    time_point32 const now = aux::time_now32();
3112
3113
    // each listen socket gets its own announce state
3114
    // so that each one should get at least one announce
3115
0
    std::vector<announce_state> listen_socket_states;
3116
3117
0
    bool const announce_to_all_tiers = settings().get_bool(settings_pack::announce_to_all_tiers);
3118
0
    bool const announce_to_all_trackers = settings().get_bool(settings_pack::announce_to_all_trackers);
3119
#ifndef TORRENT_DISABLE_LOGGING
3120
    int idx = -1;
3121
    if (should_log())
3122
    {
3123
      debug_log("*** announce: "
3124
        "[ announce_to_all_tiers: %d announce_to_all_trackers: %d num_trackers: %d ]"
3125
        , announce_to_all_tiers
3126
        , announce_to_all_trackers
3127
        , int(m_trackers.size()));
3128
    }
3129
#endif
3130
3131
0
    for (auto& ae : m_trackers)
3132
0
    {
3133
#ifndef TORRENT_DISABLE_LOGGING
3134
      ++idx;
3135
#endif
3136
0
      refresh_endpoint_list(m_ses, ae.url, is_ssl_torrent(), bool(m_complete_sent), ae.endpoints);
3137
3138
      // if trackerid is not specified for tracker use default one, probably set explicitly
3139
0
      req.trackerid = ae.trackerid.empty() ? m_trackerid : ae.trackerid;
3140
0
      req.url = ae.url;
3141
3142
0
#if TORRENT_USE_I2P
3143
0
      if (is_i2p_url(req.url))
3144
0
      {
3145
0
        req.kind |= tracker_request::i2p;
3146
0
      }
3147
0
      else if (is_i2p() && !settings().get_bool(settings_pack::allow_i2p_mixed))
3148
0
      {
3149
        // if we don't allow mixing normal peers into this i2p
3150
        // torrent, skip this announce
3151
0
        continue;
3152
0
      }
3153
0
#endif
3154
3155
0
      for (auto& aep : ae.endpoints)
3156
0
      {
3157
        // do not add code which continues to the next endpoint here!
3158
        // listen_socket_states needs to be populated even if none of the endpoints
3159
        // will be announcing for this tracker
3160
        // otherwise the early bail out when neither announce_to_all_trackers
3161
        // nor announce_to_all_tiers is set may be triggered prematurely
3162
3163
0
        auto aep_state_iter = std::find_if(listen_socket_states.begin(), listen_socket_states.end()
3164
0
          , [&](announce_state const& s) { return s.socket == aep.socket; });
3165
0
        if (aep_state_iter == listen_socket_states.end())
3166
0
        {
3167
0
          listen_socket_states.emplace_back(aep.socket);
3168
0
          aep_state_iter = listen_socket_states.end() - 1;
3169
0
        }
3170
0
        announce_state& ep_state = *aep_state_iter;
3171
3172
0
        if (!aep.enabled) continue;
3173
3174
0
        for (protocol_version const ih : all_versions)
3175
0
        {
3176
0
          if (!supports_protocol[ih]) continue;
3177
3178
0
          auto& state = ep_state.state[ih];
3179
0
          auto& a = aep.info_hashes[ih];
3180
3181
          // if we haven't sent an event=start to the tracker, there's no
3182
          // point in sending an event=stopped
3183
0
          if (!a.start_sent && req.event == event_t::stopped)
3184
0
            continue;
3185
3186
0
          if (state.done) continue;
3187
3188
#ifndef TORRENT_DISABLE_LOGGING
3189
          if (should_log())
3190
          {
3191
            debug_log("*** tracker:  (%d) [ep: %s ] \"%s\" [ "
3192
              " i->tier: %d tier: %d working: %d limit: %d"
3193
              " can: %d sent: %d ]"
3194
              , idx, print_endpoint(aep.local_endpoint).c_str()
3195
              , ae.url.c_str(), ae.tier, state.tier, a.is_working(), ae.fail_limit
3196
              , a.can_announce(now, is_seed(), ae.fail_limit), state.sent_announce);
3197
          }
3198
#endif
3199
3200
0
          if (announce_to_all_tiers
3201
0
            && !announce_to_all_trackers
3202
0
            && state.sent_announce
3203
0
            && ae.tier <= state.tier
3204
0
            && state.tier != INT_MAX)
3205
0
            continue;
3206
3207
0
          if (ae.tier > state.tier && state.sent_announce
3208
0
            && !announce_to_all_tiers) continue;
3209
0
          if (a.is_working()) { state.tier = ae.tier; state.sent_announce = false; }
3210
0
          if (!a.can_announce(now, is_seed(), ae.fail_limit))
3211
0
          {
3212
            // this counts
3213
0
            if (a.is_working())
3214
0
            {
3215
0
              state.sent_announce = true;
3216
0
              if (!announce_to_all_trackers
3217
0
                && !announce_to_all_tiers)
3218
0
              {
3219
0
                state.done = true;
3220
0
              }
3221
0
            }
3222
0
            continue;
3223
0
          }
3224
3225
0
          req.event = e;
3226
0
          if (req.event == event_t::none)
3227
0
          {
3228
0
            if (!a.start_sent) req.event = event_t::started;
3229
0
            else if (!m_complete_sent
3230
0
              && !a.complete_sent
3231
0
              && is_seed())
3232
0
            {
3233
0
              req.event = event_t::completed;
3234
0
            }
3235
0
          }
3236
3237
0
          req.triggered_manually = a.triggered_manually;
3238
0
          a.triggered_manually = false;
3239
3240
0
#if TORRENT_ABI_VERSION == 1
3241
0
          req.auth = tracker_login();
3242
0
#endif
3243
0
          req.key = tracker_key();
3244
3245
0
          req.outgoing_socket = aep.socket;
3246
0
          req.info_hash = m_torrent_file->info_hashes().get(ih);
3247
3248
#ifndef TORRENT_DISABLE_LOGGING
3249
          if (should_log())
3250
          {
3251
            debug_log("==> TRACKER REQUEST \"%s\" event: %s abort: %d ssl: %p "
3252
              "port: %d ssl-port: %d fails: %d upd: %d ep: %s"
3253
              , req.url.c_str()
3254
              , (req.event == event_t::stopped ? "stopped"
3255
                : req.event == event_t::started ? "started" : "")
3256
              , m_abort
3257
#ifdef TORRENT_SSL_PEERS
3258
              , static_cast<void*>(req.ssl_ctx)
3259
#else
3260
              , static_cast<void*>(nullptr)
3261
#endif
3262
              , m_ses.listen_port()
3263
              , m_ses.ssl_listen_port()
3264
              , a.fails
3265
              , a.updating
3266
              , print_endpoint(aep.local_endpoint).c_str());
3267
          }
3268
3269
          // if we're not logging session logs, don't bother creating an
3270
          // observer object just for logging
3271
          if (m_abort && m_ses.should_log())
3272
          {
3273
            auto tl = std::make_shared<aux::tracker_logger>(m_ses);
3274
            m_ses.queue_tracker_request(req, tl);
3275
          }
3276
          else
3277
#endif
3278
0
          {
3279
0
            m_ses.queue_tracker_request(req, shared_from_this());
3280
0
          }
3281
3282
0
          a.updating = true;
3283
0
          a.next_announce = now;
3284
0
          a.min_announce = now;
3285
3286
0
          if (m_ses.alerts().should_post<tracker_announce_alert>())
3287
0
          {
3288
0
            m_ses.alerts().emplace_alert<tracker_announce_alert>(
3289
0
              get_handle(), aep.local_endpoint, req.url, ih, req.event);
3290
0
          }
3291
3292
0
          state.sent_announce = true;
3293
0
          if (a.is_working()
3294
0
            && !announce_to_all_trackers
3295
0
            && !announce_to_all_tiers)
3296
0
          {
3297
0
            state.done = true;
3298
0
          }
3299
0
        }
3300
0
      }
3301
3302
0
      if (std::all_of(listen_socket_states.begin(), listen_socket_states.end()
3303
0
        , [supports_protocol](announce_state const& s) {
3304
0
          for (protocol_version const ih : all_versions)
3305
0
          {
3306
0
            if (supports_protocol[ih] && !s.state[ih].done)
3307
0
              return false;
3308
0
          }
3309
0
          return true;
3310
0
        }))
3311
0
        break;
3312
0
    }
3313
0
    update_tracker_timer(now);
3314
0
  }
3315
3316
  void torrent::scrape_tracker(int idx, bool const user_triggered)
3317
0
  {
3318
0
    TORRENT_ASSERT(is_single_thread());
3319
0
#if TORRENT_ABI_VERSION == 1
3320
0
    m_last_scrape = aux::time_now32();
3321
0
#endif
3322
3323
0
    if (m_trackers.empty()) return;
3324
3325
0
    if (idx < 0 || idx >= int(m_trackers.size())) idx = m_last_working_tracker;
3326
0
    if (idx < 0) idx = 0;
3327
3328
0
    tracker_request req;
3329
0
    if (settings().get_bool(settings_pack::apply_ip_filter_to_trackers)
3330
0
      && m_apply_ip_filter)
3331
0
      req.filter = m_ip_filter;
3332
3333
0
    req.kind |= tracker_request::scrape_request;
3334
0
    auto& ae = m_trackers[idx];
3335
3336
0
#if TORRENT_USE_I2P
3337
0
    if (is_i2p_url(ae.url))
3338
0
      req.kind |= tracker_request::i2p;
3339
0
    else if (is_i2p() && !settings().get_bool(settings_pack::allow_i2p_mixed))
3340
0
      return;
3341
0
#endif
3342
0
    refresh_endpoint_list(m_ses, ae.url, is_ssl_torrent(), bool(m_complete_sent), ae.endpoints);
3343
0
    req.url = ae.url;
3344
0
    req.private_torrent = m_torrent_file->priv();
3345
0
#if TORRENT_ABI_VERSION == 1
3346
0
    req.auth = tracker_login();
3347
0
#endif
3348
0
    req.key = tracker_key();
3349
0
    req.triggered_manually = user_triggered;
3350
0
    for (aux::announce_endpoint const& aep : ae.endpoints)
3351
0
    {
3352
0
      if (!aep.enabled) continue;
3353
0
      req.outgoing_socket = aep.socket;
3354
0
      m_torrent_file->info_hashes().for_each([&](sha1_hash const& ih, protocol_version)
3355
0
      {
3356
0
        req.info_hash = ih;
3357
0
        m_ses.queue_tracker_request(req, shared_from_this());
3358
0
      });
3359
0
    }
3360
0
  }
3361
3362
  void torrent::tracker_warning(tracker_request const& req, std::string const& msg)
3363
0
  {
3364
0
    TORRENT_ASSERT(is_single_thread());
3365
3366
0
    INVARIANT_CHECK;
3367
3368
0
    protocol_version const hash_version = req.info_hash == m_info_hash.v1
3369
0
      ? protocol_version::V1 : protocol_version::V2;
3370
3371
0
    aux::announce_entry* ae = find_tracker(req.url);
3372
0
    tcp::endpoint local_endpoint;
3373
0
    if (ae)
3374
0
    {
3375
0
      for (auto& aep : ae->endpoints)
3376
0
      {
3377
0
        if (aep.socket != req.outgoing_socket) continue;
3378
0
        local_endpoint = aep.local_endpoint;
3379
0
        aep.info_hashes[hash_version].message = msg;
3380
0
        break;
3381
0
      }
3382
0
    }
3383
3384
0
    if (m_ses.alerts().should_post<tracker_warning_alert>())
3385
0
      m_ses.alerts().emplace_alert<tracker_warning_alert>(get_handle()
3386
0
        , local_endpoint, req.url, hash_version, msg);
3387
0
  }
3388
3389
  void torrent::tracker_scrape_response(tracker_request const& req
3390
    , int const complete, int const incomplete, int const downloaded, int /* downloaders */)
3391
0
  {
3392
0
    TORRENT_ASSERT(is_single_thread());
3393
3394
0
    INVARIANT_CHECK;
3395
0
    TORRENT_ASSERT(req.kind & tracker_request::scrape_request);
3396
3397
0
    protocol_version const hash_version = req.info_hash == m_info_hash.v1
3398
0
      ? protocol_version::V1 : protocol_version::V2;
3399
3400
0
    aux::announce_entry* ae = find_tracker(req.url);
3401
0
    tcp::endpoint local_endpoint;
3402
0
    if (ae)
3403
0
    {
3404
0
      auto* aep = ae->find_endpoint(req.outgoing_socket);
3405
0
      if (aep)
3406
0
      {
3407
0
        local_endpoint = aep->local_endpoint;
3408
0
        if (incomplete >= 0) aep->info_hashes[hash_version].scrape_incomplete = incomplete;
3409
0
        if (complete >= 0) aep->info_hashes[hash_version].scrape_complete = complete;
3410
0
        if (downloaded >= 0) aep->info_hashes[hash_version].scrape_downloaded = downloaded;
3411
3412
0
        update_scrape_state();
3413
0
      }
3414
0
    }
3415
3416
    // if this was triggered manually we need to post this unconditionally,
3417
    // since the client expects a response from its action, regardless of
3418
    // whether all tracker events have been enabled by the alert mask
3419
0
    if (m_ses.alerts().should_post<scrape_reply_alert>()
3420
0
      || req.triggered_manually)
3421
0
    {
3422
0
      m_ses.alerts().emplace_alert<scrape_reply_alert>(
3423
0
        get_handle(), local_endpoint, incomplete, complete, req.url, hash_version);
3424
0
    }
3425
0
  }
3426
3427
  void torrent::update_scrape_state()
3428
0
  {
3429
    // loop over all trackers and find the largest numbers for each scrape field
3430
    // then update the torrent-wide understanding of number of downloaders and seeds
3431
0
    int complete = -1;
3432
0
    int incomplete = -1;
3433
0
    int downloaded = -1;
3434
0
    for (auto const& t : m_trackers)
3435
0
    {
3436
0
      for (auto const& aep : t.endpoints)
3437
0
      {
3438
0
        for (protocol_version const ih : all_versions)
3439
0
        {
3440
0
          auto& a = aep.info_hashes[ih];
3441
0
          complete = std::max(a.scrape_complete, complete);
3442
0
          incomplete = std::max(a.scrape_incomplete, incomplete);
3443
0
          downloaded = std::max(a.scrape_downloaded, downloaded);
3444
0
        }
3445
0
      }
3446
0
    }
3447
3448
0
    if ((complete >= 0 && int(m_complete) != complete)
3449
0
      || (incomplete >= 0 && int(m_incomplete) != incomplete)
3450
0
      || (downloaded >= 0 && int(m_downloaded) != downloaded))
3451
0
      state_updated();
3452
3453
0
    if (int(m_complete) != complete
3454
0
      || int(m_incomplete) != incomplete
3455
0
      || int(m_downloaded) != downloaded)
3456
0
    {
3457
0
      m_complete = std::uint32_t(complete);
3458
0
      m_incomplete = std::uint32_t(incomplete);
3459
0
      m_downloaded = std::uint32_t(downloaded);
3460
3461
0
      update_auto_sequential();
3462
3463
      // these numbers are cached in the resume data
3464
0
      set_need_save_resume(torrent_handle::if_counters_changed);
3465
0
    }
3466
0
  }
3467
3468
  void torrent::tracker_response(
3469
    tracker_request const& r
3470
    , address const& tracker_ip // this is the IP we connected to
3471
    , std::list<address> const& tracker_ips // these are all the IPs it resolved to
3472
    , struct tracker_response const& resp)
3473
0
  {
3474
0
    TORRENT_ASSERT(is_single_thread());
3475
3476
0
    INVARIANT_CHECK;
3477
0
    TORRENT_ASSERT(!(r.kind & tracker_request::scrape_request));
3478
3479
    // if the tracker told us what our external IP address is, record it with
3480
    // out external IP counter (and pass along the IP of the tracker to know
3481
    // who to attribute this vote to)
3482
0
    if (resp.external_ip != address() && !tracker_ip.is_unspecified() && r.outgoing_socket)
3483
0
      m_ses.set_external_address(r.outgoing_socket.get_local_endpoint()
3484
0
        , resp.external_ip
3485
0
        , aux::session_interface::source_tracker, tracker_ip);
3486
3487
0
    time_point32 const now = aux::time_now32();
3488
3489
0
    protocol_version const v = r.info_hash == torrent_file().info_hashes().v1
3490
0
      ? protocol_version::V1 : protocol_version::V2;
3491
3492
0
    auto const interval = std::max(resp.interval, seconds32(
3493
0
      settings().get_int(settings_pack::min_announce_interval)));
3494
3495
0
    aux::announce_entry* ae = find_tracker(r.url);
3496
0
    tcp::endpoint local_endpoint;
3497
0
    if (ae)
3498
0
    {
3499
0
      auto* aep = ae->find_endpoint(r.outgoing_socket);
3500
0
      if (aep)
3501
0
      {
3502
0
        auto& a = aep->info_hashes[v];
3503
3504
0
        local_endpoint = aep->local_endpoint;
3505
0
        if (resp.incomplete >= 0) a.scrape_incomplete = resp.incomplete;
3506
0
        if (resp.complete >= 0) a.scrape_complete = resp.complete;
3507
0
        if (resp.downloaded >= 0) a.scrape_downloaded = resp.downloaded;
3508
0
        if (!a.start_sent && r.event == event_t::started)
3509
0
          a.start_sent = true;
3510
0
        if (!a.complete_sent && r.event == event_t::completed)
3511
0
        {
3512
0
          a.complete_sent = true;
3513
          // we successfully reported event=completed to one tracker. Don't
3514
          // send it to any other ones from now on (there may be other
3515
          // announces outstanding right now though)
3516
0
          m_complete_sent = true;
3517
0
        }
3518
0
        ae->verified = true;
3519
0
        a.next_announce = now + interval;
3520
0
        a.min_announce = now + resp.min_interval;
3521
0
        a.updating = false;
3522
0
        a.fails = 0;
3523
0
        a.last_error.clear();
3524
0
        a.message = !resp.warning_message.empty() ? resp.warning_message : std::string();
3525
0
        int const tracker_index = int(ae - m_trackers.data());
3526
0
        m_last_working_tracker = std::int8_t(tracker_index);
3527
3528
0
        if ((!resp.trackerid.empty()) && (ae->trackerid != resp.trackerid))
3529
0
        {
3530
0
          ae->trackerid = resp.trackerid;
3531
0
          if (m_ses.alerts().should_post<trackerid_alert>())
3532
0
            m_ses.alerts().emplace_alert<trackerid_alert>(get_handle()
3533
0
              , aep->local_endpoint, r.url, resp.trackerid);
3534
0
        }
3535
3536
0
        update_scrape_state();
3537
0
      }
3538
0
    }
3539
0
    update_tracker_timer(now);
3540
3541
0
#if TORRENT_ABI_VERSION == 1
3542
0
    if (resp.complete >= 0 && resp.incomplete >= 0)
3543
0
      m_last_scrape = aux::time_now32();
3544
0
#endif
3545
3546
#ifndef TORRENT_DISABLE_LOGGING
3547
    if (should_log())
3548
    {
3549
      std::string resolved_to;
3550
      for (auto const& i : tracker_ips)
3551
      {
3552
        resolved_to += i.to_string();
3553
        resolved_to += ", ";
3554
      }
3555
      debug_log("TRACKER RESPONSE [ interval: %d | min-interval: %d | "
3556
        "external ip: %s | resolved to: %s | we connected to: %s ]"
3557
        , interval.count()
3558
        , resp.min_interval.count()
3559
        , print_address(resp.external_ip).c_str()
3560
        , resolved_to.c_str()
3561
        , print_address(tracker_ip).c_str());
3562
    }
3563
#else
3564
0
    TORRENT_UNUSED(tracker_ips);
3565
0
#endif
3566
3567
    // for each of the peers we got from the tracker
3568
0
    for (auto const& i : resp.peers)
3569
0
    {
3570
      // don't make connections to ourself
3571
0
      if (i.pid == m_peer_id)
3572
0
        continue;
3573
3574
0
#if TORRENT_USE_I2P
3575
0
      if (r.i2pconn)
3576
0
      {
3577
        // this is an i2p name, we need to use the SAM connection
3578
        // to do the name lookup
3579
0
        if (string_ends_with(i.hostname, ".i2p"))
3580
0
        {
3581
0
          ADD_OUTSTANDING_ASYNC("torrent::on_i2p_resolve");
3582
0
          r.i2pconn->async_name_lookup(i.hostname.c_str()
3583
0
            , [self = shared_from_this()] (error_code const& ec, char const* dest)
3584
0
            { self->torrent::on_i2p_resolve(ec, dest); });
3585
0
        }
3586
0
        else
3587
0
        {
3588
0
          torrent_state st = get_peer_list_state();
3589
0
          need_peer_list();
3590
0
          if (m_peer_list->add_i2p_peer(i.hostname, peer_info::tracker, {}, &st))
3591
0
            state_updated();
3592
0
          peers_erased(st.erased);
3593
0
        }
3594
0
      }
3595
0
      else
3596
0
#endif
3597
0
      {
3598
0
        ADD_OUTSTANDING_ASYNC("torrent::on_peer_name_lookup");
3599
0
        m_ses.get_resolver().async_resolve(i.hostname, aux::resolver_interface::abort_on_shutdown
3600
0
          , std::bind(&torrent::on_peer_name_lookup, shared_from_this(), _1, _2, i.port, v));
3601
0
      }
3602
0
    }
3603
3604
0
#if TORRENT_USE_I2P
3605
0
    if (r.i2pconn)
3606
0
    {
3607
0
      for (auto const& i : resp.i2p_peers)
3608
0
      {
3609
0
        torrent_state st = get_peer_list_state();
3610
0
        peer_entry p;
3611
0
        std::string destination = base32encode_i2p(i.destination);
3612
0
        destination += ".b32.i2p";
3613
3614
0
        ADD_OUTSTANDING_ASYNC("torrent::on_i2p_resolve");
3615
0
        r.i2pconn->async_name_lookup(destination.c_str()
3616
0
          , [self = shared_from_this()] (error_code const& ec, char const* dest)
3617
0
          { self->torrent::on_i2p_resolve(ec, dest); });
3618
0
      }
3619
0
    }
3620
0
#endif
3621
3622
    // there are 2 reasons to allow local IPs to be returned from a
3623
    // non-local tracker
3624
    // 1. retrackers are popular in russia, where an ISP runs a tracker within
3625
    //    the AS (but not on the local network) giving out peers only from the
3626
    //    local network
3627
    // 2. it might make sense to have a tracker extension in the future where
3628
    //    trackers records a peer's internal and external IP, and match up
3629
    //    peers on the same local network
3630
3631
0
    pex_flags_t flags = v == protocol_version::V2 ? pex_lt_v2 : pex_flags_t(0);
3632
3633
0
    bool need_update = false;
3634
0
    for (auto const& i : resp.peers4)
3635
0
    {
3636
0
      tcp::endpoint const a(address_v4(i.ip), i.port);
3637
0
      need_update |= bool(add_peer(a, peer_info::tracker, flags) != nullptr);
3638
0
    }
3639
3640
0
    for (auto const& i : resp.peers6)
3641
0
    {
3642
0
      tcp::endpoint const a(address_v6(i.ip), i.port);
3643
0
      need_update |= bool(add_peer(a, peer_info::tracker, flags) != nullptr);
3644
0
    }
3645
3646
#ifndef TORRENT_DISABLE_LOGGING
3647
    if (should_log() && (!resp.peers4.empty() || !resp.peers6.empty()))
3648
    {
3649
      std::string str;
3650
      for (auto const& peer : resp.peers4)
3651
      {
3652
        str += address_v4(peer.ip).to_string();
3653
        str += ' ';
3654
      }
3655
      for (auto const& peer : resp.peers6)
3656
      {
3657
        str += address_v6(peer.ip).to_string();
3658
        str += ' ';
3659
      }
3660
      debug_log("tracker add_peer() [ %s] connect-candidates: %d"
3661
        , str.c_str(), m_peer_list
3662
        ? m_peer_list->num_connect_candidates() : -1);
3663
    }
3664
#endif
3665
0
    if (need_update) state_updated();
3666
3667
0
    update_want_peers();
3668
3669
    // post unconditionally if the announce was triggered manually
3670
0
    if (m_ses.alerts().should_post<tracker_reply_alert>()
3671
0
      || r.triggered_manually)
3672
0
    {
3673
0
      int peer_count = int(resp.peers.size() + resp.peers4.size());
3674
0
#if TORRENT_USE_I2P
3675
0
      peer_count += int(resp.i2p_peers.size());
3676
0
#endif
3677
0
      m_ses.alerts().emplace_alert<tracker_reply_alert>(
3678
0
        get_handle(), local_endpoint, peer_count
3679
0
        + int(resp.peers6.size()), v, r.url);
3680
0
    }
3681
3682
0
    do_connect_boost();
3683
3684
0
    state_updated();
3685
0
  }
3686
3687
  void torrent::update_auto_sequential()
3688
68
  {
3689
68
    if (!settings().get_bool(settings_pack::auto_sequential))
3690
0
    {
3691
0
      m_auto_sequential = false;
3692
0
      return;
3693
0
    }
3694
3695
68
    if (num_peers() - m_num_connecting < 10)
3696
68
    {
3697
      // there are too few peers. Be conservative and don't assume it's
3698
      // well seeded until we can connect to more peers
3699
68
      m_auto_sequential = false;
3700
68
      return;
3701
68
    }
3702
3703
    // if there are at least 10 seeds, and there are 10 times more
3704
    // seeds than downloaders, enter sequential download mode
3705
    // (for performance)
3706
0
    int const downloaders = num_downloaders();
3707
0
    int const seeds = num_seeds();
3708
0
    m_auto_sequential = downloaders * 10 <= seeds
3709
0
      && seeds > 9;
3710
0
  }
3711
3712
  void torrent::do_connect_boost()
3713
2
  {
3714
2
    if (m_connect_boost_counter == 0) return;
3715
3716
    // this is the first tracker response for this torrent
3717
    // instead of waiting one second for session_impl::on_tick()
3718
    // to be called, connect to a few peers immediately
3719
2
    int conns = std::min(int(m_connect_boost_counter)
3720
2
      , settings().get_int(settings_pack::connections_limit) - m_ses.num_connections());
3721
3722
2
    if (conns == 0) return;
3723
3724
    // if we don't know of any peers
3725
2
    if (!m_peer_list) return;
3726
3727
0
    while (want_peers() && conns > 0)
3728
0
    {
3729
0
      TORRENT_ASSERT(m_connect_boost_counter > 0);
3730
0
      --conns;
3731
0
      --m_connect_boost_counter;
3732
0
      torrent_state st = get_peer_list_state();
3733
0
      torrent_peer* p = m_peer_list->connect_one_peer(m_ses.session_time(), &st);
3734
0
      peers_erased(st.erased);
3735
0
      inc_stats_counter(counters::connection_attempt_loops, st.loop_counter);
3736
0
      if (p == nullptr)
3737
0
      {
3738
0
        update_want_peers();
3739
0
        continue;
3740
0
      }
3741
3742
#ifndef TORRENT_DISABLE_LOGGING
3743
      if (should_log())
3744
      {
3745
        external_ip const& external = m_ses.external_address();
3746
        debug_log(" *** FOUND CONNECTION CANDIDATE ["
3747
          " ip: %s rank: %u external: %s t: %d ]"
3748
          , print_endpoint(p->ip()).c_str()
3749
          , p->rank(external, m_ses.listen_port())
3750
          , print_address(external.external_address(p->address())).c_str()
3751
          , int(m_ses.session_time() - p->last_connected));
3752
      }
3753
#endif
3754
3755
0
      if (!connect_to_peer(p))
3756
0
      {
3757
0
        m_peer_list->inc_failcount(p);
3758
0
        update_want_peers();
3759
0
      }
3760
0
      else
3761
0
      {
3762
        // increase m_ses.m_boost_connections for each connection
3763
        // attempt. This will be deducted from the connect speed
3764
        // the next time session_impl::on_tick() is triggered
3765
0
        m_ses.inc_boost_connections();
3766
0
        update_want_peers();
3767
0
      }
3768
0
    }
3769
3770
0
    if (want_peers()) m_ses.prioritize_connections(shared_from_this());
3771
0
  }
3772
3773
  // this is the entry point for the client to force a re-announce. It's
3774
  // considered a client-initiated announce (as opposed to the regular ones,
3775
  // issued by libtorrent)
3776
  void torrent::force_tracker_request(time_point const t, int const tracker_idx
3777
    , reannounce_flags_t const flags)
3778
0
  {
3779
0
    TORRENT_ASSERT_PRECOND((tracker_idx >= 0
3780
0
      && tracker_idx < int(m_trackers.size()))
3781
0
      || tracker_idx == -1);
3782
3783
0
    if (is_paused()) return;
3784
#ifndef TORRENT_DISABLE_LOGGING
3785
    bool found_one = false;
3786
#endif
3787
0
    if (tracker_idx == -1)
3788
0
    {
3789
0
      for (auto& e : m_trackers)
3790
0
      {
3791
        // make sure we check for new endpoints from the listen sockets
3792
0
        refresh_endpoint_list(m_ses, e.url, is_ssl_torrent(), bool(m_complete_sent), e.endpoints);
3793
0
        for (auto& aep : e.endpoints)
3794
0
        {
3795
0
          for (auto& a : aep.info_hashes)
3796
0
          {
3797
0
            a.next_announce = (flags & torrent_handle::ignore_min_interval)
3798
0
              ? time_point_cast<seconds32>(t) + seconds32(1)
3799
0
              : std::max(time_point_cast<seconds32>(t), a.min_announce) + seconds32(1);
3800
0
            a.min_announce = a.next_announce;
3801
0
            a.triggered_manually = true;
3802
0
          }
3803
0
        }
3804
0
      }
3805
0
    }
3806
0
    else
3807
0
    {
3808
0
      if (tracker_idx < 0 || tracker_idx >= int(m_trackers.size()))
3809
0
        return;
3810
0
      aux::announce_entry& e = m_trackers[tracker_idx];
3811
0
      for (auto& aep : e.endpoints)
3812
0
      {
3813
0
        for (auto& a : aep.info_hashes)
3814
0
        {
3815
0
          a.next_announce = (flags & torrent_handle::ignore_min_interval)
3816
0
            ? time_point_cast<seconds32>(t) + seconds32(1)
3817
0
            : std::max(time_point_cast<seconds32>(t), a.min_announce) + seconds32(1);
3818
0
          a.min_announce = a.next_announce;
3819
0
          a.triggered_manually = true;
3820
#ifndef TORRENT_DISABLE_LOGGING
3821
          found_one = true;
3822
#endif
3823
0
        }
3824
0
      }
3825
0
    }
3826
3827
#ifndef TORRENT_DISABLE_LOGGING
3828
    if (!found_one)
3829
    {
3830
      debug_log("*** found no tracker endpoints to announce");
3831
    }
3832
#endif
3833
0
    update_tracker_timer(aux::time_now32());
3834
0
  }
3835
3836
#if TORRENT_ABI_VERSION == 1
3837
  void torrent::set_tracker_login(std::string const& name
3838
    , std::string const& pw)
3839
0
  {
3840
0
    m_username = name;
3841
0
    m_password = pw;
3842
0
  }
3843
#endif
3844
3845
#if TORRENT_USE_I2P
3846
0
  void torrent::on_i2p_resolve(error_code const& ec, char const* dest) try
3847
0
  {
3848
0
    TORRENT_ASSERT(is_single_thread());
3849
3850
0
    INVARIANT_CHECK;
3851
3852
0
    COMPLETE_ASYNC("torrent::on_i2p_resolve");
3853
#ifndef TORRENT_DISABLE_LOGGING
3854
    if (ec && should_log())
3855
      debug_log("i2p_resolve error: %s", ec.message().c_str());
3856
#endif
3857
0
    if (ec || m_abort || m_ses.is_aborted()) return;
3858
3859
0
    need_peer_list();
3860
0
    torrent_state st = get_peer_list_state();
3861
0
    if (m_peer_list->add_i2p_peer(dest, peer_info::tracker, {}, &st))
3862
0
      state_updated();
3863
0
    peers_erased(st.erased);
3864
3865
0
    update_want_peers();
3866
0
  }
3867
0
  catch (...) { handle_exception(); }
3868
#endif
3869
3870
  void torrent::on_peer_name_lookup(error_code const& e
3871
    , std::vector<address> const& host_list, int const port
3872
0
    , protocol_version const v) try
3873
0
  {
3874
0
    TORRENT_ASSERT(is_single_thread());
3875
3876
0
    INVARIANT_CHECK;
3877
3878
0
    COMPLETE_ASYNC("torrent::on_peer_name_lookup");
3879
3880
#ifndef TORRENT_DISABLE_LOGGING
3881
    if (e && should_log())
3882
      debug_log("peer name lookup error: %s", e.message().c_str());
3883
#endif
3884
3885
0
    if (e || m_abort || host_list.empty() || m_ses.is_aborted()) return;
3886
3887
    // TODO: add one peer per IP the hostname resolves to
3888
0
    tcp::endpoint host(host_list.front(), std::uint16_t(port));
3889
3890
0
    if (m_ip_filter && m_ip_filter->access(host.address()) & ip_filter::blocked)
3891
0
    {
3892
#ifndef TORRENT_DISABLE_LOGGING
3893
      if (should_log())
3894
      {
3895
        debug_log("blocked ip from tracker: %s", host.address().to_string().c_str());
3896
      }
3897
#endif
3898
0
      if (m_ses.alerts().should_post<peer_blocked_alert>())
3899
0
        m_ses.alerts().emplace_alert<peer_blocked_alert>(get_handle()
3900
0
          , host, peer_blocked_alert::ip_filter);
3901
0
      return;
3902
0
    }
3903
3904
0
    if (add_peer(host, peer_info::tracker, v == protocol_version::V2 ? pex_lt_v2 : pex_flags_t(0)))
3905
0
    {
3906
0
      state_updated();
3907
3908
#ifndef TORRENT_DISABLE_LOGGING
3909
      if (should_log())
3910
      {
3911
        debug_log("name-lookup add_peer() [ %s ] connect-candidates: %d"
3912
          , host.address().to_string().c_str()
3913
          , m_peer_list ? m_peer_list->num_connect_candidates() : -1);
3914
      }
3915
#endif
3916
0
    }
3917
0
    update_want_peers();
3918
0
  }
3919
0
  catch (...) { handle_exception(); }
3920
3921
  boost::optional<std::int64_t> torrent::bytes_left() const
3922
0
  {
3923
    // if we don't have the metadata yet, we
3924
    // cannot tell how big the torrent is.
3925
0
    if (!valid_metadata()) return {};
3926
0
    TORRENT_ASSERT(m_torrent_file->num_pieces() > 0);
3927
0
    if (m_seed_mode) return std::int64_t(0);
3928
0
    if (!has_picker()) return is_seed() ? std::int64_t(0) : m_torrent_file->total_size();
3929
3930
0
    piece_count const pc = m_picker->have();
3931
0
    std::int64_t left
3932
0
      = m_torrent_file->total_size()
3933
0
      - std::int64_t(pc.num_pieces) * m_torrent_file->piece_length();
3934
3935
    // if we have the last piece, we may have subtracted too much, as it can
3936
    // be smaller than the normal piece size.
3937
    // we have to correct it
3938
0
    if (pc.last_piece)
3939
0
    {
3940
0
      left += m_torrent_file->piece_length() - m_torrent_file->piece_size(m_torrent_file->last_piece());
3941
0
    }
3942
3943
0
    return left;
3944
0
  }
3945
3946
  // we assume the last block is never a pad block. Should be a fairly
3947
  // safe assumption, and you just get a few kiB off if it is
3948
  std::int64_t calc_bytes(file_storage const& fs, piece_count const& pc)
3949
0
  {
3950
    // it's an impossible combination to have 0 pieces, but still have one of them be the last piece
3951
0
    TORRENT_ASSERT(!(pc.num_pieces == 0 && pc.last_piece == true));
3952
3953
    // if we have 0 pieces, we can't have any pad blocks either
3954
0
    TORRENT_ASSERT(!(pc.num_pieces == 0 && pc.pad_bytes > 0));
3955
3956
    // if we have all pieces, we must also have the last one
3957
0
    TORRENT_ASSERT(!(pc.num_pieces == fs.num_pieces() && pc.last_piece == false));
3958
3959
    // every block should not be a pad block
3960
0
    TORRENT_ASSERT(pc.pad_bytes <= std::int64_t(pc.num_pieces) * fs.piece_length());
3961
3962
0
    return std::int64_t(pc.num_pieces) * fs.piece_length()
3963
0
      - (pc.last_piece ? fs.piece_length() - fs.piece_size(fs.last_piece()) : 0)
3964
0
      - std::int64_t(pc.pad_bytes);
3965
0
  }
3966
3967
  // fills in total_wanted, total_wanted_done and total_done
3968
// TODO: 3 this could probably be pulled out into a free function
3969
  void torrent::bytes_done(torrent_status& st, status_flags_t const flags) const
3970
0
  {
3971
0
    INVARIANT_CHECK;
3972
3973
0
    st.total_done = 0;
3974
0
    st.total_wanted_done = 0;
3975
0
    st.total_wanted = m_size_on_disk;
3976
3977
0
    TORRENT_ASSERT(st.total_wanted <= m_torrent_file->total_size());
3978
0
    TORRENT_ASSERT(st.total_wanted >= 0);
3979
3980
0
    TORRENT_ASSERT(!valid_metadata() || m_torrent_file->num_pieces() > 0);
3981
0
    if (!valid_metadata()) return;
3982
3983
0
    if (m_seed_mode || is_seed())
3984
0
    {
3985
      // once we're a seed and remove the piece picker, we stop tracking
3986
      // piece- and file priority. We consider everything as being
3987
      // "wanted"
3988
0
      st.total_done = m_torrent_file->total_size() - m_padding_bytes;
3989
0
      st.total_wanted_done = m_size_on_disk;
3990
0
      st.total_wanted = m_size_on_disk;
3991
0
      TORRENT_ASSERT(st.total_wanted <= st.total_done);
3992
0
      TORRENT_ASSERT(st.total_wanted_done <= st.total_wanted);
3993
0
      TORRENT_ASSERT(st.total_done <= m_torrent_file->total_size());
3994
0
      return;
3995
0
    }
3996
0
    else if (!has_picker())
3997
0
    {
3998
0
      st.total_done = 0;
3999
0
      st.total_wanted_done = 0;
4000
0
      st.total_wanted = m_size_on_disk;
4001
0
      return;
4002
0
    }
4003
4004
0
    TORRENT_ASSERT(has_picker());
4005
4006
0
    file_storage const& files = m_torrent_file->files();
4007
4008
0
    st.total_wanted = std::min(m_size_on_disk, calc_bytes(files, m_picker->want()));
4009
0
    st.total_wanted_done = std::min(m_file_progress.total_on_disk()
4010
0
      , calc_bytes(files, m_picker->have_want()));
4011
0
    st.total_done = calc_bytes(files, m_picker->have());
4012
0
    st.total = calc_bytes(files, m_picker->all_pieces());
4013
4014
0
    TORRENT_ASSERT(st.total_done <= calc_bytes(files, m_picker->all_pieces()));
4015
0
    TORRENT_ASSERT(st.total_wanted <= calc_bytes(files, m_picker->all_pieces()));
4016
4017
0
    TORRENT_ASSERT(st.total_wanted_done >= 0);
4018
0
    TORRENT_ASSERT(st.total_wanted >= 0);
4019
0
    TORRENT_ASSERT(st.total_wanted >= st.total_wanted_done);
4020
0
    TORRENT_ASSERT(st.total_done >= 0);
4021
0
    TORRENT_ASSERT(st.total_done >= st.total_wanted_done);
4022
4023
    // this is expensive, we might not want to do it all the time
4024
0
    if (!(flags & torrent_handle::query_accurate_download_counters)) return;
4025
4026
    // to get higher accuracy of the download progress, include
4027
    // blocks from currently downloading pieces as well
4028
0
    std::vector<piece_picker::downloading_piece> const dl_queue
4029
0
      = m_picker->get_download_queue();
4030
4031
    // look at all unfinished pieces and add the completed
4032
    // blocks to our 'done' counter
4033
0
    for (auto i = dl_queue.begin(); i != dl_queue.end(); ++i)
4034
0
    {
4035
0
      piece_index_t const index = i->index;
4036
4037
      // completed pieces are already accounted for
4038
0
      if (m_picker->have_piece(index)) continue;
4039
4040
0
      TORRENT_ASSERT(i->finished + i->writing <= m_picker->blocks_in_piece(index));
4041
4042
0
      auto const additional_bytes = std::int64_t(i->finished + i->writing
4043
0
        - m_picker->pad_bytes_in_piece(index) / block_size())
4044
0
        * block_size();
4045
0
      TORRENT_ASSERT(additional_bytes >= 0);
4046
0
      st.total_done += additional_bytes;
4047
0
      if (m_picker->piece_priority(index) > dont_download)
4048
0
        st.total_wanted_done += additional_bytes;
4049
0
    }
4050
4051
0
    TORRENT_ASSERT(st.total_wanted_done >= 0);
4052
0
    TORRENT_ASSERT(st.total_done >= st.total_wanted_done);
4053
0
  }
4054
4055
  void torrent::on_piece_verified(aux::vector<sha256_hash> block_hashes
4056
    , piece_index_t const piece
4057
0
    , sha1_hash const& piece_hash, storage_error const& error) try
4058
0
  {
4059
0
    TORRENT_ASSERT(is_single_thread());
4060
4061
0
    if (m_abort) return;
4062
0
    if (m_deleted) return;
4063
4064
0
    m_picker->completed_hash_job(piece);
4065
4066
0
    boost::tribool passed = boost::indeterminate;
4067
0
    boost::tribool v2_passed = boost::indeterminate;
4068
4069
0
    if (settings().get_bool(settings_pack::disable_hash_checks))
4070
0
    {
4071
0
      passed = v2_passed = true;
4072
0
    }
4073
0
    else if (error)
4074
0
    {
4075
0
      passed = v2_passed = false;
4076
0
    }
4077
0
    else
4078
0
    {
4079
0
      if (torrent_file().info_hashes().has_v1())
4080
0
      {
4081
0
        passed = sha1_hash(piece_hash) == m_torrent_file->hash_for_piece(piece);
4082
0
      }
4083
4084
0
      if (!block_hashes.empty())
4085
0
      {
4086
0
        TORRENT_ASSERT(torrent_file().info_hashes().has_v2());
4087
0
        v2_passed = on_blocks_hashed(piece, block_hashes);
4088
0
      }
4089
0
    }
4090
4091
0
    if (!error && ((passed && !v2_passed) || (!passed && v2_passed)))
4092
0
    {
4093
0
      handle_inconsistent_hashes(piece);
4094
0
      return;
4095
0
    }
4096
4097
0
    bool const disk_error = (!passed || !v2_passed) && error;
4098
4099
0
    if (disk_error) handle_disk_error("piece_verified", error);
4100
4101
#ifndef TORRENT_DISABLE_LOGGING
4102
    if (should_log())
4103
    {
4104
      debug_log("*** PIECE_FINISHED [ p: %d | chk: %s | size: %d ]"
4105
        , static_cast<int>(piece)
4106
        , (passed || v2_passed) ? "passed"
4107
        : disk_error ? "disk failed"
4108
        : (!passed || !v2_passed) ? "failed"
4109
        : "-"
4110
        , m_torrent_file->piece_size(piece));
4111
    }
4112
#endif
4113
0
    TORRENT_ASSERT(valid_metadata());
4114
4115
    // if we're a seed we don't have a picker
4116
    // and we also don't have to do anything because
4117
    // we already have this piece
4118
0
    if (!has_picker() && m_have_all) return;
4119
4120
0
    need_picker();
4121
4122
0
    TORRENT_ASSERT(!m_picker->have_piece(piece));
4123
4124
0
    state_updated();
4125
4126
    // even though the piece passed the hash-check
4127
    // it might still have failed being written to disk
4128
    // if so, piece_picker::write_failed() has been
4129
    // called, and the piece is no longer finished.
4130
    // in this case, we have to ignore the fact that
4131
    // it passed the check
4132
0
    if (!m_picker->is_piece_finished(piece)) return;
4133
4134
0
    if (disk_error)
4135
0
    {
4136
0
      update_gauge();
4137
0
    }
4138
0
    else if (passed || v2_passed)
4139
0
    {
4140
      // the following call may cause picker to become invalid
4141
      // in case we just became a seed
4142
0
      piece_passed(piece);
4143
      // if we're in seed mode, we just acquired this piece
4144
      // mark it as verified
4145
0
      if (m_seed_mode) verified(piece);
4146
0
    }
4147
0
    else if (!passed || !v2_passed)
4148
0
    {
4149
      // piece_failed() will restore the piece
4150
0
      piece_failed(piece);
4151
0
    }
4152
0
  }
4153
0
  catch (...) { handle_exception(); }
4154
4155
  void torrent::add_suggest_piece(piece_index_t const index)
4156
0
  {
4157
0
    TORRENT_ASSERT(settings().get_int(settings_pack::suggest_mode)
4158
0
      == settings_pack::suggest_read_cache);
4159
4160
    // when we care about suggest mode, we keep the piece picker
4161
    // around to track piece availability
4162
0
    need_picker();
4163
0
    int const peers = std::max(num_peers(), 1);
4164
0
    int const availability = m_picker->get_availability(index) * 100 / peers;
4165
4166
0
    m_suggest_pieces.add_piece(index, availability
4167
0
      , settings().get_int(settings_pack::max_suggest_pieces));
4168
0
  }
4169
4170
  // this is called when either:
4171
  // * we have completely downloaded piece 'index' and its hash has been verified.
4172
  // * during initial file check when we find a piece whose hash is correct
4173
  // * if there's a pad-file that extends over the entire piece
4174
  // this function does not update the piece picker, telling it we have the
4175
  // piece, it just does all the torrent-level accounting that needs to
4176
  // happen. It may not be called twice for the same piece (if it is,
4177
  // file_progress will assert)
4178
  void torrent::we_have(piece_index_t const index, bool const loading_resume)
4179
663
  {
4180
663
    TORRENT_ASSERT(is_single_thread());
4181
663
    TORRENT_ASSERT(!has_picker() || m_picker->have_piece(index));
4182
4183
663
    inc_stats_counter(counters::num_have_pieces);
4184
4185
    // at this point, we have the piece for sure. It has been
4186
    // successfully written to disk. We may announce it to peers
4187
    // (unless it has already been announced through predictive_piece_announce
4188
    // feature).
4189
663
    bool announce_piece = true;
4190
663
#ifndef TORRENT_DISABLE_PREDICTIVE_PIECES
4191
663
    auto const it = std::lower_bound(m_predictive_pieces.begin()
4192
663
      , m_predictive_pieces.end(), index);
4193
663
    if (it != m_predictive_pieces.end() && *it == index)
4194
0
    {
4195
      // this means we've already announced the piece
4196
0
      announce_piece = false;
4197
0
      m_predictive_pieces.erase(it);
4198
0
    }
4199
663
#endif
4200
4201
    // make a copy of the peer list since peers
4202
    // may disconnect while looping
4203
663
    for (auto c : m_connections)
4204
0
    {
4205
0
      auto p = c->self();
4206
4207
      // received_piece will check to see if we're still interested
4208
      // in this peer, and if neither of us is interested in the other,
4209
      // disconnect it.
4210
0
      p->received_piece(index);
4211
0
      if (p->is_disconnecting()) continue;
4212
4213
      // if we're not announcing the piece, it means we
4214
      // already have, and that we might have received
4215
      // a request for it, and not sending it because
4216
      // we were waiting to receive the piece, now that
4217
      // we have received it, try to send stuff (fill_send_buffer)
4218
0
      if (announce_piece) p->announce_piece(index);
4219
0
      else p->fill_send_buffer();
4220
0
    }
4221
4222
663
#ifndef TORRENT_DISABLE_EXTENSIONS
4223
663
    for (auto& ext : m_extensions)
4224
0
    {
4225
0
      ext->on_piece_pass(index);
4226
0
    }
4227
663
#endif
4228
4229
    // since this piece just passed, we might have
4230
    // become uninterested in some peers where this
4231
    // was the last piece we were interested in
4232
    // update_interest may disconnect the peer and
4233
    // invalidate the iterator
4234
663
    for (auto p : m_connections)
4235
0
    {
4236
0
      TORRENT_INCREMENT(m_iterating_connections);
4237
      // if we're not interested already, no need to check
4238
0
      if (!p->is_interesting()) continue;
4239
      // if the peer doesn't have the piece we just got, it
4240
      // shouldn't affect our interest
4241
0
      if (!p->has_piece(index)) continue;
4242
0
      p->update_interest();
4243
0
    }
4244
4245
663
    if (!loading_resume)
4246
0
    {
4247
0
      set_need_save_resume(torrent_handle::if_download_progress);
4248
0
      state_updated();
4249
0
      update_want_tick();
4250
0
    }
4251
4252
663
    if (m_ses.alerts().should_post<piece_finished_alert>())
4253
0
      m_ses.alerts().emplace_alert<piece_finished_alert>(get_handle(), index);
4254
4255
    // update m_file_progress (if we have one)
4256
663
    m_file_progress.update(m_torrent_file->files(), index
4257
663
      , [this](file_index_t const file_index)
4258
663
      {
4259
23
        if (m_ses.alerts().should_post<file_completed_alert>())
4260
0
        {
4261
          // this file just completed, post alert
4262
0
          m_ses.alerts().emplace_alert<file_completed_alert>(
4263
0
            get_handle(), file_index);
4264
0
        }
4265
23
      });
4266
4267
663
#ifndef TORRENT_DISABLE_STREAMING
4268
663
    remove_time_critical_piece(index, true);
4269
663
#endif
4270
4271
663
    if (is_downloading_state(m_state))
4272
0
    {
4273
0
      if (m_state != torrent_status::finished
4274
0
        && m_state != torrent_status::seeding
4275
0
        && is_finished())
4276
0
      {
4277
        // torrent finished
4278
        // i.e. all the pieces we're interested in have
4279
        // been downloaded. Release the files (they will open
4280
        // in read only mode if needed)
4281
0
        finished();
4282
        // if we just became a seed, picker is now invalid, since it
4283
        // is deallocated by the torrent once it starts seeding
4284
0
      }
4285
4286
0
      m_last_download = aux::time_now32();
4287
4288
0
#ifndef TORRENT_DISABLE_SHARE_MODE
4289
0
      if (m_share_mode)
4290
0
        recalc_share_mode();
4291
0
#endif
4292
0
    }
4293
663
    update_want_tick();
4294
663
  }
4295
4296
  boost::tribool torrent::on_blocks_hashed(piece_index_t const piece
4297
    , span<sha256_hash const> const block_hashes)
4298
0
  {
4299
0
    boost::tribool ret = boost::indeterminate;
4300
0
    need_hash_picker();
4301
4302
0
    int const blocks_in_piece = torrent_file().orig_files().blocks_in_piece2(piece);
4303
0
    int const blocks_per_piece = torrent_file().blocks_per_piece();
4304
4305
    // the blocks are guaranteed to represent exactly one piece
4306
0
    TORRENT_ASSERT(blocks_in_piece == int(block_hashes.size()));
4307
4308
0
    TORRENT_ALLOCA(block_passed, bool, blocks_in_piece);
4309
0
    std::fill(block_passed.begin(), block_passed.end(), false);
4310
4311
0
    set_block_hash_result last_result = set_block_hash_result(set_block_hash_result::result::unknown);
4312
4313
0
    for (int i = 0; i < blocks_in_piece; ++i)
4314
0
    {
4315
      // if there was an enoent or eof error the block hashes array may be incomplete
4316
      // bail if we've hit the end of the valid hashes
4317
0
      if (block_hashes[i].is_all_zeros()) return false;
4318
4319
0
      auto const result = get_hash_picker().set_block_hash(piece
4320
0
        , i * default_block_size, block_hashes[i]);
4321
0
      last_result = result;
4322
4323
      // all verified ranges should always be full pieces or less
4324
0
      TORRENT_ASSERT(result.first_verified_block >= 0
4325
0
        || (result.first_verified_block % blocks_per_piece) == 0);
4326
0
      TORRENT_ASSERT(result.num_verified <= blocks_per_piece
4327
0
        || (result.num_verified % blocks_per_piece) == 0);
4328
4329
0
      if (result.status == set_block_hash_result::result::success)
4330
0
      {
4331
0
        TORRENT_ASSERT(result.first_verified_block < blocks_in_piece);
4332
0
        TORRENT_ASSERT(blocks_in_piece <= blocks_per_piece);
4333
4334
        // note that result.num_verified may cover pad blocks too, and
4335
        // so may be > blocks_in_piece
4336
4337
        // sometimes, completing a single block may "unlock" validating
4338
        // multiple pieces. e.g. if we don't have the piece layer yet,
4339
        // but we completed the last block in the whole torrent, now we
4340
        // can validate everything. For this reason,
4341
        // first_verified_block may be negative.
4342
4343
        // In this call, we track the blocks in this piece though, in
4344
        // the block_passed array. For that tracking we need to clamp
4345
        // the start index to 0.
4346
0
        auto const first_block = std::max(0, result.first_verified_block);
4347
0
        auto const count = std::min(blocks_in_piece - first_block, result.num_verified);
4348
0
        std::fill_n(block_passed.begin() + first_block, count, true);
4349
4350
        // the current block (i) should be part of the range that was
4351
        // verified
4352
0
        TORRENT_ASSERT(first_block <= i);
4353
0
        TORRENT_ASSERT(i < first_block + count);
4354
4355
        // if the hashes for more than one piece have been verified,
4356
        // check for any pieces which were already checked but couldn't
4357
        // be verified and mark them as verified
4358
0
        for (piece_index_t verified_piece : result.piece_range(piece, blocks_per_piece))
4359
0
        {
4360
0
          if (!has_picker()
4361
0
            || verified_piece == piece
4362
0
            || !m_picker->is_piece_finished(verified_piece)
4363
0
            || m_picker->have_piece(verified_piece))
4364
0
            continue;
4365
4366
0
          TORRENT_ASSERT(get_hash_picker().piece_verified(verified_piece));
4367
0
          m_picker->piece_flushed(verified_piece);
4368
0
          update_gauge();
4369
0
          we_have(verified_piece);
4370
0
        }
4371
0
      }
4372
0
      else if (result.status == set_block_hash_result::result::block_hash_failed)
4373
0
      {
4374
0
        ret = false;
4375
0
      }
4376
0
    }
4377
0
    if (last_result.status == set_block_hash_result::result::piece_hash_failed)
4378
0
    {
4379
      // only if the *last* block causes the piece to fail, do we know
4380
      // it actually failed. Otherwise it might have been failing
4381
      // because of other, previously existing block hashes.
4382
0
      ret = false;
4383
4384
      // if the hashes for more than one piece have been verified,
4385
      // check for any pieces which were already checked but couldn't
4386
      // be verified and mark them as verified
4387
0
      for (piece_index_t verified_piece : last_result.piece_range(piece, blocks_per_piece))
4388
0
      {
4389
0
        if (!has_picker()
4390
0
          || verified_piece == piece)
4391
0
          continue;
4392
4393
0
        m_picker->we_dont_have(verified_piece);
4394
0
        update_gauge();
4395
0
        piece_failed(verified_piece);
4396
0
      }
4397
0
    }
4398
4399
0
    if (boost::indeterminate(ret) && std::all_of(block_passed.begin(), block_passed.end()
4400
0
      , [](bool e) { return e; }))
4401
0
    {
4402
0
      ret = true;
4403
0
    }
4404
0
    return ret;
4405
0
  }
4406
4407
  // this is called when the piece hash is checked as correct. Note
4408
  // that the piece picker and the torrent won't necessarily consider
4409
  // us to have this piece yet, since it might not have been flushed
4410
  // to disk yet. Only if we have predictive_piece_announce on will
4411
  // we announce this piece to peers at this point.
4412
  void torrent::piece_passed(piece_index_t const index)
4413
0
  {
4414
//    INVARIANT_CHECK;
4415
0
    TORRENT_ASSERT(is_single_thread());
4416
0
    TORRENT_ASSERT(!m_picker->have_piece(index));
4417
4418
#ifndef TORRENT_DISABLE_LOGGING
4419
    if (should_log())
4420
      debug_log("PIECE_PASSED (%d) (num_have: %d)", int(index), num_have());
4421
#endif
4422
4423
//    std::fprintf(stderr, "torrent::piece_passed piece:%d\n", index);
4424
4425
0
    TORRENT_ASSERT(index >= piece_index_t(0));
4426
0
    TORRENT_ASSERT(index < m_torrent_file->end_piece());
4427
4428
0
    set_need_save_resume(torrent_handle::if_download_progress);
4429
4430
0
    inc_stats_counter(counters::num_piece_passed);
4431
4432
0
    if (settings().get_int(settings_pack::suggest_mode)
4433
0
      == settings_pack::suggest_read_cache)
4434
0
    {
4435
      // we just got a new piece. Chances are that it's actually the
4436
      // rarest piece (since we're likely to download pieces rarest first)
4437
      // if it's rarer than any other piece that we currently suggest, insert
4438
      // it in the suggest set and pop the last one out
4439
0
      add_suggest_piece(index);
4440
0
    }
4441
4442
    // increase the trust point of all peers that sent
4443
    // parts of this piece.
4444
0
    std::set<torrent_peer*> const peers = [&]
4445
0
    {
4446
0
      std::vector<torrent_peer*> const downloaders = m_picker->get_downloaders(index);
4447
4448
0
      std::set<torrent_peer*> ret;
4449
      // these torrent_peer pointers are owned by m_peer_list and they may be
4450
      // invalidated if a peer disconnects. We cannot keep them across any
4451
      // significant operations, but we should use them right away
4452
      // ignore nullptrs
4453
0
      std::remove_copy(downloaders.begin(), downloaders.end()
4454
0
        , std::inserter(ret, ret.begin()), static_cast<torrent_peer*>(nullptr));
4455
0
      return ret;
4456
0
    }();
4457
4458
0
    for (auto p : peers)
4459
0
    {
4460
0
      TORRENT_ASSERT(p != nullptr);
4461
0
      if (p == nullptr) continue;
4462
0
      TORRENT_ASSERT(p->in_use);
4463
0
      p->on_parole = false;
4464
0
      int trust_points = p->trust_points;
4465
0
      ++trust_points;
4466
0
      if (trust_points > 8) trust_points = 8;
4467
0
      p->trust_points = trust_points;
4468
0
      if (p->connection)
4469
0
      {
4470
0
        auto* peer = static_cast<peer_connection*>(p->connection);
4471
0
        TORRENT_ASSERT(peer->m_in_use == 1337);
4472
0
        peer->received_valid_data(index);
4473
0
      }
4474
0
    }
4475
4476
0
    m_picker->piece_passed(index);
4477
0
    update_gauge();
4478
0
    we_have(index);
4479
4480
#ifndef TORRENT_DISABLE_LOGGING
4481
    if (should_log())
4482
      debug_log("we_have(%d) (num_have: %d)", int(index), num_have());
4483
#endif
4484
0
#ifndef TORRENT_DISABLE_STREAMING
4485
0
    remove_time_critical_piece(index, true);
4486
0
#endif
4487
0
  }
4488
4489
#ifndef TORRENT_DISABLE_PREDICTIVE_PIECES
4490
  // we believe we will complete this piece very soon
4491
  // announce it to peers ahead of time to eliminate the
4492
  // round-trip times involved in announcing it, requesting it
4493
  // and sending it
4494
  // TODO: 2 use chrono type for time duration
4495
  void torrent::predicted_have_piece(piece_index_t const index, int const milliseconds)
4496
0
  {
4497
0
    auto const i = std::lower_bound(m_predictive_pieces.begin()
4498
0
      , m_predictive_pieces.end(), index);
4499
0
    if (i != m_predictive_pieces.end() && *i == index) return;
4500
4501
0
    for (auto p : m_connections)
4502
0
    {
4503
0
      TORRENT_INCREMENT(m_iterating_connections);
4504
#ifndef TORRENT_DISABLE_LOGGING
4505
      p->peer_log(peer_log_alert::outgoing, "PREDICTIVE_HAVE", "piece: %d expected in %d ms"
4506
        , static_cast<int>(index), milliseconds);
4507
#else
4508
0
      TORRENT_UNUSED(milliseconds);
4509
0
#endif
4510
0
      p->announce_piece(index);
4511
0
    }
4512
4513
0
    m_predictive_pieces.insert(i, index);
4514
0
  }
4515
#endif
4516
4517
  // blocks may contain the block indices of the blocks that failed (if this is
4518
  // a v2 torrent).
4519
  void torrent::piece_failed(piece_index_t const index, std::vector<int> blocks)
4520
0
  {
4521
    // if the last piece fails the peer connection will still
4522
    // think that it has received all of it until this function
4523
    // resets the download queue. So, we cannot do the
4524
    // invariant check here since it assumes:
4525
    // (total_done == m_torrent_file->total_size()) => is_seed()
4526
0
    INVARIANT_CHECK;
4527
0
    TORRENT_ASSERT(is_single_thread());
4528
4529
0
    TORRENT_ASSERT(has_picker());
4530
0
    TORRENT_ASSERT(index >= piece_index_t(0));
4531
0
    TORRENT_ASSERT(index < m_torrent_file->end_piece());
4532
0
    TORRENT_ASSERT(std::is_sorted(blocks.begin(), blocks.end()));
4533
4534
0
    inc_stats_counter(counters::num_piece_failed);
4535
4536
0
#ifndef TORRENT_DISABLE_PREDICTIVE_PIECES
4537
0
    auto const it = std::lower_bound(m_predictive_pieces.begin()
4538
0
      , m_predictive_pieces.end(), index);
4539
0
    if (it != m_predictive_pieces.end() && *it == index)
4540
0
    {
4541
0
      for (auto p : m_connections)
4542
0
      {
4543
0
        TORRENT_INCREMENT(m_iterating_connections);
4544
        // send reject messages for
4545
        // potential outstanding requests to this piece
4546
0
        p->reject_piece(index);
4547
        // let peers that support the dont-have message
4548
        // know that we don't actually have this piece
4549
0
        p->write_dont_have(index);
4550
0
      }
4551
0
      m_predictive_pieces.erase(it);
4552
0
    }
4553
0
#endif
4554
4555
0
    std::vector<torrent_peer*> const downloaders = m_picker->get_downloaders(index);
4556
4557
    // decrease the trust point of all peers that sent
4558
    // parts of this piece.
4559
    // first, build a set of all peers that participated
4560
    // if we know which blocks failed, just include the peer(s) sending those
4561
    // blocks
4562
0
    std::set<torrent_peer*> const peers = [&]
4563
0
    {
4564
0
      std::set<torrent_peer*> ret;
4565
0
      if (!blocks.empty() && !downloaders.empty())
4566
0
      {
4567
0
        for (auto const b : blocks) ret.insert(downloaders[std::size_t(b)]);
4568
0
      }
4569
0
      else
4570
0
      {
4571
0
        std::copy(downloaders.begin(), downloaders.end(), std::inserter(ret, ret.begin()));
4572
0
      }
4573
0
      return ret;
4574
0
    }();
4575
4576
    // if this piece wasn't downloaded from peers, we just found it on disk.
4577
    // In that case, we should just consider it as "not-have" and there's no
4578
    // need to try to get higher fidelity hashes (yet)
4579
0
    bool const found_on_disk = peers.size() == 1 && peers.count(nullptr);
4580
4581
0
    if (!torrent_file().info_hashes().has_v1() && blocks.empty() && !found_on_disk)
4582
0
    {
4583
      // TODO: only do this if the piece size > 1 blocks
4584
      // This is a v2 torrent so we can request get block
4585
      // level hashes.
4586
0
      verify_block_hashes(index);
4587
0
    }
4588
4589
    // the below code is penalizing peers that sent use bad data.
4590
    // increase the total amount of failed bytes
4591
0
    if (!found_on_disk)
4592
0
    {
4593
0
      if (blocks.empty())
4594
0
        add_failed_bytes(m_torrent_file->piece_size(index));
4595
0
      else
4596
0
        add_failed_bytes(static_cast<int>(blocks.size()) * default_block_size);
4597
4598
0
#ifndef TORRENT_DISABLE_EXTENSIONS
4599
0
      for (auto& ext : m_extensions)
4600
0
      {
4601
0
        ext->on_piece_failed(index);
4602
0
      }
4603
0
#endif
4604
4605
      // did we receive this piece from a single peer?
4606
      // if we know exactly which blocks failed the hash, we can also be certain
4607
      // that all peers in the list sent us bad data
4608
0
      bool const known_bad_peer = (!found_on_disk && peers.size() == 1) || !blocks.empty();
4609
4610
0
      penalize_peers(peers, index, known_bad_peer);
4611
0
    }
4612
4613
    // If m_storage isn't set here, it means we're shutting down
4614
0
    if (m_storage)
4615
0
    {
4616
      // it doesn't make much sense to fail to hash a piece
4617
      // without having a storage associated with the torrent.
4618
      // restoring the piece in the piece picker without calling
4619
      // clear piece on the disk thread will make them out of
4620
      // sync, and if we try to write more blocks to this piece
4621
      // the disk thread will barf, because it hasn't been cleared
4622
0
      TORRENT_ASSERT(m_storage);
4623
4624
      // don't allow picking any blocks from this piece
4625
      // until we're done synchronizing with the disk threads.
4626
0
      m_picker->lock_piece(index);
4627
4628
      // don't do this until after the plugins have had a chance
4629
      // to read back the blocks that failed, for blame purposes
4630
      // this way they have a chance to hit the cache
4631
0
      m_ses.disk_thread().async_clear_piece(m_storage, index
4632
0
        , [self = shared_from_this(), c = std::move(blocks)](piece_index_t const& p)
4633
0
        { self->on_piece_sync(p, c); });
4634
0
      m_ses.deferred_submit_jobs();
4635
0
    }
4636
0
    else
4637
0
    {
4638
0
      TORRENT_ASSERT(m_abort);
4639
      // it doesn't really matter what we do
4640
      // here, since we're about to destruct the
4641
      // torrent anyway.
4642
0
      on_piece_sync(index, std::move(blocks));
4643
0
    }
4644
0
  }
4645
4646
  void torrent::penalize_peers(std::set<torrent_peer*> const& peers
4647
    , piece_index_t const index, bool const known_bad_peer)
4648
0
  {
4649
0
    for (auto p : peers)
4650
0
    {
4651
0
      if (p == nullptr) continue;
4652
0
      TORRENT_ASSERT(p->in_use);
4653
0
      bool allow_disconnect = true;
4654
0
      if (p->connection)
4655
0
      {
4656
0
        auto* peer = static_cast<peer_connection*>(p->connection);
4657
0
        TORRENT_ASSERT(peer->m_in_use == 1337);
4658
4659
        // the peer implementation can ask not to be disconnected.
4660
        // this is used for web seeds for instance, to instead of
4661
        // disconnecting, mark the file as not being had.
4662
0
        allow_disconnect = peer->received_invalid_data(index, known_bad_peer);
4663
0
      }
4664
4665
0
      if (settings().get_bool(settings_pack::use_parole_mode))
4666
0
        p->on_parole = true;
4667
4668
0
      int hashfails = p->hashfails;
4669
0
      int trust_points = p->trust_points;
4670
4671
      // we decrease more than we increase, to keep the
4672
      // allowed failed/passed ratio low.
4673
0
      trust_points -= 2;
4674
0
      ++hashfails;
4675
0
      if (trust_points < -7) trust_points = -7;
4676
0
      p->trust_points = trust_points;
4677
0
      if (hashfails > 255) hashfails = 255;
4678
0
      p->hashfails = std::uint8_t(hashfails);
4679
4680
      // either, we have received too many failed hashes
4681
      // or this was the only peer that sent us this piece.
4682
      // if we have failed more than 3 pieces from this peer,
4683
      // don't trust it regardless.
4684
0
      if (p->trust_points <= -7
4685
0
        || (known_bad_peer && allow_disconnect))
4686
0
      {
4687
        // we don't trust this peer anymore
4688
        // ban it.
4689
0
        if (m_ses.alerts().should_post<peer_ban_alert>())
4690
0
        {
4691
0
          peer_id const pid = p->connection
4692
0
            ? p->connection->pid() : peer_id();
4693
0
          m_ses.alerts().emplace_alert<peer_ban_alert>(
4694
0
            get_handle(), p->ip(), pid);
4695
0
        }
4696
4697
        // mark the peer as banned
4698
0
        ban_peer(p);
4699
0
        update_want_peers();
4700
0
        inc_stats_counter(counters::banned_for_hash_failure);
4701
4702
0
        if (p->connection)
4703
0
        {
4704
0
          auto* peer = static_cast<peer_connection*>(p->connection);
4705
#ifndef TORRENT_DISABLE_LOGGING
4706
          if (should_log())
4707
          {
4708
            debug_log("*** BANNING PEER: \"%s\" Too many corrupt pieces"
4709
              , print_endpoint(p->ip()).c_str());
4710
          }
4711
          peer->peer_log(peer_log_alert::info, "BANNING_PEER", "Too many corrupt pieces");
4712
#endif
4713
0
          peer->disconnect(errors::too_many_corrupt_pieces, operation_t::bittorrent);
4714
0
        }
4715
0
      }
4716
0
    }
4717
0
  }
4718
4719
  void torrent::peer_is_interesting(peer_connection& c)
4720
493
  {
4721
493
    INVARIANT_CHECK;
4722
4723
    // no peer should be interesting if we're finished
4724
493
    TORRENT_ASSERT(!is_finished());
4725
4726
493
    if (c.in_handshake()) return;
4727
493
    c.send_interested();
4728
493
    if (c.has_peer_choked()
4729
493
      && c.allowed_fast().empty())
4730
100
      return;
4731
4732
393
    if (request_a_block(*this, c))
4733
132
      inc_stats_counter(counters::interesting_piece_picks);
4734
393
    c.send_block_requests();
4735
393
  }
4736
4737
0
  void torrent::on_piece_sync(piece_index_t const piece, std::vector<int> const& blocks) try
4738
0
  {
4739
    // the user may have called force_recheck, which clears
4740
    // the piece picker
4741
0
    if (!has_picker()) return;
4742
4743
    // unlock the piece and restore it, as if no block was
4744
    // ever downloaded for it.
4745
0
    m_picker->restore_piece(piece, blocks);
4746
4747
0
    if (m_ses.alerts().should_post<hash_failed_alert>())
4748
0
      m_ses.alerts().emplace_alert<hash_failed_alert>(get_handle(), piece);
4749
4750
    // we have to let the piece_picker know that
4751
    // this piece failed the check as it can restore it
4752
    // and mark it as being interesting for download
4753
0
    TORRENT_ASSERT(!m_picker->have_piece(piece));
4754
4755
    // loop over all peers and re-request potential duplicate
4756
    // blocks to this piece
4757
0
    for (auto p : m_connections)
4758
0
    {
4759
0
      TORRENT_INCREMENT(m_iterating_connections);
4760
0
      for (auto const& b : p->download_queue())
4761
0
      {
4762
0
        if (b.timed_out || b.not_wanted) continue;
4763
0
        if (b.block.piece_index != piece) continue;
4764
0
        if (!blocks.empty()
4765
0
          && std::find(blocks.begin(), blocks.end(), b.block.block_index) == blocks.end())
4766
0
          continue;
4767
0
        m_picker->mark_as_downloading(b.block, p->peer_info_struct()
4768
0
          , p->picker_options());
4769
0
      }
4770
0
      for (auto const& b : p->request_queue())
4771
0
      {
4772
0
        if (b.block.piece_index != piece) continue;
4773
0
        if (!blocks.empty()
4774
0
          && std::find(blocks.begin(), blocks.end(), b.block.block_index) == blocks.end())
4775
0
          continue;
4776
0
        m_picker->mark_as_downloading(b.block, p->peer_info_struct()
4777
0
          , p->picker_options());
4778
0
      }
4779
0
    }
4780
0
  }
4781
0
  catch (...) { handle_exception(); }
4782
4783
  void torrent::peer_has(piece_index_t const index, peer_connection const* peer)
4784
330
  {
4785
330
    if (has_picker())
4786
330
    {
4787
330
      torrent_peer* pp = peer->peer_info_struct();
4788
330
      m_picker->inc_refcount(index, pp);
4789
330
    }
4790
0
    else
4791
0
    {
4792
0
      TORRENT_ASSERT(is_seed() || !m_have_all);
4793
0
    }
4794
330
  }
4795
4796
  // when we get a bitfield message, this is called for that piece
4797
  void torrent::peer_has(typed_bitfield<piece_index_t> const& bits
4798
    , peer_connection const* peer)
4799
2.57k
  {
4800
2.57k
    if (has_picker())
4801
2.57k
    {
4802
2.57k
      TORRENT_ASSERT(bits.size() == torrent_file().num_pieces());
4803
2.57k
      torrent_peer* pp = peer->peer_info_struct();
4804
2.57k
      m_picker->inc_refcount(bits, pp);
4805
2.57k
    }
4806
0
    else
4807
0
    {
4808
0
      TORRENT_ASSERT(is_seed() || !m_have_all);
4809
0
    }
4810
2.57k
  }
4811
4812
  void torrent::peer_has_all(peer_connection const* peer)
4813
52
  {
4814
52
    if (has_picker())
4815
52
    {
4816
52
      torrent_peer* pp = peer->peer_info_struct();
4817
52
      m_picker->inc_refcount_all(pp);
4818
52
    }
4819
0
    else
4820
0
    {
4821
0
      TORRENT_ASSERT(is_seed() || !m_have_all);
4822
0
    }
4823
52
  }
4824
4825
  void torrent::peer_lost(typed_bitfield<piece_index_t> const& bits
4826
    , peer_connection const* peer)
4827
2.78k
  {
4828
2.78k
    if (has_picker())
4829
2.78k
    {
4830
2.78k
      TORRENT_ASSERT(bits.size() == torrent_file().num_pieces());
4831
2.78k
      torrent_peer* pp = peer->peer_info_struct();
4832
2.78k
      m_picker->dec_refcount(bits, pp);
4833
2.78k
    }
4834
0
    else
4835
0
    {
4836
0
      TORRENT_ASSERT(is_seed() || !m_have_all);
4837
0
    }
4838
2.78k
  }
4839
4840
  void torrent::peer_lost(piece_index_t const index, peer_connection const* peer)
4841
21
  {
4842
21
    if (m_picker)
4843
21
    {
4844
21
      torrent_peer* pp = peer->peer_info_struct();
4845
21
      m_picker->dec_refcount(index, pp);
4846
21
    }
4847
0
    else
4848
0
    {
4849
0
      TORRENT_ASSERT(is_seed() || !m_have_all);
4850
0
    }
4851
21
  }
4852
4853
  void torrent::abort()
4854
1.88k
  {
4855
1.88k
    TORRENT_ASSERT(is_single_thread());
4856
4857
1.88k
    if (m_abort) return;
4858
4859
1.88k
    m_abort = true;
4860
1.88k
    update_want_peers();
4861
1.88k
    update_want_tick();
4862
1.88k
    update_want_scrape();
4863
1.88k
    update_gauge();
4864
1.88k
    stop_announcing();
4865
4866
    // remove from download queue
4867
1.88k
    m_ses.set_queue_position(this, queue_position_t{-1});
4868
4869
1.88k
    if (m_peer_class > peer_class_t{0})
4870
351
    {
4871
351
      remove_class(m_ses.peer_classes(), m_peer_class);
4872
351
      m_ses.peer_classes().decref(m_peer_class);
4873
351
      m_peer_class = peer_class_t{0};
4874
351
    }
4875
4876
1.88k
    m_inactivity_timer.cancel();
4877
4878
#ifndef TORRENT_DISABLE_LOGGING
4879
    log_to_all_peers("aborting");
4880
#endif
4881
4882
    // disconnect all peers and close all
4883
    // files belonging to the torrents
4884
1.88k
    disconnect_all(errors::torrent_aborted, operation_t::bittorrent);
4885
4886
    // make sure to destruct the peers immediately
4887
1.88k
    on_remove_peers();
4888
1.88k
    TORRENT_ASSERT(m_connections.empty());
4889
4890
    // post a message to the main thread to destruct
4891
    // the torrent object from there
4892
1.88k
    if (m_storage)
4893
1.88k
    {
4894
1.88k
      try {
4895
1.88k
        m_ses.disk_thread().async_stop_torrent(m_storage
4896
1.88k
          , std::bind(&torrent::on_torrent_aborted, shared_from_this()));
4897
1.88k
      }
4898
1.88k
      catch (std::exception const& e)
4899
1.88k
      {
4900
0
        TORRENT_UNUSED(e);
4901
0
        m_storage.reset();
4902
#ifndef TORRENT_DISABLE_LOGGING
4903
        debug_log("Failed to flush disk cache: %s", e.what());
4904
#endif
4905
        // clients may rely on this alert to be posted, so it's probably a
4906
        // good idea to post it here, even though we failed
4907
        // TODO: 3 should this alert have an error code in it?
4908
0
        if (alerts().should_post<cache_flushed_alert>())
4909
0
          alerts().emplace_alert<cache_flushed_alert>(get_handle());
4910
0
      }
4911
1.88k
      m_ses.deferred_submit_jobs();
4912
1.88k
    }
4913
0
    else
4914
0
    {
4915
0
      if (alerts().should_post<cache_flushed_alert>())
4916
0
        alerts().emplace_alert<cache_flushed_alert>(get_handle());
4917
0
      alerts().emplace_alert<torrent_removed_alert>(get_handle()
4918
0
        , info_hash(), get_userdata());
4919
0
    }
4920
4921
    // TODO: 2 abort lookups this torrent has made via the
4922
    // session host resolver interface
4923
4924
1.88k
    if (!m_apply_ip_filter)
4925
1.27k
    {
4926
1.27k
      inc_stats_counter(counters::non_filter_torrents, -1);
4927
1.27k
      m_apply_ip_filter = true;
4928
1.27k
    }
4929
4930
1.88k
    m_paused = false;
4931
1.88k
    m_auto_managed = false;
4932
1.88k
    update_state_list();
4933
16.9k
    for (torrent_list_index_t i{}; i != m_links.end_index(); ++i)
4934
15.0k
    {
4935
15.0k
      if (!m_links[i].in_list()) continue;
4936
584
      m_links[i].unlink(m_ses.torrent_list(i), i);
4937
584
    }
4938
    // don't re-add this torrent to the state-update list
4939
1.88k
    m_state_subscription = false;
4940
1.88k
  }
4941
4942
  // this is called when we're destructing non-gracefully. i.e. we're _just_
4943
  // destructing everything.
4944
  void torrent::panic()
4945
0
  {
4946
0
    m_storage.reset();
4947
    // if there are any other peers allocated still, we need to clear them
4948
    // now. They can't be cleared later because the allocator will already
4949
    // have been destructed
4950
0
    if (m_peer_list) m_peer_list->clear();
4951
0
    m_connections.clear();
4952
0
    m_outgoing_pids.clear();
4953
0
    m_peers_to_disconnect.clear();
4954
0
    m_num_uploads = 0;
4955
0
    m_num_connecting = 0;
4956
0
    m_num_connecting_seeds = 0;
4957
0
  }
4958
4959
#ifndef TORRENT_DISABLE_SUPERSEEDING
4960
  void torrent::set_super_seeding(bool const on)
4961
0
  {
4962
0
    if (on == m_super_seeding) return;
4963
4964
0
    m_super_seeding = on;
4965
0
    set_need_save_resume(torrent_handle::if_state_changed);
4966
0
    state_updated();
4967
4968
0
    if (m_super_seeding) return;
4969
4970
    // disable super seeding for all peers
4971
0
    for (auto pc : *this)
4972
0
    {
4973
0
      pc->superseed_piece(piece_index_t(-1), piece_index_t(-1));
4974
0
    }
4975
0
  }
4976
4977
  // TODO: 3 this should return optional<>. piece index -1 should not be
4978
  // allowed
4979
  piece_index_t torrent::get_piece_to_super_seed(typed_bitfield<piece_index_t> const& bits)
4980
0
  {
4981
    // return a piece with low availability that is not in
4982
    // the bitfield and that is not currently being super
4983
    // seeded by any peer
4984
0
    TORRENT_ASSERT(m_super_seeding);
4985
4986
    // do a linear search from the first piece
4987
0
    int min_availability = 9999;
4988
0
    std::vector<piece_index_t> avail_vec;
4989
0
    for (auto const i : m_torrent_file->piece_range())
4990
0
    {
4991
0
      if (bits[i]) continue;
4992
4993
0
      int availability = 0;
4994
0
      for (auto pc : *this)
4995
0
      {
4996
0
        if (pc->super_seeded_piece(i))
4997
0
        {
4998
          // avoid super-seeding the same piece to more than one
4999
          // peer if we can avoid it. Do this by artificially
5000
          // increase the availability
5001
0
          availability = 999;
5002
0
          break;
5003
0
        }
5004
0
        if (pc->has_piece(i)) ++availability;
5005
0
      }
5006
0
      if (availability > min_availability) continue;
5007
0
      if (availability == min_availability)
5008
0
      {
5009
0
        avail_vec.push_back(i);
5010
0
        continue;
5011
0
      }
5012
0
      TORRENT_ASSERT(availability < min_availability);
5013
0
      min_availability = availability;
5014
0
      avail_vec.clear();
5015
0
      avail_vec.push_back(i);
5016
0
    }
5017
5018
0
    if (avail_vec.empty()) return piece_index_t{-1};
5019
0
    return avail_vec[random(std::uint32_t(avail_vec.size() - 1))];
5020
0
  }
5021
#endif
5022
5023
0
  void torrent::on_files_deleted(storage_error const& error) try
5024
0
  {
5025
0
    TORRENT_ASSERT(is_single_thread());
5026
5027
0
    if (error)
5028
0
    {
5029
0
      if (alerts().should_post<torrent_delete_failed_alert>())
5030
0
        alerts().emplace_alert<torrent_delete_failed_alert>(get_handle()
5031
0
          , error.ec, m_torrent_file->info_hashes());
5032
0
    }
5033
0
    else
5034
0
    {
5035
0
      alerts().emplace_alert<torrent_deleted_alert>(get_handle(), m_torrent_file->info_hashes());
5036
0
    }
5037
0
  }
5038
0
  catch (...) { handle_exception(); }
5039
5040
  void torrent::on_file_renamed(std::string const& filename
5041
    , file_index_t const file_idx
5042
0
    , storage_error const& error) try
5043
0
  {
5044
0
    TORRENT_ASSERT(is_single_thread());
5045
5046
0
    if (error)
5047
0
    {
5048
0
      if (alerts().should_post<file_rename_failed_alert>())
5049
0
        alerts().emplace_alert<file_rename_failed_alert>(get_handle()
5050
0
          , file_idx, error.ec);
5051
0
    }
5052
0
    else
5053
0
    {
5054
0
      if (alerts().should_post<file_renamed_alert>())
5055
0
        alerts().emplace_alert<file_renamed_alert>(get_handle()
5056
0
          , filename, m_torrent_file->files().file_path(file_idx), file_idx);
5057
0
      m_torrent_file->rename_file(file_idx, filename);
5058
5059
0
      set_need_save_resume(torrent_handle::if_state_changed);
5060
0
    }
5061
0
  }
5062
0
  catch (...) { handle_exception(); }
5063
5064
558
  void torrent::on_torrent_paused() try
5065
558
  {
5066
558
    TORRENT_ASSERT(is_single_thread());
5067
5068
558
    if (alerts().should_post<torrent_paused_alert>())
5069
0
      alerts().emplace_alert<torrent_paused_alert>(get_handle());
5070
558
  }
5071
558
  catch (...) { handle_exception(); }
5072
5073
#if TORRENT_ABI_VERSION == 1
5074
  std::string torrent::tracker_login() const
5075
0
  {
5076
0
    if (m_username.empty() && m_password.empty()) return "";
5077
0
    return m_username + ":" + m_password;
5078
0
  }
5079
#endif
5080
5081
  std::uint32_t torrent::tracker_key() const
5082
0
  {
5083
0
    auto const self = reinterpret_cast<uintptr_t>(this);
5084
0
    auto const ses = reinterpret_cast<uintptr_t>(&m_ses);
5085
0
    std::uint32_t const storage = m_storage
5086
0
      ? static_cast<std::uint32_t>(static_cast<storage_index_t>(m_storage))
5087
0
      : 0;
5088
0
    sha1_hash const h = hasher(reinterpret_cast<char const*>(&self), sizeof(self))
5089
0
      .update(reinterpret_cast<char const*>(&storage), sizeof(storage))
5090
0
      .update(reinterpret_cast<char const*>(&ses), sizeof(ses))
5091
0
      .final();
5092
0
    unsigned char const* ptr = &h[0];
5093
0
    return aux::read_uint32(ptr);
5094
0
  }
5095
5096
#ifndef TORRENT_DISABLE_STREAMING
5097
  void torrent::cancel_non_critical()
5098
0
  {
5099
    // if we don't have a piece picker, there's nothing to cancel.
5100
    // e.g. We may have become a seed already.
5101
0
    if (!has_picker()) return;
5102
5103
0
    std::set<piece_index_t> time_critical;
5104
0
    for (auto const& p : m_time_critical_pieces)
5105
0
      time_critical.insert(p.piece);
5106
5107
0
    for (auto p : m_connections)
5108
0
    {
5109
0
      TORRENT_INCREMENT(m_iterating_connections);
5110
      // for each peer, go through its download and request queue
5111
      // and cancel everything, except pieces that are time critical
5112
5113
      // make a copy of the download queue since we may be cancelling entries
5114
      // from it from within the loop
5115
0
      std::vector<pending_block> dq = p->download_queue();
5116
0
      for (auto const& k : dq)
5117
0
      {
5118
0
        if (time_critical.count(k.block.piece_index)) continue;
5119
0
        if (k.not_wanted || k.timed_out) continue;
5120
0
        p->cancel_request(k.block, true);
5121
0
      }
5122
5123
      // make a copy of the download queue since we may be cancelling entries
5124
      // from it from within the loop
5125
0
      std::vector<pending_block> rq = p->request_queue();
5126
0
      for (auto const& k : rq)
5127
0
      {
5128
0
        if (time_critical.count(k.block.piece_index)) continue;
5129
0
        p->cancel_request(k.block, true);
5130
0
      }
5131
0
    }
5132
0
  }
5133
5134
  void torrent::set_piece_deadline(piece_index_t const piece, int const t
5135
    , deadline_flags_t const flags)
5136
0
  {
5137
0
    INVARIANT_CHECK;
5138
5139
0
    TORRENT_ASSERT_PRECOND(piece >= piece_index_t(0));
5140
0
    TORRENT_ASSERT_PRECOND(valid_metadata());
5141
0
    TORRENT_ASSERT_PRECOND(valid_metadata() && piece < m_torrent_file->end_piece());
5142
5143
0
    if (m_abort || !valid_metadata()
5144
0
      || piece < piece_index_t(0)
5145
0
      || piece >= m_torrent_file->end_piece())
5146
0
    {
5147
      // failed
5148
0
      if (flags & torrent_handle::alert_when_available)
5149
0
      {
5150
0
        m_ses.alerts().emplace_alert<read_piece_alert>(
5151
0
          get_handle(), piece, error_code(boost::system::errc::operation_canceled, generic_category()));
5152
0
      }
5153
0
      return;
5154
0
    }
5155
5156
0
    time_point const deadline = aux::time_now() + milliseconds(t);
5157
5158
    // if we already have the piece, no need to set the deadline.
5159
    // however, if the user asked to get the piece data back, we still
5160
    // need to read it and post it back to the user
5161
0
    if (is_seed() || (has_picker() && m_picker->have_piece(piece)))
5162
0
    {
5163
0
      if (flags & torrent_handle::alert_when_available)
5164
0
        read_piece(piece);
5165
0
      return;
5166
0
    }
5167
5168
    // if this is the first time critical piece we add. in order to make it
5169
    // react quickly, cancel all the currently outstanding requests
5170
0
    if (m_time_critical_pieces.empty())
5171
0
    {
5172
      // defer this by posting it to the end of the message queue.
5173
      // this gives the client a chance to specify multiple time-critical
5174
      // pieces before libtorrent cancels requests
5175
0
      auto self = shared_from_this();
5176
0
      post(m_ses.get_context(), [self] { self->wrap(&torrent::cancel_non_critical); });
5177
0
    }
5178
5179
0
    for (auto i = m_time_critical_pieces.begin()
5180
0
      , end(m_time_critical_pieces.end()); i != end; ++i)
5181
0
    {
5182
0
      if (i->piece != piece) continue;
5183
0
      i->deadline = deadline;
5184
0
      i->flags = flags;
5185
5186
      // resort i since deadline might have changed
5187
0
      while (std::next(i) != m_time_critical_pieces.end() && i->deadline > std::next(i)->deadline)
5188
0
      {
5189
0
        std::iter_swap(i, std::next(i));
5190
0
        ++i;
5191
0
      }
5192
0
      while (i != m_time_critical_pieces.begin() && i->deadline < std::prev(i)->deadline)
5193
0
      {
5194
0
        std::iter_swap(i, std::prev(i));
5195
0
        --i;
5196
0
      }
5197
      // just in case this piece had priority 0
5198
0
      download_priority_t const prev_prio = m_picker->piece_priority(piece);
5199
0
      bool const was_finished = is_finished();
5200
0
      bool const filter_updated = m_picker->set_piece_priority(piece, top_priority);
5201
0
      if (prev_prio == dont_download)
5202
0
      {
5203
0
        update_gauge();
5204
0
        if (filter_updated) update_peer_interest(was_finished);
5205
0
      }
5206
0
      return;
5207
0
    }
5208
5209
0
    need_picker();
5210
5211
0
    time_critical_piece p;
5212
0
    p.first_requested = min_time();
5213
0
    p.last_requested = min_time();
5214
0
    p.flags = flags;
5215
0
    p.deadline = deadline;
5216
0
    p.peers = 0;
5217
0
    p.piece = piece;
5218
0
    auto const critical_piece_it = std::upper_bound(m_time_critical_pieces.begin()
5219
0
      , m_time_critical_pieces.end(), p);
5220
0
    m_time_critical_pieces.insert(critical_piece_it, p);
5221
5222
    // just in case this piece had priority 0
5223
0
    download_priority_t const prev_prio = m_picker->piece_priority(piece);
5224
0
    bool const was_finished = is_finished();
5225
0
    bool const filter_updated = m_picker->set_piece_priority(piece, top_priority);
5226
0
    if (prev_prio == dont_download)
5227
0
    {
5228
0
      update_gauge();
5229
0
      if (filter_updated) update_peer_interest(was_finished);
5230
0
    }
5231
5232
0
    piece_picker::downloading_piece pi;
5233
0
    m_picker->piece_info(piece, pi);
5234
0
    if (pi.requested == 0) return;
5235
    // this means we have outstanding requests (or queued
5236
    // up requests that haven't been sent yet). Promote them
5237
    // to deadline pieces immediately
5238
0
    std::vector<torrent_peer*> const downloaders
5239
0
      = m_picker->get_downloaders(piece);
5240
5241
0
    int block = 0;
5242
0
    for (auto i = downloaders.begin()
5243
0
      , end(downloaders.end()); i != end; ++i, ++block)
5244
0
    {
5245
0
      torrent_peer* const tp = *i;
5246
0
      if (tp == nullptr || tp->connection == nullptr) continue;
5247
0
      auto* peer = static_cast<peer_connection*>(tp->connection);
5248
0
      peer->make_time_critical(piece_block(piece, block));
5249
0
    }
5250
0
  }
5251
5252
  void torrent::reset_piece_deadline(piece_index_t piece)
5253
0
  {
5254
0
    remove_time_critical_piece(piece);
5255
0
  }
5256
5257
  void torrent::remove_time_critical_piece(piece_index_t const piece, bool const finished)
5258
663
  {
5259
663
    for (auto i = m_time_critical_pieces.begin(), end(m_time_critical_pieces.end());
5260
663
      i != end; ++i)
5261
0
    {
5262
0
      if (i->piece != piece) continue;
5263
0
      if (finished)
5264
0
      {
5265
0
        if (i->flags & torrent_handle::alert_when_available)
5266
0
        {
5267
0
          read_piece(i->piece);
5268
0
        }
5269
5270
        // if first_requested is min_time(), it wasn't requested as a critical piece
5271
        // and we shouldn't adjust any average download times
5272
0
        if (i->first_requested != min_time())
5273
0
        {
5274
          // update the average download time and average
5275
          // download time deviation
5276
0
          int const dl_time = aux::numeric_cast<int>(total_milliseconds(aux::time_now() - i->first_requested));
5277
5278
0
          if (m_average_piece_time == 0)
5279
0
          {
5280
0
            m_average_piece_time = dl_time;
5281
0
          }
5282
0
          else
5283
0
          {
5284
0
            int diff = std::abs(dl_time - m_average_piece_time);
5285
0
            if (m_piece_time_deviation == 0) m_piece_time_deviation = diff;
5286
0
            else m_piece_time_deviation = (m_piece_time_deviation * 9 + diff) / 10;
5287
5288
0
            m_average_piece_time = (m_average_piece_time * 9 + dl_time) / 10;
5289
0
          }
5290
0
        }
5291
0
      }
5292
0
      else if (i->flags & torrent_handle::alert_when_available)
5293
0
      {
5294
        // post an empty read_piece_alert to indicate it failed
5295
0
        alerts().emplace_alert<read_piece_alert>(
5296
0
          get_handle(), piece, error_code(boost::system::errc::operation_canceled, generic_category()));
5297
0
      }
5298
0
      if (has_picker()) m_picker->set_piece_priority(piece, low_priority);
5299
0
      m_time_critical_pieces.erase(i);
5300
0
      return;
5301
0
    }
5302
663
  }
5303
5304
  void torrent::clear_time_critical()
5305
0
  {
5306
0
    for (auto i = m_time_critical_pieces.begin(); i != m_time_critical_pieces.end();)
5307
0
    {
5308
0
      if (i->flags & torrent_handle::alert_when_available)
5309
0
      {
5310
        // post an empty read_piece_alert to indicate it failed
5311
0
        m_ses.alerts().emplace_alert<read_piece_alert>(
5312
0
          get_handle(), i->piece, error_code(boost::system::errc::operation_canceled, generic_category()));
5313
0
      }
5314
0
      if (has_picker()) m_picker->set_piece_priority(i->piece, low_priority);
5315
0
      i = m_time_critical_pieces.erase(i);
5316
0
    }
5317
0
  }
5318
5319
  // remove time critical pieces where priority is 0
5320
  void torrent::remove_time_critical_pieces(aux::vector<download_priority_t, piece_index_t> const& priority)
5321
756
  {
5322
756
    for (auto i = m_time_critical_pieces.begin(); i != m_time_critical_pieces.end();)
5323
0
    {
5324
0
      if (priority[i->piece] == dont_download)
5325
0
      {
5326
0
        if (i->flags & torrent_handle::alert_when_available)
5327
0
        {
5328
          // post an empty read_piece_alert to indicate it failed
5329
0
          alerts().emplace_alert<read_piece_alert>(
5330
0
            get_handle(), i->piece, error_code(boost::system::errc::operation_canceled, generic_category()));
5331
0
        }
5332
0
        i = m_time_critical_pieces.erase(i);
5333
0
        continue;
5334
0
      }
5335
0
      ++i;
5336
0
    }
5337
756
  }
5338
#endif // TORRENT_DISABLE_STREAMING
5339
5340
  void torrent::post_piece_availability()
5341
0
  {
5342
0
    aux::vector<int, piece_index_t> avail;
5343
0
    piece_availability(avail);
5344
0
    alerts().emplace_alert<piece_availability_alert>(get_handle(), std::move(avail));
5345
0
  }
5346
5347
  void torrent::piece_availability(aux::vector<int, piece_index_t>& avail) const
5348
0
  {
5349
0
    INVARIANT_CHECK;
5350
5351
0
    TORRENT_ASSERT(valid_metadata());
5352
0
    if (!has_picker())
5353
0
    {
5354
0
      avail.clear();
5355
0
      return;
5356
0
    }
5357
5358
0
    m_picker->get_availability(avail);
5359
0
  }
5360
5361
  void torrent::set_piece_priority(piece_index_t const index
5362
    , download_priority_t const priority)
5363
0
  {
5364
//    INVARIANT_CHECK;
5365
5366
#ifndef TORRENT_DISABLE_LOGGING
5367
    if (!valid_metadata())
5368
    {
5369
      debug_log("*** SET_PIECE_PRIORITY [ idx: %d prio: %d ignored. "
5370
        "no metadata yet ]", static_cast<int>(index)
5371
        , static_cast<std::uint8_t>(priority));
5372
    }
5373
#endif
5374
0
    if (!valid_metadata() || is_seed()) return;
5375
5376
    // this call is only valid on torrents with metadata
5377
0
    if (index < piece_index_t(0) || index >= m_torrent_file->end_piece())
5378
0
    {
5379
0
      return;
5380
0
    }
5381
5382
0
    need_picker();
5383
5384
0
    bool const was_finished = is_finished();
5385
0
    bool const filter_updated = m_picker->set_piece_priority(index, priority);
5386
5387
0
    update_gauge();
5388
5389
0
    if (filter_updated)
5390
0
    {
5391
0
      update_peer_interest(was_finished);
5392
0
#ifndef TORRENT_DISABLE_STREAMING
5393
0
      if (priority == dont_download) remove_time_critical_piece(index);
5394
0
#endif // TORRENT_DISABLE_STREAMING
5395
0
    }
5396
5397
0
  }
5398
5399
  download_priority_t torrent::piece_priority(piece_index_t const index) const
5400
53
  {
5401
//    INVARIANT_CHECK;
5402
5403
53
    if (!has_picker()) return default_priority;
5404
5405
    // this call is only valid on torrents with metadata
5406
53
    TORRENT_ASSERT(valid_metadata());
5407
53
    if (index < piece_index_t(0) || index >= m_torrent_file->end_piece())
5408
0
    {
5409
0
      TORRENT_ASSERT_FAIL();
5410
0
      return dont_download;
5411
0
    }
5412
5413
53
    return m_picker->piece_priority(index);
5414
53
  }
5415
5416
  void torrent::prioritize_piece_list(std::vector<std::pair<piece_index_t
5417
    , download_priority_t>> const& pieces)
5418
0
  {
5419
0
    INVARIANT_CHECK;
5420
5421
    // this call is only valid on torrents with metadata
5422
0
    TORRENT_ASSERT(valid_metadata());
5423
0
    if (is_seed()) return;
5424
5425
0
    need_picker();
5426
5427
0
    bool filter_updated = false;
5428
0
    bool const was_finished = is_finished();
5429
0
    for (auto const& p : pieces)
5430
0
    {
5431
0
      static_assert(std::is_unsigned<decltype(p.second)::underlying_type>::value
5432
0
        , "we need assert p.second >= dont_download");
5433
0
      TORRENT_ASSERT(p.second <= top_priority);
5434
0
      TORRENT_ASSERT(p.first >= piece_index_t(0));
5435
0
      TORRENT_ASSERT(p.first < m_torrent_file->end_piece());
5436
5437
0
      if (p.first < piece_index_t(0)
5438
0
        || p.first >= m_torrent_file->end_piece()
5439
0
        || p.second > top_priority)
5440
0
      {
5441
0
        static_assert(std::is_unsigned<decltype(p.second)::underlying_type>::value
5442
0
          , "we need additional condition: p.second < dont_download");
5443
0
        continue;
5444
0
      }
5445
5446
0
      filter_updated |= m_picker->set_piece_priority(p.first, p.second);
5447
0
    }
5448
0
    update_gauge();
5449
0
    if (filter_updated)
5450
0
    {
5451
      // we need to save this new state
5452
0
      set_need_save_resume(torrent_handle::if_config_changed);
5453
5454
0
      update_peer_interest(was_finished);
5455
0
    }
5456
5457
0
    state_updated();
5458
0
  }
5459
5460
  void torrent::prioritize_pieces(aux::vector<download_priority_t, piece_index_t> const& pieces)
5461
1.02k
  {
5462
1.02k
    INVARIANT_CHECK;
5463
5464
    // this call is only valid on torrents with metadata
5465
1.02k
    TORRENT_ASSERT(valid_metadata());
5466
1.02k
    if (is_seed()) return;
5467
5468
862
    if (!valid_metadata())
5469
0
    {
5470
#ifndef TORRENT_DISABLE_LOGGING
5471
      debug_log("*** PRIORITIZE_PIECES [ ignored. no metadata yet ]");
5472
#endif
5473
0
      return;
5474
0
    }
5475
5476
862
    need_picker();
5477
5478
862
    piece_index_t index(0);
5479
862
    bool filter_updated = false;
5480
862
    bool const was_finished = is_finished();
5481
862
    for (auto prio : pieces)
5482
8.62k
    {
5483
8.62k
      static_assert(std::is_unsigned<decltype(prio)::underlying_type>::value
5484
8.62k
        , "we need assert prio >= dont_download");
5485
8.62k
      TORRENT_ASSERT(prio <= top_priority);
5486
8.62k
      filter_updated |= m_picker->set_piece_priority(index, prio);
5487
8.62k
      ++index;
5488
8.62k
    }
5489
862
    update_gauge();
5490
862
    update_want_tick();
5491
5492
862
    if (filter_updated)
5493
756
    {
5494
      // we need to save this new state
5495
756
      set_need_save_resume(torrent_handle::if_config_changed);
5496
5497
756
      update_peer_interest(was_finished);
5498
756
#ifndef TORRENT_DISABLE_STREAMING
5499
756
      remove_time_critical_pieces(pieces);
5500
756
#endif
5501
756
    }
5502
5503
862
    state_updated();
5504
862
    update_state_list();
5505
862
  }
5506
5507
  void torrent::piece_priorities(aux::vector<download_priority_t, piece_index_t>* pieces) const
5508
0
  {
5509
0
    INVARIANT_CHECK;
5510
5511
    // this call is only valid on torrents with metadata
5512
0
    if (!valid_metadata())
5513
0
    {
5514
0
      pieces->clear();
5515
0
      return;
5516
0
    }
5517
5518
0
    if (!has_picker())
5519
0
    {
5520
0
      pieces->clear();
5521
0
      pieces->resize(m_torrent_file->num_pieces(), default_priority);
5522
0
      return;
5523
0
    }
5524
5525
0
    TORRENT_ASSERT(m_picker);
5526
0
    m_picker->piece_priorities(*pieces);
5527
0
  }
5528
5529
  namespace
5530
  {
5531
    aux::vector<download_priority_t, file_index_t> fix_priorities(
5532
      aux::vector<download_priority_t, file_index_t> input
5533
      , file_storage const* fs)
5534
0
    {
5535
0
      if (fs) input.resize(fs->num_files(), default_priority);
5536
5537
0
      for (file_index_t i : input.range())
5538
0
      {
5539
        // initialize pad files to priority 0
5540
0
        if (input[i] > dont_download && fs && fs->pad_file_at(i))
5541
0
          input[i] = dont_download;
5542
0
        else if (input[i] > top_priority)
5543
0
          input[i] = top_priority;
5544
0
      }
5545
5546
0
      return input;
5547
0
    }
5548
  }
5549
5550
  void torrent::on_file_priority(storage_error const& err
5551
    , aux::vector<download_priority_t, file_index_t> prios)
5552
0
  {
5553
0
    m_outstanding_file_priority = false;
5554
0
    COMPLETE_ASYNC("file_priority");
5555
5556
0
    if (m_file_priority != prios)
5557
0
    {
5558
0
      update_piece_priorities(prios);
5559
0
      m_file_priority = std::move(prios);
5560
0
      set_need_save_resume(torrent_handle::if_config_changed);
5561
0
#ifndef TORRENT_DISABLE_SHARE_MODE
5562
0
      if (m_share_mode)
5563
0
        recalc_share_mode();
5564
0
#endif
5565
0
    }
5566
5567
0
    if (err)
5568
0
    {
5569
      // in this case, some file priorities failed to get set
5570
0
      if (alerts().should_post<file_error_alert>())
5571
0
        alerts().emplace_alert<file_error_alert>(err.ec
5572
0
          , resolve_filename(err.file()), err.operation, get_handle());
5573
5574
0
      set_error(err.ec, err.file());
5575
0
      pause();
5576
0
      return;
5577
0
    }
5578
5579
0
    if (alerts().should_post<file_prio_alert>())
5580
0
      alerts().emplace_alert<file_prio_alert>(get_handle());
5581
5582
0
    if (!m_deferred_file_priorities.empty() && !m_abort)
5583
0
    {
5584
0
      auto new_priority = m_file_priority;
5585
      // resize the vector if we have to. The last item in the map has the
5586
      // highest file index.
5587
0
      auto const max_idx = std::prev(m_deferred_file_priorities.end())->first;
5588
0
      if (new_priority.end_index() <= max_idx)
5589
0
      {
5590
        // any unallocated slot is assumed to have the default priority
5591
0
        new_priority.resize(static_cast<int>(max_idx) + 1, default_priority);
5592
0
      }
5593
0
      for (auto const& p : m_deferred_file_priorities)
5594
0
      {
5595
0
        file_index_t const index = p.first;
5596
0
        download_priority_t const prio = p.second;
5597
0
        new_priority[index] = prio;
5598
0
      }
5599
0
      m_deferred_file_priorities.clear();
5600
0
      prioritize_files(std::move(new_priority));
5601
0
    }
5602
0
  }
5603
5604
  void torrent::prioritize_files(aux::vector<download_priority_t, file_index_t> files)
5605
0
  {
5606
0
    INVARIANT_CHECK;
5607
5608
0
    auto new_priority = fix_priorities(std::move(files)
5609
0
      , valid_metadata() ? &m_torrent_file->files() : nullptr);
5610
5611
0
    m_deferred_file_priorities.clear();
5612
5613
    // storage may be NULL during shutdown
5614
0
    if (m_storage)
5615
0
    {
5616
      // the update of m_file_priority is deferred until the disk job comes
5617
      // back, but to preserve sanity and consistency, the piece priorities are
5618
      // updated immediately. If, on the off-chance, there's a disk failure, the
5619
      // piece priorities still stay the same, but the file priorities are
5620
      // possibly not fully updated.
5621
5622
0
      m_outstanding_file_priority = true;
5623
0
      ADD_OUTSTANDING_ASYNC("file_priority");
5624
0
      m_ses.disk_thread().async_set_file_priority(m_storage
5625
0
        , std::move(new_priority)
5626
0
        , [self = shared_from_this()] (storage_error const& ec, aux::vector<download_priority_t, file_index_t> p)
5627
0
        { self->on_file_priority(ec, std::move(p)); });
5628
0
      m_ses.deferred_submit_jobs();
5629
0
    }
5630
0
    else
5631
0
    {
5632
0
      m_file_priority = std::move(new_priority);
5633
0
      set_need_save_resume(torrent_handle::if_config_changed);
5634
0
    }
5635
0
  }
5636
5637
  void torrent::set_file_priority(file_index_t const index
5638
    , download_priority_t prio)
5639
0
  {
5640
0
    INVARIANT_CHECK;
5641
5642
    // setting file priority on a torrent that doesn't have metadata yet is
5643
    // similar to having passed in file priorities through add_torrent_params.
5644
    // we store the priorities in m_file_priority until we get the metadata
5645
0
    if (index < file_index_t(0)
5646
0
      || (valid_metadata() && index >= m_torrent_file->files().end_file()))
5647
0
    {
5648
0
      return;
5649
0
    }
5650
5651
0
    prio = aux::clamp(prio, dont_download, top_priority);
5652
5653
0
    if (m_outstanding_file_priority)
5654
0
    {
5655
0
      m_deferred_file_priorities[index] = prio;
5656
0
      return;
5657
0
    }
5658
5659
0
    auto new_priority = m_file_priority;
5660
0
    if (new_priority.end_index() <= index)
5661
0
    {
5662
      // any unallocated slot is assumed to have the default priority
5663
0
      new_priority.resize(static_cast<int>(index) + 1, default_priority);
5664
0
    }
5665
5666
0
    new_priority[index] = prio;
5667
5668
    // storage may be nullptr during shutdown
5669
0
    if (m_storage)
5670
0
    {
5671
0
      m_outstanding_file_priority = true;
5672
0
      ADD_OUTSTANDING_ASYNC("file_priority");
5673
0
      m_ses.disk_thread().async_set_file_priority(m_storage
5674
0
        , std::move(new_priority)
5675
0
        , [self = shared_from_this()] (storage_error const& ec, aux::vector<download_priority_t, file_index_t> p)
5676
0
        { self->on_file_priority(ec, std::move(p)); });
5677
0
      m_ses.deferred_submit_jobs();
5678
0
    }
5679
0
    else
5680
0
    {
5681
0
      m_file_priority = std::move(new_priority);
5682
0
      set_need_save_resume(torrent_handle::if_config_changed);
5683
0
    }
5684
0
  }
5685
5686
  download_priority_t torrent::file_priority(file_index_t const index) const
5687
0
  {
5688
0
    TORRENT_ASSERT_PRECOND(index >= file_index_t(0));
5689
0
    if (index < file_index_t(0)) return dont_download;
5690
5691
    // if we have metadata, perform additional checks
5692
0
    if (valid_metadata())
5693
0
    {
5694
0
      file_storage const& fs = m_torrent_file->files();
5695
0
      TORRENT_ASSERT_PRECOND(index < fs.end_file());
5696
0
      if (index >= fs.end_file()) return dont_download;
5697
5698
      // pad files always have priority 0
5699
0
      if (fs.pad_file_at(index)) return dont_download;
5700
0
    }
5701
5702
    // any unallocated slot is assumed to have the default priority
5703
0
    if (m_file_priority.end_index() <= index) return default_priority;
5704
5705
0
    return m_file_priority[index];
5706
0
  }
5707
5708
  void torrent::file_priorities(aux::vector<download_priority_t, file_index_t>* files) const
5709
0
  {
5710
0
    INVARIANT_CHECK;
5711
5712
0
    files->assign(m_file_priority.begin(), m_file_priority.end());
5713
5714
0
    if (!valid_metadata())
5715
0
    {
5716
0
      return;
5717
0
    }
5718
5719
0
    files->resize(m_torrent_file->num_files(), default_priority);
5720
0
  }
5721
5722
  void torrent::update_piece_priorities(
5723
    aux::vector<download_priority_t, file_index_t> const& file_prios)
5724
1.02k
  {
5725
1.02k
    INVARIANT_CHECK;
5726
5727
1.02k
    if (m_torrent_file->num_pieces() == 0) return;
5728
5729
1.02k
    bool need_update = false;
5730
    // initialize the piece priorities to 0, then only allow
5731
    // setting higher priorities
5732
1.02k
    aux::vector<download_priority_t, piece_index_t> pieces(aux::numeric_cast<std::size_t>(
5733
1.02k
      m_torrent_file->num_pieces()), dont_download);
5734
1.02k
    file_storage const& fs = m_torrent_file->files();
5735
1.02k
    for (auto const i : fs.file_range())
5736
1.02k
    {
5737
1.02k
      std::int64_t const size = m_torrent_file->files().file_size(i);
5738
1.02k
      if (size == 0) continue;
5739
5740
      // pad files always have priority 0
5741
1.02k
      download_priority_t const file_prio
5742
1.02k
        = fs.pad_file_at(i) ? dont_download
5743
1.02k
        : i >= file_prios.end_index() ? default_priority
5744
1.02k
        : file_prios[i];
5745
5746
1.02k
      if (file_prio == dont_download)
5747
906
      {
5748
        // the pieces already start out as priority 0, no need to update
5749
        // the pieces vector in this case
5750
906
        need_update = true;
5751
906
        continue;
5752
906
      }
5753
5754
      // mark all pieces of the file with this file's priority
5755
      // but only if the priority is higher than the pieces
5756
      // already set (to avoid problems with overlapping pieces)
5757
122
      piece_index_t start;
5758
122
      piece_index_t end;
5759
122
      std::tie(start, end) = file_piece_range_inclusive(fs, i);
5760
5761
      // if one piece spans several files, we might
5762
      // come here several times with the same start_piece, end_piece
5763
1.34k
      for (piece_index_t p = start; p < end; ++p)
5764
1.22k
        pieces[p] = std::max(pieces[p], file_prio);
5765
5766
122
      need_update = true;
5767
122
    }
5768
1.02k
    if (need_update) prioritize_pieces(pieces);
5769
1.02k
  }
5770
5771
  // this is called when piece priorities have been updated
5772
  // updates the interested flag in peers
5773
  void torrent::update_peer_interest(bool const was_finished)
5774
756
  {
5775
756
    for (auto i = begin(); i != end();)
5776
0
    {
5777
0
      peer_connection* p = *i;
5778
      // update_interest may disconnect the peer and
5779
      // invalidate the iterator
5780
0
      ++i;
5781
0
      p->update_interest();
5782
0
    }
5783
5784
756
    if (!is_downloading_state(m_state))
5785
756
    {
5786
#ifndef TORRENT_DISABLE_LOGGING
5787
      debug_log("*** UPDATE_PEER_INTEREST [ skipping, state: %d ]"
5788
        , int(m_state));
5789
#endif
5790
756
      return;
5791
756
    }
5792
5793
#ifndef TORRENT_DISABLE_LOGGING
5794
    if (should_log())
5795
    {
5796
      debug_log("*** UPDATE_PEER_INTEREST [ finished: %d was_finished %d ]"
5797
        , is_finished(), was_finished);
5798
    }
5799
#endif
5800
5801
    // the torrent just became finished
5802
0
    if (!was_finished && is_finished())
5803
0
    {
5804
0
      finished();
5805
0
    }
5806
0
    else if (was_finished && !is_finished())
5807
0
    {
5808
      // if we used to be finished, but we aren't anymore
5809
      // we may need to connect to peers again
5810
0
      resume_download();
5811
0
    }
5812
0
  }
5813
5814
  void torrent::post_trackers()
5815
0
  {
5816
0
    auto t = trackers();
5817
0
    m_ses.alerts().emplace_alert<tracker_list_alert>(get_handle(), std::move(t));
5818
0
  }
5819
5820
  std::vector<announce_entry> torrent::trackers() const
5821
0
  {
5822
0
    std::vector<announce_entry> ret;
5823
0
    ret.reserve(m_trackers.size());
5824
0
    for (auto const& t : m_trackers)
5825
0
    {
5826
0
      ret.emplace_back(t.url);
5827
0
      auto& tr = ret.back();
5828
0
      tr.source = t.source;
5829
0
      tr.trackerid = t.trackerid;
5830
0
      tr.verified = t.verified;
5831
0
      tr.tier = t.tier;
5832
0
      tr.fail_limit = t.fail_limit;
5833
0
      tr.endpoints.reserve(t.endpoints.size());
5834
0
      for (auto const& ep : t.endpoints)
5835
0
      {
5836
0
        tr.endpoints.emplace_back();
5837
0
        auto& aep = tr.endpoints.back();
5838
0
        aep.local_endpoint = ep.local_endpoint;
5839
0
        aep.enabled = ep.enabled;
5840
5841
0
        for (protocol_version v : {protocol_version::V1, protocol_version::V2})
5842
0
        {
5843
0
          aep.info_hashes[v].message = ep.info_hashes[v].message;
5844
0
          aep.info_hashes[v].last_error = ep.info_hashes[v].last_error;
5845
0
          aep.info_hashes[v].next_announce = ep.info_hashes[v].next_announce;
5846
0
          aep.info_hashes[v].min_announce = ep.info_hashes[v].min_announce;
5847
0
          aep.info_hashes[v].scrape_incomplete = ep.info_hashes[v].scrape_incomplete;
5848
0
          aep.info_hashes[v].scrape_complete = ep.info_hashes[v].scrape_complete;
5849
0
          aep.info_hashes[v].scrape_downloaded = ep.info_hashes[v].scrape_downloaded;
5850
0
          aep.info_hashes[v].fails = ep.info_hashes[v].fails;
5851
0
          aep.info_hashes[v].updating = ep.info_hashes[v].updating;
5852
0
          aep.info_hashes[v].start_sent = ep.info_hashes[v].start_sent;
5853
0
          aep.info_hashes[v].complete_sent = ep.info_hashes[v].complete_sent;
5854
0
          aep.info_hashes[v].triggered_manually = ep.info_hashes[v].triggered_manually;
5855
0
#if TORRENT_ABI_VERSION == 1
5856
0
          tr.complete_sent |= ep.info_hashes[v].complete_sent;
5857
0
#endif
5858
0
        }
5859
0
#if TORRENT_ABI_VERSION <= 2
5860
0
#include "libtorrent/aux_/disable_warnings_push.hpp"
5861
0
        aep.message = aep.info_hashes[protocol_version::V1].message;
5862
0
        aep.scrape_incomplete = ep.info_hashes[protocol_version::V1].scrape_incomplete;
5863
0
        aep.scrape_complete = ep.info_hashes[protocol_version::V1].scrape_complete;
5864
0
        aep.scrape_downloaded = ep.info_hashes[protocol_version::V1].scrape_downloaded;
5865
0
        aep.complete_sent = ep.info_hashes[protocol_version::V1].complete_sent;
5866
0
        aep.last_error = ep.info_hashes[protocol_version::V1].last_error;
5867
0
        aep.fails = ep.info_hashes[protocol_version::V1].fails;
5868
0
        aep.next_announce = ep.info_hashes[protocol_version::V1].next_announce;
5869
0
        aep.min_announce = ep.info_hashes[protocol_version::V1].min_announce;
5870
0
        aep.updating = ep.info_hashes[protocol_version::V1].updating;
5871
0
#include "libtorrent/aux_/disable_warnings_pop.hpp"
5872
0
#endif
5873
0
      }
5874
0
    }
5875
0
    return ret;
5876
0
  }
5877
5878
  void torrent::replace_trackers(std::vector<announce_entry> const& urls)
5879
0
  {
5880
0
    m_trackers.clear();
5881
0
    for (auto const& t : urls)
5882
0
    {
5883
0
      if (t.url.empty()) continue;
5884
0
      m_trackers.emplace_back(t);
5885
0
    }
5886
5887
    // make sure the trackers are correctly ordered by tier
5888
0
    std::sort(m_trackers.begin(), m_trackers.end()
5889
0
      , [](aux::announce_entry const& lhs, aux::announce_entry const& rhs)
5890
0
      { return lhs.tier < rhs.tier; });
5891
5892
0
    m_last_working_tracker = -1;
5893
5894
0
    if (settings().get_bool(settings_pack::prefer_udp_trackers))
5895
0
      prioritize_udp_trackers();
5896
5897
0
    if (m_announcing && !m_trackers.empty()) announce_with_tracker();
5898
5899
0
    set_need_save_resume(torrent_handle::if_metadata_changed);
5900
0
  }
5901
5902
  void torrent::prioritize_udp_trackers()
5903
1.88k
  {
5904
    // look for udp-trackers
5905
1.88k
    for (auto i = m_trackers.begin(), end(m_trackers.end()); i != end; ++i)
5906
0
    {
5907
0
      if (i->url.substr(0, 6) != "udp://") continue;
5908
      // now, look for trackers with the same hostname
5909
      // that is has higher priority than this one
5910
      // if we find one, swap with the udp-tracker
5911
0
      error_code ec;
5912
0
      std::string udp_hostname;
5913
0
      using std::ignore;
5914
0
      std::tie(ignore, ignore, udp_hostname, ignore, ignore)
5915
0
        = parse_url_components(i->url, ec);
5916
0
      for (auto j = m_trackers.begin(); j != i; ++j)
5917
0
      {
5918
0
        std::string hostname;
5919
0
        std::tie(ignore, ignore, hostname, ignore, ignore)
5920
0
          = parse_url_components(j->url, ec);
5921
0
        if (hostname != udp_hostname) continue;
5922
0
        if (j->url.substr(0, 6) == "udp://") continue;
5923
0
        using std::swap;
5924
0
        using std::iter_swap;
5925
0
        swap(i->tier, j->tier);
5926
0
        iter_swap(i, j);
5927
0
        break;
5928
0
      }
5929
0
    }
5930
1.88k
  }
5931
5932
  bool torrent::add_tracker(announce_entry const& url)
5933
0
  {
5934
0
    if (url.url.empty()) return false;
5935
0
    if(auto k = find_tracker(url.url))
5936
0
    {
5937
0
      k->source |= url.source;
5938
0
      return false;
5939
0
    }
5940
0
    auto k = std::upper_bound(m_trackers.begin(), m_trackers.end(), url.tier
5941
0
      , [] (int tier, aux::announce_entry const& v) { return tier < v.tier; });
5942
0
    if (k - m_trackers.begin() < m_last_working_tracker) ++m_last_working_tracker;
5943
0
    k = m_trackers.insert(k, aux::announce_entry(url.url));
5944
0
    if (url.source == 0) k->source = announce_entry::source_client;
5945
0
    else k->source = url.source;
5946
0
    k->trackerid = url.trackerid;
5947
0
    k->tier = url.tier;
5948
0
    k->fail_limit = url.fail_limit;
5949
0
    set_need_save_resume(torrent_handle::if_metadata_changed);
5950
0
    if (m_announcing && !m_trackers.empty()) announce_with_tracker();
5951
0
    return true;
5952
0
  }
5953
5954
  bool torrent::choke_peer(peer_connection& c)
5955
0
  {
5956
0
    INVARIANT_CHECK;
5957
5958
0
    TORRENT_ASSERT(!c.is_choked());
5959
0
    TORRENT_ASSERT(!c.ignore_unchoke_slots());
5960
0
    TORRENT_ASSERT(m_num_uploads > 0);
5961
0
    if (!c.send_choke()) return false;
5962
0
    --m_num_uploads;
5963
0
    state_updated();
5964
0
    return true;
5965
0
  }
5966
5967
  bool torrent::unchoke_peer(peer_connection& c, bool optimistic)
5968
0
  {
5969
0
    INVARIANT_CHECK;
5970
5971
0
    TORRENT_ASSERT(!m_graceful_pause_mode);
5972
0
    TORRENT_ASSERT(c.is_choked());
5973
0
    TORRENT_ASSERT(!c.ignore_unchoke_slots());
5974
    // when we're unchoking the optimistic slots, we might
5975
    // exceed the limit temporarily while we're iterating
5976
    // over the peers
5977
0
    if (m_num_uploads >= m_max_uploads && !optimistic) return false;
5978
0
    if (!c.send_unchoke()) return false;
5979
0
    ++m_num_uploads;
5980
0
    state_updated();
5981
0
    return true;
5982
0
  }
5983
5984
  void torrent::trigger_unchoke() noexcept
5985
0
  {
5986
0
    m_ses.trigger_unchoke();
5987
0
  }
5988
5989
  void torrent::trigger_optimistic_unchoke() noexcept
5990
0
  {
5991
0
    m_ses.trigger_optimistic_unchoke();
5992
0
  }
5993
5994
  void torrent::cancel_block(piece_block block)
5995
0
  {
5996
0
    INVARIANT_CHECK;
5997
5998
0
    TORRENT_ASSERT(has_picker());
5999
6000
0
    for (auto p : m_connections)
6001
0
    {
6002
0
      TORRENT_INCREMENT(m_iterating_connections);
6003
0
      p->cancel_request(block);
6004
0
    }
6005
0
  }
6006
6007
#ifdef TORRENT_SSL_PEERS
6008
  // certificate is a filename to a .pem file which is our
6009
  // certificate. The certificate must be signed by the root
6010
  // cert of the torrent file. any peer we connect to or that
6011
  // connect to use must present a valid certificate signed
6012
  // by the torrent root cert as well
6013
  void torrent::set_ssl_cert(std::string const& certificate
6014
    , std::string const& private_key
6015
    , std::string const& dh_params
6016
    , std::string const& passphrase)
6017
0
  {
6018
0
    if (!m_ssl_ctx)
6019
0
    {
6020
0
      if (alerts().should_post<torrent_error_alert>())
6021
0
        alerts().emplace_alert<torrent_error_alert>(get_handle()
6022
0
          , errors::not_an_ssl_torrent, "");
6023
0
      return;
6024
0
    }
6025
6026
0
    error_code ec;
6027
0
    m_ssl_ctx->set_password_callback(
6028
0
        [passphrase](std::size_t, ssl::context::password_purpose purpose)
6029
0
        {
6030
0
          return purpose == ssl::context::for_reading ? passphrase : "";
6031
0
        }
6032
0
        , ec);
6033
0
    if (ec)
6034
0
    {
6035
0
      if (alerts().should_post<torrent_error_alert>())
6036
0
        alerts().emplace_alert<torrent_error_alert>(get_handle(), ec, "");
6037
0
    }
6038
0
    m_ssl_ctx->use_certificate_file(certificate, ssl::context::pem, ec);
6039
0
    if (ec)
6040
0
    {
6041
0
      if (alerts().should_post<torrent_error_alert>())
6042
0
        alerts().emplace_alert<torrent_error_alert>(get_handle(), ec, certificate);
6043
0
    }
6044
#ifndef TORRENT_DISABLE_LOGGING
6045
    if (should_log())
6046
      debug_log("*** use certificate file: %s", ec.message().c_str());
6047
#endif
6048
0
    m_ssl_ctx->use_private_key_file(private_key, ssl::context::pem, ec);
6049
0
    if (ec)
6050
0
    {
6051
0
      if (alerts().should_post<torrent_error_alert>())
6052
0
        alerts().emplace_alert<torrent_error_alert>(get_handle(), ec, private_key);
6053
0
    }
6054
#ifndef TORRENT_DISABLE_LOGGING
6055
    if (should_log())
6056
      debug_log("*** use private key file: %s", ec.message().c_str());
6057
#endif
6058
0
    m_ssl_ctx->use_tmp_dh_file(dh_params, ec);
6059
0
    if (ec)
6060
0
    {
6061
0
      if (alerts().should_post<torrent_error_alert>())
6062
0
        alerts().emplace_alert<torrent_error_alert>(get_handle(), ec, dh_params);
6063
0
    }
6064
#ifndef TORRENT_DISABLE_LOGGING
6065
    if (should_log())
6066
      debug_log("*** use DH file: %s", ec.message().c_str());
6067
#endif
6068
0
  }
6069
6070
  void torrent::set_ssl_cert_buffer(std::string const& certificate
6071
    , std::string const& private_key
6072
    , std::string const& dh_params)
6073
0
  {
6074
0
    if (!m_ssl_ctx) return;
6075
6076
0
    boost::asio::const_buffer certificate_buf(certificate.c_str(), certificate.size());
6077
6078
0
    error_code ec;
6079
0
    m_ssl_ctx->use_certificate(certificate_buf, ssl::context::pem, ec);
6080
0
    if (ec)
6081
0
    {
6082
0
      if (alerts().should_post<torrent_error_alert>())
6083
0
        alerts().emplace_alert<torrent_error_alert>(get_handle(), ec, "[certificate]");
6084
0
    }
6085
6086
0
    boost::asio::const_buffer private_key_buf(private_key.c_str(), private_key.size());
6087
0
    m_ssl_ctx->use_private_key(private_key_buf, ssl::context::pem, ec);
6088
0
    if (ec)
6089
0
    {
6090
0
      if (alerts().should_post<torrent_error_alert>())
6091
0
        alerts().emplace_alert<torrent_error_alert>(get_handle(), ec, "[private key]");
6092
0
    }
6093
6094
0
    boost::asio::const_buffer dh_params_buf(dh_params.c_str(), dh_params.size());
6095
0
    m_ssl_ctx->use_tmp_dh(dh_params_buf, ec);
6096
0
    if (ec)
6097
0
    {
6098
0
      if (alerts().should_post<torrent_error_alert>())
6099
0
        alerts().emplace_alert<torrent_error_alert>(get_handle(), ec, "[dh params]");
6100
0
    }
6101
0
  }
6102
6103
#endif
6104
6105
  void torrent::on_exception(std::exception const&)
6106
0
  {
6107
0
    set_error(errors::no_memory, torrent_status::error_file_none);
6108
0
  }
6109
6110
  void torrent::on_error(error_code const& ec)
6111
0
  {
6112
0
    set_error(ec, torrent_status::error_file_none);
6113
0
  }
6114
6115
  void torrent::remove_connection(peer_connection const* p)
6116
282
  {
6117
282
    TORRENT_ASSERT(m_iterating_connections == 0);
6118
282
    auto const i = sorted_find(m_connections, p);
6119
282
    if (i != m_connections.end())
6120
282
      m_connections.erase(i);
6121
282
  }
6122
6123
  void torrent::remove_peer(std::shared_ptr<peer_connection> p) noexcept
6124
282
  {
6125
282
    TORRENT_ASSERT(p);
6126
282
    TORRENT_ASSERT(is_single_thread());
6127
282
    TORRENT_ASSERT(std::count(m_peers_to_disconnect.begin()
6128
282
      , m_peers_to_disconnect.end(), p) == 0);
6129
6130
282
    auto it = m_outgoing_pids.find(p->our_pid());
6131
282
    if (it != m_outgoing_pids.end())
6132
0
    {
6133
0
      m_outgoing_pids.erase(it);
6134
0
    }
6135
6136
    // only schedule the peer for actual removal if in fact
6137
    // we can be sure peer_connection will be kept alive until
6138
    // the deferred function is called. If a peer_connection
6139
    // has not associated torrent, the session_impl object may
6140
    // remove it at any time, which may be while the non-owning
6141
    // pointer in m_peers_to_disconnect (if added to it) is
6142
    // waiting for the deferred function to be called.
6143
    //
6144
    // one example of this situation is if for example, this
6145
    // function is called from the attach_peer path and fail to
6146
    // do so because of too many connections.
6147
282
    bool const is_attached = p->associated_torrent().lock().get() == this;
6148
282
    if (is_attached)
6149
282
    {
6150
282
      std::weak_ptr<torrent> weak_t = shared_from_this();
6151
282
      TORRENT_ASSERT_VAL(m_peers_to_disconnect.capacity() > m_peers_to_disconnect.size()
6152
282
        , m_peers_to_disconnect.capacity());
6153
282
      m_peers_to_disconnect.push_back(p);
6154
6155
282
      using deferred_handler_type = aux::handler<
6156
282
        torrent
6157
282
        , decltype(&torrent::on_remove_peers)
6158
282
        , &torrent::on_remove_peers
6159
282
        , &torrent::on_error
6160
282
        , &torrent::on_exception
6161
282
        , decltype(m_deferred_handler_storage)
6162
282
        , &torrent::m_deferred_handler_storage
6163
282
        >;
6164
282
      static_assert(sizeof(deferred_handler_type) == sizeof(std::shared_ptr<peer_connection>)
6165
282
        , "deferred handler does not have the expected size");
6166
282
      m_deferred_disconnect.post_deferred(m_ses.get_context(), deferred_handler_type(shared_from_this()));
6167
282
    }
6168
0
    else
6169
0
    {
6170
      // if the peer was inserted in m_connections but instructed to
6171
      // be removed from this torrent, just remove it from it, see
6172
      // attach_peer logic.
6173
0
      remove_connection(p.get());
6174
0
    }
6175
6176
282
    torrent_peer* pp = p->peer_info_struct();
6177
282
    if (ready_for_connections())
6178
282
    {
6179
282
      TORRENT_ASSERT(p->associated_torrent().lock().get() == nullptr
6180
282
        || p->associated_torrent().lock().get() == this);
6181
6182
282
      if (has_picker())
6183
282
      {
6184
282
        if (p->is_seed())
6185
13
        {
6186
13
          m_picker->dec_refcount_all(pp);
6187
13
        }
6188
269
        else
6189
269
        {
6190
269
          auto const& pieces = p->get_bitfield();
6191
269
          TORRENT_ASSERT(pieces.count() <= pieces.size());
6192
269
          m_picker->dec_refcount(pieces, pp);
6193
269
        }
6194
282
      }
6195
282
    }
6196
6197
282
    if (!p->is_choked() && !p->ignore_unchoke_slots())
6198
0
    {
6199
0
      --m_num_uploads;
6200
0
      trigger_unchoke();
6201
0
    }
6202
6203
282
    if (pp)
6204
282
    {
6205
282
      if (pp->optimistically_unchoked)
6206
0
      {
6207
0
        pp->optimistically_unchoked = false;
6208
0
        m_stats_counters.inc_stats_counter(
6209
0
          counters::num_peers_up_unchoked_optimistic, -1);
6210
0
        trigger_optimistic_unchoke();
6211
0
      }
6212
6213
282
      TORRENT_ASSERT(pp->prev_amount_upload == 0);
6214
282
      TORRENT_ASSERT(pp->prev_amount_download == 0);
6215
282
      pp->prev_amount_download += aux::numeric_cast<std::uint32_t>(p->statistics().total_payload_download() >> 10);
6216
282
      pp->prev_amount_upload += aux::numeric_cast<std::uint32_t>(p->statistics().total_payload_upload() >> 10);
6217
6218
      // only decrement the seed count if the peer completed attaching to the torrent
6219
      // otherwise the seed count did not get incremented for this peer
6220
282
      if (is_attached && pp->seed)
6221
35
      {
6222
35
        TORRENT_ASSERT(m_num_seeds > 0);
6223
35
        --m_num_seeds;
6224
35
      }
6225
6226
282
      if (pp->connection && m_peer_list)
6227
282
      {
6228
282
        torrent_state st = get_peer_list_state();
6229
282
        m_peer_list->connection_closed(*p, m_ses.session_time(), &st);
6230
282
        peers_erased(st.erased);
6231
282
      }
6232
282
    }
6233
6234
282
    p->set_peer_info(nullptr);
6235
6236
282
    update_want_peers();
6237
282
    update_want_tick();
6238
282
  }
6239
6240
  void torrent::on_remove_peers() noexcept
6241
2.16k
  {
6242
2.16k
    TORRENT_ASSERT(is_single_thread());
6243
2.16k
    INVARIANT_CHECK;
6244
6245
2.16k
#if TORRENT_USE_ASSERTS
6246
2.16k
    auto const num = m_peers_to_disconnect.size();
6247
2.16k
#endif
6248
2.16k
    for (auto const& p : m_peers_to_disconnect)
6249
282
    {
6250
282
      TORRENT_ASSERT(p);
6251
282
      TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
6252
6253
282
      remove_connection(p.get());
6254
282
      m_ses.close_connection(p.get());
6255
282
    }
6256
2.16k
    TORRENT_ASSERT_VAL(m_peers_to_disconnect.size() == num, m_peers_to_disconnect.size() - num);
6257
2.16k
    m_peers_to_disconnect.clear();
6258
6259
2.16k
    if (m_graceful_pause_mode && m_connections.empty())
6260
0
    {
6261
      // we're in graceful pause mode and this was the last peer we
6262
      // disconnected. This will clear the graceful_pause_mode and post the
6263
      // torrent_paused_alert.
6264
0
      TORRENT_ASSERT(is_paused());
6265
6266
      // this will post torrent_paused alert
6267
0
      set_paused(true);
6268
0
    }
6269
6270
2.16k
    update_want_peers();
6271
2.16k
    update_want_tick();
6272
2.16k
  }
6273
6274
  void torrent::remove_web_seed_iter(std::list<web_seed_t>::iterator web)
6275
0
  {
6276
0
    if (web->resolving)
6277
0
    {
6278
0
      web->removed = true;
6279
0
    }
6280
0
    else
6281
0
    {
6282
#ifndef TORRENT_DISABLE_LOGGING
6283
      debug_log("removing web seed: \"%s\"", web->url.c_str());
6284
#endif
6285
6286
0
      auto* peer = static_cast<peer_connection*>(web->peer_info.connection);
6287
0
      if (peer != nullptr)
6288
0
      {
6289
        // if we have a connection for this web seed, we also need to
6290
        // disconnect it and clear its reference to the peer_info object
6291
        // that's part of the web_seed_t we're about to remove
6292
0
        TORRENT_ASSERT(peer->m_in_use == 1337);
6293
0
        peer->disconnect(boost::asio::error::operation_aborted, operation_t::bittorrent);
6294
0
        peer->set_peer_info(nullptr);
6295
0
      }
6296
0
      if (has_picker()) picker().clear_peer(&web->peer_info);
6297
6298
0
      m_web_seeds.erase(web);
6299
0
    }
6300
6301
0
    update_want_tick();
6302
0
  }
6303
6304
  void torrent::connect_to_url_seed(std::list<web_seed_t>::iterator web)
6305
0
  {
6306
0
    TORRENT_ASSERT(is_single_thread());
6307
0
    INVARIANT_CHECK;
6308
6309
0
    TORRENT_ASSERT(!web->resolving);
6310
0
    if (web->resolving) return;
6311
6312
0
    if (num_peers() >= int(m_max_connections)
6313
0
      || m_ses.num_connections() >= settings().get_int(settings_pack::connections_limit))
6314
0
      return;
6315
6316
0
    std::string protocol;
6317
0
    std::string auth;
6318
0
    std::string hostname;
6319
0
    int port;
6320
0
    std::string path;
6321
0
    error_code ec;
6322
0
    std::tie(protocol, auth, hostname, port, path)
6323
0
      = parse_url_components(web->url, ec);
6324
6325
0
    if (!settings().get_bool(settings_pack::allow_idna) && is_idna(hostname))
6326
0
    {
6327
#ifndef TORRENT_DISABLE_LOGGING
6328
      if (should_log())
6329
        debug_log("IDNA disallowed in web seeds: %s", web->url.c_str());
6330
#endif
6331
0
      if (m_ses.alerts().should_post<url_seed_alert>())
6332
0
      {
6333
0
        m_ses.alerts().emplace_alert<url_seed_alert>(get_handle()
6334
0
          , web->url, error_code(errors::blocked_by_idna));
6335
0
      }
6336
      // never try it again
6337
0
      web->disabled = true;
6338
0
      return;
6339
0
    }
6340
6341
0
    if (port == -1)
6342
0
    {
6343
0
      port = protocol == "http" ? 80 : 443;
6344
0
    }
6345
6346
0
    if (ec)
6347
0
    {
6348
#ifndef TORRENT_DISABLE_LOGGING
6349
      if (should_log())
6350
        debug_log("failed to parse web seed url: %s", ec.message().c_str());
6351
#endif
6352
0
      if (m_ses.alerts().should_post<url_seed_alert>())
6353
0
      {
6354
0
        m_ses.alerts().emplace_alert<url_seed_alert>(get_handle()
6355
0
          , web->url, ec);
6356
0
      }
6357
      // never try it again
6358
0
      remove_web_seed_iter(web);
6359
0
      return;
6360
0
    }
6361
6362
0
    if (web->peer_info.banned)
6363
0
    {
6364
#ifndef TORRENT_DISABLE_LOGGING
6365
      debug_log("banned web seed: %s", web->url.c_str());
6366
#endif
6367
0
      if (m_ses.alerts().should_post<url_seed_alert>())
6368
0
      {
6369
0
        m_ses.alerts().emplace_alert<url_seed_alert>(get_handle(), web->url
6370
0
          , libtorrent::errors::peer_banned);
6371
0
      }
6372
      // never try it again
6373
0
      web->disabled = true;
6374
0
      return;
6375
0
    }
6376
6377
0
#if TORRENT_USE_SSL
6378
0
    if (protocol != "http" && protocol != "https")
6379
#else
6380
    if (protocol != "http")
6381
#endif
6382
0
    {
6383
0
      if (m_ses.alerts().should_post<url_seed_alert>())
6384
0
      {
6385
0
        m_ses.alerts().emplace_alert<url_seed_alert>(get_handle(), web->url, errors::unsupported_url_protocol);
6386
0
      }
6387
      // never try it again for this session
6388
0
      web->disabled = true;
6389
0
      return;
6390
0
    }
6391
6392
0
    if (hostname.empty())
6393
0
    {
6394
0
      if (m_ses.alerts().should_post<url_seed_alert>())
6395
0
      {
6396
0
        m_ses.alerts().emplace_alert<url_seed_alert>(get_handle(), web->url
6397
0
          , errors::invalid_hostname);
6398
0
      }
6399
      // never try it again
6400
0
      remove_web_seed_iter(web);
6401
0
      return;
6402
0
    }
6403
6404
0
    if (port == 0)
6405
0
    {
6406
0
      if (m_ses.alerts().should_post<url_seed_alert>())
6407
0
      {
6408
0
        m_ses.alerts().emplace_alert<url_seed_alert>(get_handle(), web->url
6409
0
          , errors::invalid_port);
6410
0
      }
6411
      // never try it again
6412
0
      remove_web_seed_iter(web);
6413
0
      return;
6414
0
    }
6415
6416
0
    if (m_ses.get_port_filter().access(std::uint16_t(port)) & port_filter::blocked)
6417
0
    {
6418
0
      if (m_ses.alerts().should_post<url_seed_alert>())
6419
0
      {
6420
0
        m_ses.alerts().emplace_alert<url_seed_alert>(get_handle()
6421
0
          , web->url, errors::port_blocked);
6422
0
      }
6423
      // never try it again
6424
0
      web->disabled = true;
6425
0
      return;
6426
0
    }
6427
6428
0
    if (!web->endpoints.empty())
6429
0
    {
6430
0
      connect_web_seed(web, web->endpoints.front());
6431
0
      return;
6432
0
    }
6433
6434
0
    aux::proxy_settings const& ps = m_ses.proxy();
6435
0
    if ((ps.type == settings_pack::http
6436
0
      || ps.type == settings_pack::http_pw)
6437
0
      && ps.proxy_peer_connections)
6438
0
    {
6439
#ifndef TORRENT_DISABLE_LOGGING
6440
      debug_log("resolving proxy for web seed: %s", web->url.c_str());
6441
#endif
6442
6443
0
      std::uint16_t const proxy_port = ps.port;
6444
6445
      // use proxy
6446
0
      web->resolving = true;
6447
0
      m_ses.get_resolver().async_resolve(ps.hostname, aux::resolver_interface::abort_on_shutdown
6448
0
        , [self = shared_from_this(), web, proxy_port](error_code const& e, std::vector<address> const& addrs)
6449
0
        { self->wrap(&torrent::on_proxy_name_lookup, e, addrs, web, proxy_port); });
6450
0
    }
6451
0
    else if (ps.proxy_hostnames
6452
0
      && (ps.type == settings_pack::socks5
6453
0
        || ps.type == settings_pack::socks5_pw)
6454
0
      && ps.proxy_peer_connections)
6455
0
    {
6456
0
      connect_web_seed(web, {address(), std::uint16_t(port)});
6457
0
    }
6458
0
    else
6459
0
    {
6460
#ifndef TORRENT_DISABLE_LOGGING
6461
      debug_log("resolving web seed: \"%s\" %s", hostname.c_str(), web->url.c_str());
6462
#endif
6463
6464
0
      auto self = shared_from_this();
6465
0
      web->resolving = true;
6466
6467
0
      m_ses.get_resolver().async_resolve(hostname, aux::resolver_interface::abort_on_shutdown
6468
0
        , [self, web, port](error_code const& e, std::vector<address> const& addrs)
6469
0
        {
6470
0
          self->wrap(&torrent::on_name_lookup, e, addrs, port, web);
6471
0
        });
6472
0
    }
6473
0
  }
6474
6475
  void torrent::on_proxy_name_lookup(error_code const& e
6476
    , std::vector<address> const& addrs
6477
0
    , std::list<web_seed_t>::iterator web, int port) try
6478
0
  {
6479
0
    TORRENT_ASSERT(is_single_thread());
6480
6481
0
    INVARIANT_CHECK;
6482
6483
0
    TORRENT_ASSERT(web->resolving);
6484
#ifndef TORRENT_DISABLE_LOGGING
6485
    debug_log("completed resolve proxy hostname for: %s", web->url.c_str());
6486
    if (e && should_log())
6487
      debug_log("proxy name lookup error: %s", e.message().c_str());
6488
#endif
6489
0
    web->resolving = false;
6490
6491
0
    if (web->removed)
6492
0
    {
6493
#ifndef TORRENT_DISABLE_LOGGING
6494
      debug_log("removed web seed");
6495
#endif
6496
0
      remove_web_seed_iter(web);
6497
0
      return;
6498
0
    }
6499
6500
0
    if (m_abort) return;
6501
0
    if (m_ses.is_aborted()) return;
6502
6503
0
    if (e || addrs.empty())
6504
0
    {
6505
0
      if (m_ses.alerts().should_post<url_seed_alert>())
6506
0
      {
6507
0
        m_ses.alerts().emplace_alert<url_seed_alert>(get_handle()
6508
0
          , web->url, e);
6509
0
      }
6510
6511
      // the name lookup failed for the http host. Don't try
6512
      // this host again
6513
0
      web->disabled = true;
6514
0
      return;
6515
0
    }
6516
6517
0
    if (num_peers() >= int(m_max_connections)
6518
0
      || m_ses.num_connections() >= settings().get_int(settings_pack::connections_limit))
6519
0
      return;
6520
6521
0
    tcp::endpoint a(addrs[0], std::uint16_t(port));
6522
6523
0
    std::string hostname;
6524
0
    error_code ec;
6525
0
    std::string protocol;
6526
0
    std::tie(protocol, std::ignore, hostname, port, std::ignore)
6527
0
      = parse_url_components(web->url, ec);
6528
0
    if (port == -1) port = protocol == "http" ? 80 : 443;
6529
6530
0
    if (ec)
6531
0
    {
6532
0
      if (m_ses.alerts().should_post<url_seed_alert>())
6533
0
      {
6534
0
        m_ses.alerts().emplace_alert<url_seed_alert>(get_handle()
6535
0
          , web->url, ec);
6536
0
      }
6537
0
      remove_web_seed_iter(web);
6538
0
      return;
6539
0
    }
6540
6541
0
    if (m_ip_filter && m_ip_filter->access(a.address()) & ip_filter::blocked)
6542
0
    {
6543
0
      if (m_ses.alerts().should_post<peer_blocked_alert>())
6544
0
        m_ses.alerts().emplace_alert<peer_blocked_alert>(get_handle()
6545
0
          , a, peer_blocked_alert::ip_filter);
6546
0
      return;
6547
0
    }
6548
6549
0
    auto self = shared_from_this();
6550
0
    web->resolving = true;
6551
0
    m_ses.get_resolver().async_resolve(hostname, aux::resolver_interface::abort_on_shutdown
6552
0
      , [self, web, port](error_code const& err, std::vector<address> const& addr)
6553
0
      {
6554
0
        self->wrap(&torrent::on_name_lookup, err, addr, port, web);
6555
0
      });
6556
0
  }
6557
0
  catch (...) { handle_exception(); }
6558
6559
  void torrent::on_name_lookup(error_code const& e
6560
    , std::vector<address> const& addrs
6561
    , int const port
6562
0
    , std::list<web_seed_t>::iterator web) try
6563
0
  {
6564
0
    TORRENT_ASSERT(is_single_thread());
6565
6566
0
    INVARIANT_CHECK;
6567
6568
0
    TORRENT_ASSERT(web->resolving);
6569
#ifndef TORRENT_DISABLE_LOGGING
6570
    debug_log("completed resolve: %s", web->url.c_str());
6571
#endif
6572
0
    web->resolving = false;
6573
0
    if (web->removed)
6574
0
    {
6575
#ifndef TORRENT_DISABLE_LOGGING
6576
      debug_log("removed web seed");
6577
#endif
6578
0
      remove_web_seed_iter(web);
6579
0
      return;
6580
0
    }
6581
6582
0
    if (m_abort) return;
6583
6584
0
    if (e || addrs.empty())
6585
0
    {
6586
0
      if (m_ses.alerts().should_post<url_seed_alert>())
6587
0
        m_ses.alerts().emplace_alert<url_seed_alert>(get_handle(), web->url, e);
6588
#ifndef TORRENT_DISABLE_LOGGING
6589
      if (should_log())
6590
      {
6591
        debug_log("*** HOSTNAME LOOKUP FAILED: %s: (%d) %s"
6592
          , web->url.c_str(), e.value(), e.message().c_str());
6593
      }
6594
#endif
6595
6596
      // unavailable, retry in `settings_pack::web_seed_name_lookup_retry` seconds
6597
0
      web->retry = aux::time_now32()
6598
0
        + seconds32(settings().get_int(settings_pack::web_seed_name_lookup_retry));
6599
0
      return;
6600
0
    }
6601
6602
0
    for (auto const& addr : addrs)
6603
0
    {
6604
      // if this is set, we don't allow this web seed to have resolved to a
6605
      // local IP
6606
0
      if (web->no_local_ips && !aux::is_global(addr)) continue;
6607
6608
      // fill in the peer struct's address field
6609
0
      web->endpoints.emplace_back(addr, std::uint16_t(port));
6610
6611
#ifndef TORRENT_DISABLE_LOGGING
6612
      if (should_log())
6613
        debug_log("  -> %s", print_endpoint(tcp::endpoint(addr, std::uint16_t(port))).c_str());
6614
#endif
6615
0
    }
6616
6617
0
    if (web->endpoints.empty())
6618
0
    {
6619
0
      if (m_ses.alerts().should_post<url_seed_alert>())
6620
0
      {
6621
0
        m_ses.alerts().emplace_alert<url_seed_alert>(get_handle()
6622
0
          , web->url, errors::banned_by_ip_filter);
6623
0
      }
6624
6625
      // the name lookup failed for the http host. Don't try
6626
      // this host again
6627
0
      web->disabled = true;
6628
0
      return;
6629
0
    }
6630
6631
0
    if (num_peers() >= int(m_max_connections)
6632
0
      || m_ses.num_connections() >= settings().get_int(settings_pack::connections_limit))
6633
0
      return;
6634
6635
0
    connect_web_seed(web, web->endpoints.front());
6636
0
  }
6637
0
  catch (...) { handle_exception(); }
6638
6639
  void torrent::connect_web_seed(std::list<web_seed_t>::iterator web, tcp::endpoint a)
6640
0
  {
6641
0
    INVARIANT_CHECK;
6642
6643
0
    TORRENT_ASSERT(is_single_thread());
6644
0
    if (m_abort) return;
6645
6646
0
    if (m_ip_filter && m_ip_filter->access(a.address()) & ip_filter::blocked)
6647
0
    {
6648
0
      if (m_ses.alerts().should_post<peer_blocked_alert>())
6649
0
        m_ses.alerts().emplace_alert<peer_blocked_alert>(get_handle()
6650
0
          , a, peer_blocked_alert::ip_filter);
6651
0
      return;
6652
0
    }
6653
6654
0
    TORRENT_ASSERT(!web->resolving);
6655
0
    TORRENT_ASSERT(web->peer_info.connection == nullptr);
6656
6657
0
    if (aux::is_v4(a))
6658
0
    {
6659
0
      web->peer_info.addr = a.address().to_v4();
6660
0
      web->peer_info.port = a.port();
6661
0
    }
6662
6663
0
    if (is_paused()) return;
6664
0
    if (m_ses.is_aborted()) return;
6665
0
    if (is_upload_only()) return;
6666
6667
    // this web seed may have redirected all files to other URLs, leaving it
6668
    // having no file left, and there's no longer any point in connecting to
6669
    // it.
6670
0
    if (!web->have_files.empty()
6671
0
      && web->have_files.none_set()) return;
6672
6673
0
    void* userdata = nullptr;
6674
0
#if TORRENT_USE_SSL
6675
0
    const bool ssl = string_begins_no_case("https://", web->url.c_str());
6676
0
    if (ssl)
6677
0
    {
6678
0
#ifdef TORRENT_SSL_PEERS
6679
0
      userdata = m_ssl_ctx.get();
6680
0
#endif
6681
0
      if (!userdata) userdata = m_ses.ssl_ctx();
6682
0
    }
6683
0
#endif
6684
0
    aux::socket_type s = instantiate_connection(m_ses.get_context()
6685
0
      , m_ses.proxy(), userdata, nullptr, true, false);
6686
6687
0
    if (boost::get<http_stream>(&s))
6688
0
    {
6689
      // the web seed connection will talk immediately to
6690
      // the proxy, without requiring CONNECT support
6691
0
      boost::get<http_stream>(s).set_no_connect(true);
6692
0
    }
6693
6694
0
    std::string hostname;
6695
0
    std::string path;
6696
0
    error_code ec;
6697
0
    using std::ignore;
6698
0
    std::tie(ignore, ignore, hostname, ignore, path)
6699
0
      = parse_url_components(web->url, ec);
6700
0
    if (ec)
6701
0
    {
6702
0
      if (m_ses.alerts().should_post<url_seed_alert>())
6703
0
        m_ses.alerts().emplace_alert<url_seed_alert>(get_handle(), web->url, ec);
6704
0
      return;
6705
0
    }
6706
6707
0
    if (!settings().get_bool(settings_pack::allow_idna) && is_idna(hostname))
6708
0
    {
6709
#ifndef TORRENT_DISABLE_LOGGING
6710
      if (should_log())
6711
        debug_log("IDNA disallowed in web seeds: %s", web->url.c_str());
6712
#endif
6713
0
      if (m_ses.alerts().should_post<url_seed_alert>())
6714
0
      {
6715
0
        m_ses.alerts().emplace_alert<url_seed_alert>(get_handle()
6716
0
          , web->url, error_code(errors::blocked_by_idna));
6717
0
      }
6718
      // never try it again
6719
0
      web->disabled = true;
6720
0
      return;
6721
0
    }
6722
6723
    // The SSRF mitigation for web seeds is that any HTTP server on the
6724
    // local network may not use any query string parameters
6725
0
    if (settings().get_bool(settings_pack::ssrf_mitigation)
6726
0
      && aux::is_local(web->peer_info.addr)
6727
0
      && path.find('?') != std::string::npos)
6728
0
    {
6729
#ifndef TORRENT_DISABLE_LOGGING
6730
      if (should_log())
6731
      {
6732
        debug_log("*** SSRF MITIGATION BLOCKED WEB SEED: %s"
6733
          , web->url.c_str());
6734
      }
6735
#endif
6736
0
      if (m_ses.alerts().should_post<url_seed_alert>())
6737
0
        m_ses.alerts().emplace_alert<url_seed_alert>(get_handle()
6738
0
          , web->url, errors::ssrf_mitigation);
6739
0
      if (m_ses.alerts().should_post<peer_blocked_alert>())
6740
0
        m_ses.alerts().emplace_alert<peer_blocked_alert>(get_handle()
6741
0
          , a, peer_blocked_alert::ssrf_mitigation);
6742
      // never try it again
6743
0
      web->disabled = true;
6744
0
      return;
6745
0
    }
6746
6747
0
    bool const is_ip = aux::is_ip_address(hostname);
6748
0
    if (is_ip) a.address(make_address(hostname, ec));
6749
0
    bool const proxy_hostnames = settings().get_bool(settings_pack::proxy_hostnames)
6750
0
      && !is_ip;
6751
6752
0
    if (proxy_hostnames
6753
0
      && (boost::get<socks5_stream>(&s)
6754
0
#if TORRENT_USE_SSL
6755
0
        || boost::get<ssl_stream<socks5_stream>>(&s)
6756
0
#endif
6757
0
        ))
6758
0
    {
6759
      // we're using a socks proxy and we're resolving
6760
      // hostnames through it
6761
0
      socks5_stream& str =
6762
0
#if TORRENT_USE_SSL
6763
0
        ssl ? boost::get<ssl_stream<socks5_stream>>(s).next_layer() :
6764
0
#endif
6765
0
      boost::get<socks5_stream>(s);
6766
6767
0
      str.set_dst_name(hostname);
6768
0
    }
6769
6770
0
    setup_ssl_hostname(s, hostname, ec);
6771
0
    if (ec)
6772
0
    {
6773
0
      if (m_ses.alerts().should_post<url_seed_alert>())
6774
0
        m_ses.alerts().emplace_alert<url_seed_alert>(get_handle(), web->url, ec);
6775
0
      return;
6776
0
    }
6777
6778
0
    peer_connection_args pack{
6779
0
      &m_ses
6780
0
      , &settings()
6781
0
      , &m_ses.stats_counters()
6782
0
      , &m_ses.disk_thread()
6783
0
      , &m_ses.get_context()
6784
0
      , shared_from_this()
6785
0
      , std::move(s)
6786
0
      , a
6787
0
      , &web->peer_info
6788
0
      , aux::generate_peer_id(settings())
6789
0
    };
6790
6791
0
    std::shared_ptr<peer_connection> c;
6792
0
    if (web->type == web_seed_entry::url_seed)
6793
0
    {
6794
0
      c = std::make_shared<web_peer_connection>(pack, *web);
6795
0
    }
6796
0
    else if (web->type == web_seed_entry::http_seed)
6797
0
    {
6798
0
      c = std::make_shared<http_seed_connection>(pack, *web);
6799
0
    }
6800
0
    if (!c) return;
6801
6802
0
#if TORRENT_USE_ASSERTS
6803
0
    c->m_in_constructor = false;
6804
0
#endif
6805
6806
0
#ifndef TORRENT_DISABLE_EXTENSIONS
6807
0
    for (auto const& ext : m_extensions)
6808
0
    {
6809
0
      std::shared_ptr<peer_plugin>
6810
0
        pp(ext->new_connection(peer_connection_handle(c->self())));
6811
0
      if (pp) c->add_extension(pp);
6812
0
    }
6813
0
#endif
6814
6815
0
    TORRENT_ASSERT(!c->m_in_constructor);
6816
    // add the newly connected peer to this torrent's peer list
6817
0
    TORRENT_ASSERT(m_iterating_connections == 0);
6818
6819
    // we don't want to have to allocate memory to disconnect this peer, so
6820
    // make sure there's enough memory allocated in the deferred_disconnect
6821
    // list up-front
6822
0
    m_peers_to_disconnect.reserve(m_connections.size() + 1);
6823
6824
0
    sorted_insert(m_connections, c.get());
6825
0
    update_want_peers();
6826
0
    update_want_tick();
6827
0
    m_ses.insert_peer(c);
6828
6829
0
    if (web->peer_info.seed)
6830
0
    {
6831
0
      TORRENT_ASSERT(m_num_seeds < 0xffff);
6832
0
      ++m_num_seeds;
6833
0
    }
6834
6835
0
    TORRENT_ASSERT(!web->peer_info.connection);
6836
0
    web->peer_info.connection = c.get();
6837
0
#if TORRENT_USE_ASSERTS
6838
0
    web->peer_info.in_use = true;
6839
0
#endif
6840
6841
0
    c->add_stat(std::int64_t(web->peer_info.prev_amount_download) << 10
6842
0
      , std::int64_t(web->peer_info.prev_amount_upload) << 10);
6843
0
    web->peer_info.prev_amount_download = 0;
6844
0
    web->peer_info.prev_amount_upload = 0;
6845
#ifndef TORRENT_DISABLE_LOGGING
6846
    if (should_log())
6847
    {
6848
      debug_log("web seed connection started: [%s] %s"
6849
        , print_endpoint(a).c_str(), web->url.c_str());
6850
    }
6851
#endif
6852
6853
0
    c->start();
6854
6855
0
    if (c->is_disconnecting()) return;
6856
6857
#ifndef TORRENT_DISABLE_LOGGING
6858
    debug_log("START queue peer [%p] (%d)", static_cast<void*>(c.get())
6859
      , num_peers());
6860
#endif
6861
0
  }
6862
6863
  hash_request torrent::pick_hashes(peer_connection* peer)
6864
1.02k
  {
6865
1.02k
    need_hash_picker();
6866
1.02k
    if (!m_hash_picker) return {};
6867
1.02k
    return m_hash_picker->pick_hashes(peer->get_bitfield());
6868
1.02k
  }
6869
6870
  std::vector<sha256_hash> torrent::get_hashes(hash_request const& req) const
6871
61
  {
6872
61
    TORRENT_ASSERT(m_torrent_file->is_valid());
6873
61
    if (!m_torrent_file->is_valid()) return {};
6874
61
    TORRENT_ASSERT(validate_hash_request(req, m_torrent_file->files()));
6875
6876
61
    auto const& f = m_merkle_trees[req.file];
6877
6878
61
    return f.get_hashes(req.base, req.index, req.count, req.proof_layers);
6879
61
  }
6880
6881
  bool torrent::add_hashes(hash_request const& req, span<sha256_hash> hashes)
6882
0
  {
6883
0
    need_hash_picker();
6884
0
    if (!m_hash_picker) return true;
6885
0
    add_hashes_result const result = m_hash_picker->add_hashes(req, hashes);
6886
0
    for (auto& p : result.hash_failed)
6887
0
    {
6888
0
      if (torrent_file().info_hashes().has_v1() && have_piece(p.first))
6889
0
      {
6890
0
        handle_inconsistent_hashes(p.first);
6891
0
        return result.valid;
6892
0
      }
6893
6894
0
      TORRENT_ASSERT(!have_piece(p.first));
6895
6896
      // the piece may not have been downloaded in this session
6897
      // it should be open for downloading so nothing needs to be done here
6898
0
      if (!m_picker || !m_picker->is_downloading(p.first)) continue;
6899
0
      piece_failed(p.first, p.second);
6900
0
    }
6901
0
    for (piece_index_t p : result.hash_passed)
6902
0
    {
6903
0
      if (torrent_file().info_hashes().has_v1() && !have_piece(p))
6904
0
      {
6905
0
        handle_inconsistent_hashes(p);
6906
0
        return result.valid;
6907
0
      }
6908
6909
0
      if (m_picker && m_picker->is_downloading(p) && m_picker->is_piece_finished(p)
6910
0
        && !m_picker->is_hashing(p))
6911
0
      {
6912
0
        piece_passed(p);
6913
0
      }
6914
0
    }
6915
0
    return result.valid;
6916
0
  }
6917
6918
  void torrent::hashes_rejected(hash_request const& req)
6919
0
  {
6920
0
    if (!m_hash_picker) return;
6921
0
    m_hash_picker->hashes_rejected(req);
6922
    // we need to poke all of the v2 peers in case there are no other
6923
    // outstanding hash requests
6924
0
    for (auto peer : m_connections)
6925
0
    {
6926
0
      if (peer->type() != connection_type::bittorrent) continue;
6927
0
      auto* const btpeer = static_cast<bt_peer_connection*>(peer);
6928
0
      btpeer->maybe_send_hash_request();
6929
0
    }
6930
0
  }
6931
6932
  void torrent::verify_block_hashes(piece_index_t index)
6933
0
  {
6934
0
    need_hash_picker();
6935
0
    if (!m_hash_picker) return;
6936
#ifndef TORRENT_DISABLE_LOGGING
6937
    if (should_log())
6938
    {
6939
      debug_log("Piece %d hash failure, requesting block hashes", int(index));
6940
    }
6941
#endif
6942
0
    m_hash_picker->verify_block_hashes(index);
6943
0
  }
6944
6945
  std::shared_ptr<const torrent_info> torrent::get_torrent_file() const
6946
0
  {
6947
0
    if (!m_torrent_file->is_valid()) return {};
6948
0
    return m_torrent_file;
6949
0
  }
6950
6951
  std::shared_ptr<torrent_info> torrent::get_torrent_copy_with_hashes() const
6952
0
  {
6953
0
    if (!m_torrent_file->is_valid()) return {};
6954
0
    auto ret = std::make_shared<torrent_info>(*m_torrent_file);
6955
6956
0
    if (ret->v2())
6957
0
    {
6958
0
      aux::vector<aux::vector<char>, file_index_t> v2_hashes;
6959
0
      for (auto const& tree : m_merkle_trees)
6960
0
      {
6961
0
        auto const& layer = tree.get_piece_layer();
6962
0
        std::vector<char> out_layer;
6963
0
        out_layer.reserve(layer.size() * sha256_hash::size());
6964
0
        for (auto const& h : layer)
6965
0
        {
6966
          // we're missing a piece layer. We can't return a valid
6967
          // torrent
6968
0
          if (h.is_all_zeros()) return {};
6969
0
          out_layer.insert(out_layer.end(), h.data(), h.data() + sha256_hash::size());
6970
0
        }
6971
0
        v2_hashes.emplace_back(std::move(out_layer));
6972
0
      }
6973
0
      ret->set_piece_layers(std::move(v2_hashes));
6974
0
    }
6975
6976
0
    return ret;
6977
0
  }
6978
6979
  std::vector<std::vector<sha256_hash>> torrent::get_piece_layers() const
6980
0
  {
6981
0
    std::vector<std::vector<sha256_hash>> ret;
6982
0
    for (auto const& tree : m_merkle_trees)
6983
0
      ret.emplace_back(tree.get_piece_layer());
6984
0
    return ret;
6985
0
  }
6986
6987
  void torrent::enable_all_trackers()
6988
0
  {
6989
0
    for (aux::announce_entry& ae : m_trackers)
6990
0
      for (aux::announce_endpoint& aep : ae.endpoints)
6991
0
        aep.enabled = true;
6992
0
  }
6993
6994
  void torrent::write_resume_data(resume_data_flags_t const flags, add_torrent_params& ret) const
6995
0
  {
6996
0
    ret.version = LIBTORRENT_VERSION_NUM;
6997
0
    ret.storage_mode = storage_mode();
6998
0
    ret.total_uploaded = m_total_uploaded;
6999
0
    ret.total_downloaded = m_total_downloaded;
7000
7001
    // cast to seconds in case that internal values doesn't have ratio<1>
7002
0
    ret.active_time = static_cast<int>(total_seconds(active_time()));
7003
0
    ret.finished_time = static_cast<int>(total_seconds(finished_time()));
7004
0
    ret.seeding_time = static_cast<int>(total_seconds(seeding_time()));
7005
0
    ret.last_seen_complete = m_last_seen_complete;
7006
0
    ret.last_upload = aux::to_time_t(m_last_upload);
7007
0
    ret.last_download = aux::to_time_t(m_last_download);
7008
7009
0
    ret.num_complete = m_complete;
7010
0
    ret.num_incomplete = m_incomplete;
7011
0
    ret.num_downloaded = m_downloaded;
7012
7013
0
    ret.flags = this->flags();
7014
7015
0
    ret.added_time = m_added_time;
7016
0
    ret.completed_time = m_completed_time;
7017
7018
0
    ret.save_path = m_save_path;
7019
7020
0
    ret.info_hashes = torrent_file().info_hashes();
7021
0
    if (valid_metadata()) ret.name = m_torrent_file->name();
7022
0
    else if (m_name) ret.name = *m_name;
7023
7024
0
#if TORRENT_ABI_VERSION < 3
7025
0
    ret.info_hash = ret.info_hashes.get_best();
7026
0
#endif
7027
7028
0
    if (valid_metadata() && (flags & torrent_handle::save_info_dict))
7029
0
    {
7030
0
      ret.ti = m_torrent_file;
7031
0
    }
7032
7033
    // if this torrent is a seed, we won't have a piece picker
7034
    // if we don't have anything, we may also not have a picker
7035
    // in either case; there will be no half-finished pieces.
7036
0
    if (has_picker())
7037
0
    {
7038
0
      int const num_blocks_per_piece = torrent_file().blocks_per_piece();
7039
7040
0
      std::vector<piece_picker::downloading_piece> const q
7041
0
        = m_picker->get_download_queue();
7042
7043
      // info for each unfinished piece
7044
0
      for (auto const& dp : q)
7045
0
      {
7046
0
        if (dp.finished == 0 && dp.writing == 0)
7047
0
          continue;
7048
7049
0
        bitfield bitmask;
7050
0
        bitmask.resize(num_blocks_per_piece, false);
7051
7052
0
        auto const info = m_picker->blocks_for_piece(dp);
7053
0
        for (int i = 0; i < int(info.size()); ++i)
7054
0
        {
7055
0
          if (info[i].state == piece_picker::block_info::state_finished)
7056
0
            bitmask.set_bit(i);
7057
0
        }
7058
0
        ret.unfinished_pieces.emplace(dp.index, std::move(bitmask));
7059
0
      }
7060
0
    }
7061
7062
    // save trackers
7063
0
    for (auto const& tr : m_trackers)
7064
0
    {
7065
0
      ret.trackers.push_back(tr.url);
7066
0
      ret.tracker_tiers.push_back(tr.tier);
7067
0
    }
7068
7069
    // save web seeds
7070
0
    for (auto const& ws : m_web_seeds)
7071
0
    {
7072
0
      if (ws.removed || ws.ephemeral) continue;
7073
0
      if (ws.type == web_seed_entry::url_seed)
7074
0
        ret.url_seeds.push_back(ws.url);
7075
0
      else if (ws.type == web_seed_entry::http_seed)
7076
0
        ret.http_seeds.push_back(ws.url);
7077
0
    }
7078
7079
0
    ret.dht_nodes = m_torrent_file->nodes();
7080
7081
    // write have bitmask
7082
    // the pieces string has one byte per piece. Each
7083
    // byte is a bitmask representing different properties
7084
    // for the piece
7085
    // bit 0: set if we have the piece
7086
    // bit 1: set if we have verified the piece (in seed mode)
7087
0
    bool const is_checking = state() == torrent_status::checking_files;
7088
7089
    // if we are checking, only save the have_pieces bitfield up to the piece
7090
    // we have actually checked. This allows us to resume the checking when we
7091
    // load this torrent up again. If we have not completed checking nor is
7092
    // currently checking, don't save any pieces from the have_pieces
7093
    // bitfield.
7094
0
    piece_index_t const max_piece
7095
0
      = is_checking ? m_num_checked_pieces
7096
0
      : m_files_checked ? m_torrent_file->end_piece()
7097
0
      : piece_index_t(0);
7098
7099
0
    TORRENT_ASSERT(ret.have_pieces.empty());
7100
0
    if (max_piece > piece_index_t(0))
7101
0
    {
7102
0
      if (is_seed())
7103
0
      {
7104
0
        ret.have_pieces.resize(static_cast<int>(max_piece), true);
7105
0
      }
7106
0
      else if (has_picker())
7107
0
      {
7108
0
        ret.have_pieces.resize(static_cast<int>(max_piece), false);
7109
0
        for (auto const i : ret.have_pieces.range())
7110
0
          if (m_picker->is_piece_flushed(i)) ret.have_pieces.set_bit(i);
7111
0
      }
7112
7113
0
      if (m_seed_mode)
7114
0
        ret.verified_pieces = m_verified;
7115
0
    }
7116
7117
    // write renamed files
7118
0
    if (valid_metadata()
7119
0
      && &m_torrent_file->files() != &m_torrent_file->orig_files()
7120
0
      && m_torrent_file->files().num_files() == m_torrent_file->orig_files().num_files())
7121
0
    {
7122
0
      file_storage const& fs = m_torrent_file->files();
7123
0
      file_storage const& orig_fs = m_torrent_file->orig_files();
7124
0
      for (auto const i : fs.file_range())
7125
0
      {
7126
0
        if (fs.file_path(i) != orig_fs.file_path(i))
7127
0
          ret.renamed_files[i] = fs.file_path(i);
7128
0
      }
7129
0
    }
7130
7131
    // write local peers
7132
0
    std::vector<torrent_peer const*> deferred_peers;
7133
0
    if (m_peer_list)
7134
0
    {
7135
0
      for (auto p : *m_peer_list)
7136
0
      {
7137
0
#if TORRENT_USE_I2P
7138
0
        if (p->is_i2p_addr) continue;
7139
0
#endif
7140
0
        if (p->banned)
7141
0
        {
7142
0
          ret.banned_peers.push_back(p->ip());
7143
0
          continue;
7144
0
        }
7145
7146
        // we cannot save remote connection
7147
        // since we don't know their listen port
7148
        // unless they gave us their listen port
7149
        // through the extension handshake
7150
        // so, if the peer is not connectable (i.e. we
7151
        // don't know its listen port) or if it has
7152
        // been banned, don't save it.
7153
0
        if (!p->connectable) continue;
7154
7155
        // don't save peers that don't work
7156
0
        if (int(p->failcount) > 0) continue;
7157
7158
        // don't save peers that appear to send corrupt data
7159
0
        if (int(p->trust_points) < 0) continue;
7160
7161
0
        if (p->last_connected == 0)
7162
0
        {
7163
          // we haven't connected to this peer. It might still
7164
          // be useful to save it, but only save it if we
7165
          // don't have enough peers that we actually did connect to
7166
0
          if (int(deferred_peers.size()) < 100)
7167
0
            deferred_peers.push_back(p);
7168
0
          continue;
7169
0
        }
7170
7171
0
        ret.peers.push_back(p->ip());
7172
0
      }
7173
0
    }
7174
7175
    // if we didn't save 100 peers, fill in with second choice peers
7176
0
    if (int(ret.peers.size()) < 100)
7177
0
    {
7178
0
      aux::random_shuffle(deferred_peers);
7179
0
      for (auto const p : deferred_peers)
7180
0
      {
7181
0
        ret.peers.push_back(p->ip());
7182
0
        if (int(ret.peers.size()) >= 100) break;
7183
0
      }
7184
0
    }
7185
7186
0
    ret.upload_limit = upload_limit();
7187
0
    ret.download_limit = download_limit();
7188
0
    ret.max_connections = max_connections();
7189
0
    ret.max_uploads = max_uploads();
7190
7191
    // piece priorities and file priorities are mutually exclusive. If there
7192
    // are file priorities set, don't save piece priorities.
7193
    // when in seed mode (i.e. the client promises that we have all files)
7194
    // it does not make sense to save file priorities.
7195
0
    if (!m_file_priority.empty() && !m_seed_mode)
7196
0
    {
7197
      // write file priorities
7198
0
      ret.file_priorities = m_file_priority;
7199
0
    }
7200
7201
0
    if (valid_metadata() && has_picker())
7202
0
    {
7203
      // write piece priorities
7204
      // but only if they are not set to the default
7205
0
      bool default_prio = true;
7206
0
      for (auto const i : m_torrent_file->piece_range())
7207
0
      {
7208
0
        if (m_picker->piece_priority(i) == default_priority) continue;
7209
0
        default_prio = false;
7210
0
        break;
7211
0
      }
7212
7213
0
      if (!default_prio)
7214
0
      {
7215
0
        ret.piece_priorities.clear();
7216
0
        ret.piece_priorities.reserve(static_cast<std::size_t>(m_torrent_file->num_pieces()));
7217
7218
0
        for (auto const i : m_torrent_file->piece_range())
7219
0
          ret.piece_priorities.push_back(m_picker->piece_priority(i));
7220
0
      }
7221
0
    }
7222
7223
0
    if (m_torrent_file->info_hashes().has_v2())
7224
0
    {
7225
0
      auto const num_files = m_merkle_trees.size();
7226
0
      ret.merkle_trees.clear();
7227
0
      ret.merkle_trees.reserve(num_files);
7228
0
      ret.merkle_tree_mask.clear();
7229
0
      ret.merkle_tree_mask.reserve(num_files);
7230
0
      ret.verified_leaf_hashes.clear();
7231
0
      ret.verified_leaf_hashes.reserve(num_files);
7232
0
      for (auto const& t : m_merkle_trees)
7233
0
      {
7234
        // use structured binding in C++17
7235
0
        aux::vector<bool> mask;
7236
0
        std::vector<sha256_hash> sparse_tree;
7237
0
        std::tie(sparse_tree, mask) = t.build_sparse_vector();
7238
0
        ret.merkle_trees.emplace_back(std::move(sparse_tree));
7239
0
        ret.merkle_tree_mask.emplace_back(std::move(mask));
7240
0
        ret.verified_leaf_hashes.emplace_back(t.verified_leafs());
7241
0
      }
7242
7243
0
      if (!has_hash_picker() && !m_have_all)
7244
0
      {
7245
0
        file_storage const& fs = m_torrent_file->files();
7246
0
        ret.verified_leaf_hashes.reserve(fs.num_files());
7247
0
        for (file_index_t f(0); f != fs.end_file(); ++f)
7248
0
        {
7249
0
          if (fs.pad_file_at(f) || fs.file_size(f) == 0)
7250
0
          {
7251
0
            ret.verified_leaf_hashes.emplace_back();
7252
0
            continue;
7253
0
          }
7254
0
          ret.verified_leaf_hashes.emplace_back(
7255
0
            fs.file_num_blocks(f), false);
7256
0
        }
7257
0
      }
7258
0
    }
7259
0
  }
7260
7261
#if TORRENT_ABI_VERSION == 1
7262
  void torrent::get_full_peer_list(std::vector<peer_list_entry>* v) const
7263
0
  {
7264
0
    v->clear();
7265
0
    if (!m_peer_list) return;
7266
7267
0
    v->reserve(aux::numeric_cast<std::size_t>(m_peer_list->num_peers()));
7268
0
    for (auto p : *m_peer_list)
7269
0
    {
7270
0
      peer_list_entry e;
7271
0
      e.ip = p->ip();
7272
0
      e.flags = p->banned ? peer_list_entry::banned : 0;
7273
0
      e.failcount = p->failcount;
7274
0
      e.source = p->source;
7275
0
      v->push_back(e);
7276
0
    }
7277
0
  }
7278
#endif
7279
7280
  void torrent::get_peer_info(std::vector<peer_info>* v)
7281
0
  {
7282
0
    v->clear();
7283
0
    for (auto const peer : *this)
7284
0
    {
7285
0
      TORRENT_ASSERT(peer->m_in_use == 1337);
7286
7287
      // incoming peers that haven't finished the handshake should
7288
      // not be included in this list
7289
0
      if (peer->associated_torrent().expired()) continue;
7290
7291
0
      v->emplace_back();
7292
0
      peer_info& p = v->back();
7293
7294
0
      peer->get_peer_info(p);
7295
0
    }
7296
0
  }
7297
7298
  void torrent::post_peer_info()
7299
0
  {
7300
0
    std::vector<peer_info> v;
7301
0
    get_peer_info(&v);
7302
0
    alerts().emplace_alert<peer_info_alert>(get_handle(), std::move(v));
7303
0
  }
7304
7305
namespace {
7306
  void initialize_piece_info(piece_picker const& p
7307
    , torrent_info const& ti
7308
    , int const block_size
7309
    , std::vector<block_info>& blk
7310
    , span<piece_picker::downloading_piece const> q
7311
    , std::vector<partial_piece_info>* queue)
7312
0
  {
7313
0
    const int blocks_per_piece = p.blocks_in_piece(piece_index_t(0));
7314
0
    int counter = 0;
7315
0
    for (auto i = q.begin(); i != q.end(); ++i, ++counter)
7316
0
    {
7317
0
      partial_piece_info pi;
7318
0
      pi.blocks_in_piece = p.blocks_in_piece(i->index);
7319
0
      pi.finished = int(i->finished);
7320
0
      pi.writing = int(i->writing);
7321
0
      pi.requested = int(i->requested);
7322
0
#if TORRENT_ABI_VERSION == 1
7323
0
      pi.piece_state = partial_piece_info::none;
7324
0
#endif
7325
0
      TORRENT_ASSERT(counter * blocks_per_piece + pi.blocks_in_piece <= int(blk.size()));
7326
0
      block_info* blocks = &blk[std::size_t(counter * blocks_per_piece)];
7327
0
      pi.blocks = blocks;
7328
0
      int const piece_size = ti.piece_size(i->index);
7329
0
      int idx = -1;
7330
0
      for (auto const& info : p.blocks_for_piece(*i))
7331
0
      {
7332
0
        ++idx;
7333
0
        block_info& bi = blocks[idx];
7334
0
        bi.state = info.state;
7335
0
        bi.block_size = idx < pi.blocks_in_piece - 1
7336
0
          ? aux::numeric_cast<std::uint32_t>(block_size)
7337
0
          : aux::numeric_cast<std::uint32_t>(piece_size - (idx * block_size));
7338
0
        bool const complete = bi.state == block_info::writing
7339
0
          || bi.state == block_info::finished;
7340
0
        if (info.peer == nullptr)
7341
0
        {
7342
0
          bi.set_peer(tcp::endpoint());
7343
0
          bi.bytes_progress = complete ? bi.block_size : 0;
7344
0
        }
7345
0
        else
7346
0
        {
7347
0
          torrent_peer* tp = info.peer;
7348
0
          TORRENT_ASSERT(tp->in_use);
7349
0
          if (tp->connection)
7350
0
          {
7351
0
            auto* peer = static_cast<peer_connection*>(tp->connection);
7352
0
            TORRENT_ASSERT(peer->m_in_use);
7353
0
            bi.set_peer(peer->remote());
7354
0
            if (bi.state == block_info::requested)
7355
0
            {
7356
0
              auto pbp = peer->downloading_piece_progress();
7357
0
              if (pbp.piece_index == i->index && pbp.block_index == idx)
7358
0
              {
7359
0
                bi.bytes_progress = aux::numeric_cast<std::uint32_t>(pbp.bytes_downloaded);
7360
0
                TORRENT_ASSERT(bi.bytes_progress <= bi.block_size);
7361
0
              }
7362
0
              else
7363
0
              {
7364
0
                bi.bytes_progress = 0;
7365
0
              }
7366
0
            }
7367
0
            else
7368
0
            {
7369
0
              bi.bytes_progress = complete ? bi.block_size : 0;
7370
0
            }
7371
0
          }
7372
0
          else
7373
0
          {
7374
0
            bi.set_peer(tp->ip());
7375
0
            bi.bytes_progress = complete ? bi.block_size : 0;
7376
0
          }
7377
0
        }
7378
7379
0
        bi.num_peers = info.num_peers;
7380
0
      }
7381
0
      pi.piece_index = i->index;
7382
0
      queue->push_back(pi);
7383
0
    }
7384
0
  }
7385
}
7386
7387
  void torrent::post_download_queue()
7388
0
  {
7389
0
    std::vector<block_info> blk;
7390
0
    if (!valid_metadata() || !has_picker()) return;
7391
0
    piece_picker const& p = picker();
7392
0
    std::vector<piece_picker::downloading_piece> const q = p.get_download_queue();
7393
0
    std::vector<partial_piece_info> queue;
7394
0
    if (!q.empty())
7395
0
    {
7396
0
      const int blocks_per_piece = m_picker->blocks_in_piece(piece_index_t(0));
7397
0
      blk.resize(q.size() * aux::numeric_cast<std::size_t>(blocks_per_piece));
7398
0
      initialize_piece_info(p, torrent_file(), block_size(), blk, q, &queue);
7399
0
    }
7400
0
    alerts().emplace_alert<piece_info_alert>(get_handle(), std::move(queue), std::move(blk));
7401
0
  }
7402
7403
  void torrent::get_download_queue(std::vector<partial_piece_info>* queue) const
7404
0
  {
7405
0
    TORRENT_ASSERT(is_single_thread());
7406
0
    queue->clear();
7407
0
    std::vector<block_info>& blk = m_ses.block_info_storage();
7408
0
    blk.clear();
7409
7410
0
    if (!valid_metadata() || !has_picker()) return;
7411
0
    piece_picker const& p = picker();
7412
0
    std::vector<piece_picker::downloading_piece> q
7413
0
      = p.get_download_queue();
7414
0
    if (q.empty()) return;
7415
7416
0
    const int blocks_per_piece = m_picker->blocks_in_piece(piece_index_t(0));
7417
0
    blk.resize(q.size() * aux::numeric_cast<std::size_t>(blocks_per_piece));
7418
7419
0
    initialize_piece_info(p, torrent_file(), block_size(), blk, q, queue);
7420
0
  }
7421
7422
#if defined TORRENT_SSL_PEERS
7423
  struct hostname_visitor
7424
  {
7425
0
    explicit hostname_visitor(std::string const& h) : hostname_(h) {}
7426
    template <typename T>
7427
0
    void operator()(T&) {}
Unexecuted instantiation: void libtorrent::hostname_visitor::operator()<libtorrent::aux::noexcept_move_only<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::executor> > >(libtorrent::aux::noexcept_move_only<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::executor> >&)
Unexecuted instantiation: void libtorrent::hostname_visitor::operator()<libtorrent::socks5_stream>(libtorrent::socks5_stream&)
Unexecuted instantiation: void libtorrent::hostname_visitor::operator()<libtorrent::http_stream>(libtorrent::http_stream&)
Unexecuted instantiation: void libtorrent::hostname_visitor::operator()<libtorrent::aux::utp_stream>(libtorrent::aux::utp_stream&)
Unexecuted instantiation: void libtorrent::hostname_visitor::operator()<libtorrent::i2p_stream>(libtorrent::i2p_stream&)
7428
    template <typename T>
7429
0
    void operator()(ssl_stream<T>& s) { s.set_host_name(hostname_); }
Unexecuted instantiation: void libtorrent::hostname_visitor::operator()<libtorrent::aux::noexcept_move_only<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::executor> > >(libtorrent::ssl_stream<libtorrent::aux::noexcept_move_only<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::executor> > >&)
Unexecuted instantiation: void libtorrent::hostname_visitor::operator()<libtorrent::socks5_stream>(libtorrent::ssl_stream<libtorrent::socks5_stream>&)
Unexecuted instantiation: void libtorrent::hostname_visitor::operator()<libtorrent::http_stream>(libtorrent::ssl_stream<libtorrent::http_stream>&)
Unexecuted instantiation: void libtorrent::hostname_visitor::operator()<libtorrent::aux::utp_stream>(libtorrent::ssl_stream<libtorrent::aux::utp_stream>&)
7430
    std::string const& hostname_;
7431
  };
7432
7433
  struct ssl_handle_visitor
7434
  {
7435
    template <typename T>
7436
    ssl::stream_handle_type operator()(T&)
7437
0
    { return nullptr; }
Unexecuted instantiation: ssl_st* libtorrent::ssl_handle_visitor::operator()<libtorrent::aux::noexcept_move_only<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::executor> > >(libtorrent::aux::noexcept_move_only<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::executor> >&)
Unexecuted instantiation: ssl_st* libtorrent::ssl_handle_visitor::operator()<libtorrent::socks5_stream>(libtorrent::socks5_stream&)
Unexecuted instantiation: ssl_st* libtorrent::ssl_handle_visitor::operator()<libtorrent::http_stream>(libtorrent::http_stream&)
Unexecuted instantiation: ssl_st* libtorrent::ssl_handle_visitor::operator()<libtorrent::aux::utp_stream>(libtorrent::aux::utp_stream&)
Unexecuted instantiation: ssl_st* libtorrent::ssl_handle_visitor::operator()<libtorrent::i2p_stream>(libtorrent::i2p_stream&)
7438
7439
    template <typename T>
7440
    ssl::stream_handle_type operator()(ssl_stream<T>& s)
7441
0
    { return s.handle(); }
Unexecuted instantiation: ssl_st* libtorrent::ssl_handle_visitor::operator()<libtorrent::aux::noexcept_move_only<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::executor> > >(libtorrent::ssl_stream<libtorrent::aux::noexcept_move_only<boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::executor> > >&)
Unexecuted instantiation: ssl_st* libtorrent::ssl_handle_visitor::operator()<libtorrent::socks5_stream>(libtorrent::ssl_stream<libtorrent::socks5_stream>&)
Unexecuted instantiation: ssl_st* libtorrent::ssl_handle_visitor::operator()<libtorrent::http_stream>(libtorrent::ssl_stream<libtorrent::http_stream>&)
Unexecuted instantiation: ssl_st* libtorrent::ssl_handle_visitor::operator()<libtorrent::aux::utp_stream>(libtorrent::ssl_stream<libtorrent::aux::utp_stream>&)
7442
  };
7443
#endif
7444
7445
  bool torrent::connect_to_peer(torrent_peer* peerinfo, bool const ignore_limit)
7446
0
  {
7447
0
    TORRENT_ASSERT(is_single_thread());
7448
0
    INVARIANT_CHECK;
7449
0
    TORRENT_UNUSED(ignore_limit);
7450
7451
0
    TORRENT_ASSERT(peerinfo);
7452
0
    TORRENT_ASSERT(peerinfo->connection == nullptr);
7453
7454
0
    if (m_abort) return false;
7455
7456
0
    peerinfo->last_connected = m_ses.session_time();
7457
0
#if TORRENT_USE_ASSERTS
7458
0
    if (!settings().get_bool(settings_pack::allow_multiple_connections_per_ip))
7459
0
    {
7460
      // this asserts that we don't have duplicates in the peer_list's peer list
7461
0
      peer_iterator i_ = std::find_if(m_connections.begin(), m_connections.end()
7462
0
        , [peerinfo] (peer_connection const* p)
7463
0
        { return !p->is_disconnecting() && p->remote() == peerinfo->ip(); });
7464
0
#if TORRENT_USE_I2P
7465
0
      TORRENT_ASSERT(i_ == m_connections.end()
7466
0
        || (*i_)->type() != connection_type::bittorrent
7467
0
        || peerinfo->is_i2p_addr);
7468
#else
7469
      TORRENT_ASSERT(i_ == m_connections.end()
7470
        || (*i_)->type() != connection_type::bittorrent);
7471
#endif
7472
0
    }
7473
0
#endif // TORRENT_USE_ASSERTS
7474
7475
0
    TORRENT_ASSERT(want_peers() || ignore_limit);
7476
0
    TORRENT_ASSERT(m_ses.num_connections()
7477
0
      < settings().get_int(settings_pack::connections_limit) || ignore_limit);
7478
7479
0
    tcp::endpoint a(peerinfo->ip());
7480
0
    TORRENT_ASSERT(!m_apply_ip_filter
7481
0
      || !m_ip_filter
7482
0
      || (m_ip_filter->access(peerinfo->address()) & ip_filter::blocked) == 0);
7483
7484
    // this is where we determine if we open a regular TCP connection
7485
    // or a uTP connection. If the utp_socket_manager pointer is not passed in
7486
    // we'll instantiate a TCP connection
7487
0
    aux::utp_socket_manager* sm = nullptr;
7488
7489
0
#if TORRENT_USE_I2P
7490
0
    if (peerinfo->is_i2p_addr)
7491
0
    {
7492
0
      if (settings().get_str(settings_pack::i2p_hostname).empty())
7493
0
      {
7494
        // we have an i2p torrent, but we're not connected to an i2p
7495
        // SAM proxy.
7496
0
        if (alerts().should_post<i2p_alert>())
7497
0
          alerts().emplace_alert<i2p_alert>(errors::no_i2p_router);
7498
0
        return false;
7499
0
      }
7500
0
    }
7501
0
    else
7502
0
#endif
7503
0
    {
7504
0
      if (settings().get_bool(settings_pack::enable_outgoing_utp)
7505
0
        && (!settings().get_bool(settings_pack::enable_outgoing_tcp)
7506
0
          || peerinfo->supports_utp
7507
0
          || peerinfo->confirmed_supports_utp))
7508
0
      {
7509
0
        sm = m_ses.utp_socket_manager();
7510
0
      }
7511
7512
      // don't make a TCP connection if it's disabled
7513
0
      if (sm == nullptr && !settings().get_bool(settings_pack::enable_outgoing_tcp))
7514
0
      {
7515
#ifndef TORRENT_DISABLE_LOGGING
7516
        if (should_log())
7517
        {
7518
          debug_log("discarding peer \"%s\": TCP connections disabled "
7519
            "[ supports-utp: %d ]", peerinfo->to_string().c_str()
7520
            , peerinfo->supports_utp);
7521
        }
7522
#endif
7523
0
        return false;
7524
0
      }
7525
0
    }
7526
7527
    // TODO: come up with a better way of doing this, instead of an
7528
    // immediately invoked lambda expression.
7529
0
    aux::socket_type s = [&] {
7530
7531
0
#if TORRENT_USE_I2P
7532
0
    if (peerinfo->is_i2p_addr)
7533
0
    {
7534
      // It's not entirely obvious why this peer connection is not marked as
7535
      // one. The main feature of a peer connection is that whether or not we
7536
      // proxy it is configurable. When we use i2p, we want to always prox
7537
      // everything via i2p.
7538
7539
0
      aux::proxy_settings proxy;
7540
0
      proxy.hostname = settings().get_str(settings_pack::i2p_hostname);
7541
0
      proxy.port = std::uint16_t(settings().get_int(settings_pack::i2p_port));
7542
0
      proxy.type = settings_pack::i2p_proxy;
7543
7544
0
      aux::socket_type ret = instantiate_connection(m_ses.get_context()
7545
0
        , proxy, nullptr, nullptr, false, false);
7546
0
      i2p_stream& str = boost::get<i2p_stream>(ret);
7547
0
      str.set_local_i2p_endpoint(m_ses.local_i2p_endpoint());
7548
0
      str.set_destination(static_cast<i2p_peer*>(peerinfo)->dest());
7549
0
      str.set_command(i2p_stream::cmd_connect);
7550
0
      str.set_session_id(m_ses.i2p_session());
7551
0
      return ret;
7552
0
    }
7553
0
    else
7554
0
#endif
7555
0
    {
7556
0
      void* userdata = nullptr;
7557
0
#ifdef TORRENT_SSL_PEERS
7558
0
      if (is_ssl_torrent())
7559
0
      {
7560
0
        userdata = m_ssl_ctx.get();
7561
        // if we're creating a uTP socket, since this is SSL now, make sure
7562
        // to pass in the corresponding utp socket manager
7563
0
        if (sm) sm = m_ses.ssl_utp_socket_manager();
7564
0
      }
7565
0
#endif
7566
7567
0
      aux::socket_type ret = instantiate_connection(m_ses.get_context()
7568
0
        , m_ses.proxy(), userdata, sm, true, false);
7569
7570
0
#if defined TORRENT_SSL_PEERS
7571
0
      if (is_ssl_torrent())
7572
0
      {
7573
        // for ssl sockets, set the hostname
7574
0
        std::string const host_name = aux::to_hex(
7575
0
          m_torrent_file->info_hashes().get(peerinfo->protocol()));
7576
7577
0
        boost::apply_visitor(hostname_visitor{host_name}, ret);
7578
0
      }
7579
0
#endif
7580
0
      return ret;
7581
0
    }
7582
0
    }();
7583
7584
0
    peer_id const our_pid = aux::generate_peer_id(settings());
7585
0
    peer_connection_args pack{
7586
0
      &m_ses
7587
0
      , &settings()
7588
0
      , &m_ses.stats_counters()
7589
0
      , &m_ses.disk_thread()
7590
0
      , &m_ses.get_context()
7591
0
      , shared_from_this()
7592
0
      , std::move(s)
7593
0
      , a
7594
0
      , peerinfo
7595
0
      , our_pid
7596
0
    };
7597
7598
0
    auto c = std::make_shared<bt_peer_connection>(pack);
7599
7600
0
#if TORRENT_USE_ASSERTS
7601
0
    c->m_in_constructor = false;
7602
0
#endif
7603
7604
0
    c->add_stat(std::int64_t(peerinfo->prev_amount_download) << 10
7605
0
      , std::int64_t(peerinfo->prev_amount_upload) << 10);
7606
0
    peerinfo->prev_amount_download = 0;
7607
0
    peerinfo->prev_amount_upload = 0;
7608
7609
0
#ifndef TORRENT_DISABLE_EXTENSIONS
7610
0
    for (auto const& ext : m_extensions)
7611
0
    {
7612
0
      std::shared_ptr<peer_plugin> pp(ext->new_connection(
7613
0
          peer_connection_handle(c->self())));
7614
0
      if (pp) c->add_extension(pp);
7615
0
    }
7616
0
#endif
7617
7618
    // add the newly connected peer to this torrent's peer list
7619
0
    TORRENT_ASSERT(m_iterating_connections == 0);
7620
7621
    // we don't want to have to allocate memory to disconnect this peer, so
7622
    // make sure there's enough memory allocated in the deferred_disconnect
7623
    // list up-front
7624
0
    m_peers_to_disconnect.reserve(m_connections.size() + 1);
7625
7626
0
    sorted_insert(m_connections, c.get());
7627
0
    try
7628
0
    {
7629
0
      m_outgoing_pids.insert(our_pid);
7630
0
      m_ses.insert_peer(c);
7631
0
      need_peer_list();
7632
0
      m_peer_list->set_connection(peerinfo, c.get());
7633
0
      if (peerinfo->seed)
7634
0
      {
7635
0
        TORRENT_ASSERT(m_num_seeds < 0xffff);
7636
0
        ++m_num_seeds;
7637
0
      }
7638
0
      update_want_peers();
7639
0
      update_want_tick();
7640
0
      c->start();
7641
7642
0
      if (c->is_disconnecting()) return false;
7643
0
    }
7644
0
    catch (std::exception const&)
7645
0
    {
7646
0
      TORRENT_ASSERT(m_iterating_connections == 0);
7647
0
      c->disconnect(errors::no_error, operation_t::bittorrent, peer_connection_interface::failure);
7648
0
      return false;
7649
0
    }
7650
7651
0
#ifndef TORRENT_DISABLE_SHARE_MODE
7652
0
    if (m_share_mode)
7653
0
      recalc_share_mode();
7654
0
#endif
7655
7656
0
    return peerinfo->connection != nullptr;
7657
0
  }
7658
7659
  error_code torrent::initialize_merkle_trees()
7660
1.88k
  {
7661
1.88k
    if (!info_hash().has_v2()) return {};
7662
7663
1.88k
    bool valid = m_torrent_file->v2_piece_hashes_verified();
7664
7665
1.88k
    file_storage const& fs = m_torrent_file->orig_files();
7666
1.88k
    m_merkle_trees.reserve(fs.num_files());
7667
1.88k
    for (file_index_t i : fs.file_range())
7668
1.88k
    {
7669
1.88k
      if (fs.pad_file_at(i) || fs.file_size(i) == 0)
7670
0
      {
7671
0
        m_merkle_trees.emplace_back();
7672
0
        continue;
7673
0
      }
7674
1.88k
      m_merkle_trees.emplace_back(fs.file_num_blocks(i)
7675
1.88k
        , fs.blocks_per_piece(), fs.root_ptr(i));
7676
1.88k
      auto const piece_layer = m_torrent_file->piece_layer(i);
7677
1.88k
      if (piece_layer.empty())
7678
0
      {
7679
0
        valid = false;
7680
0
        continue;
7681
0
      }
7682
7683
1.88k
      if (!m_merkle_trees[i].load_piece_layer(piece_layer))
7684
0
      {
7685
0
        m_merkle_trees[i] = aux::merkle_tree();
7686
0
        m_v2_piece_layers_validated = false;
7687
0
        return errors::torrent_invalid_piece_layer;
7688
0
      }
7689
1.88k
    }
7690
7691
1.88k
    m_v2_piece_layers_validated = valid;
7692
7693
1.88k
    m_torrent_file->free_piece_layers();
7694
1.88k
    return {};
7695
1.88k
  }
7696
7697
  bool torrent::set_metadata(span<char const> metadata_buf)
7698
0
  {
7699
0
    TORRENT_ASSERT(is_single_thread());
7700
0
    INVARIANT_CHECK;
7701
7702
0
    if (m_torrent_file->is_valid()) return false;
7703
7704
0
    if (m_torrent_file->info_hashes().has_v1())
7705
0
    {
7706
0
      sha1_hash const info_hash = hasher(metadata_buf).final();
7707
0
      if (info_hash != m_torrent_file->info_hashes().v1)
7708
0
      {
7709
        // check if the v1 hash is a truncated v2 hash
7710
0
        sha256_hash const info_hash2 = hasher256(metadata_buf).final();
7711
0
        if (sha1_hash(info_hash2.data()) != m_torrent_file->info_hashes().v1)
7712
0
        {
7713
0
          if (alerts().should_post<metadata_failed_alert>())
7714
0
          {
7715
0
            alerts().emplace_alert<metadata_failed_alert>(get_handle()
7716
0
              , errors::mismatching_info_hash);
7717
0
          }
7718
0
          return false;
7719
0
        }
7720
0
      }
7721
0
    }
7722
0
    if (m_torrent_file->info_hashes().has_v2())
7723
0
    {
7724
      // we don't have to worry about computing the v2 hash twice because
7725
      // if the v1 hash was a truncated v2 hash then the torrent_file should
7726
      // not have a v2 hash and we shouldn't get here
7727
0
      sha256_hash const info_hash = hasher256(metadata_buf).final();
7728
0
      if (info_hash != m_torrent_file->info_hashes().v2)
7729
0
      {
7730
0
        if (alerts().should_post<metadata_failed_alert>())
7731
0
        {
7732
0
          alerts().emplace_alert<metadata_failed_alert>(get_handle()
7733
0
            , errors::mismatching_info_hash);
7734
0
        }
7735
0
        return false;
7736
0
      }
7737
0
    }
7738
7739
    // the torrent's info hash might change
7740
    // e.g. it could be a hybrid torrent which we only had one of the hashes for
7741
    // so remove the existing entry
7742
0
    info_hash_t const old_ih = m_torrent_file->info_hashes();
7743
7744
0
    error_code ec;
7745
0
    int pos = 0;
7746
0
    bdecode_node const metadata = bdecode(metadata_buf, ec, &pos, 200
7747
0
      , settings().get_int(settings_pack::metadata_token_limit));
7748
7749
0
    auto info = std::make_shared<torrent_info>(*m_torrent_file);
7750
0
    if (ec || !info->parse_info_section(metadata, ec
7751
0
      , settings().get_int(settings_pack::max_piece_count)))
7752
0
    {
7753
0
      update_gauge();
7754
      // this means the metadata is correct, since we
7755
      // verified it against the info-hash, but we
7756
      // failed to parse it. Pause the torrent
7757
0
      if (alerts().should_post<metadata_failed_alert>())
7758
0
      {
7759
0
        alerts().emplace_alert<metadata_failed_alert>(get_handle(), ec);
7760
0
      }
7761
0
      set_error(errors::invalid_swarm_metadata, torrent_status::error_file_none);
7762
0
      pause();
7763
0
      return false;
7764
0
    }
7765
7766
    // we might already have this torrent in the session.
7767
0
    bool failed = false;
7768
0
    info->info_hashes().for_each([&](sha1_hash const& ih, protocol_version)
7769
0
    {
7770
0
      if (failed) return;
7771
7772
0
      auto t = m_ses.find_torrent(info_hash_t(ih)).lock();
7773
0
      if (t && t != shared_from_this())
7774
0
      {
7775
0
        TORRENT_ASSERT(!t->valid_metadata());
7776
7777
        // if we get a collision, both torrents fail and have to be
7778
        // removed. This is because updating the info_hash_t for this
7779
        // torrent would conflict with torrent "t". That would violate
7780
        // the invariants:
7781
        //   1. an info-hash can only refer to a single torrent
7782
        //   2. every torrent needs at least one info-hash.
7783
0
        t->set_error(errors::duplicate_torrent, torrent_status::error_file_metadata);
7784
0
        t->pause();
7785
7786
0
        set_error(errors::duplicate_torrent, torrent_status::error_file_metadata);
7787
0
        pause();
7788
0
        failed = true;
7789
7790
0
        if (alerts().should_post<torrent_conflict_alert>())
7791
0
        {
7792
0
          alerts().emplace_alert<torrent_conflict_alert>(get_handle()
7793
0
            , torrent_handle(std::move(t)), std::move(info));
7794
0
        }
7795
0
      }
7796
0
    });
7797
7798
0
    if (failed) return true;
7799
0
    if (m_abort) return true;
7800
7801
0
    m_torrent_file = info;
7802
0
    m_info_hash = m_torrent_file->info_hashes();
7803
7804
0
    m_size_on_disk = aux::size_on_disk(m_torrent_file->files());
7805
7806
0
    m_ses.update_torrent_info_hash(shared_from_this(), old_ih);
7807
7808
0
    ec = initialize_merkle_trees();
7809
0
    if (ec)
7810
0
    {
7811
0
      set_error(ec, torrent_status::error_file_metadata);
7812
0
      pause();
7813
0
      return false;
7814
0
    }
7815
7816
0
    update_gauge();
7817
0
    update_want_tick();
7818
7819
0
    if (m_ses.alerts().should_post<metadata_received_alert>())
7820
0
    {
7821
0
      m_ses.alerts().emplace_alert<metadata_received_alert>(
7822
0
        get_handle());
7823
0
    }
7824
7825
    // we have to initialize the torrent before we start
7826
    // disconnecting redundant peers, otherwise we'll think
7827
    // we're a seed, because we have all 0 pieces
7828
0
    init();
7829
7830
0
    inc_stats_counter(counters::num_total_pieces_added
7831
0
      , m_torrent_file->num_pieces());
7832
7833
    // disconnect redundant peers
7834
0
    for (auto p : m_connections)
7835
0
      p->disconnect_if_redundant();
7836
7837
0
    set_need_save_resume(torrent_handle::if_metadata_changed);
7838
7839
0
    return true;
7840
0
  }
7841
7842
  namespace {
7843
7844
  bool connecting_time_compare(peer_connection const* lhs, peer_connection const* rhs)
7845
0
  {
7846
0
    bool const lhs_connecting = lhs->is_connecting() && !lhs->is_disconnecting();
7847
0
    bool const rhs_connecting = rhs->is_connecting() && !rhs->is_disconnecting();
7848
0
    if (lhs_connecting != rhs_connecting) return (int(lhs_connecting) < int(rhs_connecting));
7849
7850
    // a lower value of connected_time means it's been waiting
7851
    // longer. This is a less-than comparison, so if lhs has
7852
    // waited longer than rhs, we should return false.
7853
0
    return lhs->connected_time() > rhs->connected_time();
7854
0
  }
7855
7856
  } // anonymous namespace
7857
7858
282
  bool torrent::attach_peer(peer_connection* p) try
7859
282
  {
7860
//    INVARIANT_CHECK;
7861
7862
282
#ifdef TORRENT_SSL_PEERS
7863
282
    if (is_ssl_torrent())
7864
0
    {
7865
      // if this is an SSL torrent, don't allow non SSL peers on it
7866
0
      aux::socket_type& s = p->get_socket();
7867
7868
0
      auto stream_handle = boost::apply_visitor(ssl_handle_visitor{}, s);
7869
7870
0
      if (!stream_handle)
7871
0
      {
7872
        // don't allow non SSL peers on SSL torrents
7873
0
        p->disconnect(errors::requires_ssl_connection, operation_t::bittorrent);
7874
0
        return false;
7875
0
      }
7876
7877
0
      if (!m_ssl_ctx)
7878
0
      {
7879
        // we don't have a valid cert, don't accept any connection!
7880
0
        p->disconnect(errors::invalid_ssl_cert, operation_t::ssl_handshake);
7881
0
        return false;
7882
0
      }
7883
7884
0
      if (!ssl::has_context(stream_handle, ssl::get_handle(*m_ssl_ctx)))
7885
0
      {
7886
        // if the SSL context associated with this connection is
7887
        // not the one belonging to this torrent, the SSL handshake
7888
        // connected to one torrent, and the BitTorrent protocol
7889
        // to a different one. This is probably an attempt to circumvent
7890
        // access control. Don't allow it.
7891
0
        p->disconnect(errors::invalid_ssl_cert, operation_t::bittorrent);
7892
0
        return false;
7893
0
      }
7894
0
    }
7895
#else // TORRENT_SSL_PEERS
7896
    if (is_ssl_torrent())
7897
    {
7898
      // Don't accidentally allow seeding of SSL torrents, just
7899
      // because libtorrent wasn't built with SSL support
7900
      p->disconnect(errors::requires_ssl_connection, operation_t::ssl_handshake);
7901
      return false;
7902
    }
7903
#endif // TORRENT_SSL_PEERS
7904
7905
282
    TORRENT_ASSERT(p != nullptr);
7906
282
    TORRENT_ASSERT(!p->is_outgoing());
7907
7908
282
    m_has_incoming = true;
7909
7910
282
    if (m_apply_ip_filter
7911
282
      && m_ip_filter
7912
282
      && m_ip_filter->access(p->remote().address()) & ip_filter::blocked)
7913
0
    {
7914
0
      if (m_ses.alerts().should_post<peer_blocked_alert>())
7915
0
        m_ses.alerts().emplace_alert<peer_blocked_alert>(get_handle()
7916
0
          , p->remote(), peer_blocked_alert::ip_filter);
7917
0
      p->disconnect(errors::banned_by_ip_filter, operation_t::bittorrent);
7918
0
      return false;
7919
0
    }
7920
7921
282
    if (!is_downloading_state(m_state) && valid_metadata())
7922
0
    {
7923
0
      p->disconnect(errors::torrent_not_ready, operation_t::bittorrent);
7924
0
      return false;
7925
0
    }
7926
7927
282
    if (!m_ses.has_connection(p))
7928
0
    {
7929
0
      p->disconnect(errors::peer_not_constructed, operation_t::bittorrent);
7930
0
      return false;
7931
0
    }
7932
7933
282
    if (m_ses.is_aborted())
7934
0
    {
7935
0
      p->disconnect(errors::session_closing, operation_t::bittorrent);
7936
0
      return false;
7937
0
    }
7938
7939
282
    int connection_limit_factor = 0;
7940
846
    for (int i = 0; i < p->num_classes(); ++i)
7941
564
    {
7942
564
      peer_class_t pc = p->class_at(i);
7943
564
      if (m_ses.peer_classes().at(pc) == nullptr) continue;
7944
564
      int f = m_ses.peer_classes().at(pc)->connection_limit_factor;
7945
564
      if (connection_limit_factor < f) connection_limit_factor = f;
7946
564
    }
7947
282
    if (connection_limit_factor == 0) connection_limit_factor = 100;
7948
7949
282
    std::int64_t const limit = std::int64_t(m_max_connections) * 100 / connection_limit_factor;
7950
7951
282
    bool maybe_replace_peer = false;
7952
7953
282
    if (m_connections.end_index() >= limit)
7954
0
    {
7955
      // if more than 10% of the connections are outgoing
7956
      // connection attempts that haven't completed yet,
7957
      // disconnect one of them and let this incoming
7958
      // connection through.
7959
0
      if (m_num_connecting > m_max_connections / 10)
7960
0
      {
7961
        // find one of the connecting peers and disconnect it
7962
        // find any peer that's connecting (i.e. a half-open TCP connection)
7963
        // that's also not disconnecting
7964
        // disconnect the peer that's been waiting to establish a connection
7965
        // the longest
7966
0
        auto i = std::max_element(begin(), end(), &connecting_time_compare);
7967
7968
0
        if (i == end() || !(*i)->is_connecting() || (*i)->is_disconnecting())
7969
0
        {
7970
          // this seems odd, but we might as well handle it
7971
0
          p->disconnect(errors::too_many_connections, operation_t::bittorrent);
7972
0
          return false;
7973
0
        }
7974
0
        (*i)->disconnect(errors::too_many_connections, operation_t::bittorrent);
7975
7976
        // if this peer was let in via connections slack,
7977
        // it has done its duty of causing the disconnection
7978
        // of another peer
7979
0
        p->peer_disconnected_other();
7980
0
      }
7981
0
      else
7982
0
      {
7983
0
        maybe_replace_peer = true;
7984
0
      }
7985
0
    }
7986
7987
282
#ifndef TORRENT_DISABLE_EXTENSIONS
7988
282
    for (auto& ext : m_extensions)
7989
846
    {
7990
846
      std::shared_ptr<peer_plugin> pp(ext->new_connection(
7991
846
          peer_connection_handle(p->self())));
7992
846
      if (pp) p->add_extension(pp);
7993
846
    }
7994
282
#endif
7995
282
    torrent_state st = get_peer_list_state();
7996
282
    need_peer_list();
7997
282
    if (!m_peer_list->new_connection(*p, m_ses.session_time(), &st))
7998
0
    {
7999
0
      peers_erased(st.erased);
8000
#ifndef TORRENT_DISABLE_LOGGING
8001
      if (should_log())
8002
      {
8003
        debug_log("CLOSING CONNECTION \"%s\" peer list full "
8004
          "connections: %d limit: %d"
8005
          , print_endpoint(p->remote()).c_str()
8006
          , num_peers()
8007
          , m_max_connections);
8008
      }
8009
#endif
8010
0
      p->disconnect(errors::too_many_connections, operation_t::bittorrent);
8011
0
      return false;
8012
0
    }
8013
282
    peers_erased(st.erased);
8014
8015
282
    m_peers_to_disconnect.reserve(m_connections.size() + 1);
8016
282
    m_connections.reserve(m_connections.size() + 1);
8017
8018
282
#if TORRENT_USE_ASSERTS
8019
282
    error_code ec;
8020
282
    TORRENT_ASSERT(p->remote() == p->get_socket().remote_endpoint(ec) || ec);
8021
282
#endif
8022
8023
282
    TORRENT_ASSERT(p->peer_info_struct() != nullptr);
8024
8025
    // we need to do this after we've added the peer to the peer_list
8026
    // since that's when the peer is assigned its peer_info object,
8027
    // which holds the rank
8028
282
    if (maybe_replace_peer)
8029
0
    {
8030
      // now, find the lowest rank peer and disconnect that
8031
      // if it's lower rank than the incoming connection
8032
0
      peer_connection* peer = find_lowest_ranking_peer();
8033
8034
      // TODO: 2 if peer is a really good peer, maybe we shouldn't disconnect it
8035
      // perhaps this logic should be disabled if we have too many idle peers
8036
      // (with some definition of idle)
8037
0
      if (peer != nullptr && peer->peer_rank() < p->peer_rank())
8038
0
      {
8039
#ifndef TORRENT_DISABLE_LOGGING
8040
        if (should_log())
8041
        {
8042
          debug_log("CLOSING CONNECTION \"%s\" peer list full (low peer rank) "
8043
            "connections: %d limit: %d"
8044
            , print_endpoint(peer->remote()).c_str()
8045
            , num_peers()
8046
            , m_max_connections);
8047
        }
8048
#endif
8049
0
        peer->disconnect(errors::too_many_connections, operation_t::bittorrent);
8050
0
        p->peer_disconnected_other();
8051
0
      }
8052
0
      else
8053
0
      {
8054
#ifndef TORRENT_DISABLE_LOGGING
8055
        if (should_log())
8056
        {
8057
          debug_log("CLOSING CONNECTION \"%s\" peer list full (low peer rank) "
8058
            "connections: %d limit: %d"
8059
            , print_endpoint(p->remote()).c_str()
8060
            , num_peers()
8061
            , m_max_connections);
8062
        }
8063
#endif
8064
0
        p->disconnect(errors::too_many_connections, operation_t::bittorrent);
8065
        // we have to do this here because from the peer's point of view
8066
        // it wasn't really attached to the torrent, but we do need
8067
        // to let peer_list know we're removing it
8068
0
        remove_peer(p->self());
8069
0
        return false;
8070
0
      }
8071
0
    }
8072
8073
#if TORRENT_USE_INVARIANT_CHECKS
8074
    if (m_peer_list) m_peer_list->check_invariant();
8075
#endif
8076
8077
282
#ifndef TORRENT_DISABLE_SHARE_MODE
8078
282
    if (m_share_mode)
8079
0
      recalc_share_mode();
8080
282
#endif
8081
8082
    // once we add the peer to our m_connections list, we can't throw an
8083
    // exception. That will end up violating an invariant between the session,
8084
    // torrent and peers
8085
282
    TORRENT_ASSERT(sorted_find(m_connections, p) == m_connections.end());
8086
282
    TORRENT_ASSERT(m_iterating_connections == 0);
8087
282
    sorted_insert(m_connections, p);
8088
282
    update_want_peers();
8089
282
    update_want_tick();
8090
8091
282
    if (p->peer_info_struct() && p->peer_info_struct()->seed)
8092
35
    {
8093
35
      TORRENT_ASSERT(m_num_seeds < 0xffff);
8094
35
      ++m_num_seeds;
8095
35
    }
8096
8097
#ifndef TORRENT_DISABLE_LOGGING
8098
    if (should_log()) try
8099
    {
8100
      debug_log("ATTACHED CONNECTION \"%s\" connections: %d limit: %d num-peers: %d"
8101
        , print_endpoint(p->remote()).c_str(), num_peers()
8102
        , m_max_connections
8103
        , num_peers());
8104
    }
8105
    catch (std::exception const&) {}
8106
#endif
8107
8108
282
    return true;
8109
282
  }
8110
282
  catch (...)
8111
282
  {
8112
0
    p->disconnect(errors::torrent_not_ready, operation_t::bittorrent);
8113
    // from the peer's point of view it was never really added to the torrent.
8114
    // So we need to clean it up here before propagating the error
8115
0
    remove_peer(p->self());
8116
0
    return false;
8117
0
  }
8118
8119
  bool torrent::want_tick() const
8120
15.7k
  {
8121
15.7k
    if (m_abort) return false;
8122
8123
10.1k
    if (!m_connections.empty()) return true;
8124
8125
    // we might want to connect web seeds
8126
9.53k
    if (!is_finished() && !m_web_seeds.empty() && m_files_checked)
8127
0
      return true;
8128
8129
9.53k
    if (m_stat.low_pass_upload_rate() > 0 || m_stat.low_pass_download_rate() > 0)
8130
0
      return true;
8131
8132
    // if we don't get ticks we won't become inactive
8133
9.53k
    if (!m_paused && !m_inactive) return true;
8134
8135
3.79k
    return false;
8136
9.53k
  }
8137
8138
  void torrent::update_want_tick()
8139
15.7k
  {
8140
15.7k
    update_list(aux::session_interface::torrent_want_tick, want_tick());
8141
15.7k
  }
8142
8143
  // this function adjusts which lists this torrent is part of (checking,
8144
  // seeding or downloading)
8145
  void torrent::update_state_list()
8146
7.68k
  {
8147
7.68k
    bool is_checking = false;
8148
7.68k
    bool is_downloading = false;
8149
7.68k
    bool is_seeding = false;
8150
8151
7.68k
    if (is_auto_managed() && !has_error())
8152
1.93k
    {
8153
1.93k
      if (m_state == torrent_status::checking_files)
8154
55
      {
8155
55
        is_checking = true;
8156
55
      }
8157
1.88k
      else if (m_state == torrent_status::downloading_metadata
8158
1.88k
        || m_state == torrent_status::downloading
8159
1.88k
        || m_state == torrent_status::finished
8160
1.88k
        || m_state == torrent_status::seeding)
8161
413
      {
8162
        // torrents that are started (not paused) and
8163
        // inactive are not part of any list. They will not be touched because
8164
        // they are inactive
8165
413
        if (is_finished())
8166
270
          is_seeding = true;
8167
143
        else
8168
143
          is_downloading = true;
8169
413
      }
8170
1.93k
    }
8171
8172
7.68k
    update_list(aux::session_interface::torrent_downloading_auto_managed
8173
7.68k
      , is_downloading);
8174
7.68k
    update_list(aux::session_interface::torrent_seeding_auto_managed
8175
7.68k
      , is_seeding);
8176
7.68k
    update_list(aux::session_interface::torrent_checking_auto_managed
8177
7.68k
      , is_checking);
8178
7.68k
  }
8179
8180
  // returns true if this torrent is interested in connecting to more peers
8181
  bool torrent::want_peers() const
8182
7.03k
  {
8183
    // if all our connection slots are taken, we can't connect to more
8184
7.03k
    if (num_peers() >= int(m_max_connections)) return false;
8185
8186
    // if we're paused, obviously we're not connecting to peers
8187
6.96k
    if (is_paused() || m_abort || m_graceful_pause_mode) return false;
8188
8189
    // if metadata are valid and we are either checking files or checking resume data without no_verify_files flag,
8190
    // we don't want peers
8191
2.33k
    if ((m_state == torrent_status::checking_files
8192
2.33k
      || (m_state == torrent_status::checking_resume_data
8193
2.33k
        && !(m_add_torrent_params && m_add_torrent_params->flags & torrent_flags::no_verify_files)))
8194
2.33k
      && valid_metadata())
8195
0
      return false;
8196
8197
    // if we don't know of any more potential peers to connect to, there's
8198
    // no point in trying
8199
2.33k
    if (!m_peer_list || m_peer_list->num_connect_candidates() == 0)
8200
2.08k
      return false;
8201
8202
    // if the user disabled outgoing connections for seeding torrents,
8203
    // don't make any
8204
244
    if (!settings().get_bool(settings_pack::seeding_outgoing_connections)
8205
244
      && (m_state == torrent_status::seeding
8206
0
        || m_state == torrent_status::finished))
8207
0
      return false;
8208
8209
244
    if (!settings().get_bool(settings_pack::enable_outgoing_tcp)
8210
244
      && !settings().get_bool(settings_pack::enable_outgoing_utp))
8211
244
      return false;
8212
8213
0
    return true;
8214
244
  }
8215
8216
  bool torrent::want_peers_download() const
8217
13.1k
  {
8218
13.1k
    return (m_state == torrent_status::downloading
8219
13.1k
      || m_state == torrent_status::downloading_metadata)
8220
13.1k
      && want_peers();
8221
13.1k
  }
8222
8223
  bool torrent::want_peers_finished() const
8224
13.1k
  {
8225
13.1k
    return (m_state == torrent_status::finished
8226
13.1k
      || m_state == torrent_status::seeding)
8227
13.1k
      && want_peers();
8228
13.1k
  }
8229
8230
  void torrent::update_want_peers()
8231
13.1k
  {
8232
13.1k
    update_list(aux::session_interface::torrent_want_peers_download, want_peers_download());
8233
13.1k
    update_list(aux::session_interface::torrent_want_peers_finished, want_peers_finished());
8234
13.1k
  }
8235
8236
  void torrent::update_want_scrape()
8237
4.21k
  {
8238
4.21k
    update_list(aux::session_interface::torrent_want_scrape
8239
4.21k
      , m_paused && m_auto_managed && !m_abort);
8240
4.21k
  }
8241
8242
  namespace {
8243
8244
#ifndef TORRENT_DISABLE_LOGGING
8245
  char const* list_name(torrent_list_index_t const idx)
8246
  {
8247
#define TORRENT_LIST_NAME(n) case static_cast<int>(aux::session_interface:: n): return #n
8248
    switch (static_cast<int>(idx))
8249
    {
8250
      TORRENT_LIST_NAME(torrent_state_updates);
8251
      TORRENT_LIST_NAME(torrent_want_tick);
8252
      TORRENT_LIST_NAME(torrent_want_peers_download);
8253
      TORRENT_LIST_NAME(torrent_want_peers_finished);
8254
      TORRENT_LIST_NAME(torrent_want_scrape);
8255
      TORRENT_LIST_NAME(torrent_downloading_auto_managed);
8256
      TORRENT_LIST_NAME(torrent_seeding_auto_managed);
8257
      TORRENT_LIST_NAME(torrent_checking_auto_managed);
8258
      default: TORRENT_ASSERT_FAIL_VAL(idx);
8259
    }
8260
#undef TORRENT_LIST_NAME
8261
    return "";
8262
  }
8263
#endif // TORRENT_DISABLE_LOGGING
8264
8265
  } // anonymous namespace
8266
8267
  void torrent::update_list(torrent_list_index_t const list, bool in)
8268
69.3k
  {
8269
69.3k
    link& l = m_links[list];
8270
69.3k
    aux::vector<torrent*>& v = m_ses.torrent_list(list);
8271
8272
69.3k
    if (in)
8273
7.02k
    {
8274
7.02k
      if (l.in_list()) return;
8275
2.01k
      l.insert(v, this);
8276
2.01k
    }
8277
62.3k
    else
8278
62.3k
    {
8279
62.3k
      if (!l.in_list()) return;
8280
2.01k
      l.unlink(v, list);
8281
2.01k
    }
8282
8283
#ifndef TORRENT_DISABLE_LOGGING
8284
    if (should_log())
8285
      debug_log("*** UPDATE LIST [ %s : %d ]", list_name(list), int(in));
8286
#endif
8287
69.3k
  }
8288
8289
  void torrent::disconnect_all(error_code const& ec, operation_t op)
8290
2.15k
  {
8291
2.15k
    TORRENT_ASSERT(m_iterating_connections == 0);
8292
2.15k
    for (auto const& p : m_connections)
8293
0
    {
8294
0
      TORRENT_INCREMENT(m_iterating_connections);
8295
0
      TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
8296
0
      p->disconnect(ec, op);
8297
0
    }
8298
8299
2.15k
    update_want_peers();
8300
2.15k
    update_want_tick();
8301
2.15k
  }
8302
8303
  namespace {
8304
8305
  // this returns true if lhs is a better disconnect candidate than rhs
8306
  bool compare_disconnect_peer(peer_connection const* lhs, peer_connection const* rhs)
8307
0
  {
8308
    // prefer to disconnect peers that are already disconnecting
8309
0
    if (lhs->is_disconnecting() != rhs->is_disconnecting())
8310
0
      return lhs->is_disconnecting();
8311
8312
    // prefer to disconnect peers we're not interested in
8313
0
    if (lhs->is_interesting() != rhs->is_interesting())
8314
0
      return rhs->is_interesting();
8315
8316
    // prefer to disconnect peers that are not seeds
8317
0
    if (lhs->is_seed() != rhs->is_seed())
8318
0
      return rhs->is_seed();
8319
8320
    // prefer to disconnect peers that are on parole
8321
0
    if (lhs->on_parole() != rhs->on_parole())
8322
0
      return lhs->on_parole();
8323
8324
    // prefer to disconnect peers that send data at a lower rate
8325
0
    std::int64_t lhs_transferred = lhs->statistics().total_payload_download();
8326
0
    std::int64_t rhs_transferred = rhs->statistics().total_payload_download();
8327
8328
0
    time_point const now = aux::time_now();
8329
0
    std::int64_t const lhs_time_connected = total_seconds(now - lhs->connected_time());
8330
0
    std::int64_t const rhs_time_connected = total_seconds(now - rhs->connected_time());
8331
8332
0
    lhs_transferred /= lhs_time_connected + 1;
8333
0
    rhs_transferred /= (rhs_time_connected + 1);
8334
0
    if (lhs_transferred != rhs_transferred)
8335
0
      return lhs_transferred < rhs_transferred;
8336
8337
    // prefer to disconnect peers that chokes us
8338
0
    if (lhs->is_choked() != rhs->is_choked())
8339
0
      return lhs->is_choked();
8340
8341
0
    return lhs->last_received() < rhs->last_received();
8342
0
  }
8343
8344
  } // anonymous namespace
8345
8346
  int torrent::disconnect_peers(int const num, error_code const& ec)
8347
0
  {
8348
0
    INVARIANT_CHECK;
8349
8350
0
#if TORRENT_USE_ASSERTS
8351
    // make sure we don't have any dangling pointers
8352
0
    for (auto p : m_connections)
8353
0
    {
8354
0
      TORRENT_INCREMENT(m_iterating_connections);
8355
0
      TORRENT_ASSERT(m_ses.has_peer(p));
8356
0
    }
8357
0
#endif
8358
0
    aux::vector<peer_connection*> to_disconnect;
8359
0
    to_disconnect.resize(num);
8360
0
    auto end = std::partial_sort_copy(m_connections.begin(), m_connections.end()
8361
0
      , to_disconnect.begin(), to_disconnect.end(), compare_disconnect_peer);
8362
0
    for (auto p : aux::range(to_disconnect.begin(), end))
8363
0
    {
8364
0
      TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
8365
0
      p->disconnect(ec, operation_t::bittorrent);
8366
0
    }
8367
0
    return static_cast<int>(end - to_disconnect.begin());
8368
0
  }
8369
8370
  // called when torrent is finished (all interesting
8371
  // pieces have been downloaded)
8372
  void torrent::finished()
8373
553
  {
8374
553
    update_want_tick();
8375
553
    update_state_list();
8376
8377
553
    INVARIANT_CHECK;
8378
8379
553
    TORRENT_ASSERT(is_finished());
8380
8381
553
    set_state(torrent_status::finished);
8382
553
    set_queue_position(no_pos);
8383
8384
553
    m_became_finished = aux::time_now32();
8385
8386
    // we have to call completed() before we start
8387
    // disconnecting peers, since there's an assert
8388
    // to make sure we're cleared the piece picker
8389
553
    if (is_seed()) completed();
8390
8391
553
    send_upload_only();
8392
553
    state_updated();
8393
8394
553
    if (m_completed_time == 0)
8395
553
      m_completed_time = time(nullptr);
8396
8397
    // disconnect all seeds
8398
553
    if (settings().get_bool(settings_pack::close_redundant_connections))
8399
553
    {
8400
      // TODO: 1 should disconnect all peers that have the pieces we have
8401
      // not just seeds. It would be pretty expensive to check all pieces
8402
      // for all peers though
8403
553
      std::vector<peer_connection*> seeds;
8404
553
      for (auto const p : m_connections)
8405
0
      {
8406
0
        TORRENT_INCREMENT(m_iterating_connections);
8407
0
        TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
8408
0
        if (p->upload_only() && p->can_disconnect(errors::torrent_finished))
8409
0
        {
8410
#ifndef TORRENT_DISABLE_LOGGING
8411
          p->peer_log(peer_log_alert::info, "SEED", "CLOSING CONNECTION");
8412
#endif
8413
0
          seeds.push_back(p);
8414
0
        }
8415
0
      }
8416
553
      for (auto& p : seeds)
8417
0
        p->disconnect(errors::torrent_finished, operation_t::bittorrent
8418
0
          , peer_connection_interface::normal);
8419
553
    }
8420
8421
553
    if (m_abort) return;
8422
8423
553
    update_want_peers();
8424
8425
553
    if (m_storage)
8426
553
    {
8427
      // we need to keep the object alive during this operation
8428
553
      m_ses.disk_thread().async_release_files(m_storage
8429
553
        , std::bind(&torrent::on_cache_flushed, shared_from_this(), false));
8430
553
      m_ses.deferred_submit_jobs();
8431
553
    }
8432
8433
    // this torrent just completed downloads, which means it will fall
8434
    // under a different limit with the auto-manager. Make sure we
8435
    // update auto-manage torrents in that case
8436
553
    if (m_auto_managed)
8437
115
      m_ses.trigger_auto_manage();
8438
553
  }
8439
8440
  // this is called when we were finished, but some files were
8441
  // marked for downloading, and we are no longer finished
8442
  void torrent::resume_download()
8443
0
  {
8444
    // the invariant doesn't hold here, because it expects the torrent
8445
    // to be in downloading state (which it will be set to shortly)
8446
//    INVARIANT_CHECK;
8447
8448
0
    TORRENT_ASSERT(m_state != torrent_status::checking_resume_data
8449
0
      && m_state != torrent_status::checking_files);
8450
8451
    // we're downloading now, which means we're no longer in seed mode
8452
0
    if (m_seed_mode)
8453
0
      leave_seed_mode(seed_mode_t::check_files);
8454
8455
0
    TORRENT_ASSERT(!is_finished());
8456
0
    set_state(torrent_status::downloading);
8457
0
    set_queue_position(last_pos);
8458
8459
0
    m_completed_time = 0;
8460
8461
#ifndef TORRENT_DISABLE_LOGGING
8462
    debug_log("*** RESUME_DOWNLOAD");
8463
#endif
8464
0
    send_upload_only();
8465
0
    update_want_tick();
8466
0
    update_state_list();
8467
0
  }
8468
8469
  void torrent::maybe_done_flushing()
8470
3.14k
  {
8471
3.14k
    if (!has_picker()) return;
8472
8473
2.48k
    if (m_picker->is_seeding())
8474
23
    {
8475
      // no need for the piece picker anymore
8476
      // when we're suggesting read cache pieces, we
8477
      // still need the piece picker, to keep track
8478
      // of availability counts for pieces
8479
23
      if (settings().get_int(settings_pack::suggest_mode)
8480
23
        != settings_pack::suggest_read_cache)
8481
23
      {
8482
23
        m_picker.reset();
8483
23
        m_hash_picker.reset();
8484
23
        m_file_progress.clear();
8485
23
      }
8486
23
      m_have_all = true;
8487
23
    }
8488
2.48k
    update_gauge();
8489
2.48k
  }
8490
8491
  // called when torrent is complete. i.e. all pieces downloaded
8492
  // not necessarily flushed to disk
8493
  void torrent::completed()
8494
183
  {
8495
183
    maybe_done_flushing();
8496
8497
183
    set_state(torrent_status::seeding);
8498
183
    m_became_seed = aux::time_now32();
8499
8500
183
    if (!m_announcing) return;
8501
8502
0
    time_point32 const now = aux::time_now32();
8503
0
    for (auto& t : m_trackers)
8504
0
    {
8505
0
      for (auto& aep : t.endpoints)
8506
0
      {
8507
0
        if (!aep.enabled) continue;
8508
0
        for (auto& a : aep.info_hashes)
8509
0
        {
8510
0
          if (a.complete_sent) continue;
8511
0
          a.next_announce = now;
8512
0
          a.min_announce = now;
8513
0
        }
8514
0
      }
8515
0
    }
8516
0
    announce_with_tracker();
8517
0
  }
8518
8519
  int torrent::deprioritize_tracker(int index)
8520
0
  {
8521
0
    INVARIANT_CHECK;
8522
8523
0
    TORRENT_ASSERT(index >= 0);
8524
0
    TORRENT_ASSERT(index < int(m_trackers.size()));
8525
0
    if (index >= int(m_trackers.size())) return -1;
8526
8527
0
    while (index < int(m_trackers.size()) - 1 && m_trackers[index].tier == m_trackers[index + 1].tier)
8528
0
    {
8529
0
      using std::swap;
8530
0
      swap(m_trackers[index], m_trackers[index + 1]);
8531
0
      if (m_last_working_tracker == index) ++m_last_working_tracker;
8532
0
      else if (m_last_working_tracker == index + 1) --m_last_working_tracker;
8533
0
      ++index;
8534
0
    }
8535
0
    return index;
8536
0
  }
8537
8538
  void torrent::files_checked()
8539
920
  {
8540
920
    TORRENT_ASSERT(is_single_thread());
8541
920
    TORRENT_ASSERT(m_torrent_file->is_valid());
8542
8543
920
    if (m_abort)
8544
0
    {
8545
#ifndef TORRENT_DISABLE_LOGGING
8546
      debug_log("files_checked(), paused");
8547
#endif
8548
0
      return;
8549
0
    }
8550
8551
    // calling pause will also trigger the auto managed
8552
    // recalculation
8553
    // if we just got here by downloading the metadata,
8554
    // just keep going, no need to disconnect all peers just
8555
    // to restart the torrent in a second
8556
920
    if (m_auto_managed)
8557
360
    {
8558
      // if this is an auto managed torrent, force a recalculation
8559
      // of which torrents to have active
8560
360
      m_ses.trigger_auto_manage();
8561
360
    }
8562
8563
920
    if (!is_seed())
8564
737
    {
8565
737
#ifndef TORRENT_DISABLE_SUPERSEEDING
8566
      // turn off super seeding if we're not a seed
8567
737
      if (m_super_seeding)
8568
181
      {
8569
181
        m_super_seeding = false;
8570
181
        set_need_save_resume(torrent_handle::if_state_changed);
8571
181
        state_updated();
8572
181
      }
8573
737
#endif
8574
8575
737
      if (m_state != torrent_status::finished && is_finished())
8576
370
        finished();
8577
737
    }
8578
183
    else
8579
183
    {
8580
      // we just added this torrent as a seed, or force-rechecked it, and we
8581
      // have all of it. Assume that we sent the event=completed when we
8582
      // finished downloading it, and don't send any more.
8583
183
      m_complete_sent = true;
8584
183
      for (auto& t : m_trackers)
8585
0
      {
8586
0
        for (auto& aep : t.endpoints)
8587
0
        {
8588
0
          for (auto& a : aep.info_hashes)
8589
0
            a.complete_sent = true;
8590
0
        }
8591
0
      }
8592
8593
183
      if (m_state != torrent_status::finished
8594
183
        && m_state != torrent_status::seeding)
8595
183
        finished();
8596
183
    }
8597
8598
    // we might be finished already, in which case we should
8599
    // not switch to downloading mode. If all files are
8600
    // filtered, we're finished when we start.
8601
920
    if (m_state != torrent_status::finished
8602
920
      && m_state != torrent_status::seeding
8603
920
      && !m_seed_mode)
8604
367
    {
8605
367
      set_state(torrent_status::downloading);
8606
367
    }
8607
8608
920
    INVARIANT_CHECK;
8609
8610
920
    if (m_ses.alerts().should_post<torrent_checked_alert>())
8611
2
    {
8612
2
      m_ses.alerts().emplace_alert<torrent_checked_alert>(
8613
2
        get_handle());
8614
2
    }
8615
8616
920
#ifndef TORRENT_DISABLE_EXTENSIONS
8617
920
    for (auto& ext : m_extensions)
8618
6
    {
8619
6
      ext->on_files_checked();
8620
6
    }
8621
920
#endif
8622
8623
920
    bool const notify_initialized = !m_connections_initialized;
8624
920
    m_connections_initialized = true;
8625
920
    m_files_checked = true;
8626
8627
920
    update_want_tick();
8628
8629
920
    for (auto pc : m_connections)
8630
0
    {
8631
0
      TORRENT_INCREMENT(m_iterating_connections);
8632
      // all peer connections have to initialize themselves now that the metadata
8633
      // is available
8634
0
      if (notify_initialized)
8635
0
      {
8636
0
        if (pc->is_disconnecting()) continue;
8637
0
        pc->on_metadata_impl();
8638
0
        if (pc->is_disconnecting()) continue;
8639
0
        pc->init();
8640
0
      }
8641
8642
#ifndef TORRENT_DISABLE_LOGGING
8643
      pc->peer_log(peer_log_alert::info, "ON_FILES_CHECKED");
8644
#endif
8645
0
      if (pc->is_interesting() && !pc->has_peer_choked())
8646
0
      {
8647
0
        if (request_a_block(*this, *pc))
8648
0
        {
8649
0
          inc_stats_counter(counters::unchoke_piece_picks);
8650
0
          pc->send_block_requests();
8651
0
        }
8652
0
      }
8653
0
    }
8654
8655
920
    start_announcing();
8656
8657
920
    maybe_connect_web_seeds();
8658
920
  }
8659
8660
  aux::alert_manager& torrent::alerts() const
8661
58.4k
  {
8662
58.4k
    TORRENT_ASSERT(is_single_thread());
8663
58.4k
    return m_ses.alerts();
8664
58.4k
  }
8665
8666
  bool torrent::is_seed() const
8667
29.2k
  {
8668
29.2k
    if (!valid_metadata()) return false;
8669
29.2k
    if (m_seed_mode) return true;
8670
25.2k
    if (m_have_all) return true;
8671
25.0k
    if (m_picker && m_picker->is_seeding()) return true;
8672
24.8k
    return m_state == torrent_status::seeding;
8673
25.0k
  }
8674
8675
  bool torrent::is_finished() const
8676
20.3k
  {
8677
20.3k
    if (is_seed()) return true;
8678
16.9k
    return valid_metadata() && has_picker() && m_picker->is_finished();
8679
20.3k
  }
8680
8681
  bool torrent::is_inactive() const
8682
2
  {
8683
2
    if (!settings().get_bool(settings_pack::dont_count_slow_torrents))
8684
0
      return false;
8685
2
    return m_inactive;
8686
2
  }
8687
8688
  std::string torrent::save_path() const
8689
0
  {
8690
0
    return m_save_path;
8691
0
  }
8692
8693
  void torrent::rename_file(file_index_t const index, std::string name)
8694
0
  {
8695
0
    INVARIANT_CHECK;
8696
8697
0
    file_storage const& fs = m_torrent_file->files();
8698
0
    TORRENT_ASSERT(index >= file_index_t(0));
8699
0
    TORRENT_ASSERT(index < fs.end_file());
8700
0
    TORRENT_UNUSED(fs);
8701
8702
    // storage may be nullptr during shutdown
8703
0
    if (!m_storage)
8704
0
    {
8705
0
      if (alerts().should_post<file_rename_failed_alert>())
8706
0
        alerts().emplace_alert<file_rename_failed_alert>(get_handle()
8707
0
          , index, errors::session_is_closing);
8708
0
      return;
8709
0
    }
8710
8711
0
    m_ses.disk_thread().async_rename_file(m_storage, index, std::move(name)
8712
0
      , std::bind(&torrent::on_file_renamed, shared_from_this(), _1, _2, _3));
8713
0
    m_ses.deferred_submit_jobs();
8714
0
  }
8715
8716
  void torrent::move_storage(std::string const& save_path, move_flags_t const flags)
8717
0
  {
8718
0
    TORRENT_ASSERT(is_single_thread());
8719
0
    INVARIANT_CHECK;
8720
8721
0
    if (m_abort)
8722
0
    {
8723
0
      if (alerts().should_post<storage_moved_failed_alert>())
8724
0
        alerts().emplace_alert<storage_moved_failed_alert>(get_handle()
8725
0
          , boost::asio::error::operation_aborted
8726
0
          , "", operation_t::unknown);
8727
0
      return;
8728
0
    }
8729
8730
    // if we don't have metadata yet, we don't know anything about the file
8731
    // structure and we have to assume we don't have any file.
8732
0
    if (!valid_metadata())
8733
0
    {
8734
0
      if (alerts().should_post<storage_moved_alert>())
8735
0
        alerts().emplace_alert<storage_moved_alert>(get_handle(), save_path, m_save_path);
8736
#if TORRENT_USE_UNC_PATHS
8737
      std::string path = canonicalize_path(save_path);
8738
#else
8739
0
      std::string const& path = save_path;
8740
0
#endif
8741
0
      m_save_path = complete(path);
8742
0
      return;
8743
0
    }
8744
8745
    // storage may be nullptr during shutdown
8746
0
    if (m_storage)
8747
0
    {
8748
#if TORRENT_USE_UNC_PATHS
8749
      std::string path = canonicalize_path(save_path);
8750
#else
8751
0
      std::string path = save_path;
8752
0
#endif
8753
0
      m_ses.disk_thread().async_move_storage(m_storage, std::move(path), flags
8754
0
        , std::bind(&torrent::on_storage_moved, shared_from_this(), _1, _2, _3));
8755
0
      m_moving_storage = true;
8756
0
      m_ses.deferred_submit_jobs();
8757
0
    }
8758
0
    else
8759
0
    {
8760
0
      if (alerts().should_post<storage_moved_alert>())
8761
0
        alerts().emplace_alert<storage_moved_alert>(get_handle(), save_path, m_save_path);
8762
8763
#if TORRENT_USE_UNC_PATHS
8764
      m_save_path = canonicalize_path(save_path);
8765
#else
8766
8767
0
      m_save_path = save_path;
8768
0
#endif
8769
0
      set_need_save_resume(torrent_handle::if_config_changed);
8770
0
    }
8771
0
  }
8772
8773
  void torrent::on_storage_moved(status_t const status, std::string const& path
8774
0
    , storage_error const& error) try
8775
0
  {
8776
0
    TORRENT_ASSERT(is_single_thread());
8777
8778
0
    m_moving_storage = false;
8779
0
    if (status == status_t::no_error
8780
0
      || status == status_t::need_full_check)
8781
0
    {
8782
0
      if (alerts().should_post<storage_moved_alert>())
8783
0
        alerts().emplace_alert<storage_moved_alert>(get_handle(), path, m_save_path);
8784
0
      m_save_path = path;
8785
0
      set_need_save_resume(torrent_handle::if_config_changed);
8786
0
      if (status == status_t::need_full_check)
8787
0
        force_recheck();
8788
0
    }
8789
0
    else
8790
0
    {
8791
0
      if (alerts().should_post<storage_moved_failed_alert>())
8792
0
        alerts().emplace_alert<storage_moved_failed_alert>(get_handle(), error.ec
8793
0
          , resolve_filename(error.file()), error.operation);
8794
0
    }
8795
0
  }
8796
0
  catch (...) { handle_exception(); }
8797
8798
  torrent_handle torrent::get_handle()
8799
32.2k
  {
8800
32.2k
    TORRENT_ASSERT(is_single_thread());
8801
32.2k
    return torrent_handle(shared_from_this());
8802
32.2k
  }
8803
8804
  aux::session_settings const& torrent::settings() const
8805
15.9k
  {
8806
15.9k
    TORRENT_ASSERT(is_single_thread());
8807
15.9k
    return m_ses.settings();
8808
15.9k
  }
8809
8810
#if TORRENT_USE_INVARIANT_CHECKS
8811
  void torrent::check_invariant() const
8812
  {
8813
    TORRENT_ASSERT(m_connections.size() >= m_outgoing_pids.size());
8814
8815
    // the piece picker and the file progress states are supposed to be
8816
    // created in sync
8817
    TORRENT_ASSERT(has_picker() == !m_file_progress.empty());
8818
    TORRENT_ASSERT(current_stats_state() == int(m_current_gauge_state + counters::num_checking_torrents)
8819
      || m_current_gauge_state == no_gauge_state);
8820
8821
    TORRENT_ASSERT(m_sequence_number == no_pos
8822
      || m_ses.verify_queue_position(this, m_sequence_number));
8823
8824
#ifndef TORRENT_DISABLE_STREAMING
8825
    for (auto const& i : m_time_critical_pieces)
8826
    {
8827
      TORRENT_ASSERT(!is_seed());
8828
      TORRENT_ASSERT(!has_picker() || !m_picker->have_piece(i.piece));
8829
    }
8830
#endif
8831
8832
    switch (current_stats_state())
8833
    {
8834
      case counters::num_error_torrents: TORRENT_ASSERT(has_error()); break;
8835
      case counters::num_checking_torrents:
8836
#if TORRENT_ABI_VERSION == 1
8837
        TORRENT_ASSERT(state() == torrent_status::checking_files
8838
          || state() == torrent_status::queued_for_checking);
8839
#else
8840
        TORRENT_ASSERT(state() == torrent_status::checking_files);
8841
#endif
8842
        break;
8843
      case counters::num_seeding_torrents: TORRENT_ASSERT(is_seed()); break;
8844
      case counters::num_upload_only_torrents: TORRENT_ASSERT(is_upload_only()); break;
8845
      case counters::num_stopped_torrents: TORRENT_ASSERT(!is_auto_managed()
8846
        && (m_paused || m_graceful_pause_mode));
8847
        break;
8848
      case counters::num_queued_seeding_torrents:
8849
        TORRENT_ASSERT((m_paused || m_graceful_pause_mode) && is_seed()); break;
8850
    }
8851
8852
    if (m_torrent_file)
8853
    {
8854
      TORRENT_ASSERT(m_info_hash.v1 == m_torrent_file->info_hashes().v1);
8855
      TORRENT_ASSERT(m_info_hash.v2 == m_torrent_file->info_hashes().v2);
8856
    }
8857
8858
    for (torrent_list_index_t i{}; i != m_links.end_index(); ++i)
8859
    {
8860
      if (!m_links[i].in_list()) continue;
8861
      int const index = m_links[i].index;
8862
8863
      TORRENT_ASSERT(index >= 0);
8864
      TORRENT_ASSERT(index < int(m_ses.torrent_list(i).size()));
8865
    }
8866
8867
    TORRENT_ASSERT(want_peers_download() == m_links[aux::session_interface::torrent_want_peers_download].in_list());
8868
    TORRENT_ASSERT(want_peers_finished() == m_links[aux::session_interface::torrent_want_peers_finished].in_list());
8869
    TORRENT_ASSERT(want_tick() == m_links[aux::session_interface::torrent_want_tick].in_list());
8870
    TORRENT_ASSERT((m_paused && m_auto_managed && !m_abort) == m_links[aux::session_interface::torrent_want_scrape].in_list());
8871
8872
    bool is_checking = false;
8873
    bool is_downloading = false;
8874
    bool is_seeding = false;
8875
8876
    if (is_auto_managed() && !has_error())
8877
    {
8878
      if (m_state == torrent_status::checking_files)
8879
      {
8880
        is_checking = true;
8881
      }
8882
      else if (m_state == torrent_status::downloading_metadata
8883
        || m_state == torrent_status::downloading
8884
        || m_state == torrent_status::finished
8885
        || m_state == torrent_status::seeding)
8886
      {
8887
        if (is_finished())
8888
          is_seeding = true;
8889
        else
8890
          is_downloading = true;
8891
      }
8892
    }
8893
8894
    TORRENT_ASSERT(m_links[aux::session_interface::torrent_checking_auto_managed].in_list()
8895
      == is_checking);
8896
    TORRENT_ASSERT(m_links[aux::session_interface::torrent_downloading_auto_managed].in_list()
8897
      == is_downloading);
8898
    TORRENT_ASSERT(m_links[aux::session_interface::torrent_seeding_auto_managed].in_list()
8899
      == is_seeding);
8900
8901
    if (m_seed_mode)
8902
    {
8903
      TORRENT_ASSERT(is_seed());
8904
    }
8905
8906
    TORRENT_ASSERT(is_single_thread());
8907
    // this fires during disconnecting peers
8908
    if (is_paused()) TORRENT_ASSERT(num_peers() == 0 || m_graceful_pause_mode);
8909
8910
    int seeds = 0;
8911
    int num_uploads = 0;
8912
    int num_connecting = 0;
8913
    int num_connecting_seeds = 0;
8914
    std::map<piece_block, int> num_requests;
8915
    for (peer_connection const* peer : *this)
8916
    {
8917
      peer_connection const& p = *peer;
8918
8919
      if (p.is_connecting()) ++num_connecting;
8920
8921
      if (p.is_connecting() && p.peer_info_struct()->seed)
8922
        ++num_connecting_seeds;
8923
8924
      if (p.peer_info_struct())
8925
      {
8926
        if (p.peer_info_struct()->seed)
8927
        {
8928
          ++seeds;
8929
        }
8930
        else
8931
        {
8932
          TORRENT_ASSERT(!p.is_seed());
8933
        }
8934
      }
8935
8936
      for (auto const& j : p.request_queue())
8937
      {
8938
        if (!j.not_wanted && !j.timed_out) ++num_requests[j.block];
8939
      }
8940
8941
      for (auto const& j : p.download_queue())
8942
      {
8943
        if (!j.not_wanted && !j.timed_out) ++num_requests[j.block];
8944
      }
8945
8946
      if (!p.is_choked() && !p.ignore_unchoke_slots()) ++num_uploads;
8947
      torrent* associated_torrent = p.associated_torrent().lock().get();
8948
      if (associated_torrent != this && associated_torrent != nullptr)
8949
        TORRENT_ASSERT_FAIL();
8950
    }
8951
    TORRENT_ASSERT_VAL(num_uploads == int(m_num_uploads), int(m_num_uploads) - num_uploads);
8952
    TORRENT_ASSERT_VAL(seeds == int(m_num_seeds), int(m_num_seeds) - seeds);
8953
    TORRENT_ASSERT_VAL(num_connecting == int(m_num_connecting), int(m_num_connecting) - num_connecting);
8954
    TORRENT_ASSERT_VAL(num_connecting_seeds == int(m_num_connecting_seeds)
8955
      , int(m_num_connecting_seeds) - num_connecting_seeds);
8956
    TORRENT_ASSERT_VAL(int(m_num_uploads) <= num_peers(), m_num_uploads - num_peers());
8957
    TORRENT_ASSERT_VAL(int(m_num_seeds) <= num_peers(), m_num_seeds - num_peers());
8958
    TORRENT_ASSERT_VAL(int(m_num_connecting) <= num_peers(), int(m_num_connecting) - num_peers());
8959
    TORRENT_ASSERT_VAL(int(m_num_connecting_seeds) <= num_peers(), int(m_num_connecting_seeds) - num_peers());
8960
    TORRENT_ASSERT_VAL(int(m_num_connecting) + int(m_num_seeds) >= int(m_num_connecting_seeds)
8961
      , int(m_num_connecting_seeds) - (int(m_num_connecting) + int(m_num_seeds)));
8962
    TORRENT_ASSERT_VAL(int(m_num_connecting) + int(m_num_seeds) - int(m_num_connecting_seeds) <= num_peers()
8963
      , num_peers() - (int(m_num_connecting) + int(m_num_seeds) - int(m_num_connecting_seeds)));
8964
8965
    if (has_picker())
8966
    {
8967
      for (std::map<piece_block, int>::iterator i = num_requests.begin()
8968
        , end(num_requests.end()); i != end; ++i)
8969
      {
8970
        piece_block b = i->first;
8971
        int count = i->second;
8972
        int picker_count = m_picker->num_peers(b);
8973
        // if we're no longer downloading the piece
8974
        // (for instance, it may be fully downloaded and waiting
8975
        // for the hash check to return), the piece picker always
8976
        // returns 0 requests, regardless of how many peers may still
8977
        // have the block in their queue
8978
        if (!m_picker->is_downloaded(b) && m_picker->is_downloading(b.piece_index))
8979
        {
8980
          if (picker_count != count)
8981
          {
8982
            std::fprintf(stderr, "picker count discrepancy: "
8983
              "picker: %d != peerlist: %d\n", picker_count, count);
8984
8985
            for (const_peer_iterator j = this->begin(); j != this->end(); ++j)
8986
            {
8987
              peer_connection const& p = *(*j);
8988
              std::fprintf(stderr, "peer: %s\n", print_endpoint(p.remote()).c_str());
8989
              for (auto const& k : p.request_queue())
8990
              {
8991
                std::fprintf(stderr, "  rq: (%d, %d) %s %s %s\n"
8992
                  , static_cast<int>(k.block.piece_index)
8993
                  , k.block.block_index, k.not_wanted ? "not-wanted" : ""
8994
                  , k.timed_out ? "timed-out" : "", k.busy ? "busy": "");
8995
              }
8996
              for (auto const& k : p.download_queue())
8997
              {
8998
                std::fprintf(stderr, "  dq: (%d, %d) %s %s %s\n"
8999
                  , static_cast<int>(k.block.piece_index)
9000
                  , k.block.block_index, k.not_wanted ? "not-wanted" : ""
9001
                  , k.timed_out ? "timed-out" : "", k.busy ? "busy": "");
9002
              }
9003
            }
9004
            TORRENT_ASSERT_FAIL();
9005
          }
9006
        }
9007
      }
9008
    }
9009
9010
    if (valid_metadata())
9011
    {
9012
      TORRENT_ASSERT(m_abort || m_error || !m_picker || m_picker->num_pieces() == m_torrent_file->num_pieces());
9013
    }
9014
    else
9015
    {
9016
      TORRENT_ASSERT(m_abort || m_error || !m_picker || m_picker->num_pieces() == 0);
9017
    }
9018
9019
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
9020
    // make sure we haven't modified the peer object
9021
    // in a way that breaks the sort order
9022
    if (m_peer_list && m_peer_list->begin() != m_peer_list->end())
9023
    {
9024
      auto i = m_peer_list->begin();
9025
      auto p = i++;
9026
      auto end(m_peer_list->end());
9027
      peer_address_compare cmp;
9028
      for (; i != end; ++i, ++p)
9029
      {
9030
        TORRENT_ASSERT(!cmp(*i, *p));
9031
      }
9032
    }
9033
#endif
9034
9035
/*
9036
    if (m_picker && !m_abort)
9037
    {
9038
      // make sure that pieces that have completed the download
9039
      // of all their blocks are in the disk io thread's queue
9040
      // to be checked.
9041
      std::vector<piece_picker::downloading_piece> dl_queue
9042
        = m_picker->get_download_queue();
9043
      for (std::vector<piece_picker::downloading_piece>::const_iterator i =
9044
        dl_queue.begin(); i != dl_queue.end(); ++i)
9045
      {
9046
        const int blocks_per_piece = m_picker->blocks_in_piece(i->index);
9047
9048
        bool complete = true;
9049
        for (int j = 0; j < blocks_per_piece; ++j)
9050
        {
9051
          if (i->info[j].state == piece_picker::block_info::state_finished)
9052
            continue;
9053
          complete = false;
9054
          break;
9055
        }
9056
        TORRENT_ASSERT(complete);
9057
      }
9058
    }
9059
*/
9060
    if (m_files_checked && valid_metadata())
9061
    {
9062
      TORRENT_ASSERT(block_size() > 0);
9063
    }
9064
  }
9065
#endif
9066
9067
  void torrent::set_sequential_download(bool const sd)
9068
0
  {
9069
0
    TORRENT_ASSERT(is_single_thread());
9070
0
    if (m_sequential_download == sd) return;
9071
0
    m_sequential_download = sd;
9072
#ifndef TORRENT_DISABLE_LOGGING
9073
    debug_log("*** set-sequential-download: %d", sd);
9074
#endif
9075
9076
0
    set_need_save_resume(torrent_handle::if_config_changed);
9077
9078
0
    state_updated();
9079
0
  }
9080
9081
  void torrent::queue_up()
9082
0
  {
9083
    // finished torrents may not change their queue positions, as it's set to
9084
    // -1
9085
0
    if (m_abort || is_finished()) return;
9086
9087
0
    set_queue_position(queue_position() == queue_position_t{0}
9088
0
      ? queue_position() : prev(queue_position()));
9089
0
  }
9090
9091
  void torrent::queue_down()
9092
0
  {
9093
0
    set_queue_position(next(queue_position()));
9094
0
  }
9095
9096
  void torrent::set_queue_position(queue_position_t const p)
9097
2.43k
  {
9098
2.43k
    TORRENT_ASSERT(is_single_thread());
9099
9100
    // finished torrents may not change their queue positions, as it's set to
9101
    // -1
9102
2.43k
    if ((m_abort || is_finished()) && p != no_pos) return;
9103
9104
2.10k
    TORRENT_ASSERT((p == no_pos) == is_finished()
9105
2.10k
      || (!m_auto_managed && p == no_pos)
9106
2.10k
      || (m_abort && p == no_pos)
9107
2.10k
      || (!m_added && p == no_pos));
9108
2.10k
    if (p == m_sequence_number) return;
9109
9110
1.94k
    TORRENT_ASSERT(p >= no_pos);
9111
9112
1.94k
    state_updated();
9113
9114
1.94k
    m_ses.set_queue_position(this, p);
9115
1.94k
  }
9116
9117
  void torrent::set_max_uploads(int limit, bool const state_update)
9118
1.88k
  {
9119
1.88k
    TORRENT_ASSERT(is_single_thread());
9120
    // TODO: perhaps 0 should actually mean 0
9121
1.88k
    if (limit <= 0) limit = (1 << 24) - 1;
9122
1.88k
    if (int(m_max_uploads) == limit) return;
9123
397
    if (state_update) state_updated();
9124
397
    m_max_uploads = aux::numeric_cast<std::uint32_t>(limit);
9125
#ifndef TORRENT_DISABLE_LOGGING
9126
    if (should_log() && state_update)
9127
      debug_log("*** set-max-uploads: %d", m_max_uploads);
9128
#endif
9129
9130
397
    if (state_update)
9131
0
      set_need_save_resume(torrent_handle::if_config_changed);
9132
397
  }
9133
9134
  void torrent::set_max_connections(int limit, bool const state_update)
9135
1.88k
  {
9136
1.88k
    TORRENT_ASSERT(is_single_thread());
9137
    // TODO: perhaps 0 should actually mean 0
9138
1.88k
    if (limit <= 0) limit = (1 << 24) - 1;
9139
1.88k
    if (int(m_max_connections) == limit) return;
9140
283
    if (state_update) state_updated();
9141
283
    m_max_connections = aux::numeric_cast<std::uint32_t>(limit);
9142
283
    update_want_peers();
9143
9144
#ifndef TORRENT_DISABLE_LOGGING
9145
    if (should_log() && state_update)
9146
      debug_log("*** set-max-connections: %d", m_max_connections);
9147
#endif
9148
9149
283
    if (num_peers() > int(m_max_connections))
9150
0
    {
9151
0
      disconnect_peers(num_peers() - m_max_connections
9152
0
        , errors::too_many_connections);
9153
0
    }
9154
9155
283
    if (state_update)
9156
0
      set_need_save_resume(torrent_handle::if_config_changed);
9157
283
  }
9158
9159
  void torrent::set_upload_limit(int const limit)
9160
0
  {
9161
0
    set_limit_impl(limit, peer_connection::upload_channel);
9162
#ifndef TORRENT_DISABLE_LOGGING
9163
    debug_log("*** set-upload-limit: %d", limit);
9164
#endif
9165
0
  }
9166
9167
  void torrent::set_download_limit(int const limit)
9168
0
  {
9169
0
    set_limit_impl(limit, peer_connection::download_channel);
9170
#ifndef TORRENT_DISABLE_LOGGING
9171
    debug_log("*** set-download-limit: %d", limit);
9172
#endif
9173
0
  }
9174
9175
  void torrent::set_limit_impl(int limit, int const channel, bool const state_update)
9176
3.76k
  {
9177
3.76k
    TORRENT_ASSERT(is_single_thread());
9178
3.76k
    if (limit <= 0 || limit == aux::bandwidth_channel::inf) limit = 0;
9179
9180
3.76k
    if (m_peer_class == peer_class_t{0})
9181
3.51k
    {
9182
3.51k
      if (limit == 0) return;
9183
351
      setup_peer_class();
9184
351
    }
9185
9186
597
    struct peer_class* tpc = m_ses.peer_classes().at(m_peer_class);
9187
597
    TORRENT_ASSERT(tpc);
9188
597
    if (tpc->channel[channel].throttle() == limit) return;
9189
471
    if (state_update)
9190
0
    {
9191
0
      state_updated();
9192
0
      set_need_save_resume(torrent_handle::if_config_changed);
9193
0
    }
9194
471
    tpc->channel[channel].throttle(limit);
9195
471
  }
9196
9197
  void torrent::setup_peer_class()
9198
351
  {
9199
351
    TORRENT_ASSERT(m_peer_class == peer_class_t{0});
9200
351
    m_peer_class = m_ses.peer_classes().new_peer_class(name());
9201
351
    add_class(m_ses.peer_classes(), m_peer_class);
9202
351
  }
9203
9204
  int torrent::limit_impl(int const channel) const
9205
6
  {
9206
6
    TORRENT_ASSERT(is_single_thread());
9207
9208
6
    if (m_peer_class == peer_class_t{0}) return -1;
9209
0
    int limit = m_ses.peer_classes().at(m_peer_class)->channel[channel].throttle();
9210
0
    if (limit == std::numeric_limits<int>::max()) limit = -1;
9211
0
    return limit;
9212
6
  }
9213
9214
  int torrent::upload_limit() const
9215
3
  {
9216
3
    return limit_impl(peer_connection::upload_channel);
9217
3
  }
9218
9219
  int torrent::download_limit() const
9220
3
  {
9221
3
    return limit_impl(peer_connection::download_channel);
9222
3
  }
9223
9224
  bool torrent::delete_files(remove_flags_t const options)
9225
0
  {
9226
0
    TORRENT_ASSERT(is_single_thread());
9227
9228
#ifndef TORRENT_DISABLE_LOGGING
9229
    log_to_all_peers("deleting files");
9230
#endif
9231
9232
0
    disconnect_all(errors::torrent_removed, operation_t::bittorrent);
9233
0
    stop_announcing();
9234
9235
    // storage may be nullptr during shutdown
9236
0
    if (m_storage)
9237
0
    {
9238
0
      TORRENT_ASSERT(m_storage);
9239
0
      m_ses.disk_thread().async_delete_files(m_storage, options
9240
0
        , std::bind(&torrent::on_files_deleted, shared_from_this(), _1));
9241
0
      m_deleted = true;
9242
0
      m_ses.deferred_submit_jobs();
9243
0
      return true;
9244
0
    }
9245
0
    return false;
9246
0
  }
9247
9248
  void torrent::clear_error()
9249
2
  {
9250
2
    TORRENT_ASSERT(is_single_thread());
9251
2
    if (!m_error) return;
9252
0
    bool const checking_files = should_check_files();
9253
0
    m_ses.trigger_auto_manage();
9254
0
    m_error.clear();
9255
0
    m_error_file = torrent_status::error_file_none;
9256
9257
0
    update_gauge();
9258
0
    state_updated();
9259
0
    update_want_peers();
9260
0
    update_state_list();
9261
9262
    // if the error happened during initialization, try again now
9263
0
    if (!m_torrent_initialized && valid_metadata()) init();
9264
0
    if (!checking_files && should_check_files())
9265
0
      start_checking();
9266
0
  }
9267
  std::string torrent::resolve_filename(file_index_t const file) const
9268
0
  {
9269
0
    if (file == torrent_status::error_file_none) return "";
9270
0
    if (file == torrent_status::error_file_ssl_ctx) return "SSL Context";
9271
0
    if (file == torrent_status::error_file_exception) return "exception";
9272
0
    if (file == torrent_status::error_file_partfile) return "partfile";
9273
0
    if (file == torrent_status::error_file_metadata) return "metadata";
9274
9275
0
    if (m_storage && file >= file_index_t(0))
9276
0
    {
9277
0
      file_storage const& st = m_torrent_file->files();
9278
0
      return st.file_path(file, m_save_path);
9279
0
    }
9280
0
    else
9281
0
    {
9282
0
      return m_save_path;
9283
0
    }
9284
0
  }
9285
9286
  void torrent::set_error(error_code const& ec, file_index_t const error_file)
9287
0
  {
9288
0
    TORRENT_ASSERT(is_single_thread());
9289
0
    m_error = ec;
9290
0
    m_error_file = error_file;
9291
9292
0
    update_gauge();
9293
9294
0
    if (alerts().should_post<torrent_error_alert>())
9295
0
      alerts().emplace_alert<torrent_error_alert>(get_handle(), ec
9296
0
        , resolve_filename(error_file));
9297
9298
#ifndef TORRENT_DISABLE_LOGGING
9299
    if (ec)
9300
    {
9301
      char buf[1024];
9302
      std::snprintf(buf, sizeof(buf), "error %s: %s", ec.message().c_str()
9303
        , resolve_filename(error_file).c_str());
9304
      log_to_all_peers(buf);
9305
    }
9306
#endif
9307
9308
0
    state_updated();
9309
0
    update_state_list();
9310
0
  }
9311
9312
  void torrent::auto_managed(bool a)
9313
446
  {
9314
446
    TORRENT_ASSERT(is_single_thread());
9315
446
    INVARIANT_CHECK;
9316
9317
446
    if (m_auto_managed == a) return;
9318
178
    bool const checking_files = should_check_files();
9319
178
    m_auto_managed = a;
9320
178
    update_gauge();
9321
178
    update_want_scrape();
9322
178
    update_state_list();
9323
9324
178
    state_updated();
9325
9326
    // we need to save this new state as well
9327
178
    set_need_save_resume(torrent_handle::if_config_changed);
9328
9329
    // recalculate which torrents should be
9330
    // paused
9331
178
    m_ses.trigger_auto_manage();
9332
9333
178
    if (!checking_files && should_check_files())
9334
0
    {
9335
0
      start_checking();
9336
0
    }
9337
178
  }
9338
9339
  namespace {
9340
9341
  std::uint16_t clamped_subtract_u16(int const a, int const b)
9342
0
  {
9343
0
    if (a < b) return 0;
9344
0
    return std::uint16_t(a - b);
9345
0
  }
9346
9347
  } // anonymous namespace
9348
9349
  // this is called every time the session timer takes a step back. Since the
9350
  // session time is meant to fit in 16 bits, it only covers a range of
9351
  // about 18 hours. This means every few hours the whole epoch of this
9352
  // clock is shifted forward. All timestamp in this clock must then be
9353
  // shifted backwards to remain the same. Anything that's shifted back
9354
  // beyond the new epoch is clamped to 0 (to represent the oldest timestamp
9355
  // currently representable by the session_time)
9356
  void torrent::step_session_time(int const seconds)
9357
0
  {
9358
0
    if (m_peer_list)
9359
0
    {
9360
0
      for (auto pe : *m_peer_list)
9361
0
      {
9362
0
        pe->last_optimistically_unchoked
9363
0
          = clamped_subtract_u16(pe->last_optimistically_unchoked, seconds);
9364
0
        pe->last_connected = clamped_subtract_u16(pe->last_connected, seconds);
9365
0
      }
9366
0
    }
9367
0
  }
9368
9369
  // the higher seed rank, the more important to seed
9370
  int torrent::seed_rank(aux::session_settings const& s) const
9371
0
  {
9372
0
    TORRENT_ASSERT(is_single_thread());
9373
0
    enum flags
9374
0
    {
9375
0
      seed_ratio_not_met = 0x40000000,
9376
0
      no_seeds           = 0x20000000,
9377
0
      recently_started   = 0x10000000,
9378
0
      prio_mask          = 0x0fffffff
9379
0
    };
9380
9381
0
    if (!is_finished()) return 0;
9382
9383
0
    int scale = 1000;
9384
0
    if (!is_seed()) scale = 500;
9385
9386
0
    int ret = 0;
9387
9388
0
    seconds32 const act_time = active_time();
9389
0
    seconds32 const fin_time = finished_time();
9390
0
    seconds32 const download_time = act_time - fin_time;
9391
9392
    // if we haven't yet met the seed limits, set the seed_ratio_not_met
9393
    // flag. That will make this seed prioritized
9394
    // downloaded may be 0 if the torrent is 0-sized
9395
0
    std::int64_t const downloaded = std::max(m_total_downloaded, m_torrent_file->total_size());
9396
0
    if (fin_time < seconds(s.get_int(settings_pack::seed_time_limit))
9397
0
      && (download_time.count() > 1
9398
0
        && fin_time * 100 / download_time < s.get_int(settings_pack::seed_time_ratio_limit))
9399
0
      && downloaded > 0
9400
0
      && m_total_uploaded * 100 / downloaded < s.get_int(settings_pack::share_ratio_limit))
9401
0
      ret |= seed_ratio_not_met;
9402
9403
    // if this torrent is running, and it was started less
9404
    // than 30 minutes ago, give it priority, to avoid oscillation
9405
0
    if (!is_paused() && act_time < minutes(30))
9406
0
      ret |= recently_started;
9407
9408
    // if we have any scrape data, use it to calculate
9409
    // seed rank
9410
0
    int seeds = 0;
9411
0
    int downloaders = 0;
9412
9413
    // If we're currently seeding and using tracker supplied scrape
9414
    // data, we should remove ourselves from the seed count
9415
0
    int const self_seed = is_seed() && !is_paused() ? 1 : 0;
9416
9417
0
    if (m_complete != 0xffffff) seeds = std::max(0, int(m_complete) - self_seed);
9418
0
    else seeds = m_peer_list ? m_peer_list->num_seeds() : 0;
9419
9420
0
    if (m_incomplete != 0xffffff) downloaders = m_incomplete;
9421
0
    else downloaders = m_peer_list ? m_peer_list->num_peers() - m_peer_list->num_seeds() : 0;
9422
9423
0
    if (seeds == 0)
9424
0
    {
9425
0
      ret |= no_seeds;
9426
0
      ret |= downloaders & prio_mask;
9427
0
    }
9428
0
    else
9429
0
    {
9430
0
      ret |= ((1 + downloaders) * scale / seeds) & prio_mask;
9431
0
    }
9432
9433
0
    return ret;
9434
0
  }
9435
9436
  // this is an async operation triggered by the client
9437
  void torrent::save_resume_data(resume_data_flags_t const flags)
9438
0
  {
9439
0
    TORRENT_ASSERT(is_single_thread());
9440
0
    INVARIANT_CHECK;
9441
9442
0
    if (m_abort)
9443
0
    {
9444
0
      alerts().emplace_alert<save_resume_data_failed_alert>(get_handle()
9445
0
        , errors::torrent_removed);
9446
0
      return;
9447
0
    }
9448
9449
0
    auto conditions = flags & (
9450
0
      torrent_handle::only_if_modified
9451
0
      | torrent_handle::if_counters_changed
9452
0
      | torrent_handle::if_download_progress
9453
0
      | torrent_handle::if_config_changed
9454
0
      | torrent_handle::if_state_changed
9455
0
      | torrent_handle::if_metadata_changed
9456
0
      );
9457
9458
0
    if (conditions && !(m_need_save_resume_data & conditions))
9459
0
    {
9460
      // if conditions were specified, but none of those conditions are
9461
      // met (i.e. none of them have been updated since last
9462
      // save_resume_data()), we don't save it.
9463
0
      alerts().emplace_alert<save_resume_data_failed_alert>(get_handle()
9464
0
        , errors::resume_data_not_modified);
9465
0
      return;
9466
0
    }
9467
9468
0
    m_need_save_resume_data = resume_data_flags_t{};
9469
0
    state_updated();
9470
9471
0
    if ((flags & torrent_handle::flush_disk_cache) && m_storage)
9472
0
    {
9473
0
      m_ses.disk_thread().async_release_files(m_storage);
9474
0
      m_ses.deferred_submit_jobs();
9475
0
    }
9476
9477
0
    state_updated();
9478
9479
0
    add_torrent_params atp;
9480
0
    write_resume_data(flags, atp);
9481
0
    alerts().emplace_alert<save_resume_data_alert>(std::move(atp), get_handle());
9482
0
  }
9483
9484
  bool torrent::should_check_files() const
9485
635
  {
9486
635
    TORRENT_ASSERT(is_single_thread());
9487
635
    return m_state == torrent_status::checking_files
9488
635
      && !m_paused
9489
635
      && !has_error()
9490
635
      && !m_abort
9491
635
      && !m_session_paused;
9492
635
  }
9493
9494
  void torrent::flush_cache()
9495
0
  {
9496
0
    TORRENT_ASSERT(is_single_thread());
9497
9498
    // storage may be nullptr during shutdown
9499
0
    if (!m_storage)
9500
0
    {
9501
0
      TORRENT_ASSERT(m_abort);
9502
0
      return;
9503
0
    }
9504
0
    m_ses.disk_thread().async_release_files(m_storage
9505
0
      , std::bind(&torrent::on_cache_flushed, shared_from_this(), true));
9506
0
    m_ses.deferred_submit_jobs();
9507
0
  }
9508
9509
553
  void torrent::on_cache_flushed(bool const manually_triggered) try
9510
553
  {
9511
553
    TORRENT_ASSERT(is_single_thread());
9512
9513
553
    if (m_ses.is_aborted()) return;
9514
9515
0
    if (manually_triggered || alerts().should_post<cache_flushed_alert>())
9516
0
      alerts().emplace_alert<cache_flushed_alert>(get_handle());
9517
0
  }
9518
553
  catch (...) { handle_exception(); }
9519
9520
  void torrent::on_torrent_aborted()
9521
1.88k
  {
9522
1.88k
    TORRENT_ASSERT(is_single_thread());
9523
9524
    // there should be no more disk activity for this torrent now, we can
9525
    // release the disk io handle
9526
1.88k
    m_storage.reset();
9527
9528
1.88k
    alerts().emplace_alert<torrent_removed_alert>(get_handle()
9529
1.88k
      , info_hash(), get_userdata());
9530
1.88k
  }
9531
9532
  bool torrent::is_paused() const
9533
10.0k
  {
9534
10.0k
    return m_paused || m_session_paused;
9535
10.0k
  }
9536
9537
  void torrent::pause(pause_flags_t const flags)
9538
446
  {
9539
446
    TORRENT_ASSERT(is_single_thread());
9540
446
    INVARIANT_CHECK;
9541
9542
446
    if (!m_paused)
9543
279
    {
9544
      // we need to save this new state
9545
279
      set_need_save_resume(torrent_handle::if_state_changed);
9546
279
    }
9547
9548
446
    set_paused(true, flags);
9549
446
  }
9550
9551
  void torrent::do_pause(bool const was_paused)
9552
279
  {
9553
279
    TORRENT_ASSERT(is_single_thread());
9554
279
    if (!is_paused()) return;
9555
9556
    // this torrent may be about to consider itself inactive. If so, we want
9557
    // to prevent it from doing so, since it's being paused unconditionally
9558
    // now. An illustrative example of this is a torrent that completes
9559
    // downloading when active_seeds = 0. It completes, it gets paused and it
9560
    // should not come back to life again.
9561
279
    if (m_pending_active_change)
9562
0
    {
9563
0
      m_inactivity_timer.cancel();
9564
0
    }
9565
9566
279
#ifndef TORRENT_DISABLE_EXTENSIONS
9567
279
    for (auto& ext : m_extensions)
9568
0
    {
9569
0
      if (ext->on_pause()) return;
9570
0
    }
9571
279
#endif
9572
9573
279
    m_connect_boost_counter
9574
279
      = static_cast<std::uint8_t>(settings().get_int(settings_pack::torrent_connect_boost));
9575
279
    m_inactive = false;
9576
9577
279
    update_state_list();
9578
279
    update_want_tick();
9579
9580
    // do_paused() may be called twice, if the first time is to enter
9581
    // graceful pause, and the second time proper pause. We can only update
9582
    // these timers once, otherwise they'll be inflated
9583
279
    if (!was_paused)
9584
279
    {
9585
279
      const time_point now = aux::time_now();
9586
9587
279
      m_active_time +=
9588
279
        duration_cast<seconds32>(now - m_started);
9589
9590
279
      if (is_seed()) m_seeding_time +=
9591
49
        duration_cast<seconds32>(now - m_became_seed);
9592
9593
279
      if (is_finished()) m_finished_time +=
9594
144
        duration_cast<seconds32>(now - m_became_finished);
9595
279
    }
9596
9597
279
    m_announce_to_dht = false;
9598
279
    m_announce_to_trackers = false;
9599
279
    m_announce_to_lsd = false;
9600
9601
279
    state_updated();
9602
279
    update_want_peers();
9603
279
    update_want_scrape();
9604
279
    update_gauge();
9605
279
    update_state_list();
9606
9607
#ifndef TORRENT_DISABLE_LOGGING
9608
    log_to_all_peers("pausing");
9609
#endif
9610
9611
    // when checking and being paused in graceful pause mode, we
9612
    // post the paused alert when the last outstanding disk job completes
9613
279
    if (m_state == torrent_status::checking_files)
9614
0
    {
9615
0
      if (m_checking_piece == m_num_checked_pieces)
9616
0
      {
9617
0
        if (alerts().should_post<torrent_paused_alert>())
9618
0
          alerts().emplace_alert<torrent_paused_alert>(get_handle());
9619
0
      }
9620
0
      disconnect_all(errors::torrent_paused, operation_t::bittorrent);
9621
0
      return;
9622
0
    }
9623
9624
279
    if (!m_graceful_pause_mode)
9625
279
    {
9626
      // this will make the storage close all
9627
      // files and flush all cached data
9628
279
      if (m_storage)
9629
279
      {
9630
        // the torrent_paused alert will be posted from on_torrent_paused
9631
279
        m_ses.disk_thread().async_stop_torrent(m_storage
9632
279
          , [self = shared_from_this()] { self->on_torrent_paused(); });
9633
279
        m_ses.deferred_submit_jobs();
9634
279
      }
9635
0
      else
9636
0
      {
9637
0
        if (alerts().should_post<torrent_paused_alert>())
9638
0
          alerts().emplace_alert<torrent_paused_alert>(get_handle());
9639
0
      }
9640
9641
279
      disconnect_all(errors::torrent_paused, operation_t::bittorrent);
9642
279
    }
9643
0
    else
9644
0
    {
9645
      // disconnect all peers with no outstanding data to receive
9646
      // and choke all remaining peers to prevent responding to new
9647
      // requests
9648
0
      for (auto p : m_connections)
9649
0
      {
9650
0
        TORRENT_INCREMENT(m_iterating_connections);
9651
0
        TORRENT_ASSERT(p->associated_torrent().lock().get() == this);
9652
9653
0
        if (p->is_disconnecting()) continue;
9654
9655
0
        if (p->outstanding_bytes() > 0)
9656
0
        {
9657
#ifndef TORRENT_DISABLE_LOGGING
9658
          p->peer_log(peer_log_alert::info, "CHOKING_PEER", "torrent graceful paused");
9659
#endif
9660
          // remove any un-sent requests from the queue
9661
0
          p->clear_request_queue();
9662
          // don't accept new requests from the peer
9663
0
          p->choke_this_peer();
9664
0
          continue;
9665
0
        }
9666
9667
        // since we're currently in graceful pause mode, the last peer to
9668
        // disconnect (assuming all peers end up begin disconnected here)
9669
        // will post the torrent_paused_alert
9670
#ifndef TORRENT_DISABLE_LOGGING
9671
        p->peer_log(peer_log_alert::info, "CLOSING_CONNECTION", "torrent_paused");
9672
#endif
9673
0
        p->disconnect(errors::torrent_paused, operation_t::bittorrent);
9674
0
      }
9675
0
    }
9676
9677
279
    stop_announcing();
9678
279
  }
9679
9680
#ifndef TORRENT_DISABLE_LOGGING
9681
  void torrent::log_to_all_peers(char const* message)
9682
  {
9683
    TORRENT_ASSERT(is_single_thread());
9684
9685
    bool const log_peers = !m_connections.empty()
9686
      && m_connections.front()->should_log(peer_log_alert::info);
9687
9688
    if (log_peers)
9689
    {
9690
      for (auto const p : m_connections)
9691
      {
9692
        TORRENT_INCREMENT(m_iterating_connections);
9693
        p->peer_log(peer_log_alert::info, "TORRENT", "%s", message);
9694
      }
9695
    }
9696
9697
    debug_log("%s", message);
9698
  }
9699
#endif
9700
9701
  // add or remove a url that will be attempted for
9702
  // finding the file(s) in this torrent.
9703
  web_seed_t* torrent::add_web_seed(std::string const& url
9704
    , web_seed_entry::type_t const type
9705
    , std::string const& auth
9706
    , web_seed_entry::headers_t const& extra_headers
9707
    , web_seed_flag_t const flags)
9708
0
  {
9709
0
    web_seed_t ent(url, type, auth, extra_headers);
9710
0
    ent.ephemeral = bool(flags & ephemeral);
9711
0
    ent.no_local_ips = bool(flags & no_local_ips);
9712
9713
    // don't add duplicates
9714
0
    auto const it = std::find(m_web_seeds.begin(), m_web_seeds.end(), ent);
9715
0
    if (it != m_web_seeds.end())
9716
0
    {
9717
      // if we're adding a web seed (as non-ephemeral) and we have an
9718
      // ephemeral web seed already, promote it to non-ephemeral
9719
0
      if (it->ephemeral && !ent.ephemeral)
9720
0
      {
9721
0
        set_need_save_resume(torrent_handle::if_metadata_changed);
9722
0
        it->ephemeral = false;
9723
0
      }
9724
0
      return &*it;
9725
0
    }
9726
0
    m_web_seeds.emplace_back(std::move(ent));
9727
9728
    // ephemeral web seeds are not saved in the resume data
9729
0
    if (!ent.ephemeral)
9730
0
      set_need_save_resume(torrent_handle::if_metadata_changed);
9731
9732
0
    update_want_tick();
9733
0
    return &m_web_seeds.back();
9734
0
  }
9735
9736
  void torrent::set_session_paused(bool const b)
9737
0
  {
9738
0
    if (m_session_paused == b) return;
9739
0
    bool const paused_before = is_paused();
9740
0
    m_session_paused = b;
9741
9742
0
    if (paused_before == is_paused()) return;
9743
9744
0
    if (b) do_pause();
9745
0
    else do_resume();
9746
0
  }
9747
9748
  void torrent::set_paused(bool const b, pause_flags_t flags)
9749
448
  {
9750
448
    TORRENT_ASSERT(is_single_thread());
9751
9752
    // if there are no peers, there is no point in a graceful pause mode. In
9753
    // fact, the promise to post the torrent_paused_alert exactly once is
9754
    // maintained by the last peer to be disconnected in graceful pause mode,
9755
    // if there are no peers, we must not enter graceful pause mode, and post
9756
    // the torrent_paused_alert immediately instead.
9757
448
    if (num_peers() == 0)
9758
448
      flags &= ~torrent_handle::graceful_pause;
9759
9760
448
    if (m_paused == b)
9761
167
    {
9762
      // there is one special case here. If we are
9763
      // currently in graceful pause mode, and we just turned into regular
9764
      // paused mode, we need to actually pause the torrent properly
9765
167
      if (m_paused == true
9766
167
        && m_graceful_pause_mode == true
9767
167
        && !(flags & torrent_handle::graceful_pause))
9768
0
      {
9769
0
        m_graceful_pause_mode = false;
9770
0
        update_gauge();
9771
0
        do_pause(true);
9772
0
      }
9773
167
      return;
9774
167
    }
9775
9776
281
    bool const paused_before = is_paused();
9777
9778
281
    m_paused = b;
9779
9780
    // the session may still be paused, in which case
9781
    // the effective state of the torrent did not change
9782
281
    if (paused_before == is_paused()) return;
9783
9784
281
    m_graceful_pause_mode = bool(flags & torrent_handle::graceful_pause);
9785
9786
281
    if (b) do_pause();
9787
2
    else do_resume();
9788
281
  }
9789
9790
  void torrent::resume()
9791
0
  {
9792
0
    TORRENT_ASSERT(is_single_thread());
9793
0
    INVARIANT_CHECK;
9794
9795
0
    if (!m_paused
9796
0
      && m_announce_to_dht
9797
0
      && m_announce_to_trackers
9798
0
      && m_announce_to_lsd) return;
9799
9800
0
    m_paused = false;
9801
0
    if (!m_session_paused) m_graceful_pause_mode = false;
9802
9803
0
    update_gauge();
9804
9805
    // we need to save this new state
9806
0
    set_need_save_resume(torrent_handle::if_state_changed);
9807
9808
0
    do_resume();
9809
0
  }
9810
9811
  void torrent::do_resume()
9812
2
  {
9813
2
    TORRENT_ASSERT(is_single_thread());
9814
2
    if (is_paused())
9815
0
    {
9816
0
      update_want_tick();
9817
0
      return;
9818
0
    }
9819
9820
2
#ifndef TORRENT_DISABLE_EXTENSIONS
9821
2
    for (auto& ext : m_extensions)
9822
6
    {
9823
6
      if (ext->on_resume()) return;
9824
6
    }
9825
2
#endif
9826
9827
2
    if (alerts().should_post<torrent_resumed_alert>())
9828
2
      alerts().emplace_alert<torrent_resumed_alert>(get_handle());
9829
9830
2
    m_announce_to_dht = true;
9831
2
    m_announce_to_trackers = true;
9832
2
    m_announce_to_lsd = true;
9833
9834
2
    m_started = aux::time_now32();
9835
2
    if (is_seed()) m_became_seed = m_started;
9836
2
    if (is_finished()) m_became_finished = m_started;
9837
9838
2
    clear_error();
9839
9840
2
    if (m_state == torrent_status::checking_files
9841
2
      && m_auto_managed)
9842
0
    {
9843
0
      m_ses.trigger_auto_manage();
9844
0
    }
9845
9846
2
    if (should_check_files()) start_checking();
9847
9848
2
    state_updated();
9849
2
    update_want_peers();
9850
2
    update_want_tick();
9851
2
    update_want_scrape();
9852
2
    update_gauge();
9853
9854
2
    if (m_state == torrent_status::checking_files) return;
9855
9856
2
    start_announcing();
9857
9858
2
    do_connect_boost();
9859
2
  }
9860
9861
  namespace
9862
  {
9863
    struct timer_state
9864
    {
9865
      explicit timer_state(aux::listen_socket_handle s)
9866
0
        : socket(std::move(s)) {}
9867
9868
      aux::listen_socket_handle socket;
9869
9870
      struct state_t
9871
      {
9872
        int tier = INT_MAX;
9873
        bool found_working = false;
9874
        bool done = false;
9875
      };
9876
      aux::array<state_t, num_protocols, protocol_version> state;
9877
    };
9878
  }
9879
9880
  void torrent::update_tracker_timer(time_point32 const now)
9881
0
  {
9882
0
    TORRENT_ASSERT(is_single_thread());
9883
0
    if (!m_announcing)
9884
0
    {
9885
#ifndef TORRENT_DISABLE_LOGGING
9886
      debug_log("*** update tracker timer: not announcing");
9887
#endif
9888
0
      return;
9889
0
    }
9890
9891
0
#ifdef __clang__
9892
0
#pragma clang diagnostic push
9893
0
#pragma clang diagnostic ignored "-Wmissing-braces"
9894
0
#endif
9895
0
    aux::array<bool const, num_protocols, protocol_version> const supports_protocol{
9896
0
    {
9897
0
      m_info_hash.has_v1(),
9898
0
      m_info_hash.has_v2()
9899
0
    }};
9900
0
#ifdef __clang__
9901
0
#pragma clang diagnostic pop
9902
0
#endif
9903
9904
0
    time_point32 next_announce = time_point32::max();
9905
9906
0
    std::map<std::weak_ptr<aux::listen_socket_t>, timer_state, std::owner_less<std::weak_ptr<aux::listen_socket_t>>> listen_socket_states;
9907
9908
0
    bool const announce_to_all_tiers = settings().get_bool(settings_pack::announce_to_all_tiers);
9909
0
    bool const announce_to_all_trackers = settings().get_bool(settings_pack::announce_to_all_trackers);
9910
#ifndef TORRENT_DISABLE_LOGGING
9911
    int idx = -1;
9912
    if (should_log())
9913
    {
9914
      debug_log("*** update_tracker_timer: "
9915
        "[ announce_to_all_tiers: %d announce_to_all_trackers: %d num_trackers: %d ]"
9916
        , announce_to_all_tiers
9917
        , announce_to_all_trackers
9918
        , int(m_trackers.size()));
9919
    }
9920
#endif
9921
0
    for (auto const& t : m_trackers)
9922
0
    {
9923
#ifndef TORRENT_DISABLE_LOGGING
9924
      ++idx;
9925
#endif
9926
0
      for (auto const& aep : t.endpoints)
9927
0
      {
9928
0
        auto aep_state_iter = listen_socket_states.find(aep.socket.get_ptr());
9929
0
        if (aep_state_iter == listen_socket_states.end())
9930
0
        {
9931
0
          aep_state_iter = listen_socket_states.insert({aep.socket.get_ptr(), timer_state(aep.socket)}).first;
9932
0
        }
9933
0
        timer_state& ep_state = aep_state_iter->second;
9934
9935
0
        if (!aep.enabled) continue;
9936
0
        for (protocol_version const ih : all_versions)
9937
0
        {
9938
0
          if (!supports_protocol[ih]) continue;
9939
9940
0
          auto& state = ep_state.state[ih];
9941
0
          auto& a = aep.info_hashes[ih];
9942
9943
0
          if (state.done) continue;
9944
9945
#ifndef TORRENT_DISABLE_LOGGING
9946
          if (should_log())
9947
          {
9948
            debug_log("*** tracker: (%d) [ep: %s ] \"%s\" ["
9949
              " found: %d i->tier: %d tier: %d"
9950
              " working: %d fails: %d limit: %d upd: %d ]"
9951
              , idx, print_endpoint(aep.local_endpoint).c_str(), t.url.c_str()
9952
              , state.found_working, t.tier, state.tier, a.is_working()
9953
              , a.fails, t.fail_limit, a.updating);
9954
          }
9955
#endif
9956
9957
0
          if (announce_to_all_tiers
9958
0
            && !announce_to_all_trackers
9959
0
            && state.found_working
9960
0
            && t.tier <= state.tier
9961
0
            && state.tier != INT_MAX)
9962
0
            continue;
9963
9964
0
          if (t.tier > state.tier)
9965
0
          {
9966
0
            if (!announce_to_all_tiers) break;
9967
0
            state.found_working = false;
9968
0
          }
9969
0
          state.tier = t.tier;
9970
0
          if (a.fails >= t.fail_limit && t.fail_limit != 0) continue;
9971
0
          if (a.updating)
9972
0
          {
9973
0
            state.found_working = true;
9974
0
          }
9975
0
          else
9976
0
          {
9977
0
            time_point32 const next_tracker_announce = std::max(a.next_announce, a.min_announce);
9978
0
            if (next_tracker_announce < next_announce)
9979
0
              next_announce = next_tracker_announce;
9980
0
          }
9981
0
          if (a.is_working()) state.found_working = true;
9982
0
          if (state.found_working
9983
0
            && !announce_to_all_trackers
9984
0
            && !announce_to_all_tiers)
9985
0
            state.done = true;
9986
0
        }
9987
0
      }
9988
9989
0
      if (std::all_of(listen_socket_states.begin(), listen_socket_states.end()
9990
0
        , [supports_protocol](std::pair<std::weak_ptr<aux::listen_socket_t>, timer_state> const& s) {
9991
0
          for (protocol_version const ih : all_versions)
9992
0
          {
9993
0
            if (supports_protocol[ih] && !s.second.state[ih].done)
9994
0
              return false;
9995
0
          }
9996
0
          return true;
9997
0
        }))
9998
0
        break;
9999
0
    }
10000
10001
#ifndef TORRENT_DISABLE_LOGGING
10002
    bool before_now = false;
10003
    bool none_eligible = false;
10004
#endif
10005
0
    if (next_announce <= now)
10006
0
    {
10007
0
      next_announce = now;
10008
#ifndef TORRENT_DISABLE_LOGGING
10009
      before_now = true;
10010
#endif
10011
0
    }
10012
0
    else if (next_announce == time_point32::max())
10013
0
    {
10014
      // if no tracker can be announced to, check again in a minute
10015
0
      next_announce = now + minutes32(1);
10016
#ifndef TORRENT_DISABLE_LOGGING
10017
      none_eligible = true;
10018
#endif
10019
0
    }
10020
10021
#ifndef TORRENT_DISABLE_LOGGING
10022
    debug_log("*** update tracker timer: "
10023
      "before_now: %d "
10024
      "none_eligible: %d "
10025
      "m_waiting_tracker: %d "
10026
      "next_announce_in: %d"
10027
      , before_now
10028
      , none_eligible
10029
      , m_waiting_tracker
10030
      , int(total_seconds(next_announce - now)));
10031
#endif
10032
10033
    // don't re-issue the timer if it's the same expiration time as last time
10034
    // if m_waiting_tracker is 0, expires_at() is undefined
10035
0
    if (m_waiting_tracker && m_tracker_timer.expiry() == next_announce) return;
10036
10037
0
    m_tracker_timer.expires_at(next_announce);
10038
0
    ADD_OUTSTANDING_ASYNC("tracker::on_tracker_announce");
10039
0
    ++m_waiting_tracker;
10040
0
    m_tracker_timer.async_wait([self = shared_from_this()](error_code const& e)
10041
0
      { self->wrap(&torrent::on_tracker_announce, e); });
10042
0
  }
10043
10044
  void torrent::start_announcing()
10045
922
  {
10046
922
    TORRENT_ASSERT(is_single_thread());
10047
922
    TORRENT_ASSERT(state() != torrent_status::checking_files);
10048
922
    if (is_paused())
10049
588
    {
10050
#ifndef TORRENT_DISABLE_LOGGING
10051
      debug_log("start_announcing(), paused");
10052
#endif
10053
588
      return;
10054
588
    }
10055
    // if we don't have metadata, we need to announce
10056
    // before checking files, to get peers to
10057
    // request the metadata from
10058
334
    if (!m_files_checked && valid_metadata())
10059
0
    {
10060
#ifndef TORRENT_DISABLE_LOGGING
10061
      debug_log("start_announcing(), files not checked (with valid metadata)");
10062
#endif
10063
0
      return;
10064
0
    }
10065
334
    if (m_announcing) return;
10066
10067
334
    m_announcing = true;
10068
10069
334
#ifndef TORRENT_DISABLE_DHT
10070
334
    if ((!m_peer_list || m_peer_list->num_peers() < 50) && m_ses.dht())
10071
0
    {
10072
      // we don't have any peers, prioritize
10073
      // announcing this torrent with the DHT
10074
0
      m_ses.prioritize_dht(shared_from_this());
10075
0
    }
10076
334
#endif
10077
10078
334
    if (!m_trackers.empty())
10079
0
    {
10080
      // tell the tracker that we're back
10081
0
      for (auto& t : m_trackers) t.reset();
10082
0
    }
10083
10084
    // reset the stats, since from the tracker's
10085
    // point of view, this is a new session
10086
334
    m_total_failed_bytes = 0;
10087
334
    m_total_redundant_bytes = 0;
10088
334
    m_stat.clear();
10089
10090
334
    update_want_tick();
10091
10092
334
    announce_with_tracker();
10093
10094
334
    lsd_announce();
10095
334
  }
10096
10097
  void torrent::stop_announcing()
10098
2.31k
  {
10099
2.31k
    TORRENT_ASSERT(is_single_thread());
10100
2.31k
    if (!m_announcing) return;
10101
10102
334
    m_tracker_timer.cancel();
10103
10104
334
    m_announcing = false;
10105
10106
334
    time_point32 const now = aux::time_now32();
10107
334
    for (auto& t : m_trackers)
10108
0
    {
10109
0
      for (auto& aep : t.endpoints)
10110
0
      {
10111
0
        for (auto& a : aep.info_hashes)
10112
0
        {
10113
0
          a.next_announce = now;
10114
0
          a.min_announce = now;
10115
0
        }
10116
0
      }
10117
0
    }
10118
334
    announce_with_tracker(event_t::stopped);
10119
334
  }
10120
10121
  seconds32 torrent::finished_time() const
10122
0
  {
10123
0
    if(!is_finished() || is_paused())
10124
0
      return m_finished_time;
10125
10126
0
    return m_finished_time + duration_cast<seconds32>(
10127
0
      aux::time_now() - m_became_finished);
10128
0
  }
10129
10130
  seconds32 torrent::active_time() const
10131
0
  {
10132
0
    if (is_paused())
10133
0
      return m_active_time;
10134
10135
    // m_active_time does not account for the current "session", just the
10136
    // time before we last started this torrent. To get the current time, we
10137
    // need to add the time since we started it
10138
0
    return m_active_time + duration_cast<seconds32>(
10139
0
      aux::time_now() - m_started);
10140
0
  }
10141
10142
  seconds32 torrent::seeding_time() const
10143
0
  {
10144
0
    if(!is_seed() || is_paused())
10145
0
      return m_seeding_time;
10146
    // m_seeding_time does not account for the current "session", just the
10147
    // time before we last started this torrent. To get the current time, we
10148
    // need to add the time since we started it
10149
0
    return m_seeding_time + duration_cast<seconds32>(
10150
0
      aux::time_now() - m_became_seed);
10151
0
  }
10152
10153
  seconds32 torrent::upload_mode_time() const
10154
0
  {
10155
0
    if(!m_upload_mode)
10156
0
      return seconds32(0);
10157
10158
0
    return aux::time_now32() - m_upload_mode_time;
10159
0
  }
10160
10161
  void torrent::second_tick(int const tick_interval_ms)
10162
3
  {
10163
3
    TORRENT_ASSERT(want_tick());
10164
3
    TORRENT_ASSERT(is_single_thread());
10165
3
    INVARIANT_CHECK;
10166
10167
3
    auto self = shared_from_this();
10168
10169
3
#ifndef TORRENT_DISABLE_EXTENSIONS
10170
3
    for (auto const& ext : m_extensions)
10171
9
    {
10172
9
      ext->tick();
10173
9
    }
10174
10175
3
    if (m_abort) return;
10176
3
#endif
10177
10178
    // if we're in upload only mode and we're auto-managed
10179
    // leave upload mode every 10 minutes hoping that the error
10180
    // condition has been fixed
10181
3
    if (m_upload_mode && m_auto_managed && upload_mode_time() >=
10182
0
      seconds(settings().get_int(settings_pack::optimistic_disk_retry)))
10183
0
    {
10184
0
      set_upload_mode(false);
10185
0
    }
10186
10187
3
    if (is_paused() && !m_graceful_pause_mode)
10188
0
    {
10189
      // let the stats fade out to 0
10190
      // check the rate before ticking the stats so that the last update is sent
10191
      // with the rate equal to zero
10192
0
      if (m_stat.low_pass_upload_rate() > 0 || m_stat.low_pass_download_rate() > 0)
10193
0
        state_updated();
10194
0
      m_stat.second_tick(tick_interval_ms);
10195
10196
      // the low pass transfer rate may just have dropped to 0
10197
0
      update_want_tick();
10198
10199
0
      return;
10200
0
    }
10201
10202
3
    if (settings().get_bool(settings_pack::rate_limit_ip_overhead))
10203
3
    {
10204
3
      int const up_limit = upload_limit();
10205
3
      int const down_limit = download_limit();
10206
10207
3
      if (down_limit > 0
10208
3
        && m_stat.download_ip_overhead() >= down_limit
10209
3
        && alerts().should_post<performance_alert>())
10210
0
      {
10211
0
        alerts().emplace_alert<performance_alert>(get_handle()
10212
0
          , performance_alert::download_limit_too_low);
10213
0
      }
10214
10215
3
      if (up_limit > 0
10216
3
        && m_stat.upload_ip_overhead() >= up_limit
10217
3
        && alerts().should_post<performance_alert>())
10218
0
      {
10219
0
        alerts().emplace_alert<performance_alert>(get_handle()
10220
0
          , performance_alert::upload_limit_too_low);
10221
0
      }
10222
3
    }
10223
10224
3
#ifndef TORRENT_DISABLE_STREAMING
10225
    // ---- TIME CRITICAL PIECES ----
10226
10227
#if TORRENT_DEBUG_STREAMING > 0
10228
    std::vector<partial_piece_info> queue;
10229
    get_download_queue(&queue);
10230
10231
    std::vector<peer_info> peer_list;
10232
    get_peer_info(peer_list);
10233
10234
    std::sort(queue.begin(), queue.end(), [](partial_piece_info const& lhs, partial_piece_info const& rhs)
10235
      { return lhs.piece_index < rhs.piece_index;; });
10236
10237
    std::printf("average piece download time: %.2f s (+/- %.2f s)\n"
10238
      , m_average_piece_time / 1000.f
10239
      , m_piece_time_deviation / 1000.f);
10240
    for (auto& i : queue)
10241
    {
10242
      extern void print_piece(libtorrent::partial_piece_info* pp
10243
        , std::vector<libtorrent::peer_info> const& peers
10244
        , std::vector<time_critical_piece> const& time_critical);
10245
10246
      print_piece(&i, peer_list, m_time_critical_pieces);
10247
    }
10248
#endif // TORRENT_DEBUG_STREAMING
10249
10250
3
    if (!m_time_critical_pieces.empty() && !upload_mode())
10251
0
    {
10252
0
      request_time_critical_pieces();
10253
0
    }
10254
3
#endif // TORRENT_DISABLE_STREAMING
10255
10256
    // ---- WEB SEEDS ----
10257
10258
3
    maybe_connect_web_seeds();
10259
10260
3
    m_swarm_last_seen_complete = m_last_seen_complete;
10261
3
    for (auto p : m_connections)
10262
0
    {
10263
0
      TORRENT_INCREMENT(m_iterating_connections);
10264
10265
      // look for the peer that saw a seed most recently
10266
0
      m_swarm_last_seen_complete = std::max(p->last_seen_complete(), m_swarm_last_seen_complete);
10267
10268
      // updates the peer connection's ul/dl bandwidth
10269
      // resource requests
10270
0
      p->second_tick(tick_interval_ms);
10271
0
    }
10272
3
#if TORRENT_ABI_VERSION <= 2
10273
3
    if (m_ses.alerts().should_post<stats_alert>())
10274
0
      m_ses.alerts().emplace_alert<stats_alert>(get_handle(), tick_interval_ms, m_stat);
10275
3
#endif
10276
10277
3
    m_total_uploaded += m_stat.last_payload_uploaded();
10278
3
    m_total_downloaded += m_stat.last_payload_downloaded();
10279
3
    m_stat.second_tick(tick_interval_ms);
10280
10281
    // these counters are saved in the resume data, since they updated
10282
    // we need to save the resume data too
10283
3
    set_need_save_resume(torrent_handle::if_counters_changed);
10284
10285
    // if the rate is 0, there's no update because of network transfers
10286
3
    if (m_stat.low_pass_upload_rate() > 0 || m_stat.low_pass_download_rate() > 0)
10287
0
      state_updated();
10288
10289
    // this section determines whether the torrent is active or not. When it
10290
    // changes state, it may also trigger the auto-manage logic to reconsider
10291
    // which torrents should be queued and started. There is a low pass
10292
    // filter in order to avoid flapping (auto_manage_startup).
10293
3
    bool is_inactive = is_inactive_internal();
10294
10295
3
    if (settings().get_bool(settings_pack::dont_count_slow_torrents))
10296
3
    {
10297
3
      if (is_inactive != m_inactive && !m_pending_active_change)
10298
2
      {
10299
2
        int const delay = settings().get_int(settings_pack::auto_manage_startup);
10300
2
        m_inactivity_timer.expires_after(seconds(delay));
10301
2
        m_inactivity_timer.async_wait([self](error_code const& ec) {
10302
2
          self->wrap(&torrent::on_inactivity_tick, ec); });
10303
2
        m_pending_active_change = true;
10304
2
      }
10305
1
      else if (is_inactive == m_inactive
10306
1
        && m_pending_active_change)
10307
0
      {
10308
0
        m_inactivity_timer.cancel();
10309
0
      }
10310
3
    }
10311
10312
    // want_tick depends on whether the low pass transfer rates are non-zero
10313
    // or not. They may just have turned zero in this last tick.
10314
3
    update_want_tick();
10315
3
  }
10316
10317
  bool torrent::is_inactive_internal() const
10318
3
  {
10319
3
    if (is_finished())
10320
0
      return m_stat.upload_payload_rate()
10321
0
        < settings().get_int(settings_pack::inactive_up_rate);
10322
3
    else
10323
3
      return m_stat.download_payload_rate()
10324
3
        < settings().get_int(settings_pack::inactive_down_rate);
10325
3
  }
10326
10327
2
  void torrent::on_inactivity_tick(error_code const& ec) try
10328
2
  {
10329
2
    m_pending_active_change = false;
10330
10331
2
    if (ec) return;
10332
10333
0
    bool const is_inactive = is_inactive_internal();
10334
0
    if (is_inactive == m_inactive) return;
10335
10336
0
    m_inactive = is_inactive;
10337
10338
0
    update_state_list();
10339
0
    update_want_tick();
10340
10341
0
    if (settings().get_bool(settings_pack::dont_count_slow_torrents))
10342
0
      m_ses.trigger_auto_manage();
10343
0
  }
10344
2
  catch (...) { handle_exception(); }
10345
10346
  namespace {
10347
    int zero_or(int const val, int const def_val)
10348
0
    { return (val <= 0) ? def_val : val; }
10349
  }
10350
10351
  void torrent::maybe_connect_web_seeds()
10352
923
  {
10353
923
    if (m_abort) return;
10354
10355
    // if we have everything we want we don't need to connect to any web-seed
10356
923
    if (m_web_seeds.empty()
10357
923
      || is_finished()
10358
923
      || !m_files_checked
10359
923
      || num_peers() >= int(m_max_connections)
10360
923
      || m_ses.num_connections() >= settings().get_int(settings_pack::connections_limit))
10361
923
    {
10362
923
      return;
10363
923
    }
10364
10365
    // when set to unlimited, use 100 as the limit
10366
0
    int limit = zero_or(settings().get_int(settings_pack::max_web_seed_connections)
10367
0
      , 100);
10368
10369
0
    auto const now = aux::time_now32();
10370
10371
    // keep trying web-seeds if there are any
10372
    // first find out which web seeds we are connected to
10373
0
    for (auto i = m_web_seeds.begin(); i != m_web_seeds.end() && limit > 0;)
10374
0
    {
10375
0
      auto const w = i++;
10376
0
      if (w->disabled || w->removed || w->retry > now || !w->interesting)
10377
0
        continue;
10378
10379
0
      --limit;
10380
0
      if (w->peer_info.connection || w->resolving)
10381
0
        continue;
10382
10383
0
      connect_to_url_seed(w);
10384
0
    }
10385
0
  }
10386
10387
#ifndef TORRENT_DISABLE_SHARE_MODE
10388
  void torrent::recalc_share_mode()
10389
0
  {
10390
0
    TORRENT_ASSERT(share_mode());
10391
0
    if (is_seed()) return;
10392
10393
0
    int const pieces_in_torrent = m_torrent_file->num_pieces();
10394
0
    int num_seeds = 0;
10395
0
    int num_peers = 0;
10396
0
    int num_downloaders = 0;
10397
0
    int missing_pieces = 0;
10398
0
    for (auto const p : m_connections)
10399
0
    {
10400
0
      TORRENT_INCREMENT(m_iterating_connections);
10401
0
      if (p->is_connecting()) continue;
10402
0
      if (p->is_disconnecting()) continue;
10403
0
      ++num_peers;
10404
0
      if (p->is_seed())
10405
0
      {
10406
0
        ++num_seeds;
10407
0
        continue;
10408
0
      }
10409
10410
0
      if (p->share_mode()) continue;
10411
0
      if (p->upload_only()) continue;
10412
10413
0
      ++num_downloaders;
10414
0
      missing_pieces += pieces_in_torrent - p->num_have_pieces();
10415
0
    }
10416
10417
0
    if (num_peers == 0) return;
10418
10419
0
    if (num_seeds * 100 / num_peers > 50
10420
0
      && (num_peers * 100 / m_max_connections > 90
10421
0
        || num_peers > 20))
10422
0
    {
10423
      // we are connected to more than 50% seeds (and we're beyond
10424
      // 90% of the max number of connections). That will
10425
      // limit our ability to upload. We need more downloaders.
10426
      // disconnect some seeds so that we don't have more than 50%
10427
0
      int const to_disconnect = num_seeds - num_peers / 2;
10428
0
      aux::vector<peer_connection*> seeds;
10429
0
      seeds.reserve(num_seeds);
10430
0
      std::copy_if(m_connections.begin(), m_connections.end(), std::back_inserter(seeds)
10431
0
        , [](peer_connection const* p) { return p->is_seed(); });
10432
10433
0
      aux::random_shuffle(seeds);
10434
0
      TORRENT_ASSERT(to_disconnect <= seeds.end_index());
10435
0
      for (auto const& p : span<peer_connection*>(seeds).first(to_disconnect))
10436
0
        p->disconnect(errors::upload_upload_connection, operation_t::bittorrent);
10437
0
    }
10438
10439
0
    if (num_downloaders == 0) return;
10440
10441
    // assume that the seeds are about as fast as us. During the time
10442
    // we can download one piece, and upload one piece, each seed
10443
    // can upload two pieces.
10444
0
    missing_pieces -= 2 * num_seeds;
10445
10446
0
    if (missing_pieces <= 0) return;
10447
10448
    // missing_pieces represents our opportunity to download pieces
10449
    // and share them more than once each
10450
10451
    // now, download at least one piece, otherwise download one more
10452
    // piece if our downloaded (and downloading) pieces is less than 50%
10453
    // of the uploaded bytes
10454
0
    int const num_downloaded_pieces = std::max(m_picker->have().num_pieces
10455
0
      , m_picker->want().num_pieces);
10456
10457
0
    if (std::int64_t(num_downloaded_pieces) * m_torrent_file->piece_length()
10458
0
      * settings().get_int(settings_pack::share_mode_target) > m_total_uploaded
10459
0
      && num_downloaded_pieces > 0)
10460
0
      return;
10461
10462
    // don't have more pieces downloading in parallel than 5% of the total
10463
    // number of pieces we have downloaded
10464
0
    if (m_picker->get_download_queue_size() > num_downloaded_pieces / 20)
10465
0
      return;
10466
10467
    // one more important property is that there are enough pieces
10468
    // that more than one peer wants to download
10469
    // make sure that there are enough downloaders for the rarest
10470
    // piece. Go through all pieces, figure out which one is the rarest
10471
    // and how many peers that has that piece
10472
10473
0
    aux::vector<piece_index_t> rarest_pieces;
10474
10475
0
    int const num_pieces = m_torrent_file->num_pieces();
10476
0
    int rarest_rarity = INT_MAX;
10477
0
    for (piece_index_t i(0); i < piece_index_t(num_pieces); ++i)
10478
0
    {
10479
0
      piece_picker::piece_stats_t ps = m_picker->piece_stats(i);
10480
0
      if (ps.peer_count == 0) continue;
10481
0
      if (ps.priority == 0 && (ps.have || ps.downloading))
10482
0
      {
10483
0
        m_picker->set_piece_priority(i, default_priority);
10484
0
        continue;
10485
0
      }
10486
      // don't count pieces we already have or are trying to download
10487
0
      if (ps.priority > 0 || ps.have) continue;
10488
0
      if (ps.peer_count > rarest_rarity) continue;
10489
0
      if (ps.peer_count == rarest_rarity)
10490
0
      {
10491
0
        rarest_pieces.push_back(i);
10492
0
        continue;
10493
0
      }
10494
10495
0
      rarest_pieces.clear();
10496
0
      rarest_rarity = ps.peer_count;
10497
0
      rarest_pieces.push_back(i);
10498
0
    }
10499
10500
0
    update_gauge();
10501
0
    update_want_peers();
10502
10503
    // now, rarest_pieces is a list of all pieces that are the rarest ones.
10504
    // and rarest_rarity is the number of peers that have the rarest pieces
10505
10506
    // if there's only a single peer that doesn't have the rarest piece
10507
    // it's impossible for us to download one piece and upload it
10508
    // twice. i.e. we cannot get a positive share ratio
10509
0
    if (num_peers - rarest_rarity
10510
0
      < settings().get_int(settings_pack::share_mode_target))
10511
0
      return;
10512
10513
    // now, pick one of the rarest pieces to download
10514
0
    int const pick = int(random(aux::numeric_cast<std::uint32_t>(rarest_pieces.end_index() - 1)));
10515
0
    bool const was_finished = is_finished();
10516
0
    m_picker->set_piece_priority(rarest_pieces[pick], default_priority);
10517
0
    update_gauge();
10518
0
    update_peer_interest(was_finished);
10519
0
    update_want_peers();
10520
0
  }
10521
#endif // TORRENT_DISABLE_SHARE_MODE
10522
10523
  void torrent::sent_bytes(int const bytes_payload, int const bytes_protocol)
10524
16
  {
10525
16
    m_stat.sent_bytes(bytes_payload, bytes_protocol);
10526
16
    m_ses.sent_bytes(bytes_payload, bytes_protocol);
10527
16
  }
10528
10529
  void torrent::received_bytes(int const bytes_payload, int const bytes_protocol)
10530
152k
  {
10531
152k
    m_stat.received_bytes(bytes_payload, bytes_protocol);
10532
152k
    m_ses.received_bytes(bytes_payload, bytes_protocol);
10533
152k
  }
10534
10535
  void torrent::trancieve_ip_packet(int const bytes, bool const ipv6)
10536
211
  {
10537
211
    m_stat.trancieve_ip_packet(bytes, ipv6);
10538
211
    m_ses.trancieve_ip_packet(bytes, ipv6);
10539
211
  }
10540
10541
  void torrent::sent_syn(bool const ipv6)
10542
0
  {
10543
0
    m_stat.sent_syn(ipv6);
10544
0
    m_ses.sent_syn(ipv6);
10545
0
  }
10546
10547
  void torrent::received_synack(bool const ipv6)
10548
0
  {
10549
0
    m_stat.received_synack(ipv6);
10550
0
    m_ses.received_synack(ipv6);
10551
0
  }
10552
10553
#ifndef TORRENT_DISABLE_STREAMING
10554
10555
#if TORRENT_DEBUG_STREAMING > 0
10556
  char const* esc(char const* code)
10557
  {
10558
    // this is a silly optimization
10559
    // to avoid copying of strings
10560
    int const num_strings = 200;
10561
    static char buf[num_strings][20];
10562
    static int round_robin = 0;
10563
    char* ret = buf[round_robin];
10564
    ++round_robin;
10565
    if (round_robin >= num_strings) round_robin = 0;
10566
    ret[0] = '\033';
10567
    ret[1] = '[';
10568
    int i = 2;
10569
    int j = 0;
10570
    while (code[j]) ret[i++] = code[j++];
10571
    ret[i++] = 'm';
10572
    ret[i++] = 0;
10573
    return ret;
10574
  }
10575
10576
  int peer_index(libtorrent::tcp::endpoint addr
10577
    , std::vector<libtorrent::peer_info> const& peers)
10578
  {
10579
    std::vector<peer_info>::const_iterator i = std::find_if(peers.begin()
10580
      , peers.end(), std::bind(&peer_info::ip, _1) == addr);
10581
    if (i == peers.end()) return -1;
10582
10583
    return i - peers.begin();
10584
  }
10585
10586
  void print_piece(libtorrent::partial_piece_info* pp
10587
    , std::vector<libtorrent::peer_info> const& peers
10588
    , std::vector<time_critical_piece> const& time_critical)
10589
  {
10590
    time_point const now = clock_type::now();
10591
10592
    float deadline = 0.f;
10593
    float last_request = 0.f;
10594
    int timed_out = -1;
10595
10596
    int piece = pp->piece_index;
10597
    std::vector<time_critical_piece>::const_iterator i
10598
      = std::find_if(time_critical.begin(), time_critical.end()
10599
        , std::bind(&time_critical_piece::piece, _1) == piece);
10600
    if (i != time_critical.end())
10601
    {
10602
      deadline = total_milliseconds(i->deadline - now) / 1000.f;
10603
      if (i->last_requested == min_time())
10604
        last_request = -1;
10605
      else
10606
        last_request = total_milliseconds(now - i->last_requested) / 1000.f;
10607
      timed_out = i->timed_out;
10608
    }
10609
10610
    int num_blocks = pp->blocks_in_piece;
10611
10612
    std::printf("%5d: [", piece);
10613
    for (int j = 0; j < num_blocks; ++j)
10614
    {
10615
      int index = pp ? peer_index(pp->blocks[j].peer(), peers) % 36 : -1;
10616
      char chr = '+';
10617
      if (index >= 0)
10618
        chr = (index < 10)?'0' + index:'A' + index - 10;
10619
10620
      char const* color = "";
10621
      char const* multi_req = "";
10622
10623
      if (pp->blocks[j].num_peers > 1)
10624
        multi_req = esc("1");
10625
10626
      if (pp->blocks[j].bytes_progress > 0
10627
        && pp->blocks[j].state == block_info::requested)
10628
      {
10629
        color = esc("33;7");
10630
        chr = '0' + (pp->blocks[j].bytes_progress * 10 / pp->blocks[j].block_size);
10631
      }
10632
      else if (pp->blocks[j].state == block_info::finished) color = esc("32;7");
10633
      else if (pp->blocks[j].state == block_info::writing) color = esc("36;7");
10634
      else if (pp->blocks[j].state == block_info::requested) color = esc("0");
10635
      else { color = esc("0"); chr = ' '; }
10636
10637
      std::printf("%s%s%c%s", color, multi_req, chr, esc("0"));
10638
    }
10639
    std::printf("%s]", esc("0"));
10640
    if (deadline != 0.f)
10641
      std::printf(" deadline: %f last-req: %f timed_out: %d\n"
10642
        , deadline, last_request, timed_out);
10643
    else
10644
      std::printf("\n");
10645
  }
10646
#endif // TORRENT_DEBUG_STREAMING
10647
10648
  namespace {
10649
10650
  struct busy_block_t
10651
  {
10652
    int peers;
10653
    int index;
10654
0
    bool operator<(busy_block_t const& rhs) const { return peers < rhs.peers; }
10655
  };
10656
10657
  void pick_busy_blocks(piece_picker const* picker
10658
    , piece_index_t const piece
10659
    , int const blocks_in_piece
10660
    , int const timed_out
10661
    , std::vector<piece_block>& interesting_blocks
10662
    , piece_picker::downloading_piece const& pi)
10663
0
  {
10664
    // if there aren't any free blocks in the piece, and the piece is
10665
    // old enough, we may switch into busy mode for this piece. In this
10666
    // case busy_blocks and busy_count are set to contain the eligible
10667
    // busy blocks we may pick
10668
    // first, figure out which blocks are eligible for picking
10669
    // in "busy-mode"
10670
0
    TORRENT_ALLOCA(busy_blocks, busy_block_t, blocks_in_piece);
10671
0
    int busy_count = 0;
10672
10673
    // pick busy blocks from the piece
10674
0
    int idx = -1;
10675
0
    for (auto const& info : picker->blocks_for_piece(pi))
10676
0
    {
10677
0
      ++idx;
10678
      // only consider blocks that have been requested
10679
      // and we're still waiting for them
10680
0
      if (info.state != piece_picker::block_info::state_requested)
10681
0
        continue;
10682
10683
0
      piece_block b(piece, idx);
10684
10685
      // only allow a single additional request per block, in order
10686
      // to spread it out evenly across all stalled blocks
10687
0
      if (int(info.num_peers) > timed_out)
10688
0
        continue;
10689
10690
0
      busy_blocks[busy_count].peers = info.num_peers;
10691
0
      busy_blocks[busy_count].index = idx;
10692
0
      ++busy_count;
10693
10694
#if TORRENT_DEBUG_STREAMING > 1
10695
      std::printf(" [%d (%d)]", b.block_index, info.num_peers);
10696
#endif
10697
0
    }
10698
#if TORRENT_DEBUG_STREAMING > 1
10699
    std::printf("\n");
10700
#endif
10701
10702
0
    busy_blocks = busy_blocks.first(busy_count);
10703
10704
    // then sort blocks by the number of peers with requests
10705
    // to the blocks (request the blocks with the fewest peers
10706
    // first)
10707
0
    std::sort(busy_blocks.begin(), busy_blocks.end());
10708
10709
    // then insert them into the interesting_blocks vector
10710
0
    for (auto const& block : busy_blocks)
10711
0
      interesting_blocks.emplace_back(piece, block.index);
10712
0
  }
10713
10714
  void pick_time_critical_block(std::vector<peer_connection*>& peers
10715
    , std::vector<peer_connection*>& ignore_peers
10716
    , std::set<peer_connection*>& peers_with_requests
10717
    , piece_picker::downloading_piece const& pi
10718
    , time_critical_piece* i
10719
    , piece_picker const* picker
10720
    , int const blocks_in_piece
10721
    , int const timed_out)
10722
0
  {
10723
0
    std::vector<piece_block> interesting_blocks;
10724
0
    std::vector<piece_block> backup1;
10725
0
    std::vector<piece_block> backup2;
10726
0
    std::vector<piece_index_t> ignore;
10727
10728
0
    time_point const now = aux::time_now();
10729
10730
    // loop until every block has been requested from this piece (i->piece)
10731
0
    do
10732
0
    {
10733
      // if this peer's download time exceeds 2 seconds, we're done.
10734
      // We don't want to build unreasonably long request queues
10735
0
      if (!peers.empty() && peers[0]->download_queue_time() > milliseconds(2000))
10736
0
      {
10737
#if TORRENT_DEBUG_STREAMING > 1
10738
        std::printf("queue time: %d ms, done\n"
10739
          , int(total_milliseconds(peers[0]->download_queue_time())));
10740
#endif
10741
0
        break;
10742
0
      }
10743
10744
      // pick the peer with the lowest download_queue_time that has i->piece
10745
0
      auto p = std::find_if(peers.begin(), peers.end()
10746
0
        , std::bind(&peer_connection::has_piece, _1, i->piece));
10747
10748
      // obviously we'll have to skip it if we don't have a peer that has
10749
      // this piece
10750
0
      if (p == peers.end())
10751
0
      {
10752
#if TORRENT_DEBUG_STREAMING > 1
10753
        std::printf("out of peers, done\n");
10754
#endif
10755
0
        break;
10756
0
      }
10757
0
      peer_connection& c = **p;
10758
10759
0
      interesting_blocks.clear();
10760
0
      backup1.clear();
10761
0
      backup2.clear();
10762
10763
      // specifically request blocks with no affinity towards fast or slow
10764
      // pieces. If we would, the picked block might end up in one of
10765
      // the backup lists
10766
0
      picker->add_blocks(i->piece, c.get_bitfield(), interesting_blocks
10767
0
        , backup1, backup2, blocks_in_piece, 0, c.peer_info_struct()
10768
0
        , ignore, {});
10769
10770
0
      interesting_blocks.insert(interesting_blocks.end()
10771
0
        , backup1.begin(), backup1.end());
10772
0
      interesting_blocks.insert(interesting_blocks.end()
10773
0
        , backup2.begin(), backup2.end());
10774
10775
0
      bool busy_mode = false;
10776
10777
0
      if (interesting_blocks.empty())
10778
0
      {
10779
0
        busy_mode = true;
10780
10781
#if TORRENT_DEBUG_STREAMING > 1
10782
        std::printf("interesting_blocks.empty()\n");
10783
#endif
10784
10785
        // there aren't any free blocks to pick, and the piece isn't
10786
        // old enough to pick busy blocks yet. break to continue to
10787
        // the next piece.
10788
0
        if (timed_out == 0)
10789
0
        {
10790
#if TORRENT_DEBUG_STREAMING > 1
10791
          std::printf("not timed out, moving on to next piece\n");
10792
#endif
10793
0
          break;
10794
0
        }
10795
10796
#if TORRENT_DEBUG_STREAMING > 1
10797
        std::printf("pick busy blocks\n");
10798
#endif
10799
10800
0
        pick_busy_blocks(picker, i->piece, blocks_in_piece, timed_out
10801
0
          , interesting_blocks, pi);
10802
0
      }
10803
10804
      // we can't pick anything from this piece, we're done with it.
10805
      // move on to the next one
10806
0
      if (interesting_blocks.empty()) break;
10807
10808
0
      piece_block const b = interesting_blocks.front();
10809
10810
      // in busy mode we need to make sure we don't do silly
10811
      // things like requesting the same block twice from the
10812
      // same peer
10813
0
      std::vector<pending_block> const& dq = c.download_queue();
10814
10815
0
      bool const already_requested = std::find_if(dq.begin(), dq.end()
10816
0
        , aux::has_block(b)) != dq.end();
10817
10818
0
      if (already_requested)
10819
0
      {
10820
        // if the piece is stalled, we may end up picking a block
10821
        // that we've already requested from this peer. If so, we should
10822
        // simply disregard this peer from this piece, since this peer
10823
        // is likely to be causing the stall. We should request it
10824
        // from the next peer in the list
10825
        // the peer will be put back in the set for the next piece
10826
0
        ignore_peers.push_back(*p);
10827
0
        peers.erase(p);
10828
#if TORRENT_DEBUG_STREAMING > 1
10829
        std::printf("piece already requested by peer, try next peer\n");
10830
#endif
10831
        // try next peer
10832
0
        continue;
10833
0
      }
10834
10835
0
      std::vector<pending_block> const& rq = c.request_queue();
10836
10837
0
      bool const already_in_queue = std::find_if(rq.begin(), rq.end()
10838
0
        , aux::has_block(b)) != rq.end();
10839
10840
0
      if (already_in_queue)
10841
0
      {
10842
0
        if (!c.make_time_critical(b))
10843
0
        {
10844
#if TORRENT_DEBUG_STREAMING > 1
10845
          std::printf("piece already time-critical and in queue for peer, trying next peer\n");
10846
#endif
10847
0
          ignore_peers.push_back(*p);
10848
0
          peers.erase(p);
10849
0
          continue;
10850
0
        }
10851
0
        i->last_requested = now;
10852
10853
#if TORRENT_DEBUG_STREAMING > 1
10854
        std::printf("piece already in queue for peer, making time-critical\n");
10855
#endif
10856
10857
        // we inserted a new block in the request queue, this
10858
        // makes us actually send it later
10859
0
        peers_with_requests.insert(peers_with_requests.begin(), &c);
10860
0
      }
10861
0
      else
10862
0
      {
10863
0
        if (!c.add_request(b, peer_connection::time_critical
10864
0
          | (busy_mode ? peer_connection::busy : request_flags_t{})))
10865
0
        {
10866
#if TORRENT_DEBUG_STREAMING > 1
10867
          std::printf("failed to request block [%d, %d]\n"
10868
            , b.piece_index, b.block_index);
10869
#endif
10870
0
          ignore_peers.push_back(*p);
10871
0
          peers.erase(p);
10872
0
          continue;
10873
0
        }
10874
10875
#if TORRENT_DEBUG_STREAMING > 1
10876
        std::printf("requested block [%d, %d]\n"
10877
          , b.piece_index, b.block_index);
10878
#endif
10879
0
        peers_with_requests.insert(peers_with_requests.begin(), &c);
10880
0
      }
10881
10882
0
      if (!busy_mode) i->last_requested = now;
10883
10884
0
      if (i->first_requested == min_time()) i->first_requested = now;
10885
10886
0
      if (!c.can_request_time_critical())
10887
0
      {
10888
#if TORRENT_DEBUG_STREAMING > 1
10889
        std::printf("peer cannot pick time critical pieces\n");
10890
#endif
10891
0
        peers.erase(p);
10892
        // try next peer
10893
0
        continue;
10894
0
      }
10895
10896
      // resort p, since it will have a higher download_queue_time now
10897
0
      while (p != peers.end()-1 && (*p)->download_queue_time()
10898
0
        > (*(p+1))->download_queue_time())
10899
0
      {
10900
0
        std::iter_swap(p, p+1);
10901
0
        ++p;
10902
0
      }
10903
0
    } while (!interesting_blocks.empty());
10904
0
  }
10905
10906
  } // anonymous namespace
10907
10908
  void torrent::request_time_critical_pieces()
10909
0
  {
10910
0
    TORRENT_ASSERT(is_single_thread());
10911
0
    TORRENT_ASSERT(!upload_mode());
10912
10913
    // build a list of peers and sort it by download_queue_time
10914
    // we use this sorted list to determine which peer we should
10915
    // request a block from. The earlier a peer is in the list,
10916
    // the sooner we will fully download the block we request.
10917
0
    aux::vector<peer_connection*> peers;
10918
0
    peers.reserve(num_peers());
10919
10920
    // some peers are marked as not being able to request time critical
10921
    // blocks from. For instance, peers that have choked us, peers that are
10922
    // on parole (i.e. they are believed to have sent us bad data), peers
10923
    // that are being disconnected, in upload mode etc.
10924
0
    std::remove_copy_if(m_connections.begin(), m_connections.end()
10925
0
      , std::back_inserter(peers), [] (peer_connection* p)
10926
0
      { return !p->can_request_time_critical(); });
10927
10928
    // sort by the time we believe it will take this peer to send us all
10929
    // blocks we've requested from it. The shorter time, the better candidate
10930
    // it is to request a time critical block from.
10931
0
    std::sort(peers.begin(), peers.end()
10932
0
      , [] (peer_connection const* lhs, peer_connection const* rhs)
10933
0
      { return lhs->download_queue_time(16*1024) < rhs->download_queue_time(16*1024); });
10934
10935
    // remove the bottom 10% of peers from the candidate set.
10936
    // this is just to remove outliers that might stall downloads
10937
0
    int const new_size = (peers.end_index() * 9 + 9) / 10;
10938
0
    TORRENT_ASSERT(new_size <= peers.end_index());
10939
0
    peers.resize(new_size);
10940
10941
    // remember all the peers we issued requests to, so we can commit them
10942
    // at the end of this function. Instead of sending the requests right
10943
    // away, we batch them up and send them in a single write to the TCP
10944
    // socket, increasing the chance that they will all be sent in the same
10945
    // packet.
10946
0
    std::set<peer_connection*> peers_with_requests;
10947
10948
    // peers that should be temporarily ignored for a specific piece
10949
    // in order to give priority to other peers. They should be used for
10950
    // subsequent pieces, so they are stored in this vector until the
10951
    // piece is done
10952
0
    std::vector<peer_connection*> ignore_peers;
10953
10954
0
    time_point const now = clock_type::now();
10955
10956
    // now, iterate over all time critical pieces, in order of importance, and
10957
    // request them from the peers, in order of responsiveness. i.e. request
10958
    // the most time critical pieces from the fastest peers.
10959
0
    bool first_piece{true};
10960
0
    for (auto& i : m_time_critical_pieces)
10961
0
    {
10962
#if TORRENT_DEBUG_STREAMING > 1
10963
      std::printf("considering %d\n", i->piece);
10964
#endif
10965
10966
0
      if (peers.empty())
10967
0
      {
10968
#if TORRENT_DEBUG_STREAMING > 1
10969
        std::printf("out of peers, done\n");
10970
#endif
10971
0
        break;
10972
0
      }
10973
10974
      // the +1000 is to compensate for the fact that we only call this
10975
      // function once per second, so if we need to request it 500 ms from
10976
      // now, we should request it right away
10977
0
      if (!first_piece && i.deadline > now
10978
0
        + milliseconds(m_average_piece_time + m_piece_time_deviation * 4 + 1000))
10979
0
      {
10980
        // don't request pieces whose deadline is too far in the future
10981
        // this is one of the termination conditions. We don't want to
10982
        // send requests for all pieces in the torrent right away
10983
#if TORRENT_DEBUG_STREAMING > 0
10984
        std::printf("reached deadline horizon [%f + %f * 4 + 1]\n"
10985
          , m_average_piece_time / 1000.f
10986
          , m_piece_time_deviation / 1000.f);
10987
#endif
10988
0
        break;
10989
0
      }
10990
0
      first_piece = false;
10991
10992
0
      piece_picker::downloading_piece pi;
10993
0
      m_picker->piece_info(i.piece, pi);
10994
10995
      // the number of "times" this piece has timed out.
10996
0
      int timed_out = 0;
10997
10998
0
      int const blocks_in_piece = m_picker->blocks_in_piece(i.piece);
10999
11000
#if TORRENT_DEBUG_STREAMING > 0
11001
      i.timed_out = timed_out;
11002
#endif
11003
0
      int const free_to_request = blocks_in_piece
11004
0
        - pi.finished - pi.writing - pi.requested;
11005
11006
0
      if (free_to_request == 0)
11007
0
      {
11008
0
        if (i.last_requested == min_time())
11009
0
          i.last_requested = now;
11010
11011
        // if it's been more than half of the typical download time
11012
        // of a piece since we requested the last block, allow
11013
        // one more request per block
11014
0
        if (m_average_piece_time > 0)
11015
0
          timed_out = int(total_milliseconds(now - i.last_requested)
11016
0
            / std::max(int(m_average_piece_time + m_piece_time_deviation / 2), 1));
11017
11018
#if TORRENT_DEBUG_STREAMING > 0
11019
        i.timed_out = timed_out;
11020
#endif
11021
        // every block in this piece is already requested
11022
        // there's no need to consider this piece, unless it
11023
        // appears to be stalled.
11024
0
        if (pi.requested == 0 || timed_out == 0)
11025
0
        {
11026
#if TORRENT_DEBUG_STREAMING > 1
11027
          std::printf("skipping %d (full) [req: %d timed_out: %d ]\n"
11028
            , i.piece, pi.requested
11029
            , timed_out);
11030
#endif
11031
11032
          // if requested is 0, it means all blocks have been received, and
11033
          // we're just waiting for it to flush them to disk.
11034
          // if last_requested is recent enough, we should give it some
11035
          // more time
11036
          // skip to the next piece
11037
0
          continue;
11038
0
        }
11039
11040
        // it's been too long since we requested the last block from
11041
        // this piece. Allow re-requesting blocks from this piece
11042
#if TORRENT_DEBUG_STREAMING > 1
11043
        std::printf("timed out [average-piece-time: %d ms ]\n"
11044
          , m_average_piece_time);
11045
#endif
11046
0
      }
11047
11048
      // pick all blocks for this piece. the peers list is kept up to date
11049
      // and sorted. when we issue a request to a peer, its download queue
11050
      // time will increase and it may need to be bumped in the peers list,
11051
      // since it's ordered by download queue time
11052
0
      pick_time_critical_block(peers, ignore_peers
11053
0
        , peers_with_requests
11054
0
        , pi, &i, m_picker.get()
11055
0
        , blocks_in_piece, timed_out);
11056
11057
      // put back the peers we ignored into the peer list for the next piece
11058
0
      if (!ignore_peers.empty())
11059
0
      {
11060
0
        peers.insert(peers.begin(), ignore_peers.begin(), ignore_peers.end());
11061
0
        ignore_peers.clear();
11062
11063
        // TODO: instead of resorting the whole list, insert the peers
11064
        // directly into the right place
11065
0
        std::sort(peers.begin(), peers.end()
11066
0
          , [] (peer_connection const* lhs, peer_connection const* rhs)
11067
0
          { return lhs->download_queue_time(16*1024) < rhs->download_queue_time(16*1024); });
11068
0
      }
11069
11070
      // if this peer's download time exceeds 2 seconds, we're done.
11071
      // We don't want to build unreasonably long request queues
11072
0
      if (!peers.empty() && peers[0]->download_queue_time() > milliseconds(2000))
11073
0
        break;
11074
0
    }
11075
11076
    // commit all the time critical requests
11077
0
    for (auto p : peers_with_requests)
11078
0
    {
11079
0
      p->send_block_requests();
11080
0
    }
11081
0
  }
11082
#endif // TORRENT_DISABLE_STREAMING
11083
11084
  std::set<std::string> torrent::web_seeds(web_seed_entry::type_t const type) const
11085
0
  {
11086
0
    TORRENT_ASSERT(is_single_thread());
11087
0
    std::set<std::string> ret;
11088
0
    for (auto const& s : m_web_seeds)
11089
0
    {
11090
0
      if (s.peer_info.banned) continue;
11091
0
      if (s.removed) continue;
11092
0
      if (s.type != type) continue;
11093
0
      ret.insert(s.url);
11094
0
    }
11095
0
    return ret;
11096
0
  }
11097
11098
  void torrent::remove_web_seed(std::string const& url, web_seed_entry::type_t const type)
11099
0
  {
11100
0
    auto const i = std::find_if(m_web_seeds.begin(), m_web_seeds.end()
11101
0
      , [&] (web_seed_t const& w) { return w.url == url && w.type == type; });
11102
11103
0
    if (i != m_web_seeds.end())
11104
0
    {
11105
0
      if (!i->ephemeral)
11106
0
        set_need_save_resume(torrent_handle::if_metadata_changed);
11107
0
      remove_web_seed_iter(i);
11108
0
    }
11109
0
  }
11110
11111
  void torrent::remove_web_seed_conn(peer_connection* p)
11112
0
  {
11113
0
    auto const i = std::find_if(m_web_seeds.begin(), m_web_seeds.end()
11114
0
      , [p] (web_seed_t const& ws) { return ws.peer_info.connection == p; });
11115
11116
0
    TORRENT_ASSERT(i != m_web_seeds.end());
11117
0
    if (i == m_web_seeds.end()) return;
11118
0
    remove_web_seed_iter(i);
11119
0
  }
11120
11121
  void torrent::retry_web_seed(peer_connection* p, boost::optional<seconds32> const retry)
11122
0
  {
11123
0
    TORRENT_ASSERT(is_single_thread());
11124
0
    auto const i = std::find_if(m_web_seeds.begin(), m_web_seeds.end()
11125
0
      , [p] (web_seed_t const& ws) { return ws.peer_info.connection == p; });
11126
11127
0
    TORRENT_ASSERT(i != m_web_seeds.end());
11128
0
    if (i == m_web_seeds.end()) return;
11129
0
    if (i->removed || i->disabled) return;
11130
0
    i->retry = aux::time_now32() + value_or(retry, seconds32(
11131
0
      settings().get_int(settings_pack::urlseed_wait_retry)));
11132
0
  }
11133
11134
  torrent_state torrent::get_peer_list_state()
11135
572
  {
11136
572
    torrent_state ret;
11137
572
    ret.is_finished = is_finished();
11138
572
    ret.allow_multiple_connections_per_ip = settings().get_bool(settings_pack::allow_multiple_connections_per_ip);
11139
572
    ret.max_peerlist_size = is_paused()
11140
572
      ? settings().get_int(settings_pack::max_paused_peerlist_size)
11141
572
      : settings().get_int(settings_pack::max_peerlist_size);
11142
572
    ret.min_reconnect_time = settings().get_int(settings_pack::min_reconnect_time);
11143
11144
572
    ret.ip = m_ses.external_address();
11145
572
    ret.port = m_ses.listen_port();
11146
572
    ret.max_failcount = settings().get_int(settings_pack::max_failcount);
11147
572
    return ret;
11148
572
  }
11149
11150
  bool torrent::try_connect_peer()
11151
0
  {
11152
0
    TORRENT_ASSERT(is_single_thread());
11153
0
    TORRENT_ASSERT(want_peers());
11154
11155
0
    torrent_state st = get_peer_list_state();
11156
0
    need_peer_list();
11157
0
    torrent_peer* p = m_peer_list->connect_one_peer(m_ses.session_time(), &st);
11158
0
    peers_erased(st.erased);
11159
0
    inc_stats_counter(counters::connection_attempt_loops, st.loop_counter);
11160
11161
0
    if (p == nullptr)
11162
0
    {
11163
0
      m_stats_counters.inc_stats_counter(counters::no_peer_connection_attempts);
11164
0
      update_want_peers();
11165
0
      return false;
11166
0
    }
11167
11168
0
    if (!connect_to_peer(p))
11169
0
    {
11170
0
      m_stats_counters.inc_stats_counter(counters::missed_connection_attempts);
11171
0
      m_peer_list->inc_failcount(p);
11172
0
      update_want_peers();
11173
0
      return false;
11174
0
    }
11175
0
    update_want_peers();
11176
11177
0
    return true;
11178
0
  }
11179
11180
  torrent_peer* torrent::add_peer(tcp::endpoint const& adr
11181
    , peer_source_flags_t const source, pex_flags_t flags)
11182
0
  {
11183
0
    TORRENT_ASSERT(is_single_thread());
11184
11185
0
    TORRENT_ASSERT(info_hash().has_v2() || !(flags & pex_lt_v2));
11186
11187
0
    if (m_apply_ip_filter
11188
0
      && m_ip_filter
11189
0
      && m_ip_filter->access(adr.address()) & ip_filter::blocked)
11190
0
    {
11191
0
      if (alerts().should_post<peer_blocked_alert>())
11192
0
        alerts().emplace_alert<peer_blocked_alert>(get_handle()
11193
0
          , adr, peer_blocked_alert::ip_filter);
11194
11195
0
#ifndef TORRENT_DISABLE_EXTENSIONS
11196
0
      notify_extension_add_peer(adr, source, torrent_plugin::filtered);
11197
0
#endif
11198
0
      return nullptr;
11199
0
    }
11200
11201
0
    if (m_ses.get_port_filter().access(adr.port()) & port_filter::blocked)
11202
0
    {
11203
0
      if (alerts().should_post<peer_blocked_alert>())
11204
0
        alerts().emplace_alert<peer_blocked_alert>(get_handle()
11205
0
          , adr, peer_blocked_alert::port_filter);
11206
0
#ifndef TORRENT_DISABLE_EXTENSIONS
11207
0
      notify_extension_add_peer(adr, source, torrent_plugin::filtered);
11208
0
#endif
11209
0
      return nullptr;
11210
0
    }
11211
11212
0
#if TORRENT_USE_I2P
11213
    // if this is an i2p torrent, and we don't allow mixed mode
11214
    // no regular peers should ever be added!
11215
0
    if (!settings().get_bool(settings_pack::allow_i2p_mixed) && is_i2p())
11216
0
    {
11217
0
      if (alerts().should_post<peer_blocked_alert>())
11218
0
        alerts().emplace_alert<peer_blocked_alert>(get_handle()
11219
0
          , adr, peer_blocked_alert::i2p_mixed);
11220
0
      return nullptr;
11221
0
    }
11222
0
#endif
11223
11224
0
    if (settings().get_bool(settings_pack::no_connect_privileged_ports) && adr.port() < 1024)
11225
0
    {
11226
0
      if (alerts().should_post<peer_blocked_alert>())
11227
0
        alerts().emplace_alert<peer_blocked_alert>(get_handle()
11228
0
          , adr, peer_blocked_alert::privileged_ports);
11229
0
#ifndef TORRENT_DISABLE_EXTENSIONS
11230
0
      notify_extension_add_peer(adr, source, torrent_plugin::filtered);
11231
0
#endif
11232
0
      return nullptr;
11233
0
    }
11234
11235
0
#ifndef TORRENT_DISABLE_DHT
11236
0
    if (source != peer_info::resume_data)
11237
0
    {
11238
      // try to send a DHT ping to this peer
11239
      // as well, to figure out if it supports
11240
      // DHT (uTorrent and BitComet don't
11241
      // advertise support)
11242
0
      session().add_dht_node({adr.address(), adr.port()});
11243
0
    }
11244
0
#endif
11245
11246
0
    if (!torrent_file().info_hashes().has_v1())
11247
0
      flags |= pex_lt_v2;
11248
11249
0
    need_peer_list();
11250
0
    torrent_state st = get_peer_list_state();
11251
0
    torrent_peer* p = m_peer_list->add_peer(adr, source, flags, &st);
11252
0
    peers_erased(st.erased);
11253
11254
0
    if (p)
11255
0
    {
11256
0
      state_updated();
11257
0
#ifndef TORRENT_DISABLE_EXTENSIONS
11258
0
      notify_extension_add_peer(adr, source
11259
0
        , st.first_time_seen
11260
0
          ? torrent_plugin::first_time
11261
0
          : add_peer_flags_t{});
11262
0
#endif
11263
0
    }
11264
0
    else
11265
0
    {
11266
0
#ifndef TORRENT_DISABLE_EXTENSIONS
11267
0
      notify_extension_add_peer(adr, source, torrent_plugin::filtered);
11268
0
#endif
11269
0
    }
11270
0
    update_want_peers();
11271
0
    state_updated();
11272
0
    return p;
11273
0
  }
11274
11275
  bool torrent::ban_peer(torrent_peer* tp)
11276
0
  {
11277
0
    if (!settings().get_bool(settings_pack::ban_web_seeds) && tp->web_seed)
11278
0
      return false;
11279
11280
0
    need_peer_list();
11281
0
    if (!m_peer_list->ban_peer(tp)) return false;
11282
0
    update_want_peers();
11283
11284
0
    inc_stats_counter(counters::num_banned_peers);
11285
0
    return true;
11286
0
  }
11287
11288
  void torrent::set_seed(torrent_peer* p, bool const s)
11289
2.88k
  {
11290
2.88k
    if (bool(p->seed) == s) return;
11291
68
    if (s)
11292
34
    {
11293
34
      TORRENT_ASSERT(m_num_seeds < 0xffff);
11294
34
      ++m_num_seeds;
11295
34
    }
11296
34
    else
11297
34
    {
11298
34
      TORRENT_ASSERT(m_num_seeds > 0);
11299
34
      --m_num_seeds;
11300
34
    }
11301
11302
68
    need_peer_list();
11303
68
    m_peer_list->set_seed(p, s);
11304
68
    update_auto_sequential();
11305
68
  }
11306
11307
  void torrent::clear_failcount(torrent_peer* p)
11308
282
  {
11309
282
    need_peer_list();
11310
282
    m_peer_list->set_failcount(p, 0);
11311
282
    update_want_peers();
11312
282
  }
11313
11314
  std::pair<peer_list::iterator, peer_list::iterator> torrent::find_peers(address const& a)
11315
0
  {
11316
0
    need_peer_list();
11317
0
    return m_peer_list->find_peers(a);
11318
0
  }
11319
11320
  void torrent::update_peer_port(int const port, torrent_peer* p
11321
    , peer_source_flags_t const src)
11322
8
  {
11323
8
    need_peer_list();
11324
8
    torrent_state st = get_peer_list_state();
11325
8
    m_peer_list->update_peer_port(port, p, src, &st);
11326
8
    peers_erased(st.erased);
11327
8
    update_want_peers();
11328
8
  }
11329
11330
  // verify piece is used when checking resume data or when the user
11331
  // adds a piece
11332
  void torrent::verify_piece(piece_index_t const piece)
11333
0
  {
11334
0
    TORRENT_ASSERT(m_storage);
11335
0
    TORRENT_ASSERT(!m_picker->is_hashing(piece));
11336
11337
    // we just completed the piece, it should be flushed to disk
11338
0
    disk_job_flags_t flags{};
11339
11340
0
    auto const write_mode = settings().get_int(settings_pack::disk_io_write_mode);
11341
0
    if (write_mode == settings_pack::write_through)
11342
0
      flags |= disk_interface::flush_piece;
11343
0
    else if (write_mode == settings_pack::disable_os_cache)
11344
0
      flags |= disk_interface::flush_piece | disk_interface::volatile_read;
11345
0
    if (torrent_file().info_hashes().has_v1())
11346
0
      flags |= disk_interface::v1_hash;
11347
11348
0
    aux::vector<sha256_hash> hashes;
11349
0
    if (torrent_file().info_hashes().has_v2())
11350
0
    {
11351
0
      hashes.resize(torrent_file().orig_files().blocks_in_piece2(piece));
11352
0
    }
11353
11354
0
    if (settings().get_bool(settings_pack::disable_hash_checks))
11355
0
    {
11356
      // short-circuit the hash check if it's disabled
11357
0
      m_picker->started_hash_job(piece);
11358
0
      on_piece_verified(std::move(hashes), piece, sha1_hash(), storage_error{});
11359
0
      return;
11360
0
    }
11361
11362
0
    span<sha256_hash> v2_span(hashes);
11363
0
    m_ses.disk_thread().async_hash(m_storage, piece, v2_span, flags
11364
0
      , [self = shared_from_this(), hashes1 = std::move(hashes)]
11365
0
      (piece_index_t p, sha1_hash const& h, storage_error const& error) mutable
11366
0
      { self->on_piece_verified(std::move(hashes1), p, h, error); });
11367
0
    m_picker->started_hash_job(piece);
11368
0
    m_ses.deferred_submit_jobs();
11369
0
  }
11370
11371
  aux::announce_entry* torrent::find_tracker(std::string const& url)
11372
0
  {
11373
0
    auto i = std::find_if(m_trackers.begin(), m_trackers.end()
11374
0
      , [&url](aux::announce_entry const& ae) { return ae.url == url; });
11375
0
    if (i == m_trackers.end()) return nullptr;
11376
0
    return &*i;
11377
0
  }
11378
11379
  void torrent::ip_filter_updated()
11380
608
  {
11381
608
    if (!m_apply_ip_filter) return;
11382
608
    if (!m_peer_list) return;
11383
0
    if (!m_ip_filter) return;
11384
11385
0
    torrent_state st = get_peer_list_state();
11386
0
    std::vector<address> banned;
11387
0
    m_peer_list->apply_ip_filter(*m_ip_filter, &st, banned);
11388
11389
0
    if (alerts().should_post<peer_blocked_alert>())
11390
0
    {
11391
0
      for (auto const& addr : banned)
11392
0
        alerts().emplace_alert<peer_blocked_alert>(get_handle()
11393
0
          , tcp::endpoint(addr, 0)
11394
0
          , peer_blocked_alert::ip_filter);
11395
0
    }
11396
11397
0
    peers_erased(st.erased);
11398
0
  }
11399
11400
  // this call will disconnect any peers whose remote port is < 1024
11401
  void torrent::privileged_port_updated()
11402
0
  {
11403
0
    if (!m_peer_list) return;
11404
11405
0
    port_filter ports;
11406
0
    ports.add_rule(0, 1023, port_filter::blocked);
11407
11408
0
    torrent_state st = get_peer_list_state();
11409
0
    std::vector<tcp::endpoint> banned;
11410
0
    m_peer_list->apply_port_filter(ports, &st, banned);
11411
11412
0
    if (alerts().should_post<peer_blocked_alert>())
11413
0
    {
11414
0
      for (auto const& ep : banned)
11415
0
        alerts().emplace_alert<peer_blocked_alert>(get_handle()
11416
0
          , ep, peer_blocked_alert::privileged_ports);
11417
0
    }
11418
11419
0
    peers_erased(st.erased);
11420
0
  }
11421
11422
  void torrent::port_filter_updated()
11423
0
  {
11424
0
    if (!m_peer_list) return;
11425
11426
0
    torrent_state st = get_peer_list_state();
11427
0
    std::vector<tcp::endpoint> banned;
11428
0
    m_peer_list->apply_port_filter(m_ses.get_port_filter(), &st, banned);
11429
11430
0
    if (alerts().should_post<peer_blocked_alert>())
11431
0
    {
11432
0
      for (auto const& ep : banned)
11433
0
        alerts().emplace_alert<peer_blocked_alert>(get_handle()
11434
0
          , ep, peer_blocked_alert::port_filter);
11435
0
    }
11436
11437
0
    peers_erased(st.erased);
11438
0
  }
11439
11440
  // this is called when torrent_peers are removed from the peer_list
11441
  // (peer-list). It removes any references we may have to those torrent_peers,
11442
  // so we don't leave then dangling
11443
  void torrent::peers_erased(std::vector<torrent_peer*> const& peers)
11444
572
  {
11445
572
    if (!has_picker()) return;
11446
11447
572
    for (auto const p : peers)
11448
0
    {
11449
0
      m_picker->clear_peer(p);
11450
0
    }
11451
#if TORRENT_USE_INVARIANT_CHECKS
11452
    m_picker->check_peers();
11453
#endif
11454
572
  }
11455
11456
#if TORRENT_ABI_VERSION == 1
11457
#if !TORRENT_NO_FPU
11458
  void torrent::file_progress_float(aux::vector<float, file_index_t>& fp)
11459
0
  {
11460
0
    TORRENT_ASSERT(is_single_thread());
11461
0
    if (!valid_metadata())
11462
0
    {
11463
0
      fp.clear();
11464
0
      return;
11465
0
    }
11466
11467
0
    fp.resize(m_torrent_file->num_files(), 1.f);
11468
0
    if (is_seed()) return;
11469
11470
0
    aux::vector<std::int64_t, file_index_t> progress;
11471
0
    file_progress(progress, {});
11472
0
    file_storage const& fs = m_torrent_file->files();
11473
0
    for (auto const i : fs.file_range())
11474
0
    {
11475
0
      std::int64_t file_size = m_torrent_file->files().file_size(i);
11476
0
      if (file_size == 0) fp[i] = 1.f;
11477
0
      else fp[i] = float(progress[i]) / float(file_size);
11478
0
    }
11479
0
  }
11480
#endif
11481
#endif // TORRENT_ABI_VERSION
11482
11483
  void torrent::post_file_progress(file_progress_flags_t const flags)
11484
0
  {
11485
0
    aux::vector<std::int64_t, file_index_t> fp;
11486
0
    file_progress(fp, flags);
11487
0
    alerts().emplace_alert<file_progress_alert>(get_handle(), std::move(fp));
11488
0
  }
11489
11490
  void torrent::file_progress(aux::vector<std::int64_t, file_index_t>& fp
11491
    , file_progress_flags_t const flags)
11492
0
  {
11493
0
    TORRENT_ASSERT(is_single_thread());
11494
0
    if (!valid_metadata())
11495
0
    {
11496
0
      fp.clear();
11497
0
      return;
11498
0
    }
11499
11500
    // if we're a seed, we don't have an m_file_progress anyway
11501
    // since we don't need one. We know we have all files
11502
    // just fill in the full file sizes as a shortcut
11503
0
    if (is_seed())
11504
0
    {
11505
0
      fp.resize(m_torrent_file->num_files());
11506
0
      file_storage const& fs = m_torrent_file->files();
11507
0
      for (auto const i : fs.file_range())
11508
0
        fp[i] = fs.file_size(i);
11509
0
      return;
11510
0
    }
11511
11512
0
    if (num_have() == 0 || m_file_progress.empty())
11513
0
    {
11514
      // if we don't have any pieces, just return zeroes
11515
0
      fp.clear();
11516
0
      fp.resize(m_torrent_file->num_files(), 0);
11517
0
    }
11518
0
    else
11519
0
    {
11520
0
      m_file_progress.export_progress(fp);
11521
0
    }
11522
11523
0
    if (flags & torrent_handle::piece_granularity)
11524
0
      return;
11525
11526
0
    if (!has_picker())
11527
0
      return;
11528
11529
0
    std::vector<piece_picker::downloading_piece> q = m_picker->get_download_queue();
11530
11531
0
    file_storage const& fs = m_torrent_file->files();
11532
0
    for (auto const& dp : q)
11533
0
    {
11534
0
      if (have_piece(dp.index))
11535
0
      {
11536
        // in this case this piece has already been accounted for in fp
11537
0
        continue;
11538
0
      }
11539
11540
0
      std::int64_t offset = std::int64_t(static_cast<int>(dp.index))
11541
0
        * m_torrent_file->piece_length();
11542
0
      file_index_t file = fs.file_index_at_offset(offset);
11543
0
      int idx = -1;
11544
0
      for (auto const& info : m_picker->blocks_for_piece(dp))
11545
0
      {
11546
0
        ++idx;
11547
0
        TORRENT_ASSERT(file < fs.end_file());
11548
0
        TORRENT_ASSERT(offset == std::int64_t(static_cast<int>(dp.index))
11549
0
          * m_torrent_file->piece_length()
11550
0
          + idx * block_size());
11551
0
        TORRENT_ASSERT(offset < m_torrent_file->total_size());
11552
0
        while (offset >= fs.file_offset(file) + fs.file_size(file))
11553
0
        {
11554
0
          ++file;
11555
0
        }
11556
0
        TORRENT_ASSERT(file < fs.end_file());
11557
11558
0
        std::int64_t block = block_size();
11559
11560
0
        if (info.state == piece_picker::block_info::state_none)
11561
0
        {
11562
0
          offset += block;
11563
0
          continue;
11564
0
        }
11565
11566
0
        if (info.state == piece_picker::block_info::state_requested)
11567
0
        {
11568
0
          block = 0;
11569
0
          torrent_peer* p = info.peer;
11570
0
          if (p != nullptr && p->connection)
11571
0
          {
11572
0
            auto* peer = static_cast<peer_connection*>(p->connection);
11573
0
            auto pbp = peer->downloading_piece_progress();
11574
0
            if (pbp.piece_index == dp.index && pbp.block_index == idx)
11575
0
              block = pbp.bytes_downloaded;
11576
0
            TORRENT_ASSERT(block <= block_size());
11577
0
          }
11578
11579
0
          if (block == 0)
11580
0
          {
11581
0
            offset += block_size();
11582
0
            continue;
11583
0
          }
11584
0
        }
11585
11586
0
        if (offset + block > fs.file_offset(file) + fs.file_size(file))
11587
0
        {
11588
0
          std::int64_t left_over = block_size() - block;
11589
          // split the block on multiple files
11590
0
          while (block > 0)
11591
0
          {
11592
0
            TORRENT_ASSERT(offset <= fs.file_offset(file) + fs.file_size(file));
11593
0
            std::int64_t const slice = std::min(fs.file_offset(file) + fs.file_size(file) - offset
11594
0
              , block);
11595
0
            TORRENT_ASSERT(fp[file] <= fs.file_size(file) - slice);
11596
0
            fp[file] += slice;
11597
0
            offset += slice;
11598
0
            block -= slice;
11599
0
            TORRENT_ASSERT(offset <= fs.file_offset(file) + fs.file_size(file));
11600
0
            if (offset == fs.file_offset(file) + fs.file_size(file))
11601
0
            {
11602
0
              ++file;
11603
0
              if (file == fs.end_file())
11604
0
              {
11605
0
                offset += block;
11606
0
                break;
11607
0
              }
11608
0
            }
11609
0
          }
11610
0
          offset += left_over;
11611
0
          TORRENT_ASSERT(offset == std::int64_t(static_cast<int>(dp.index))
11612
0
            * m_torrent_file->piece_length()
11613
0
            + (idx + 1) * block_size());
11614
0
        }
11615
0
        else
11616
0
        {
11617
0
          TORRENT_ASSERT(fp[file] <= fs.file_size(file) - block);
11618
0
          fp[file] += block;
11619
0
          offset += block_size();
11620
0
        }
11621
0
        TORRENT_ASSERT(file <= fs.end_file());
11622
0
      }
11623
0
    }
11624
0
  }
11625
11626
  void torrent::new_external_ip()
11627
1
  {
11628
1
    if (m_peer_list) m_peer_list->clear_peer_prio();
11629
1
  }
11630
11631
  void torrent::stop_when_ready(bool const b)
11632
0
  {
11633
0
    m_stop_when_ready = b;
11634
11635
    // to avoid race condition, if we're already in a downloading state,
11636
    // trigger the stop-when-ready logic immediately.
11637
0
    if (m_stop_when_ready && is_downloading_state(m_state))
11638
0
    {
11639
#ifndef TORRENT_DISABLE_LOGGING
11640
      debug_log("stop_when_ready triggered");
11641
#endif
11642
0
      auto_managed(false);
11643
0
      pause();
11644
0
      m_stop_when_ready = false;
11645
0
    }
11646
0
  }
11647
11648
  void torrent::set_state(torrent_status::state_t const s)
11649
3.13k
  {
11650
3.13k
    TORRENT_ASSERT(is_single_thread());
11651
3.13k
    TORRENT_ASSERT(s != 0); // this state isn't used anymore
11652
11653
3.13k
#if TORRENT_USE_ASSERTS
11654
11655
3.13k
    if (s == torrent_status::seeding)
11656
183
    {
11657
183
      TORRENT_ASSERT(is_seed());
11658
183
      TORRENT_ASSERT(is_finished());
11659
183
    }
11660
3.13k
    if (s == torrent_status::finished)
11661
553
      TORRENT_ASSERT(is_finished());
11662
3.13k
    if (s == torrent_status::downloading && m_state == torrent_status::finished)
11663
0
      TORRENT_ASSERT(!is_finished());
11664
3.13k
#endif
11665
11666
3.13k
    if (int(m_state) == s) return;
11667
11668
1.25k
    if (m_ses.alerts().should_post<state_changed_alert>())
11669
2
    {
11670
2
      m_ses.alerts().emplace_alert<state_changed_alert>(get_handle()
11671
2
        , s, static_cast<torrent_status::state_t>(m_state));
11672
2
    }
11673
11674
1.25k
    if (s == torrent_status::finished
11675
1.25k
      && alerts().should_post<torrent_finished_alert>())
11676
0
    {
11677
0
      alerts().emplace_alert<torrent_finished_alert>(
11678
0
        get_handle());
11679
0
    }
11680
11681
1.25k
    bool const trigger_stop = m_stop_when_ready
11682
1.25k
      && !is_downloading_state(m_state)
11683
1.25k
      && is_downloading_state(s);
11684
11685
    // we need to update the state before calling pause(), because otherwise
11686
    // it may think we're still checking files, even though we're just
11687
    // leaving that state
11688
1.25k
    m_state = s;
11689
11690
1.25k
    update_gauge();
11691
1.25k
    update_want_peers();
11692
1.25k
    update_want_tick();
11693
1.25k
    update_state_list();
11694
11695
1.25k
    state_updated();
11696
11697
#ifndef TORRENT_DISABLE_LOGGING
11698
    debug_log("set_state() %d", m_state);
11699
#endif
11700
11701
1.25k
    if (trigger_stop)
11702
446
    {
11703
#ifndef TORRENT_DISABLE_LOGGING
11704
      debug_log("stop_when_ready triggered");
11705
#endif
11706
      // stop_when_ready is set, and we're transitioning from a downloading
11707
      // state to a non-downloading state. pause the torrent. Note that
11708
      // "downloading" is defined broadly to include any state where we
11709
      // either upload or download (for the purpose of this flag).
11710
446
      auto_managed(false);
11711
446
      pause();
11712
446
      m_stop_when_ready = false;
11713
446
    }
11714
11715
1.25k
#ifndef TORRENT_DISABLE_EXTENSIONS
11716
1.25k
    for (auto& ext : m_extensions)
11717
6
    {
11718
6
      ext->on_state(state());
11719
6
    }
11720
1.25k
#endif
11721
1.25k
  }
11722
11723
#ifndef TORRENT_DISABLE_EXTENSIONS
11724
  void torrent::notify_extension_add_peer(tcp::endpoint const& ip
11725
    , peer_source_flags_t const src, add_peer_flags_t const flags)
11726
0
  {
11727
0
    for (auto& ext : m_extensions)
11728
0
    {
11729
0
      ext->on_add_peer(ip, src, flags);
11730
0
    }
11731
0
  }
11732
#endif
11733
11734
  void torrent::state_updated()
11735
10.8k
  {
11736
    // if this fails, this function is probably called
11737
    // from within the torrent constructor, which it
11738
    // shouldn't be. Whichever function ends up calling
11739
    // this should probably be moved to torrent::start()
11740
10.8k
    TORRENT_ASSERT(shared_from_this());
11741
11742
    // we can't call state_updated() while the session
11743
    // is building the status update alert
11744
10.8k
    TORRENT_ASSERT(!m_ses.is_posting_torrent_updates());
11745
11746
    // we're not subscribing to this torrent, don't add it
11747
10.8k
    if (!m_state_subscription) return;
11748
11749
4.18k
    aux::vector<torrent*>& list = m_ses.torrent_list(aux::session_interface::torrent_state_updates);
11750
11751
    // if it has already been updated this round, no need to
11752
    // add it to the list twice
11753
4.18k
    if (m_links[aux::session_interface::torrent_state_updates].in_list())
11754
3.60k
    {
11755
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
11756
      TORRENT_ASSERT(find(list.begin(), list.end(), this) != list.end());
11757
#endif
11758
3.60k
      return;
11759
3.60k
    }
11760
11761
#ifdef TORRENT_EXPENSIVE_INVARIANT_CHECKS
11762
    TORRENT_ASSERT(find(list.begin(), list.end(), this) == list.end());
11763
#endif
11764
11765
584
    m_links[aux::session_interface::torrent_state_updates].insert(list, this);
11766
584
  }
11767
11768
  void torrent::post_status(status_flags_t const flags)
11769
0
  {
11770
0
    std::vector<torrent_status> s;
11771
0
    s.resize(1);
11772
0
    status(&s.front(), flags);
11773
0
    m_ses.alerts().emplace_alert<state_update_alert>(std::move(s));
11774
0
  }
11775
11776
  void torrent::status(torrent_status* st, status_flags_t const flags)
11777
0
  {
11778
0
    INVARIANT_CHECK;
11779
11780
0
    time_point32 const now = aux::time_now32();
11781
11782
0
    st->handle = get_handle();
11783
0
    st->info_hashes = info_hash();
11784
0
#if TORRENT_ABI_VERSION < 3
11785
0
    st->info_hash = info_hash().get_best();
11786
0
#endif
11787
0
#if TORRENT_ABI_VERSION == 1
11788
0
    st->is_loaded = true;
11789
0
#endif
11790
11791
0
    if (flags & torrent_handle::query_name)
11792
0
      st->name = name();
11793
11794
0
    if (flags & torrent_handle::query_save_path)
11795
0
      st->save_path = save_path();
11796
11797
0
    if (flags & torrent_handle::query_torrent_file)
11798
0
      st->torrent_file = m_torrent_file;
11799
11800
0
    st->has_incoming = m_has_incoming;
11801
0
    st->errc = m_error;
11802
0
    st->error_file = m_error_file;
11803
11804
0
#if TORRENT_ABI_VERSION == 1
11805
0
    if (m_error) st->error = convert_from_native(m_error.message())
11806
0
      + ": " + resolve_filename(m_error_file);
11807
0
    st->seed_mode = m_seed_mode;
11808
0
#endif
11809
0
    st->moving_storage = m_moving_storage;
11810
11811
0
    st->announcing_to_trackers = m_announce_to_trackers;
11812
0
    st->announcing_to_lsd = m_announce_to_lsd;
11813
0
    st->announcing_to_dht = m_announce_to_dht;
11814
0
#if TORRENT_ABI_VERSION == 1
11815
0
    st->stop_when_ready = m_stop_when_ready;
11816
0
#endif
11817
11818
0
    st->added_time = m_added_time;
11819
0
    st->completed_time = m_completed_time;
11820
11821
0
#if TORRENT_ABI_VERSION == 1
11822
0
    st->last_scrape = static_cast<int>(total_seconds(now - m_last_scrape));
11823
0
#endif
11824
11825
0
#if TORRENT_ABI_VERSION == 1
11826
0
#ifndef TORRENT_DISABLE_SHARE_MODE
11827
0
    st->share_mode = m_share_mode;
11828
#else
11829
    st->share_mode = false;
11830
#endif
11831
0
    st->upload_mode = m_upload_mode;
11832
0
#endif
11833
0
    st->up_bandwidth_queue = 0;
11834
0
    st->down_bandwidth_queue = 0;
11835
0
#if TORRENT_ABI_VERSION == 1
11836
0
    st->priority = priority();
11837
0
#endif
11838
11839
0
    st->num_peers = num_peers() - m_num_connecting;
11840
11841
0
    st->list_peers = m_peer_list ? m_peer_list->num_peers() : 0;
11842
0
    st->list_seeds = m_peer_list ? m_peer_list->num_seeds() : 0;
11843
0
    st->connect_candidates = m_peer_list ? m_peer_list->num_connect_candidates() : 0;
11844
0
    TORRENT_ASSERT(st->connect_candidates >= 0);
11845
0
    st->seed_rank = seed_rank(settings());
11846
11847
0
    st->all_time_upload = m_total_uploaded;
11848
0
    st->all_time_download = m_total_downloaded;
11849
11850
    // activity time
11851
0
#if TORRENT_ABI_VERSION == 1
11852
0
    st->finished_time = int(total_seconds(finished_time()));
11853
0
    st->active_time = int(total_seconds(active_time()));
11854
0
    st->seeding_time = int(total_seconds(seeding_time()));
11855
11856
0
    time_point32 const unset{seconds32(0)};
11857
11858
0
    st->time_since_upload = m_last_upload == unset ? -1
11859
0
      : static_cast<int>(total_seconds(now - m_last_upload));
11860
0
    st->time_since_download = m_last_download == unset ? -1
11861
0
      : static_cast<int>(total_seconds(now - m_last_download));
11862
0
#endif
11863
11864
0
    st->finished_duration = finished_time();
11865
0
    st->active_duration = active_time();
11866
0
    st->seeding_duration = seeding_time();
11867
11868
0
    st->last_upload = m_last_upload;
11869
0
    st->last_download = m_last_download;
11870
11871
0
    st->storage_mode = static_cast<storage_mode_t>(m_storage_mode);
11872
11873
0
    st->num_complete = (m_complete == 0xffffff) ? -1 : m_complete;
11874
0
    st->num_incomplete = (m_incomplete == 0xffffff) ? -1 : m_incomplete;
11875
0
#if TORRENT_ABI_VERSION == 1
11876
0
    st->paused = is_torrent_paused();
11877
0
    st->auto_managed = m_auto_managed;
11878
0
    st->sequential_download = m_sequential_download;
11879
0
#endif
11880
0
    st->is_seeding = is_seed();
11881
0
    st->is_finished = is_finished();
11882
0
#if TORRENT_ABI_VERSION == 1
11883
0
#ifndef TORRENT_DISABLE_SUPERSEEDING
11884
0
    st->super_seeding = m_super_seeding;
11885
0
#endif
11886
0
#endif
11887
0
    st->has_metadata = valid_metadata();
11888
0
    bytes_done(*st, flags);
11889
0
    TORRENT_ASSERT(st->total_wanted_done >= 0);
11890
0
    TORRENT_ASSERT(st->total_done >= st->total_wanted_done);
11891
11892
    // payload transfer
11893
0
    st->total_payload_download = m_stat.total_payload_download();
11894
0
    st->total_payload_upload = m_stat.total_payload_upload();
11895
11896
    // total transfer
11897
0
    st->total_download = m_stat.total_payload_download()
11898
0
      + m_stat.total_protocol_download();
11899
0
    st->total_upload = m_stat.total_payload_upload()
11900
0
      + m_stat.total_protocol_upload();
11901
11902
    // failed bytes
11903
0
    st->total_failed_bytes = m_total_failed_bytes;
11904
0
    st->total_redundant_bytes = m_total_redundant_bytes;
11905
11906
    // transfer rate
11907
0
    st->download_rate = m_stat.download_rate();
11908
0
    st->upload_rate = m_stat.upload_rate();
11909
0
    st->download_payload_rate = m_stat.download_payload_rate();
11910
0
    st->upload_payload_rate = m_stat.upload_payload_rate();
11911
11912
0
    if (is_paused() || m_tracker_timer.expiry() < now)
11913
0
      st->next_announce = seconds(0);
11914
0
    else
11915
0
      st->next_announce = m_tracker_timer.expiry() - now;
11916
11917
0
    if (st->next_announce.count() < 0)
11918
0
      st->next_announce = seconds(0);
11919
11920
0
#if TORRENT_ABI_VERSION == 1
11921
0
    st->announce_interval = seconds(0);
11922
0
#endif
11923
11924
0
    st->current_tracker.clear();
11925
0
    if (m_last_working_tracker >= 0)
11926
0
    {
11927
0
      TORRENT_ASSERT(m_last_working_tracker < m_trackers.end_index());
11928
0
      const int i = m_last_working_tracker;
11929
0
      st->current_tracker = m_trackers[i].url;
11930
0
    }
11931
0
    else
11932
0
    {
11933
0
#ifdef __clang__
11934
0
#pragma clang diagnostic push
11935
0
#pragma clang diagnostic ignored "-Wmissing-braces"
11936
0
#endif
11937
0
      aux::array<bool const, num_protocols, protocol_version> const supports_protocol{
11938
0
      {
11939
0
        m_info_hash.has_v1(),
11940
0
        m_info_hash.has_v2()
11941
0
      }};
11942
0
#ifdef __clang__
11943
0
#pragma clang diagnostic pop
11944
0
#endif
11945
11946
0
      for (auto const& t : m_trackers)
11947
0
      {
11948
0
        if (std::any_of(t.endpoints.begin(), t.endpoints.end()
11949
0
          , [supports_protocol](aux::announce_endpoint const& aep) {
11950
0
            for (protocol_version const ih : all_versions)
11951
0
            {
11952
0
              if (supports_protocol[ih] && aep.info_hashes[ih].updating)
11953
0
                return false;
11954
0
            }
11955
0
            return true;
11956
0
          })) continue;
11957
0
        if (!t.verified) continue;
11958
0
        st->current_tracker = t.url;
11959
0
        break;
11960
0
      }
11961
0
    }
11962
11963
0
    if ((flags & torrent_handle::query_verified_pieces))
11964
0
    {
11965
0
      st->verified_pieces = m_verified;
11966
0
    }
11967
11968
0
    st->num_uploads = m_num_uploads;
11969
0
    st->uploads_limit = m_max_uploads == (1 << 24) - 1 ? -1 : m_max_uploads;
11970
0
    st->num_connections = num_peers();
11971
0
    st->connections_limit = m_max_connections == (1 << 24) - 1 ? -1 : m_max_connections;
11972
    // if we don't have any metadata, stop here
11973
11974
0
    st->queue_position = queue_position();
11975
0
    st->need_save_resume = bool(m_need_save_resume_data);
11976
0
#if TORRENT_ABI_VERSION == 1
11977
0
    st->ip_filter_applies = m_apply_ip_filter;
11978
0
#endif
11979
11980
0
    st->state = static_cast<torrent_status::state_t>(m_state);
11981
0
    st->flags = this->flags();
11982
11983
0
#if TORRENT_USE_ASSERTS
11984
0
    if (st->state == torrent_status::finished
11985
0
      || st->state == torrent_status::seeding)
11986
0
    {
11987
      // it may be tempting to assume that st->is_finished == true here, but
11988
      // this assumption does not always hold. We transition to "finished"
11989
      // when we receive the last block of the last piece, which is before
11990
      // the hash check comes back. "is_finished" is set to true once all the
11991
      // pieces have been hash checked. So, there's a short window where it
11992
      // doesn't hold.
11993
0
    }
11994
0
#endif
11995
11996
0
    if (!valid_metadata())
11997
0
    {
11998
0
      st->state = torrent_status::downloading_metadata;
11999
0
      st->progress_ppm = m_progress_ppm;
12000
0
#if !TORRENT_NO_FPU
12001
0
      st->progress = m_progress_ppm / 1000000.f;
12002
0
#endif
12003
0
      st->block_size = 0;
12004
0
      return;
12005
0
    }
12006
12007
0
    st->block_size = block_size();
12008
12009
0
    if (m_state == torrent_status::checking_files)
12010
0
    {
12011
0
      st->progress_ppm = m_progress_ppm;
12012
0
#if !TORRENT_NO_FPU
12013
0
      st->progress = m_progress_ppm / 1000000.f;
12014
0
#endif
12015
0
    }
12016
0
    else if (st->total_wanted == 0)
12017
0
    {
12018
0
      st->progress_ppm = 1000000;
12019
0
      st->progress = 1.f;
12020
0
    }
12021
0
    else
12022
0
    {
12023
0
      st->progress_ppm = int(st->total_wanted_done * 1000000
12024
0
        / st->total_wanted);
12025
0
#if !TORRENT_NO_FPU
12026
0
      st->progress = float(st->progress_ppm) / 1000000.f;
12027
0
#endif
12028
0
    }
12029
12030
0
    if (flags & torrent_handle::query_pieces)
12031
0
    {
12032
0
      int const num_pieces = m_torrent_file->num_pieces();
12033
0
      if (has_picker())
12034
0
      {
12035
0
        st->pieces.resize(num_pieces, false);
12036
0
        for (auto const i : st->pieces.range())
12037
0
          if (m_picker->have_piece(i)) st->pieces.set_bit(i);
12038
0
      }
12039
0
      else if (m_have_all)
12040
0
      {
12041
0
        st->pieces.resize(num_pieces, true);
12042
0
      }
12043
0
      else
12044
0
      {
12045
0
        st->pieces.resize(num_pieces, false);
12046
0
      }
12047
0
    }
12048
0
    st->num_pieces = num_have();
12049
#if TORRENT_USE_INVARIANT_CHECKS
12050
    {
12051
      // The documentation states that `num_pieces` is the count of number
12052
      // of bits set in `pieces`. Ensure that invariant holds.
12053
      int num_have_pieces = 0;
12054
      if (m_seed_mode)
12055
      {
12056
        num_have_pieces = m_torrent_file->num_pieces();
12057
      }
12058
      else if (has_picker())
12059
      {
12060
        for (auto const i : m_torrent_file->piece_range())
12061
          if (m_picker->have_piece(i)) ++num_have_pieces;
12062
      }
12063
      else if (m_have_all)
12064
      {
12065
        num_have_pieces = m_torrent_file->num_pieces();
12066
      }
12067
      TORRENT_ASSERT(num_have_pieces == st->num_pieces);
12068
    }
12069
#endif
12070
0
    st->num_seeds = num_seeds();
12071
0
    if ((flags & torrent_handle::query_distributed_copies) && m_picker.get())
12072
0
    {
12073
0
      std::tie(st->distributed_full_copies, st->distributed_fraction) =
12074
0
        m_picker->distributed_copies();
12075
#if TORRENT_NO_FPU
12076
      st->distributed_copies = -1.f;
12077
#else
12078
0
      st->distributed_copies = float(st->distributed_full_copies)
12079
0
        + float(st->distributed_fraction) / 1000;
12080
0
#endif
12081
0
    }
12082
0
    else
12083
0
    {
12084
0
      st->distributed_full_copies = -1;
12085
0
      st->distributed_fraction = -1;
12086
0
      st->distributed_copies = -1.f;
12087
0
    }
12088
12089
0
    st->last_seen_complete = m_swarm_last_seen_complete;
12090
0
  }
12091
12092
  int torrent::priority() const
12093
0
  {
12094
0
    int priority = 0;
12095
0
    for (int i = 0; i < num_classes(); ++i)
12096
0
    {
12097
0
      int const* prio = m_ses.peer_classes().at(class_at(i))->priority;
12098
0
      priority = std::max(priority, prio[peer_connection::upload_channel]);
12099
0
      priority = std::max(priority, prio[peer_connection::download_channel]);
12100
0
    }
12101
0
    return priority;
12102
0
  }
12103
12104
#if TORRENT_ABI_VERSION == 1
12105
  void torrent::set_priority(int const prio)
12106
0
  {
12107
    // priority 1 is default
12108
0
    if (prio == 1 && m_peer_class == peer_class_t{}) return;
12109
12110
0
    if (m_peer_class == peer_class_t{})
12111
0
      setup_peer_class();
12112
12113
0
    struct peer_class* tpc = m_ses.peer_classes().at(m_peer_class);
12114
0
    TORRENT_ASSERT(tpc);
12115
0
    tpc->priority[peer_connection::download_channel] = prio;
12116
0
    tpc->priority[peer_connection::upload_channel] = prio;
12117
12118
0
    state_updated();
12119
0
  }
12120
#endif
12121
12122
  void torrent::add_redundant_bytes(int const b, waste_reason const reason)
12123
42
  {
12124
42
    TORRENT_ASSERT(is_single_thread());
12125
42
    TORRENT_ASSERT(b > 0);
12126
42
    TORRENT_ASSERT(static_cast<int>(reason) >= 0);
12127
42
    TORRENT_ASSERT(static_cast<int>(reason) < static_cast<int>(waste_reason::max));
12128
12129
42
    if (m_total_redundant_bytes <= std::numeric_limits<std::int64_t>::max() - b)
12130
42
      m_total_redundant_bytes += b;
12131
0
    else
12132
0
      m_total_redundant_bytes = std::numeric_limits<std::int64_t>::max();
12133
12134
    // the stats counters are 64 bits, so we don't check for overflow there
12135
42
    m_stats_counters.inc_stats_counter(counters::recv_redundant_bytes, b);
12136
42
    m_stats_counters.inc_stats_counter(counters::waste_piece_timed_out + static_cast<int>(reason), b);
12137
42
  }
12138
12139
  void torrent::add_failed_bytes(int const b)
12140
0
  {
12141
0
    TORRENT_ASSERT(is_single_thread());
12142
0
    TORRENT_ASSERT(b > 0);
12143
0
    if (m_total_failed_bytes <= std::numeric_limits<std::int64_t>::max() - b)
12144
0
      m_total_failed_bytes += b;
12145
0
    else
12146
0
      m_total_failed_bytes = std::numeric_limits<std::int64_t>::max();
12147
12148
    // the stats counters are 64 bits, so we don't check for overflow there
12149
0
    m_stats_counters.inc_stats_counter(counters::recv_failed_bytes, b);
12150
0
  }
12151
12152
  // the number of connected peers that are seeds
12153
  int torrent::num_seeds() const
12154
0
  {
12155
0
    TORRENT_ASSERT(is_single_thread());
12156
0
    INVARIANT_CHECK;
12157
12158
0
    return int(m_num_seeds) - int(m_num_connecting_seeds);
12159
0
  }
12160
12161
  // the number of connected peers that are not seeds
12162
  int torrent::num_downloaders() const
12163
0
  {
12164
0
    TORRENT_ASSERT(is_single_thread());
12165
0
    INVARIANT_CHECK;
12166
12167
0
    int const ret = num_peers()
12168
0
      - m_num_seeds
12169
0
      - m_num_connecting
12170
0
      + m_num_connecting_seeds;
12171
0
    TORRENT_ASSERT(ret >= 0);
12172
0
    return ret;
12173
0
  }
12174
12175
  void torrent::tracker_request_error(tracker_request const& r
12176
    , error_code const& ec, operation_t const op, std::string const& msg
12177
    , seconds32 const retry_interval)
12178
0
  {
12179
0
    TORRENT_ASSERT(is_single_thread());
12180
12181
0
    INVARIANT_CHECK;
12182
12183
// some older versions of clang had a bug where it would fire this warning here
12184
0
#ifdef __clang__
12185
0
#pragma clang diagnostic push
12186
0
#pragma clang diagnostic ignored "-Wmissing-braces"
12187
0
#endif
12188
0
    aux::array<bool const, num_protocols, protocol_version> const supports_protocol
12189
0
    { {
12190
0
      m_info_hash.has_v1(),
12191
0
      m_info_hash.has_v2()
12192
0
    } };
12193
0
#ifdef __clang__
12194
0
#pragma clang diagnostic pop
12195
0
#endif
12196
12197
#ifndef TORRENT_DISABLE_LOGGING
12198
    if (should_log())
12199
    {
12200
      debug_log("*** tracker error: (%d) %s [%s] %s", ec.value()
12201
        , ec.message().c_str(), operation_name(op), msg.c_str());
12202
    }
12203
#endif
12204
0
    if (!(r.kind & tracker_request::scrape_request))
12205
0
    {
12206
      // announce request
12207
0
      aux::announce_entry* ae = find_tracker(r.url);
12208
0
      int fails = 0;
12209
0
      tcp::endpoint local_endpoint;
12210
0
      protocol_version hash_version = protocol_version::V1;
12211
0
      if (ae)
12212
0
      {
12213
0
        auto aep = std::find_if(ae->endpoints.begin(), ae->endpoints.end()
12214
0
          , [&](aux::announce_endpoint const& e) { return e.socket == r.outgoing_socket; });
12215
12216
0
        if (aep != ae->endpoints.end())
12217
0
        {
12218
0
          hash_version = r.info_hash == m_info_hash.v1
12219
0
            ? protocol_version::V1 : protocol_version::V2;
12220
0
          auto& a = aep->info_hashes[hash_version];
12221
0
          local_endpoint = aep->local_endpoint;
12222
0
          a.failed(settings().get_int(settings_pack::tracker_backoff)
12223
0
            , retry_interval);
12224
0
          a.last_error = ec;
12225
0
          a.message = msg;
12226
0
          fails = a.fails;
12227
12228
#ifndef TORRENT_DISABLE_LOGGING
12229
          debug_log("*** increment tracker fail count [ep: %s url: %s %d]"
12230
            , print_endpoint(aep->local_endpoint).c_str(), r.url.c_str(), a.fails);
12231
#endif
12232
0
          if (ec == boost::system::errc::address_family_not_supported)
12233
0
          {
12234
            // don't try to announce from this endpoint again
12235
0
            aep->enabled = false;
12236
#ifndef TORRENT_DISABLE_LOGGING
12237
            debug_log("*** disabling endpoint [ep: %s url: %s ]"
12238
              , print_endpoint(aep->local_endpoint).c_str(), r.url.c_str());
12239
#endif
12240
0
          }
12241
0
        }
12242
0
        else if (r.outgoing_socket)
12243
0
        {
12244
#ifndef TORRENT_DISABLE_LOGGING
12245
          debug_log("*** no matching endpoint for request [%s, %s]"
12246
            , r.url.c_str(), print_endpoint(r.outgoing_socket.get_local_endpoint()).c_str());
12247
#endif
12248
0
        }
12249
12250
0
        int const tracker_index = int(ae - m_trackers.data());
12251
12252
        // never talk to this tracker again
12253
0
        if (ec == error_code(410, http_category())) ae->fail_limit = 1;
12254
12255
        // if all endpoints fail, then we de-prioritize the tracker and try
12256
        // the next one in the tier
12257
0
        if (std::all_of(ae->endpoints.begin(), ae->endpoints.end()
12258
0
          , [&](aux::announce_endpoint const& ep)
12259
0
          {
12260
0
            for (protocol_version const ih : all_versions)
12261
0
              if (supports_protocol[ih] && ep.info_hashes[ih].is_working())
12262
0
                return false;
12263
0
            return true;
12264
0
          }))
12265
0
        {
12266
0
          deprioritize_tracker(tracker_index);
12267
0
        }
12268
0
      }
12269
0
      if (m_ses.alerts().should_post<tracker_error_alert>()
12270
0
        || r.triggered_manually)
12271
0
      {
12272
0
        m_ses.alerts().emplace_alert<tracker_error_alert>(get_handle()
12273
0
          , local_endpoint, fails, hash_version, r.url, op, ec, msg);
12274
0
      }
12275
0
    }
12276
0
    else
12277
0
    {
12278
0
      aux::announce_entry* ae = find_tracker(r.url);
12279
12280
      // scrape request
12281
0
      if (ec == error_code(410, http_category()))
12282
0
      {
12283
        // never talk to this tracker again
12284
0
        if (ae != nullptr) ae->fail_limit = 1;
12285
0
      }
12286
12287
      // if this was triggered manually we need to post this unconditionally,
12288
      // since the client expects a response from its action, regardless of
12289
      // whether all tracker events have been enabled by the alert mask
12290
0
      if (m_ses.alerts().should_post<scrape_failed_alert>()
12291
0
        || r.triggered_manually)
12292
0
      {
12293
0
        tcp::endpoint local_endpoint;
12294
0
        if (ae != nullptr)
12295
0
        {
12296
0
          auto* aep = ae->find_endpoint(r.outgoing_socket);
12297
0
          if (aep != nullptr) local_endpoint = aep->local_endpoint;
12298
0
        }
12299
12300
0
        protocol_version hash_version = r.info_hash == m_info_hash.v1
12301
0
          ? protocol_version::V1 : protocol_version::V2;
12302
12303
0
        m_ses.alerts().emplace_alert<scrape_failed_alert>(get_handle()
12304
0
          , local_endpoint, r.url, hash_version, ec);
12305
0
      }
12306
0
    }
12307
    // announce to the next working tracker
12308
    // We may have changed state into checking by now, in which case we
12309
    // shouldn't keep trying to announce
12310
0
    if ((!m_abort && !is_paused() && state() != torrent_status::checking_files)
12311
0
      || r.event == event_t::stopped)
12312
0
    {
12313
0
      announce_with_tracker(r.event);
12314
0
    }
12315
0
    else
12316
0
    {
12317
0
      update_tracker_timer(aux::time_now32());
12318
0
    }
12319
0
  }
12320
12321
#ifndef TORRENT_DISABLE_LOGGING
12322
  bool torrent::should_log() const
12323
  {
12324
    return alerts().should_post<torrent_log_alert>();
12325
  }
12326
12327
  TORRENT_FORMAT(2,3)
12328
  void torrent::debug_log(char const* fmt, ...) const noexcept try
12329
  {
12330
    if (!alerts().should_post<torrent_log_alert>()) return;
12331
12332
    va_list v;
12333
    va_start(v, fmt);
12334
    alerts().emplace_alert<torrent_log_alert>(
12335
      const_cast<torrent*>(this)->get_handle(), fmt, v);
12336
    va_end(v);
12337
  }
12338
  catch (std::exception const&) {}
12339
#endif
12340
12341
}