Coverage Report

Created: 2025-08-29 06:41

/src/libtorrent/src/session_impl.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
3
Copyright (c) 2003, Magnus Jonsson
4
Copyright (c) 2015, Thomas
5
Copyright (c) 2006-2022, Arvid Norberg
6
Copyright (c) 2009, Andrew Resch
7
Copyright (c) 2014-2020, Steven Siloti
8
Copyright (c) 2015-2021, Alden Torres
9
Copyright (c) 2015, Mikhail Titov
10
Copyright (c) 2015, Thomas Yuan
11
Copyright (c) 2016-2017, Andrei Kurushin
12
Copyright (c) 2016, Falcosc
13
Copyright (c) 2016-2017, Pavel Pimenov
14
Copyright (c) 2017, sledgehammer_999
15
Copyright (c) 2018, Xiyue Deng
16
Copyright (c) 2020, Fonic
17
Copyright (c) 2020, Paul-Louis Ageneau
18
Copyright (c) 2022, Vladimir Golovnev (glassez)
19
Copyright (c) 2022, thrnz
20
Copyright (c) 2023, Joris Carrier
21
All rights reserved.
22
23
Redistribution and use in source and binary forms, with or without
24
modification, are permitted provided that the following conditions
25
are met:
26
27
    * Redistributions of source code must retain the above copyright
28
      notice, this list of conditions and the following disclaimer.
29
    * Redistributions in binary form must reproduce the above copyright
30
      notice, this list of conditions and the following disclaimer in
31
      the documentation and/or other materials provided with the distribution.
32
    * Neither the name of the author nor the names of its
33
      contributors may be used to endorse or promote products derived
34
      from this software without specific prior written permission.
35
36
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
37
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
38
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
39
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
40
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
41
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
42
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
43
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
44
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
45
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46
POSSIBILITY OF SUCH DAMAGE.
47
48
*/
49
50
#include "libtorrent/config.hpp"
51
52
#include <ctime>
53
#include <algorithm>
54
#include <cctype>
55
#include <cstdio> // for snprintf
56
#include <cinttypes> // for PRId64 et.al.
57
#include <functional>
58
#include <type_traits>
59
#include <numeric> // for accumulate
60
61
#if TORRENT_USE_INVARIANT_CHECKS
62
#include <unordered_set>
63
#endif
64
65
#include "libtorrent/aux_/disable_warnings_push.hpp"
66
#include <boost/asio/ts/internet.hpp>
67
#include <boost/asio/ts/executor.hpp>
68
#include "libtorrent/aux_/disable_warnings_pop.hpp"
69
70
#include "libtorrent/ssl.hpp"
71
#include "libtorrent/peer_id.hpp"
72
#include "libtorrent/torrent_info.hpp"
73
#include "libtorrent/tracker_manager.hpp"
74
#include "libtorrent/bencode.hpp"
75
#include "libtorrent/hasher.hpp"
76
#include "libtorrent/entry.hpp"
77
#include "libtorrent/session.hpp"
78
#include "libtorrent/fingerprint.hpp"
79
#include "libtorrent/alert_types.hpp"
80
#include "libtorrent/aux_/invariant_check.hpp"
81
#include "libtorrent/bt_peer_connection.hpp"
82
#include "libtorrent/peer_connection_handle.hpp"
83
#include "libtorrent/ip_filter.hpp"
84
#include "libtorrent/socket.hpp"
85
#include "libtorrent/aux_/session_impl.hpp"
86
#ifndef TORRENT_DISABLE_DHT
87
#include "libtorrent/kademlia/dht_tracker.hpp"
88
#include "libtorrent/kademlia/types.hpp"
89
#include "libtorrent/kademlia/node_entry.hpp"
90
#endif
91
#include "libtorrent/enum_net.hpp"
92
#include "libtorrent/utf8.hpp"
93
#include "libtorrent/upnp.hpp"
94
#include "libtorrent/natpmp.hpp"
95
#include "libtorrent/lsd.hpp"
96
#include "libtorrent/aux_/instantiate_connection.hpp"
97
#include "libtorrent/peer_info.hpp"
98
#include "libtorrent/random.hpp"
99
#include "libtorrent/magnet_uri.hpp"
100
#include "libtorrent/aux_/session_settings.hpp"
101
#include "libtorrent/torrent_peer.hpp"
102
#include "libtorrent/torrent_handle.hpp"
103
#include "libtorrent/choker.hpp"
104
#include "libtorrent/error.hpp"
105
#include "libtorrent/platform_util.hpp"
106
#include "libtorrent/aux_/bind_to_device.hpp"
107
#include "libtorrent/hex.hpp" // to_hex, from_hex
108
#include "libtorrent/aux_/scope_end.hpp"
109
#include "libtorrent/aux_/set_socket_buffer.hpp"
110
#include "libtorrent/aux_/generate_peer_id.hpp"
111
#include "libtorrent/aux_/ffs.hpp"
112
#include "libtorrent/aux_/array.hpp"
113
#include "libtorrent/aux_/set_traffic_class.hpp"
114
115
#ifndef TORRENT_DISABLE_LOGGING
116
117
#include "libtorrent/socket_io.hpp"
118
119
// for logging stat layout
120
#include "libtorrent/stat.hpp"
121
122
#include <cstdarg> // for va_list
123
124
// for logging the size of DHT structures
125
#ifndef TORRENT_DISABLE_DHT
126
#include <libtorrent/kademlia/find_data.hpp>
127
#include <libtorrent/kademlia/refresh.hpp>
128
#include <libtorrent/kademlia/node.hpp>
129
#include <libtorrent/kademlia/observer.hpp>
130
#include <libtorrent/kademlia/item.hpp>
131
#endif // TORRENT_DISABLE_DHT
132
133
#include "libtorrent/http_tracker_connection.hpp"
134
#include "libtorrent/udp_tracker_connection.hpp"
135
136
#endif // TORRENT_DISABLE_LOGGING
137
138
#ifdef TORRENT_USE_LIBGCRYPT
139
140
#if GCRYPT_VERSION_NUMBER < 0x010600
141
extern "C" {
142
GCRY_THREAD_OPTION_PTHREAD_IMPL;
143
}
144
#endif
145
146
namespace {
147
148
  // libgcrypt requires this to initialize the library
149
  struct gcrypt_setup
150
  {
151
    gcrypt_setup()
152
    {
153
      gcry_check_version(nullptr);
154
#if GCRYPT_VERSION_NUMBER < 0x010600
155
      gcry_error_t e = gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
156
      if (e != 0) std::fprintf(stderr, "libcrypt ERROR: %s\n", gcry_strerror(e));
157
      e = gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
158
      if (e != 0) std::fprintf(stderr, "initialization finished error: %s\n", gcry_strerror(e));
159
#endif
160
    }
161
  } gcrypt_global_constructor;
162
}
163
164
#endif // TORRENT_USE_LIBGCRYPT
165
166
#ifdef TORRENT_USE_OPENSSL
167
#ifdef TORRENT_WINDOWS
168
#include <wincrypt.h>
169
#endif
170
#endif // TORRENT_USE_OPENSSL
171
172
#ifdef TORRENT_WINDOWS
173
// for ERROR_SEM_TIMEOUT
174
#include <winerror.h>
175
#endif
176
177
using namespace std::placeholders;
178
179
#ifdef BOOST_NO_EXCEPTIONS
180
namespace boost {
181
182
  void throw_exception(std::exception const& e) { std::abort(); }
183
}
184
#endif
185
186
namespace libtorrent {
187
188
#if defined TORRENT_ASIO_DEBUGGING
189
  std::map<std::string, async_t> _async_ops;
190
  std::deque<wakeup_t> _wakeups;
191
  int _async_ops_nthreads = 0;
192
  std::mutex _async_ops_mutex;
193
194
  std::map<int, handler_alloc_t> _handler_storage;
195
  std::mutex _handler_storage_mutex;
196
  bool _handler_logger_registered = false;
197
#endif
198
199
namespace aux {
200
201
  constexpr listen_socket_flags_t listen_socket_t::accept_incoming;
202
  constexpr listen_socket_flags_t listen_socket_t::local_network;
203
  constexpr listen_socket_flags_t listen_socket_t::was_expanded;
204
  constexpr listen_socket_flags_t listen_socket_t::proxy;
205
206
  constexpr ip_source_t session_interface::source_dht;
207
  constexpr ip_source_t session_interface::source_peer;
208
  constexpr ip_source_t session_interface::source_tracker;
209
  constexpr ip_source_t session_interface::source_router;
210
211
void apply_deprecated_dht_settings(settings_pack& sett, bdecode_node const& s)
212
1.13k
{
213
1.13k
  bdecode_node val;
214
1.13k
  val = s.dict_find_int("max_peers_reply");
215
1.13k
  if (val) sett.set_int(settings_pack::dht_max_peers_reply, int(val.int_value()));
216
1.13k
  val = s.dict_find_int("search_branching");
217
1.13k
  if (val) sett.set_int(settings_pack::dht_search_branching, int(val.int_value()));
218
1.13k
  val = s.dict_find_int("max_fail_count");
219
1.13k
  if (val) sett.set_int(settings_pack::dht_max_fail_count, int(val.int_value()));
220
1.13k
  val = s.dict_find_int("max_torrents");
221
1.13k
  if (val) sett.set_int(settings_pack::dht_max_torrents, int(val.int_value()));
222
1.13k
  val = s.dict_find_int("max_dht_items");
223
1.13k
  if (val) sett.set_int(settings_pack::dht_max_dht_items, int(val.int_value()));
224
1.13k
  val = s.dict_find_int("max_peers");
225
1.13k
  if (val) sett.set_int(settings_pack::dht_max_peers, int(val.int_value()));
226
1.13k
  val = s.dict_find_int("max_torrent_search_reply");
227
1.13k
  if (val) sett.set_int(settings_pack::dht_max_torrent_search_reply, int(val.int_value()));
228
1.13k
  val = s.dict_find_int("restrict_routing_ips");
229
1.13k
  if (val) sett.set_bool(settings_pack::dht_restrict_routing_ips, (val.int_value() != 0));
230
1.13k
  val = s.dict_find_int("restrict_search_ips");
231
1.13k
  if (val) sett.set_bool(settings_pack::dht_restrict_search_ips, (val.int_value() != 0));
232
1.13k
  val = s.dict_find_int("extended_routing_table");
233
1.13k
  if (val) sett.set_bool(settings_pack::dht_extended_routing_table, (val.int_value() != 0));
234
1.13k
  val = s.dict_find_int("aggressive_lookups");
235
1.13k
  if (val) sett.set_bool(settings_pack::dht_aggressive_lookups, (val.int_value() != 0));
236
1.13k
  val = s.dict_find_int("privacy_lookups");
237
1.13k
  if (val) sett.set_bool(settings_pack::dht_privacy_lookups, (val.int_value() != 0));
238
1.13k
  val = s.dict_find_int("enforce_node_id");
239
1.13k
  if (val) sett.set_bool(settings_pack::dht_enforce_node_id, (val.int_value() != 0));
240
1.13k
  val = s.dict_find_int("ignore_dark_internet");
241
1.13k
  if (val) sett.set_bool(settings_pack::dht_ignore_dark_internet, (val.int_value() != 0));
242
1.13k
  val = s.dict_find_int("block_timeout");
243
1.13k
  if (val) sett.set_int(settings_pack::dht_block_timeout, int(val.int_value()));
244
1.13k
  val = s.dict_find_int("block_ratelimit");
245
1.13k
  if (val) sett.set_int(settings_pack::dht_block_ratelimit, int(val.int_value()));
246
1.13k
  val = s.dict_find_int("read_only");
247
1.13k
  if (val) sett.set_bool(settings_pack::dht_read_only, (val.int_value() != 0));
248
1.13k
  val = s.dict_find_int("item_lifetime");
249
1.13k
  if (val) sett.set_int(settings_pack::dht_item_lifetime, int(val.int_value()));
250
1.13k
}
251
252
  std::vector<std::shared_ptr<listen_socket_t>>::iterator partition_listen_sockets(
253
    std::vector<listen_endpoint_t>& eps
254
    , std::vector<std::shared_ptr<listen_socket_t>>& sockets)
255
1.83k
  {
256
1.83k
    return std::partition(sockets.begin(), sockets.end()
257
1.83k
      , [&eps](std::shared_ptr<listen_socket_t> const& sock)
258
1.83k
    {
259
0
      auto match = std::find_if(eps.begin(), eps.end()
260
0
        , [&sock](listen_endpoint_t const& ep)
261
0
      {
262
0
        return ep.ssl == sock->ssl
263
0
          && ep.port == sock->original_port
264
0
          && ep.device == sock->device
265
0
          && ep.flags == sock->flags
266
0
          && ep.addr == sock->local_endpoint.address();
267
0
      });
268
269
0
      if (match != eps.end())
270
0
      {
271
        // remove the matched endpoint so that another socket can't match it
272
        // this also signals to the caller that it doesn't need to create a
273
        // socket for the endpoint
274
0
        eps.erase(match);
275
0
        return true;
276
0
      }
277
0
      else
278
0
      {
279
0
        return false;
280
0
      }
281
0
    });
282
1.83k
  }
283
284
  // To comply with BEP 45 multi homed clients must run separate DHT nodes
285
  // on each interface they use to talk to the DHT. This is enforced
286
  // by prohibiting creating a listen socket on [::] and 0.0.0.0. Instead the list of
287
  // interfaces is enumerated and sockets are created for each of them.
288
  void expand_unspecified_address(span<ip_interface const> const ifs
289
    , span<ip_route const> const routes
290
    , std::vector<listen_endpoint_t>& eps)
291
1.83k
  {
292
1.83k
    auto unspecified_begin = std::partition(eps.begin(), eps.end()
293
1.83k
      , [](listen_endpoint_t const& ep) { return !ep.addr.is_unspecified(); });
294
1.83k
    std::vector<listen_endpoint_t> unspecified_eps(unspecified_begin, eps.end());
295
1.83k
    eps.erase(unspecified_begin, eps.end());
296
1.83k
    for (auto const& uep : unspecified_eps)
297
0
    {
298
0
      bool const v4 = uep.addr.is_v4();
299
0
      for (auto const& ipface : ifs)
300
0
      {
301
0
        if (!ipface.preferred)
302
0
          continue;
303
0
        if (ipface.interface_address.is_v4() != v4)
304
0
          continue;
305
0
        if (!uep.device.empty() && uep.device != ipface.name)
306
0
          continue;
307
0
        if (std::any_of(eps.begin(), eps.end(), [&](listen_endpoint_t const& e)
308
0
        {
309
          // ignore device name because we don't want to create
310
          // duplicates if the user explicitly configured an address
311
          // without a device name
312
0
          return e.addr == ipface.interface_address
313
0
            && e.port == uep.port
314
0
            && e.ssl == uep.ssl;
315
0
        }))
316
0
        {
317
0
          continue;
318
0
        }
319
320
        // ignore interfaces that are down
321
0
        if (ipface.state != if_state::up && ipface.state != if_state::unknown)
322
0
          continue;
323
0
        if (!(ipface.flags & if_flags::up))
324
0
          continue;
325
326
        // we assume this listen_socket_t is local-network under some
327
        // conditions, meaning we won't announce it to internet trackers
328
        // if "routes" does not contain a single route to the internet,
329
        // we don't use the last case. On MacOS, we can be notified of
330
        // network changes *before* the routing table is updated
331
0
        bool const local
332
0
          = ipface.interface_address.is_loopback()
333
0
          || is_link_local(ipface.interface_address)
334
0
          || (ipface.flags & if_flags::loopback)
335
0
          || (!is_global(ipface.interface_address)
336
0
            && !(ipface.flags & if_flags::pointopoint)
337
0
            && has_any_internet_route(routes)
338
0
            && !has_internet_route(ipface.name, family(ipface.interface_address), routes));
339
340
0
        eps.emplace_back(ipface.interface_address, uep.port, uep.device
341
0
          , uep.ssl, uep.flags | listen_socket_t::was_expanded
342
0
          | (local ? listen_socket_t::local_network : listen_socket_flags_t{}));
343
0
      }
344
0
    }
345
1.83k
  }
346
347
  void expand_devices(span<ip_interface const> const ifs
348
    , std::vector<listen_endpoint_t>& eps)
349
1.83k
  {
350
1.83k
    for (auto& ep : eps)
351
1.83k
    {
352
1.83k
      auto const iface = ep.device.empty()
353
1.83k
        ? std::find_if(ifs.begin(), ifs.end(), [&](ip_interface const& ipface)
354
1.83k
          {
355
1.83k
            return match_addr_mask(ipface.interface_address, ep.addr, ipface.netmask);
356
1.83k
          })
357
1.83k
        : std::find_if(ifs.begin(), ifs.end(), [&](ip_interface const& ipface)
358
0
          {
359
0
            return ipface.name == ep.device
360
0
              && match_addr_mask(ipface.interface_address, ep.addr, ipface.netmask);
361
0
          });
362
363
1.83k
      if (iface == ifs.end())
364
0
      {
365
        // we can't find which device this is for, just assume we can't
366
        // reach anything on it
367
0
        ep.netmask = build_netmask(0, ep.addr.is_v4() ? AF_INET : AF_INET6);
368
0
        continue;
369
0
      }
370
371
1.83k
      ep.netmask = iface->netmask;
372
1.83k
      ep.device = iface->name;
373
1.83k
    }
374
1.83k
  }
375
376
  bool listen_socket_t::can_route(address const& addr) const
377
0
  {
378
    // if this is a proxy, we assume it can reach everything
379
0
    if (flags & proxy) return true;
380
381
0
    if (is_v4(local_endpoint) != addr.is_v4()) return false;
382
383
0
    if (local_endpoint.address().is_v6()
384
0
      && local_endpoint.address().to_v6().scope_id() != addr.to_v6().scope_id())
385
0
      return false;
386
387
0
    if (local_endpoint.address() == addr) return true;
388
0
    if (local_endpoint.address().is_unspecified()) return true;
389
0
    if (match_addr_mask(addr, local_endpoint.address(), netmask)) return true;
390
0
    return !(flags & local_network);
391
0
  }
392
393
  void session_impl::init_peer_class_filter(bool unlimited_local)
394
3.67k
  {
395
    // set the default peer_class_filter to use the local peer class
396
    // for peers on local networks
397
3.67k
    std::uint32_t lfilter = 1 << static_cast<std::uint32_t>(m_local_peer_class);
398
3.67k
    std::uint32_t gfilter = 1 << static_cast<std::uint32_t>(m_global_class);
399
400
3.67k
    struct class_mapping
401
3.67k
    {
402
3.67k
      char const* first;
403
3.67k
      char const* last;
404
3.67k
      std::uint32_t filter;
405
3.67k
    };
406
407
3.67k
    static const class_mapping v4_classes[] =
408
3.67k
    {
409
      // everything
410
3.67k
      {"0.0.0.0", "255.255.255.255", gfilter},
411
      // local networks
412
3.67k
      {"10.0.0.0", "10.255.255.255", lfilter},
413
3.67k
      {"172.16.0.0", "172.31.255.255", lfilter},
414
3.67k
      {"192.168.0.0", "192.168.255.255", lfilter},
415
      // link-local
416
3.67k
      {"169.254.0.0", "169.254.255.255", lfilter},
417
      // loop-back
418
3.67k
      {"127.0.0.0", "127.255.255.255", lfilter},
419
3.67k
    };
420
421
3.67k
    static const class_mapping v6_classes[] =
422
3.67k
    {
423
      // everything
424
3.67k
      {"::0", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", gfilter},
425
      // local networks
426
3.67k
      {"fc00::", "fdff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", lfilter},
427
      // link-local
428
3.67k
      {"fe80::", "febf::ffff:ffff:ffff:ffff:ffff:ffff:ffff", lfilter},
429
      // loop-back
430
3.67k
      {"::1", "::1", lfilter},
431
3.67k
    };
432
433
3.67k
    class_mapping const* p = v4_classes;
434
3.67k
    int len = sizeof(v4_classes) / sizeof(v4_classes[0]);
435
3.67k
    if (!unlimited_local) len = 1;
436
25.7k
    for (int i = 0; i < len; ++i)
437
22.0k
    {
438
22.0k
      error_code ec;
439
22.0k
      address_v4 begin = make_address_v4(p[i].first, ec);
440
22.0k
      address_v4 end = make_address_v4(p[i].last, ec);
441
22.0k
      if (ec) continue;
442
22.0k
      m_peer_class_filter.add_rule(begin, end, p[i].filter);
443
22.0k
    }
444
3.67k
    p = v6_classes;
445
3.67k
    len = sizeof(v6_classes) / sizeof(v6_classes[0]);
446
3.67k
    if (!unlimited_local) len = 1;
447
18.3k
    for (int i = 0; i < len; ++i)
448
14.6k
    {
449
14.6k
      error_code ec;
450
14.6k
      address_v6 begin = make_address_v6(p[i].first, ec);
451
14.6k
      address_v6 end = make_address_v6(p[i].last, ec);
452
14.6k
      if (ec) continue;
453
11.0k
      m_peer_class_filter.add_rule(begin, end, p[i].filter);
454
11.0k
    }
455
3.67k
  }
456
457
#ifdef TORRENT_SSL_PEERS
458
  namespace {
459
  // when running bittorrent over SSL, the SNI (server name indication)
460
  // extension is used to know which torrent the incoming connection is
461
  // trying to connect to. The 40 first bytes in the name is expected to
462
  // be the hex encoded info-hash
463
  bool ssl_server_name_callback_impl(ssl::stream_handle_type stream_handle, std::string const& name, session_impl* si)
464
0
  {
465
0
    if (name.size() < 40)
466
0
      return false;
467
468
0
    info_hash_t info_hash;
469
0
    bool valid = aux::from_hex({name.c_str(), 40}, info_hash.v1.data());
470
471
    // the server name is not a valid hex-encoded info-hash
472
0
    if (!valid)
473
0
      return false;
474
475
    // see if there is a torrent with this info-hash
476
0
    std::shared_ptr<torrent> t = si ? si->find_torrent(info_hash).lock() : nullptr;
477
478
    // if there isn't, fail
479
0
    if (!t) return false;
480
481
    // if the torrent we found isn't an SSL torrent, also fail.
482
0
    if (!t->is_ssl_torrent()) return false;
483
484
    // if the torrent doesn't have an SSL context and should not allow
485
    // incoming SSL connections
486
0
    auto* torrent_ctx = t->ssl_ctx();
487
0
    if (!torrent_ctx) return false;
488
489
    // use this torrent's certificate
490
0
    ssl::set_context(stream_handle, ssl::get_handle(*torrent_ctx));
491
0
    return true;
492
0
  }
493
494
#if defined TORRENT_USE_OPENSSL
495
int ssl_server_name_callback(SSL* s, int*, void* arg)
496
0
{
497
0
  char const* name = SSL_get_servername(s, TLSEXT_NAMETYPE_host_name);
498
0
  auto* si = reinterpret_cast<session_impl*>(arg);
499
0
  return ssl_server_name_callback_impl(s, name ? std::string(name) : "", si)
500
0
      ? SSL_TLSEXT_ERR_OK
501
0
      : SSL_TLSEXT_ERR_ALERT_FATAL;
502
0
}
503
#elif defined TORRENT_USE_GNUTLS
504
bool ssl_server_name_callback(ssl::stream_handle_type stream_handle, std::string const& name, void* arg)
505
{
506
  session_impl* si = reinterpret_cast<session_impl*>(arg);
507
  return ssl_server_name_callback_impl(stream_handle, name, si);
508
}
509
#endif
510
  } // anonymous namespace
511
#endif // TORRENT_SSL_PEERS
512
513
  session_impl::session_impl(io_context& ioc, settings_pack const& pack
514
    , disk_io_constructor_type disk_io_constructor
515
    , session_flags_t const flags)
516
1.83k
    : m_settings(pack)
517
1.83k
    , m_io_context(ioc)
518
#if TORRENT_USE_SSL
519
1.83k
    , m_ssl_ctx(ssl::context::tls_client)
520
#ifdef TORRENT_SSL_PEERS
521
1.83k
    , m_peer_ssl_ctx(ssl::context::tls)
522
#endif
523
#endif // TORRENT_USE_SSL
524
1.83k
    , m_alerts(m_settings.get_int(settings_pack::alert_queue_size)
525
1.83k
      , alert_category_t{static_cast<unsigned int>(m_settings.get_int(settings_pack::alert_mask))})
526
1.83k
    , m_disk_thread((disk_io_constructor ? disk_io_constructor : default_disk_io_constructor)
527
1.83k
      (m_io_context, m_settings, m_stats_counters))
528
1.83k
    , m_download_rate(peer_connection::download_channel)
529
1.83k
    , m_upload_rate(peer_connection::upload_channel)
530
1.83k
    , m_host_resolver(m_io_context)
531
1.83k
    , m_tracker_manager(
532
1.83k
      std::bind(&session_impl::send_udp_packet_listen, this, _1, _2, _3, _4, _5)
533
1.83k
      , std::bind(&session_impl::send_udp_packet_hostname_listen, this, _1, _2, _3, _4, _5, _6)
534
1.83k
      , m_stats_counters
535
1.83k
      , m_host_resolver
536
1.83k
      , m_settings
537
1.83k
#if !defined TORRENT_DISABLE_LOGGING || TORRENT_USE_ASSERTS
538
1.83k
      , *this
539
1.83k
#endif
540
1.83k
      )
541
1.83k
    , m_work(make_work_guard(m_io_context))
542
#if TORRENT_USE_I2P
543
1.83k
    , m_i2p_conn(m_io_context)
544
#endif
545
1.83k
    , m_created(clock_type::now())
546
1.83k
    , m_last_tick(m_created)
547
1.83k
    , m_last_second_tick(m_created - milliseconds(900))
548
1.83k
    , m_last_choke(m_created)
549
1.83k
    , m_last_auto_manage(m_created)
550
#ifndef TORRENT_DISABLE_DHT
551
1.83k
    , m_dht_announce_timer(m_io_context)
552
#endif
553
1.83k
    , m_utp_socket_manager(
554
1.83k
      std::bind(&session_impl::send_udp_packet, this, _1, _2, _3, _4, _5)
555
1.83k
      , [this](socket_type s) { this->incoming_connection(std::move(s)); }
556
1.83k
      , m_io_context
557
1.83k
      , m_settings, m_stats_counters, nullptr)
558
#ifdef TORRENT_SSL_PEERS
559
1.83k
    , m_ssl_utp_socket_manager(
560
1.83k
      std::bind(&session_impl::send_udp_packet, this, _1, _2, _3, _4, _5)
561
1.83k
      , std::bind(&session_impl::on_incoming_utp_ssl, this, _1)
562
1.83k
      , m_io_context
563
1.83k
      , m_settings, m_stats_counters
564
1.83k
      , &m_peer_ssl_ctx)
565
#endif
566
1.83k
    , m_timer(m_io_context)
567
1.83k
    , m_lsd_announce_timer(m_io_context)
568
1.83k
    , m_close_file_timer(m_io_context)
569
1.83k
    , m_paused(flags & session::paused)
570
1.83k
  {
571
1.83k
#if !defined TORRENT_DISABLE_LOGGING || TORRENT_USE_ASSERTS
572
1.83k
    validate_settings();
573
1.83k
#endif
574
1.83k
  }
575
576
  template <typename Fun, typename... Args>
577
  void session_impl::wrap(Fun f, Args&&... a)
578
#ifndef BOOST_NO_EXCEPTIONS
579
18.3k
  try
580
18.3k
#endif
581
18.3k
  {
582
18.3k
    (this->*f)(std::forward<Args>(a)...);
583
18.3k
  }
584
18.3k
#ifndef BOOST_NO_EXCEPTIONS
585
18.3k
  catch (system_error const& e) {
586
0
    alerts().emplace_alert<session_error_alert>(e.code(), e.what());
587
0
    pause();
588
0
  } catch (std::exception const& e) {
589
0
    alerts().emplace_alert<session_error_alert>(error_code(), e.what());
590
0
    pause();
591
0
  } catch (...) {
592
0
    alerts().emplace_alert<session_error_alert>(error_code(), "unknown error");
593
0
    pause();
594
0
  }
void libtorrent::aux::session_impl::wrap<void (libtorrent::aux::session_impl::*)()>(void (libtorrent::aux::session_impl::*)())
Line
Count
Source
579
7.34k
  try
580
7.34k
#endif
581
7.34k
  {
582
7.34k
    (this->*f)(std::forward<Args>(a)...);
583
7.34k
  }
584
7.34k
#ifndef BOOST_NO_EXCEPTIONS
585
7.34k
  catch (system_error const& e) {
586
0
    alerts().emplace_alert<session_error_alert>(e.code(), e.what());
587
0
    pause();
588
0
  } catch (std::exception const& e) {
589
0
    alerts().emplace_alert<session_error_alert>(error_code(), e.what());
590
0
    pause();
591
0
  } catch (...) {
592
0
    alerts().emplace_alert<session_error_alert>(error_code(), "unknown error");
593
0
    pause();
594
0
  }
void libtorrent::aux::session_impl::wrap<void (libtorrent::aux::session_impl::*)(boost::system::error_code const&), boost::system::error_code>(void (libtorrent::aux::session_impl::*)(boost::system::error_code const&), boost::system::error_code&&)
Line
Count
Source
579
3.67k
  try
580
3.67k
#endif
581
3.67k
  {
582
3.67k
    (this->*f)(std::forward<Args>(a)...);
583
3.67k
  }
584
3.67k
#ifndef BOOST_NO_EXCEPTIONS
585
3.67k
  catch (system_error const& e) {
586
0
    alerts().emplace_alert<session_error_alert>(e.code(), e.what());
587
0
    pause();
588
0
  } catch (std::exception const& e) {
589
0
    alerts().emplace_alert<session_error_alert>(error_code(), e.what());
590
0
    pause();
591
0
  } catch (...) {
592
0
    alerts().emplace_alert<session_error_alert>(error_code(), "unknown error");
593
0
    pause();
594
0
  }
void libtorrent::aux::session_impl::wrap<void (libtorrent::aux::session_impl::*)(boost::system::error_code const&), boost::system::error_code const&>(void (libtorrent::aux::session_impl::*)(boost::system::error_code const&), boost::system::error_code const&)
Line
Count
Source
579
3.67k
  try
580
3.67k
#endif
581
3.67k
  {
582
3.67k
    (this->*f)(std::forward<Args>(a)...);
583
3.67k
  }
584
3.67k
#ifndef BOOST_NO_EXCEPTIONS
585
3.67k
  catch (system_error const& e) {
586
0
    alerts().emplace_alert<session_error_alert>(e.code(), e.what());
587
0
    pause();
588
0
  } catch (std::exception const& e) {
589
0
    alerts().emplace_alert<session_error_alert>(error_code(), e.what());
590
0
    pause();
591
0
  } catch (...) {
592
0
    alerts().emplace_alert<session_error_alert>(error_code(), "unknown error");
593
0
    pause();
594
0
  }
void libtorrent::aux::session_impl::wrap<void (libtorrent::aux::session_impl::*)(boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::executor>, boost::system::error_code const&, std::__1::weak_ptr<boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::executor> >, libtorrent::aux::transport), boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::executor>, boost::system::error_code const&, std::__1::weak_ptr<boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::executor> > const&, libtorrent::aux::transport const&>(void (libtorrent::aux::session_impl::*)(boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::executor>, boost::system::error_code const&, std::__1::weak_ptr<boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::executor> >, libtorrent::aux::transport), boost::asio::basic_stream_socket<boost::asio::ip::tcp, boost::asio::executor>&&, boost::system::error_code const&, std::__1::weak_ptr<boost::asio::basic_socket_acceptor<boost::asio::ip::tcp, boost::asio::executor> > const&, libtorrent::aux::transport const&)
Line
Count
Source
579
3.67k
  try
580
3.67k
#endif
581
3.67k
  {
582
3.67k
    (this->*f)(std::forward<Args>(a)...);
583
3.67k
  }
584
3.67k
#ifndef BOOST_NO_EXCEPTIONS
585
3.67k
  catch (system_error const& e) {
586
0
    alerts().emplace_alert<session_error_alert>(e.code(), e.what());
587
0
    pause();
588
0
  } catch (std::exception const& e) {
589
0
    alerts().emplace_alert<session_error_alert>(error_code(), e.what());
590
0
    pause();
591
0
  } catch (...) {
592
0
    alerts().emplace_alert<session_error_alert>(error_code(), "unknown error");
593
0
    pause();
594
0
  }
595
#endif
596
597
  // This function is called by the creating thread, not in the message loop's
598
  // io_context thread.
599
  // TODO: 2 is there a reason not to move all of this into init()? and just
600
  // post it to the io_context?
601
  void session_impl::start_session()
602
1.83k
  {
603
#ifndef TORRENT_DISABLE_LOGGING
604
    session_log("start session");
605
#endif
606
607
1.83k
#if TORRENT_USE_SSL
608
1.83k
    error_code ec;
609
1.83k
    m_ssl_ctx.set_default_verify_paths(ec);
610
#ifndef TORRENT_DISABLE_LOGGING
611
    if (ec) session_log("SSL set_default verify_paths failed: %s", ec.message().c_str());
612
    ec.clear();
613
#endif
614
#if defined TORRENT_WINDOWS && defined TORRENT_USE_OPENSSL && !defined TORRENT_WINRT
615
    // TODO: come up with some abstraction to do this for gnutls as well
616
    // load certificates from the windows system certificate store
617
    X509_STORE* store = X509_STORE_new();
618
    if (store)
619
    {
620
      HCERTSTORE system_store = CertOpenSystemStoreA(0, "ROOT");
621
      // this is best effort
622
      if (system_store)
623
      {
624
        CERT_CONTEXT const* ctx = nullptr;
625
        while ((ctx = CertEnumCertificatesInStore(system_store, ctx)) != nullptr)
626
        {
627
          unsigned char const* cert_ptr = reinterpret_cast<unsigned char const*>(ctx->pbCertEncoded);
628
          X509* x509 = d2i_X509(nullptr, &cert_ptr, ctx->cbCertEncoded);
629
          // this is best effort
630
          if (!x509) continue;
631
          X509_STORE_add_cert(store, x509);
632
          X509_free(x509);
633
        }
634
        CertFreeCertificateContext(ctx);
635
        CertCloseStore(system_store, 0);
636
      }
637
    }
638
639
    SSL_CTX* ssl_ctx = m_ssl_ctx.native_handle();
640
    SSL_CTX_set_cert_store(ssl_ctx, store);
641
#endif
642
#ifdef __APPLE__
643
    m_ssl_ctx.load_verify_file("/etc/ssl/cert.pem", ec);
644
#ifndef TORRENT_DISABLE_LOGGING
645
    if (ec) session_log("SSL load_verify_file failed: %s", ec.message().c_str());
646
    ec.clear();
647
#endif
648
    m_ssl_ctx.add_verify_path("/etc/ssl/certs", ec);
649
#ifndef TORRENT_DISABLE_LOGGING
650
    if (ec) session_log("SSL add_verify_path failed: %s", ec.message().c_str());
651
    ec.clear();
652
#endif
653
#endif // __APPLE__
654
1.83k
#endif // TORRENT_USE_SSL
655
1.83k
#ifdef TORRENT_SSL_PEERS
656
1.83k
    m_peer_ssl_ctx.set_verify_mode(ssl::context::verify_none, ec);
657
1.83k
    ssl::set_server_name_callback(ssl::get_handle(m_peer_ssl_ctx), ssl_server_name_callback, this, ec);
658
1.83k
#endif // TORRENT_SSL_PEERS
659
660
1.83k
#ifndef TORRENT_DISABLE_DHT
661
1.83k
    m_next_dht_torrent = 0;
662
1.83k
#endif
663
1.83k
    m_next_lsd_torrent = 0;
664
665
1.83k
    m_global_class = m_classes.new_peer_class("global");
666
1.83k
    m_tcp_peer_class = m_classes.new_peer_class("tcp");
667
1.83k
    m_local_peer_class = m_classes.new_peer_class("local");
668
    // local peers are always unchoked
669
1.83k
    m_classes.at(m_local_peer_class)->ignore_unchoke_slots = true;
670
    // local peers are allowed to exceed the normal connection
671
    // limit by 50%
672
1.83k
    m_classes.at(m_local_peer_class)->connection_limit_factor = 150;
673
674
1.83k
    TORRENT_ASSERT(m_global_class == session::global_peer_class_id);
675
1.83k
    TORRENT_ASSERT(m_tcp_peer_class == session::tcp_peer_class_id);
676
1.83k
    TORRENT_ASSERT(m_local_peer_class == session::local_peer_class_id);
677
678
1.83k
    init_peer_class_filter(true);
679
680
    // TCP, SSL/TCP and I2P connections should be assigned the TCP peer class
681
1.83k
    m_peer_class_type_filter.add(peer_class_type_filter::tcp_socket, m_tcp_peer_class);
682
1.83k
    m_peer_class_type_filter.add(peer_class_type_filter::ssl_tcp_socket, m_tcp_peer_class);
683
1.83k
    m_peer_class_type_filter.add(peer_class_type_filter::i2p_socket, m_tcp_peer_class);
684
685
#ifndef TORRENT_DISABLE_LOGGING
686
687
    session_log("version: %s revision: %" PRIx64
688
      , lt::version_str, lt::version_revision);
689
690
#endif // TORRENT_DISABLE_LOGGING
691
692
    // ---- auto-cap max connections ----
693
1.83k
    int const max_files = max_open_files();
694
    // deduct some margin for epoll/kqueue, log files,
695
    // futexes, shared objects etc.
696
    // 80% of the available file descriptors should go to connections
697
1.83k
    m_settings.set_int(settings_pack::connections_limit, std::min(
698
1.83k
      m_settings.get_int(settings_pack::connections_limit)
699
1.83k
      , std::max(5, (max_files - 20) * 8 / 10)));
700
    // 20% goes towards regular files (see disk_io_thread)
701
#ifndef TORRENT_DISABLE_LOGGING
702
    if (should_log())
703
    {
704
      session_log("max-connections: %d max-files: %d"
705
        , m_settings.get_int(settings_pack::connections_limit)
706
        , max_files);
707
    }
708
#endif
709
710
1.83k
    post(m_io_context, [this] { wrap(&session_impl::init); });
711
1.83k
  }
712
713
  void session_impl::init()
714
1.83k
  {
715
    // this is a debug facility
716
    // see single_threaded in debug.hpp
717
1.83k
    thread_started();
718
719
1.83k
    TORRENT_ASSERT(is_single_thread());
720
721
#ifndef TORRENT_DISABLE_LOGGING
722
    session_log(" *** session thread init");
723
#endif
724
725
    // this is where we should set up all async operations. This
726
    // is called from within the network thread as opposed to the
727
    // constructor which is called from the main thread
728
729
#if defined TORRENT_ASIO_DEBUGGING
730
    async_inc_threads();
731
    add_outstanding_async("session_impl::on_tick");
732
#endif
733
1.83k
    post(m_io_context, [this]{ wrap(&session_impl::on_tick, error_code()); });
734
735
1.83k
    int const lsd_announce_interval
736
1.83k
      = m_settings.get_int(settings_pack::local_service_announce_interval);
737
1.83k
    int const delay = std::max(lsd_announce_interval
738
1.83k
      / std::max(static_cast<int>(m_torrents.size()), 1), 1);
739
1.83k
    m_lsd_announce_timer.expires_after(seconds(delay));
740
1.83k
    ADD_OUTSTANDING_ASYNC("session_impl::on_lsd_announce");
741
1.83k
    m_lsd_announce_timer.async_wait([this](error_code const& e) {
742
1.83k
      wrap(&session_impl::on_lsd_announce, e); } );
743
744
#ifndef TORRENT_DISABLE_LOGGING
745
    session_log(" done starting session");
746
#endif
747
748
    // this applies unchoke settings from m_settings
749
1.83k
    recalculate_unchoke_slots();
750
751
    // apply all m_settings to this session
752
1.83k
    run_all_updates(*this);
753
1.83k
    reopen_listen_sockets(false);
754
755
#if TORRENT_USE_INVARIANT_CHECKS
756
    check_invariant();
757
#endif
758
1.83k
  }
759
760
#if TORRENT_ABI_VERSION <= 2
761
  // TODO: 2 the ip filter should probably be saved here too
762
  void session_impl::save_state(entry* eptr, save_state_flags_t const flags) const
763
0
  {
764
0
    TORRENT_ASSERT(is_single_thread());
765
766
0
    entry& e = *eptr;
767
    // make it a dict
768
0
    e.dict();
769
770
0
    if (flags & session::save_settings)
771
0
    {
772
0
      entry::dictionary_type& sett = e["settings"].dict();
773
0
      save_settings_to_dict(non_default_settings(m_settings), sett);
774
0
    }
775
776
0
#ifndef TORRENT_DISABLE_DHT
777
0
    if (flags & session::save_dht_settings)
778
0
    {
779
0
      e["dht"] = dht::save_dht_settings(get_dht_settings());
780
0
    }
781
782
0
    if (m_dht && (flags & session::save_dht_state))
783
0
    {
784
0
      e["dht state"] = dht::save_dht_state(m_dht->state());
785
0
    }
786
0
#endif
787
788
0
#ifndef TORRENT_DISABLE_EXTENSIONS
789
0
    for (auto const& ext : m_ses_extensions[plugins_all_idx])
790
0
    {
791
0
      ext->save_state(*eptr);
792
0
    }
793
0
#endif
794
0
  }
795
796
  void session_impl::load_state(bdecode_node const* e
797
    , save_state_flags_t const flags)
798
0
  {
799
0
    TORRENT_ASSERT(is_single_thread());
800
801
0
    bdecode_node settings;
802
0
    if (e->type() != bdecode_node::dict_t) return;
803
804
0
#ifndef TORRENT_DISABLE_DHT
805
0
    bool need_update_dht = false;
806
0
    if (flags & session_handle::save_dht_state)
807
0
    {
808
0
      settings = e->dict_find_dict("dht state");
809
0
      if (settings)
810
0
      {
811
0
        m_dht_state = dht::read_dht_state(settings);
812
0
        need_update_dht = true;
813
0
      }
814
0
    }
815
0
#endif
816
817
0
#if TORRENT_ABI_VERSION == 1
818
0
    bool need_update_proxy = false;
819
0
    if (flags & session_handle::save_proxy)
820
0
    {
821
0
      settings = e->dict_find_dict("proxy");
822
0
      if (settings)
823
0
      {
824
0
        m_settings.bulk_set([&settings](session_settings_single_thread& s)
825
0
        {
826
0
          bdecode_node val;
827
0
          val = settings.dict_find_int("port");
828
0
          if (val) s.set_int(settings_pack::proxy_port, int(val.int_value()));
829
0
          val = settings.dict_find_int("type");
830
0
          if (val) s.set_int(settings_pack::proxy_type, int(val.int_value()));
831
0
          val = settings.dict_find_int("proxy_hostnames");
832
0
          if (val) s.set_bool(settings_pack::proxy_hostnames, val.int_value() != 0);
833
0
          val = settings.dict_find_int("proxy_peer_connections");
834
0
          if (val) s.set_bool(settings_pack::proxy_peer_connections, val.int_value() != 0);
835
0
          val = settings.dict_find_string("hostname");
836
0
          if (val) s.set_str(settings_pack::proxy_hostname, val.string_value().to_string());
837
0
          val = settings.dict_find_string("password");
838
0
          if (val) s.set_str(settings_pack::proxy_password, val.string_value().to_string());
839
0
          val = settings.dict_find_string("username");
840
0
          if (val) s.set_str(settings_pack::proxy_username, val.string_value().to_string());
841
0
        });
842
0
        need_update_proxy = true;
843
0
      }
844
0
    }
845
846
0
    settings = e->dict_find_dict("encryption");
847
0
    if (settings)
848
0
    {
849
0
      m_settings.bulk_set([&settings](session_settings_single_thread& s)
850
0
      {
851
0
        bdecode_node val;
852
0
        val = settings.dict_find_int("prefer_rc4");
853
0
        if (val) s.set_bool(settings_pack::prefer_rc4, val.int_value() != 0);
854
0
        val = settings.dict_find_int("out_enc_policy");
855
0
        if (val) s.set_int(settings_pack::out_enc_policy, int(val.int_value()));
856
0
        val = settings.dict_find_int("in_enc_policy");
857
0
        if (val) s.set_int(settings_pack::in_enc_policy, int(val.int_value()));
858
0
        val = settings.dict_find_int("allowed_enc_level");
859
0
        if (val) s.set_int(settings_pack::allowed_enc_level, int(val.int_value()));
860
0
      });
861
0
    }
862
0
#endif
863
864
0
    if ((flags & session_handle::save_settings)
865
0
#if TORRENT_ABI_VERSION <= 2
866
0
      || (flags & session_handle::save_dht_settings)
867
0
#endif
868
0
      )
869
0
    {
870
0
      settings = e->dict_find_dict("settings");
871
0
      if (settings)
872
0
      {
873
        // apply_settings_pack will update dht and proxy
874
0
        settings_pack pack = load_pack_from_dict(settings);
875
876
        // these settings are not loaded from state
877
        // they are set by the client software, not configured by users
878
0
        pack.clear(settings_pack::user_agent);
879
0
        pack.clear(settings_pack::peer_fingerprint);
880
881
0
        apply_settings_pack_impl(pack);
882
0
#ifndef TORRENT_DISABLE_DHT
883
0
        need_update_dht = false;
884
0
#endif
885
0
#if TORRENT_ABI_VERSION == 1
886
0
        need_update_proxy = false;
887
0
#endif
888
0
      }
889
0
    }
890
891
0
#if TORRENT_ABI_VERSION <= 2
892
0
    if (flags & session_handle::save_dht_settings)
893
0
#endif
894
0
    {
895
      // This is here for backwards compatibility, to support loading state
896
      // files in the previous file format, where the DHT settings were in
897
      // its own dictionary
898
0
      settings = e->dict_find_dict("dht");
899
0
      if (settings)
900
0
      {
901
0
        settings_pack sett;
902
0
        aux::apply_deprecated_dht_settings(sett, settings);
903
0
        apply_settings_pack_impl(sett);
904
0
      }
905
0
    }
906
907
0
#ifndef TORRENT_DISABLE_DHT
908
0
    if (need_update_dht) start_dht();
909
0
#endif
910
0
#if TORRENT_ABI_VERSION == 1
911
0
    if (need_update_proxy) update_proxy();
912
0
#endif
913
914
0
#ifndef TORRENT_DISABLE_EXTENSIONS
915
0
#if TORRENT_ABI_VERSION <= 2
916
0
    for (auto& ext : m_ses_extensions[plugins_all_idx])
917
0
    {
918
0
      ext->load_state(*e);
919
0
    }
920
0
#endif
921
0
#endif
922
0
  }
923
#endif
924
925
  session_params session_impl::session_state(save_state_flags_t const flags) const
926
0
  {
927
0
    TORRENT_ASSERT(is_single_thread());
928
929
0
    session_params ret;
930
0
    if (flags & session::save_settings)
931
0
      ret.settings = non_default_settings(m_settings);
932
933
0
#ifndef TORRENT_DISABLE_DHT
934
0
#if TORRENT_ABI_VERSION <= 2
935
0
  if (flags & session_handle::save_dht_settings)
936
0
  {
937
0
    ret.dht_settings = get_dht_settings();
938
0
  }
939
0
#endif
940
941
0
    if (m_dht && (flags & session::save_dht_state))
942
0
      ret.dht_state = m_dht->state();
943
0
#endif
944
945
0
#ifndef TORRENT_DISABLE_EXTENSIONS
946
0
    if (flags & session::save_extension_state)
947
0
    {
948
0
      for (auto const& ext : m_ses_extensions[plugins_all_idx])
949
0
      {
950
0
        auto state = ext->save_state();
951
0
        for (auto& v : state)
952
0
          ret.ext_state[std::move(v.first)] = std::move(v.second);
953
0
      }
954
0
    }
955
0
#endif
956
957
0
    if ((flags & session::save_ip_filter) && m_ip_filter)
958
0
    {
959
0
      ret.ip_filter = *m_ip_filter;
960
0
    }
961
0
    return ret;
962
0
  }
963
964
  proxy_settings session_impl::proxy() const
965
1.83k
  {
966
1.83k
    return proxy_settings(m_settings);
967
1.83k
  }
968
969
#ifndef TORRENT_DISABLE_EXTENSIONS
970
971
  void session_impl::add_extension(ext_function_t ext)
972
0
  {
973
0
    TORRENT_ASSERT(is_single_thread());
974
0
    TORRENT_ASSERT(ext);
975
976
0
    add_ses_extension(std::make_shared<session_plugin_wrapper>(ext));
977
0
  }
978
979
  void session_impl::add_ses_extension(std::shared_ptr<plugin> ext)
980
5.50k
  {
981
    // this is called during startup of the session, from the thread creating
982
    // it, not its own thread
983
//    TORRENT_ASSERT(is_single_thread());
984
5.50k
    TORRENT_ASSERT_VAL(ext, ext);
985
986
5.50k
    feature_flags_t const features = ext->implemented_features();
987
988
5.50k
    m_ses_extensions[plugins_all_idx].push_back(ext);
989
990
5.50k
    if (features & plugin::optimistic_unchoke_feature)
991
0
      m_ses_extensions[plugins_optimistic_unchoke_idx].push_back(ext);
992
5.50k
    if (features & plugin::tick_feature)
993
0
      m_ses_extensions[plugins_tick_idx].push_back(ext);
994
5.50k
    if (features & plugin::dht_request_feature)
995
0
      m_ses_extensions[plugins_dht_request_idx].push_back(ext);
996
5.50k
    if (features & plugin::unknown_torrent_feature)
997
0
      m_ses_extensions[plugins_unknown_torrent_idx].push_back(ext);
998
5.50k
    if (features & plugin::alert_feature)
999
0
      m_alerts.add_extension(ext);
1000
5.50k
    session_handle h(shared_from_this());
1001
5.50k
    ext->added(h);
1002
5.50k
  }
1003
1004
#endif // TORRENT_DISABLE_EXTENSIONS
1005
1006
  void session_impl::pause()
1007
0
  {
1008
0
    TORRENT_ASSERT(is_single_thread());
1009
1010
0
    if (m_paused) return;
1011
#ifndef TORRENT_DISABLE_LOGGING
1012
    session_log(" *** session paused ***");
1013
#endif
1014
    // this will abort all tracker announces other than event=stopped
1015
0
    m_tracker_manager.abort_all_requests();
1016
1017
0
    m_paused = true;
1018
0
    for (auto& te : m_torrents)
1019
0
    {
1020
0
      te->set_session_paused(true);
1021
0
    }
1022
0
  }
1023
1024
  void session_impl::resume()
1025
0
  {
1026
0
    TORRENT_ASSERT(is_single_thread());
1027
1028
0
    if (!m_paused) return;
1029
0
    m_paused = false;
1030
1031
0
    for (auto& te : m_torrents)
1032
0
    {
1033
0
      te->set_session_paused(false);
1034
0
    }
1035
0
  }
1036
1037
  void session_impl::abort() noexcept
1038
1.83k
  {
1039
1.83k
    TORRENT_ASSERT(is_single_thread());
1040
1041
1.83k
    if (m_abort) return;
1042
#ifndef TORRENT_DISABLE_LOGGING
1043
    session_log(" *** ABORT CALLED ***");
1044
#endif
1045
1046
    // at this point we cannot call the notify function anymore, since the
1047
    // session will become invalid.
1048
1.83k
    m_alerts.set_notify_function({});
1049
1050
1.83k
#ifndef TORRENT_DISABLE_EXTENSIONS
1051
1.83k
    for (auto& ext : m_ses_extensions[plugins_all_idx])
1052
5.50k
    {
1053
5.50k
      ext->abort();
1054
5.50k
    }
1055
1.83k
#endif
1056
1057
    // this will cancel requests that are not critical for shutting down
1058
    // cleanly. i.e. essentially tracker hostname lookups that we're not
1059
    // about to send event=stopped to
1060
1.83k
    m_host_resolver.abort();
1061
1062
1.83k
    m_close_file_timer.cancel();
1063
1064
    // abort the main thread
1065
1.83k
    m_abort = true;
1066
1.83k
    error_code ec;
1067
1068
    // we rely on on_tick() during shutdown, but we don't need to wait a
1069
    // whole second for it to fire
1070
1.83k
    m_timer.cancel();
1071
1072
1.83k
#if TORRENT_USE_I2P
1073
1.83k
    m_i2p_conn.close(ec);
1074
1.83k
#endif
1075
1.83k
    stop_ip_notifier();
1076
1.83k
    stop_lsd();
1077
1.83k
    stop_upnp();
1078
1.83k
    stop_natpmp();
1079
1.83k
#ifndef TORRENT_DISABLE_DHT
1080
1.83k
    stop_dht();
1081
1.83k
    m_dht_announce_timer.cancel();
1082
1.83k
#endif
1083
1.83k
    m_lsd_announce_timer.cancel();
1084
1085
1.83k
#ifdef TORRENT_SSL_PEERS
1086
1.83k
    {
1087
1.83k
      auto const sockets = std::move(m_incoming_sockets);
1088
1.83k
      for (auto const& s : sockets)
1089
0
      {
1090
0
        s->close(ec);
1091
0
        TORRENT_ASSERT(!ec);
1092
0
      }
1093
1.83k
    }
1094
1.83k
#endif
1095
1096
1.83k
#if TORRENT_USE_I2P
1097
1.83k
    if (m_i2p_listen_socket && m_i2p_listen_socket->is_open())
1098
0
    {
1099
0
      m_i2p_listen_socket->close(ec);
1100
0
      TORRENT_ASSERT(!ec);
1101
0
    }
1102
1.83k
#endif
1103
1104
#ifndef TORRENT_DISABLE_LOGGING
1105
    session_log(" aborting all torrents (%d)", int(m_torrents.size()));
1106
#endif
1107
    // abort all torrents
1108
1.83k
    for (auto const& te : m_torrents)
1109
1.83k
    {
1110
1.83k
      te->abort();
1111
1.83k
    }
1112
1.83k
    m_torrents.clear();
1113
1.83k
    m_stats_counters.set_value(counters::num_peers_up_unchoked_all, 0);
1114
1.83k
    m_stats_counters.set_value(counters::num_peers_up_unchoked, 0);
1115
1.83k
    m_stats_counters.set_value(counters::num_peers_up_unchoked_optimistic, 0);
1116
1117
#ifndef TORRENT_DISABLE_LOGGING
1118
    session_log(" aborting all tracker requests");
1119
#endif
1120
1.83k
    m_tracker_manager.stop();
1121
1122
#ifndef TORRENT_DISABLE_LOGGING
1123
    session_log(" aborting all connections (%d)", int(m_connections.size()));
1124
#endif
1125
    // abort all connections
1126
1.83k
    for (auto i = m_connections.begin(); i != m_connections.end();)
1127
0
    {
1128
0
      peer_connection* p = (*i).get();
1129
0
      ++i;
1130
0
      p->disconnect(errors::stopping_torrent, operation_t::bittorrent);
1131
0
    }
1132
1133
    // close the listen sockets
1134
1.83k
    for (auto const& l : m_listen_sockets)
1135
1.83k
    {
1136
1.83k
      if (l->sock)
1137
1.83k
      {
1138
1.83k
        l->sock->close(ec);
1139
1.83k
        TORRENT_ASSERT(!ec);
1140
1.83k
      }
1141
1142
      // TODO: 3 closing the udp sockets here means that
1143
      // the uTP connections cannot be closed gracefully
1144
1.83k
      if (l->udp_sock)
1145
1.83k
      {
1146
1.83k
        l->udp_sock->sock.close();
1147
1.83k
      }
1148
1.83k
    }
1149
1150
    // we need to give all the sockets an opportunity to actually have their handlers
1151
    // called and cancelled before we continue the shutdown. This is a bit
1152
    // complicated, if there are no "undead" peers, it's safe to resume the
1153
    // shutdown, but if there are, we have to wait for them to be cleared out
1154
    // first. In session_impl::on_tick() we check them periodically. If we're
1155
    // shutting down and we remove the last one, we'll initiate
1156
    // shutdown_stage2 from there.
1157
1.83k
    if (m_undead_peers.empty())
1158
1.83k
    {
1159
1.83k
      post(m_io_context, make_handler([this] { abort_stage2(); }
1160
1.83k
        , m_abort_handler_storage, *this));
1161
1.83k
    }
1162
1.83k
  }
1163
1164
  void session_impl::abort_stage2() noexcept
1165
3.67k
  {
1166
3.67k
    m_download_rate.close();
1167
3.67k
    m_upload_rate.close();
1168
1169
    // it's OK to detach the threads here. The disk_io_thread
1170
    // has an internal counter and won't release the network
1171
    // thread until they're all dead (via m_work).
1172
3.67k
    m_disk_thread->abort(false);
1173
1174
    // now it's OK for the network thread to exit
1175
3.67k
    m_work.reset();
1176
3.67k
  }
1177
1178
  bool session_impl::has_connection(peer_connection* p) const
1179
0
  {
1180
0
    return m_connections.find(p->self()) != m_connections.end();
1181
0
  }
1182
1183
  void session_impl::insert_peer(std::shared_ptr<peer_connection> const& c)
1184
0
  {
1185
0
    TORRENT_ASSERT(!c->m_in_constructor);
1186
1187
    // removing a peer may not throw an exception, so prepare for this
1188
    // connection to be added to the undead peers now.
1189
0
    m_undead_peers.reserve(m_undead_peers.size() + m_connections.size() + 1);
1190
0
    m_connections.insert(c);
1191
1192
0
    TORRENT_ASSERT_VAL(m_undead_peers.capacity() >= m_connections.size()
1193
0
      , m_undead_peers.capacity());
1194
0
  }
1195
1196
  void session_impl::set_port_filter(port_filter const& f)
1197
0
  {
1198
0
    m_port_filter = f;
1199
    // Close connections whose endpoint is filtered
1200
    // by the new port-filter
1201
0
    for (auto const& t : m_torrents)
1202
0
      t->port_filter_updated();
1203
0
  }
1204
1205
  void session_impl::set_ip_filter(std::shared_ptr<ip_filter> f)
1206
0
  {
1207
0
    INVARIANT_CHECK;
1208
1209
0
    m_ip_filter = std::move(f);
1210
1211
    // Close connections whose endpoint is filtered
1212
    // by the new ip-filter
1213
0
    for (auto& i : m_torrents)
1214
0
      i->set_ip_filter(m_ip_filter);
1215
0
  }
1216
1217
  void session_impl::ban_ip(address addr)
1218
0
  {
1219
0
    TORRENT_ASSERT(is_single_thread());
1220
0
    if (!m_ip_filter) m_ip_filter = std::make_shared<ip_filter>();
1221
0
    m_ip_filter->add_rule(addr, addr, ip_filter::blocked);
1222
0
    for (auto& i : m_torrents)
1223
0
      i->set_ip_filter(m_ip_filter);
1224
0
  }
1225
1226
  ip_filter const& session_impl::get_ip_filter()
1227
0
  {
1228
0
    TORRENT_ASSERT(is_single_thread());
1229
0
    if (!m_ip_filter) m_ip_filter = std::make_shared<ip_filter>();
1230
0
    return *m_ip_filter;
1231
0
  }
1232
1233
  port_filter const& session_impl::get_port_filter() const
1234
0
  {
1235
0
    TORRENT_ASSERT(is_single_thread());
1236
0
    return m_port_filter;
1237
0
  }
1238
1239
  peer_class_t session_impl::create_peer_class(char const* name)
1240
0
  {
1241
0
    TORRENT_ASSERT(is_single_thread());
1242
0
    return m_classes.new_peer_class(name);
1243
0
  }
1244
1245
  void session_impl::delete_peer_class(peer_class_t const cid)
1246
0
  {
1247
0
    TORRENT_ASSERT(is_single_thread());
1248
    // if you hit this assert, you're deleting a non-existent peer class
1249
0
    TORRENT_ASSERT_PRECOND(m_classes.at(cid));
1250
0
    if (m_classes.at(cid) == nullptr) return;
1251
0
    m_classes.decref(cid);
1252
0
  }
1253
1254
  peer_class_info session_impl::get_peer_class(peer_class_t const cid) const
1255
0
  {
1256
0
    peer_class_info ret{};
1257
0
    peer_class const* pc = m_classes.at(cid);
1258
    // if you hit this assert, you're passing in an invalid cid
1259
0
    TORRENT_ASSERT_PRECOND(pc);
1260
0
    if (pc == nullptr)
1261
0
    {
1262
#if TORRENT_USE_INVARIANT_CHECKS
1263
      // make it obvious that the return value is undefined
1264
      ret.upload_limit = 0xf0f0f0f;
1265
      ret.download_limit = 0xf0f0f0f;
1266
      ret.label.resize(20);
1267
      url_random(span<char>(ret.label));
1268
      ret.ignore_unchoke_slots = false;
1269
      ret.connection_limit_factor = 0xf0f0f0f;
1270
      ret.upload_priority = 0xf0f0f0f;
1271
      ret.download_priority = 0xf0f0f0f;
1272
#endif
1273
0
      return ret;
1274
0
    }
1275
1276
0
    pc->get_info(&ret);
1277
0
    return ret;
1278
0
  }
1279
1280
namespace {
1281
1282
  std::uint16_t make_announce_port(std::uint16_t const p)
1283
0
  { return p == 0 ? 1 : p; }
1284
}
1285
1286
  void session_impl::queue_tracker_request(tracker_request req
1287
    , std::weak_ptr<request_callback> c)
1288
0
  {
1289
0
    req.listen_port = 0;
1290
0
#if TORRENT_USE_I2P
1291
0
    if (!m_settings.get_str(settings_pack::i2p_hostname).empty())
1292
0
    {
1293
0
      req.i2pconn = &m_i2p_conn;
1294
0
    }
1295
0
#endif
1296
1297
0
#if TORRENT_USE_SSL
1298
0
#ifdef TORRENT_SSL_PEERS
1299
0
    bool const use_ssl = req.ssl_ctx != nullptr && req.ssl_ctx != &m_ssl_ctx;
1300
0
    if (!use_ssl)
1301
0
#endif
1302
0
      req.ssl_ctx = &m_ssl_ctx;
1303
0
#endif
1304
0
    if (const auto announce_port = std::uint16_t(m_settings.get_int(settings_pack::announce_port)))
1305
0
    {
1306
0
      req.listen_port = announce_port;
1307
0
    }
1308
0
    else if (auto ls = req.outgoing_socket.get())
1309
0
    {
1310
0
      req.listen_port =
1311
0
#ifdef TORRENT_SSL_PEERS
1312
      // SSL torrents use the SSL listen port
1313
0
      use_ssl ? make_announce_port(ssl_listen_port(ls)) :
1314
0
#endif
1315
0
      make_announce_port(listen_port(ls));
1316
0
    }
1317
0
    else
1318
0
    {
1319
0
      TORRENT_ASSERT(req.kind == tracker_request::i2p);
1320
0
      req.listen_port = 1;
1321
0
    }
1322
0
    m_tracker_manager.queue_request(get_context(), std::move(req), m_settings, c);
1323
0
  }
1324
1325
  void session_impl::set_peer_class(peer_class_t const cid, peer_class_info const& pci)
1326
0
  {
1327
0
    peer_class* pc = m_classes.at(cid);
1328
    // if you hit this assert, you're passing in an invalid cid
1329
0
    TORRENT_ASSERT_PRECOND(pc);
1330
0
    if (pc == nullptr) return;
1331
1332
0
    pc->set_info(&pci);
1333
0
  }
1334
1335
  void session_impl::set_peer_class_filter(ip_filter const& f)
1336
0
  {
1337
0
    INVARIANT_CHECK;
1338
0
    m_peer_class_filter = f;
1339
0
  }
1340
1341
  ip_filter const& session_impl::get_peer_class_filter() const
1342
0
  {
1343
0
    return m_peer_class_filter;
1344
0
  }
1345
1346
  void session_impl::set_peer_class_type_filter(peer_class_type_filter f)
1347
0
  {
1348
0
    m_peer_class_type_filter = f;
1349
0
  }
1350
1351
  peer_class_type_filter session_impl::get_peer_class_type_filter()
1352
0
  {
1353
0
    return m_peer_class_type_filter;
1354
0
  }
1355
1356
  void session_impl::set_peer_classes(peer_class_set* s, address const& a, socket_type_t const st)
1357
0
  {
1358
0
    std::uint32_t peer_class_mask = m_peer_class_filter.access(a);
1359
1360
0
    using sock_t = peer_class_type_filter::socket_type_t;
1361
    // assign peer class based on socket type
1362
0
    static aux::array<sock_t, 9, socket_type_t> const mapping{{{
1363
0
      sock_t::tcp_socket
1364
0
      , sock_t::tcp_socket
1365
0
      , sock_t::tcp_socket
1366
0
      , sock_t::utp_socket
1367
0
      , sock_t::i2p_socket
1368
0
      , sock_t::ssl_tcp_socket
1369
0
      , sock_t::ssl_tcp_socket
1370
0
      , sock_t::ssl_tcp_socket
1371
0
      , sock_t::ssl_utp_socket
1372
0
    }}};
1373
0
    sock_t const socket_type = mapping[st];
1374
    // filter peer classes based on type
1375
0
    peer_class_mask = m_peer_class_type_filter.apply(socket_type, peer_class_mask);
1376
1377
0
    for (peer_class_t i{0}; peer_class_mask; peer_class_mask >>= 1, ++i)
1378
0
    {
1379
0
      if ((peer_class_mask & 1) == 0) continue;
1380
1381
      // if you hit this assert, your peer class filter contains
1382
      // a bitmask referencing a non-existent peer class
1383
0
      TORRENT_ASSERT_PRECOND(m_classes.at(i));
1384
1385
0
      if (m_classes.at(i) == nullptr) continue;
1386
0
      s->add_class(m_classes, i);
1387
0
    }
1388
0
  }
1389
1390
  bool session_impl::ignore_unchoke_slots_set(peer_class_set const& set) const
1391
0
  {
1392
0
    int num = set.num_classes();
1393
0
    for (int i = 0; i < num; ++i)
1394
0
    {
1395
0
      peer_class const* pc = m_classes.at(set.class_at(i));
1396
0
      if (pc == nullptr) continue;
1397
0
      if (pc->ignore_unchoke_slots) return true;
1398
0
    }
1399
0
    return false;
1400
0
  }
1401
1402
  bandwidth_manager* session_impl::get_bandwidth_manager(int channel)
1403
0
  {
1404
0
    return (channel == peer_connection::download_channel)
1405
0
      ? &m_download_rate : &m_upload_rate;
1406
0
  }
1407
1408
  void session_impl::deferred_submit_jobs()
1409
3.56k
  {
1410
3.56k
    if (m_deferred_submit_disk_jobs) return;
1411
1.83k
    m_deferred_submit_disk_jobs = true;
1412
1.83k
    post(m_io_context, make_handler(
1413
1.83k
      [this] { wrap(&session_impl::submit_disk_jobs); }
1414
1.83k
      , m_submit_jobs_handler_storage, *this));
1415
1.83k
  }
1416
1417
  void session_impl::submit_disk_jobs()
1418
1.83k
  {
1419
1.83k
    TORRENT_ASSERT(m_deferred_submit_disk_jobs);
1420
1.83k
    m_deferred_submit_disk_jobs = false;
1421
1.83k
    m_disk_thread->submit_jobs();
1422
1.83k
  }
1423
1424
  // copies pointers to bandwidth channels from the peer classes
1425
  // into the array. Only bandwidth channels with a bandwidth limit
1426
  // is considered pertinent and copied
1427
  // returns the number of pointers copied
1428
  // channel is upload_channel or download_channel
1429
  int session_impl::copy_pertinent_channels(peer_class_set const& set
1430
    , int channel, bandwidth_channel** dst, int const max)
1431
0
  {
1432
0
    int num_channels = set.num_classes();
1433
0
    int num_copied = 0;
1434
0
    for (int i = 0; i < num_channels; ++i)
1435
0
    {
1436
0
      peer_class* pc = m_classes.at(set.class_at(i));
1437
0
      TORRENT_ASSERT(pc);
1438
0
      if (pc == nullptr) continue;
1439
0
      bandwidth_channel* chan = &pc->channel[channel];
1440
      // no need to include channels that don't have any bandwidth limits
1441
0
      if (chan->throttle() == 0) continue;
1442
0
      dst[num_copied] = chan;
1443
0
      ++num_copied;
1444
0
      if (num_copied == max) break;
1445
0
    }
1446
0
    return num_copied;
1447
0
  }
1448
1449
  bool session_impl::use_quota_overhead(bandwidth_channel* ch, int amount)
1450
0
  {
1451
0
    ch->use_quota(amount);
1452
0
    return (ch->throttle() > 0 && ch->throttle() < amount);
1453
0
  }
1454
1455
  int session_impl::use_quota_overhead(peer_class_set& set, int const amount_down, int const amount_up)
1456
0
  {
1457
0
    int ret = 0;
1458
0
    int const num = set.num_classes();
1459
0
    for (int i = 0; i < num; ++i)
1460
0
    {
1461
0
      peer_class* p = m_classes.at(set.class_at(i));
1462
0
      if (p == nullptr) continue;
1463
1464
0
      bandwidth_channel* ch = &p->channel[peer_connection::download_channel];
1465
0
      if (use_quota_overhead(ch, amount_down))
1466
0
        ret |= 1 << peer_connection::download_channel;
1467
0
      ch = &p->channel[peer_connection::upload_channel];
1468
0
      if (use_quota_overhead(ch, amount_up))
1469
0
        ret |= 1 << peer_connection::upload_channel;
1470
0
    }
1471
0
    return ret;
1472
0
  }
1473
1474
  // session_impl is responsible for deleting 'pack'
1475
  void session_impl::apply_settings_pack(std::shared_ptr<settings_pack> pack)
1476
0
  {
1477
0
    INVARIANT_CHECK;
1478
0
    apply_settings_pack_impl(*pack);
1479
0
  }
1480
1481
  settings_pack session_impl::get_settings() const
1482
0
  {
1483
0
    settings_pack ret;
1484
    // TODO: it would be nice to reserve() these vectors up front
1485
0
    for (int i = settings_pack::string_type_base;
1486
0
      i < settings_pack::max_string_setting_internal; ++i)
1487
0
    {
1488
0
      ret.set_str(i, m_settings.get_str(i));
1489
0
    }
1490
0
    for (int i = settings_pack::int_type_base;
1491
0
      i < settings_pack::max_int_setting_internal; ++i)
1492
0
    {
1493
0
      ret.set_int(i, m_settings.get_int(i));
1494
0
    }
1495
0
    for (int i = settings_pack::bool_type_base;
1496
0
      i < settings_pack::max_bool_setting_internal; ++i)
1497
0
    {
1498
0
      ret.set_bool(i, m_settings.get_bool(i));
1499
0
    }
1500
0
    return ret;
1501
0
  }
1502
1503
namespace {
1504
  template <typename Pack>
1505
  int get_setting_impl(Pack const& p, int name, int*)
1506
0
  { return p.get_int(name); }
Unexecuted instantiation: session_impl.cpp:int libtorrent::aux::(anonymous namespace)::get_setting_impl<libtorrent::settings_pack>(libtorrent::settings_pack const&, int, int*)
Unexecuted instantiation: session_impl.cpp:int libtorrent::aux::(anonymous namespace)::get_setting_impl<libtorrent::aux::session_settings>(libtorrent::aux::session_settings const&, int, int*)
1507
1508
  template <typename Pack>
1509
  bool get_setting_impl(Pack const& p, int name, bool*)
1510
0
  { return p.get_bool(name); }
Unexecuted instantiation: session_impl.cpp:bool libtorrent::aux::(anonymous namespace)::get_setting_impl<libtorrent::settings_pack>(libtorrent::settings_pack const&, int, bool*)
Unexecuted instantiation: session_impl.cpp:bool libtorrent::aux::(anonymous namespace)::get_setting_impl<libtorrent::aux::session_settings>(libtorrent::aux::session_settings const&, int, bool*)
1511
1512
  template <typename Pack>
1513
  std::string get_setting_impl(Pack const& p, int name, std::string*)
1514
0
  { return p.get_str(name); }
Unexecuted instantiation: session_impl.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > libtorrent::aux::(anonymous namespace)::get_setting_impl<libtorrent::settings_pack>(libtorrent::settings_pack const&, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*)
Unexecuted instantiation: session_impl.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > libtorrent::aux::(anonymous namespace)::get_setting_impl<libtorrent::aux::session_settings>(libtorrent::aux::session_settings const&, int, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*)
1515
1516
  template <typename Type, typename Pack>
1517
  Type get_setting(Pack const& p, int name)
1518
0
  {
1519
0
    return get_setting_impl(p, name, static_cast<Type*>(nullptr));
1520
0
  }
Unexecuted instantiation: session_impl.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > libtorrent::aux::(anonymous namespace)::get_setting<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, libtorrent::settings_pack>(libtorrent::settings_pack const&, int)
Unexecuted instantiation: session_impl.cpp:std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > libtorrent::aux::(anonymous namespace)::get_setting<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, libtorrent::aux::session_settings>(libtorrent::aux::session_settings const&, int)
Unexecuted instantiation: session_impl.cpp:int libtorrent::aux::(anonymous namespace)::get_setting<int, libtorrent::settings_pack>(libtorrent::settings_pack const&, int)
Unexecuted instantiation: session_impl.cpp:int libtorrent::aux::(anonymous namespace)::get_setting<int, libtorrent::aux::session_settings>(libtorrent::aux::session_settings const&, int)
Unexecuted instantiation: session_impl.cpp:bool libtorrent::aux::(anonymous namespace)::get_setting<bool, libtorrent::settings_pack>(libtorrent::settings_pack const&, int)
Unexecuted instantiation: session_impl.cpp:bool libtorrent::aux::(anonymous namespace)::get_setting<bool, libtorrent::aux::session_settings>(libtorrent::aux::session_settings const&, int)
1521
1522
  template <typename Type>
1523
  bool setting_changed(settings_pack const& pack, aux::session_settings const& sett, int name)
1524
0
  {
1525
0
    return pack.has_val(name)
1526
0
      && get_setting<Type>(pack, name) != get_setting<Type>(sett, name);
1527
0
  }
Unexecuted instantiation: session_impl.cpp:bool libtorrent::aux::(anonymous namespace)::setting_changed<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(libtorrent::settings_pack const&, libtorrent::aux::session_settings const&, int)
Unexecuted instantiation: session_impl.cpp:bool libtorrent::aux::(anonymous namespace)::setting_changed<int>(libtorrent::settings_pack const&, libtorrent::aux::session_settings const&, int)
Unexecuted instantiation: session_impl.cpp:bool libtorrent::aux::(anonymous namespace)::setting_changed<bool>(libtorrent::settings_pack const&, libtorrent::aux::session_settings const&, int)
1528
}
1529
1530
#if !defined TORRENT_DISABLE_LOGGING || TORRENT_USE_ASSERTS
1531
  void session_impl::validate_setting(int const int_name, int const min, int const max)
1532
20.1k
  {
1533
20.1k
    int const val = m_settings.get_int(int_name);
1534
20.1k
    TORRENT_ASSERT_PRECOND_MSG(val >= min, name_for_setting(int_name));
1535
20.1k
    TORRENT_ASSERT_PRECOND_MSG(val <= max, name_for_setting(int_name));
1536
#ifndef TORRENT_DISABLE_LOGGING
1537
    if (val < min || val > max)
1538
      session_log("invalid %s setting: %d", name_for_setting(int_name), val);
1539
#endif
1540
20.1k
  }
1541
1542
  void session_impl::validate_settings()
1543
1.83k
  {
1544
1.83k
    validate_setting(settings_pack::out_enc_policy, 0, 2);
1545
1.83k
    validate_setting(settings_pack::in_enc_policy, 0, 2);
1546
1.83k
    validate_setting(settings_pack::allowed_enc_level, 1, 3);
1547
1.83k
    validate_setting(settings_pack::mixed_mode_algorithm, 0, 1);
1548
1.83k
    validate_setting(settings_pack::proxy_type, 0, 5);
1549
1.83k
    validate_setting(settings_pack::disk_io_read_mode, 0, 3);
1550
1.83k
    validate_setting(settings_pack::disk_io_write_mode, 0, 3);
1551
1.83k
    validate_setting(settings_pack::choking_algorithm, 0, 3);
1552
1.83k
    validate_setting(settings_pack::seed_choking_algorithm, 0, 3);
1553
1.83k
    validate_setting(settings_pack::suggest_mode, 0, 1);
1554
1.83k
    validate_setting(settings_pack::disk_write_mode, 0, 2);
1555
1.83k
  }
1556
#endif
1557
1558
  void session_impl::apply_settings_pack_impl(settings_pack const& pack)
1559
0
  {
1560
0
    bool const reopen_listen_port
1561
0
      = setting_changed<std::string>(pack, m_settings, settings_pack::listen_interfaces)
1562
0
      || setting_changed<int>(pack, m_settings, settings_pack::proxy_type)
1563
0
      || setting_changed<bool>(pack, m_settings, settings_pack::proxy_peer_connections)
1564
0
#if TORRENT_ABI_VERSION == 1
1565
0
      || setting_changed<int>(pack, m_settings, settings_pack::ssl_listen)
1566
0
#endif
1567
0
      ;
1568
1569
0
    bool const update_want_peers
1570
0
      = setting_changed<bool>(pack, m_settings, settings_pack::seeding_outgoing_connections)
1571
0
      || setting_changed<bool>(pack, m_settings, settings_pack::enable_outgoing_tcp)
1572
0
      || setting_changed<bool>(pack, m_settings, settings_pack::enable_outgoing_utp)
1573
0
    ;
1574
1575
#ifndef TORRENT_DISABLE_LOGGING
1576
    session_log("applying settings pack, reopen_listen_port=%s"
1577
      , reopen_listen_port ? "true" : "false");
1578
#endif
1579
1580
0
    apply_pack(&pack, m_settings, this);
1581
1582
0
#if !defined TORRENT_DISABLE_LOGGING || TORRENT_USE_ASSERTS
1583
0
    validate_settings();
1584
0
#endif
1585
1586
0
    m_disk_thread->settings_updated();
1587
1588
0
    if (!reopen_listen_port)
1589
0
    {
1590
      // no need to call this if reopen_listen_port is true
1591
      // since the apply_pack will do it
1592
0
      update_listen_interfaces();
1593
0
    }
1594
0
    else
1595
0
    {
1596
0
      reopen_listen_sockets();
1597
0
    }
1598
1599
0
    if (update_want_peers)
1600
0
    {
1601
0
      for (auto const& t : m_torrents)
1602
0
        t->update_want_peers();
1603
0
    }
1604
0
  }
1605
1606
  std::shared_ptr<listen_socket_t> session_impl::setup_listener(
1607
    listen_endpoint_t const& lep, error_code& ec)
1608
1.83k
  {
1609
1.83k
    int retries = m_settings.get_int(settings_pack::max_retry_port_bind);
1610
1.83k
    tcp::endpoint bind_ep(lep.addr, std::uint16_t(lep.port));
1611
1612
#ifndef TORRENT_DISABLE_LOGGING
1613
    if (should_log())
1614
    {
1615
      session_log("attempting to open listen socket to: %s on device: %s %s%s%s%s%s"
1616
        , print_endpoint(bind_ep).c_str(), lep.device.c_str()
1617
        , (lep.ssl == transport::ssl) ? "ssl " : ""
1618
        , (lep.flags & listen_socket_t::local_network) ? "local-network " : ""
1619
        , (lep.flags & listen_socket_t::accept_incoming) ? "accept-incoming " : "no-incoming "
1620
        , (lep.flags & listen_socket_t::was_expanded) ? "expanded-ip " : ""
1621
        , (lep.flags & listen_socket_t::proxy) ? "proxy " : "");
1622
    }
1623
#endif
1624
1625
1.83k
    auto ret = std::make_shared<listen_socket_t>();
1626
1.83k
    ret->ssl = lep.ssl;
1627
1.83k
    ret->original_port = bind_ep.port();
1628
1.83k
    ret->flags = lep.flags;
1629
1.83k
    ret->netmask = lep.netmask;
1630
1.83k
    operation_t last_op = operation_t::unknown;
1631
1.83k
    socket_type_t const sock_type
1632
1.83k
      = (lep.ssl == transport::ssl)
1633
1.83k
      ? socket_type_t::tcp_ssl
1634
1.83k
      : socket_type_t::tcp;
1635
1636
    // if we're in force-proxy mode, don't open TCP listen sockets. We cannot
1637
    // accept connections on our local machine in this case.
1638
    // TODO: 3 the logic in this if-block should be factored out into a
1639
    // separate function. At least most of it
1640
1.83k
    if (ret->flags & listen_socket_t::accept_incoming)
1641
1.83k
    {
1642
1.83k
      ret->sock = std::make_shared<tcp::acceptor>(m_io_context);
1643
1.83k
      ret->sock->open(bind_ep.protocol(), ec);
1644
1.83k
      last_op = operation_t::sock_open;
1645
1.83k
      if (ec)
1646
0
      {
1647
#ifndef TORRENT_DISABLE_LOGGING
1648
        if (should_log())
1649
        {
1650
          session_log("failed to open socket: %s"
1651
            , ec.message().c_str());
1652
        }
1653
#endif
1654
1655
0
        if (m_alerts.should_post<listen_failed_alert>())
1656
0
          m_alerts.emplace_alert<listen_failed_alert>(lep.device, bind_ep, last_op
1657
0
            , ec, sock_type);
1658
0
        return ret;
1659
0
      }
1660
1661
#ifdef TORRENT_WINDOWS
1662
      {
1663
        // this is best-effort. ignore errors
1664
        error_code err;
1665
        ret->sock->set_option(exclusive_address_use(true), err);
1666
#ifndef TORRENT_DISABLE_LOGGING
1667
        if (err && should_log())
1668
        {
1669
          session_log("failed enable exclusive address use on listen socket: %s"
1670
            , err.message().c_str());
1671
        }
1672
#endif // TORRENT_DISABLE_LOGGING
1673
      }
1674
#else
1675
1676
1.83k
      {
1677
        // this is best-effort. ignore errors
1678
1.83k
        error_code err;
1679
1.83k
        ret->sock->set_option(tcp::acceptor::reuse_address(true), err);
1680
#ifndef TORRENT_DISABLE_LOGGING
1681
        if (err && should_log())
1682
        {
1683
          session_log("failed enable reuse-address on listen socket: %s"
1684
            , err.message().c_str());
1685
        }
1686
#endif // TORRENT_DISABLE_LOGGING
1687
1.83k
      }
1688
1.83k
#endif // TORRENT_WINDOWS
1689
1690
1.83k
      if (is_v6(bind_ep))
1691
0
      {
1692
0
        error_code err; // ignore errors here
1693
0
        ret->sock->set_option(boost::asio::ip::v6_only(true), err);
1694
#ifndef TORRENT_DISABLE_LOGGING
1695
        if (err && should_log())
1696
        {
1697
          session_log("failed enable v6 only on listen socket: %s"
1698
            , err.message().c_str());
1699
        }
1700
#endif // LOGGING
1701
1702
#ifdef TORRENT_WINDOWS
1703
        // enable Teredo on windows
1704
        ret->sock->set_option(v6_protection_level(PROTECTION_LEVEL_UNRESTRICTED), err);
1705
#ifndef TORRENT_DISABLE_LOGGING
1706
        if (err && should_log())
1707
        {
1708
          session_log("failed enable IPv6 unrestricted protection level on "
1709
            "listen socket: %s", err.message().c_str());
1710
        }
1711
#endif // TORRENT_DISABLE_LOGGING
1712
#endif // TORRENT_WINDOWS
1713
0
      }
1714
1715
1.83k
      if (!lep.device.empty())
1716
1.83k
      {
1717
        // we have an actual device we're interested in listening on, if we
1718
        // have SO_BINDTODEVICE functionality, use it now.
1719
1.83k
#if TORRENT_HAS_BINDTODEVICE
1720
1.83k
        bind_device(*ret->sock, lep.device.c_str(), ec);
1721
#ifndef TORRENT_DISABLE_LOGGING
1722
        if (ec && should_log())
1723
        {
1724
          session_log("bind to device failed (device: %s): %s"
1725
            , lep.device.c_str(), ec.message().c_str());
1726
        }
1727
#endif // TORRENT_DISABLE_LOGGING
1728
1.83k
        ec.clear();
1729
1.83k
#endif // TORRENT_HAS_BINDTODEVICE
1730
1.83k
      }
1731
1732
1.83k
      ret->sock->bind(bind_ep, ec);
1733
1.83k
      last_op = operation_t::sock_bind;
1734
1735
1.83k
      while (ec == error_code(error::address_in_use) && retries > 0)
1736
0
      {
1737
0
        TORRENT_ASSERT_VAL(ec, ec);
1738
#ifndef TORRENT_DISABLE_LOGGING
1739
        if (should_log())
1740
        {
1741
          session_log("failed to bind listen socket to: %s on device: %s :"
1742
            " [%s] (%d) %s (retries: %d)"
1743
            , print_endpoint(bind_ep).c_str()
1744
            , lep.device.c_str()
1745
            , ec.category().name(), ec.value(), ec.message().c_str()
1746
            , retries);
1747
        }
1748
#endif
1749
0
        ec.clear();
1750
0
        --retries;
1751
0
        bind_ep.port(bind_ep.port() + 1);
1752
0
        ret->sock->bind(bind_ep, ec);
1753
0
      }
1754
1755
1.83k
      if (ec == error_code(error::address_in_use)
1756
1.83k
        && m_settings.get_bool(settings_pack::listen_system_port_fallback)
1757
1.83k
        && bind_ep.port() != 0)
1758
0
      {
1759
        // instead of giving up, try let the OS pick a port
1760
0
        bind_ep.port(0);
1761
0
        ec.clear();
1762
0
        ret->sock->bind(bind_ep, ec);
1763
0
        last_op = operation_t::sock_bind;
1764
0
      }
1765
1766
1.83k
      if (ec)
1767
0
      {
1768
        // not even that worked, give up
1769
1770
#ifndef TORRENT_DISABLE_LOGGING
1771
        if (should_log())
1772
        {
1773
          session_log("failed to bind listen socket to: %s on device: %s :"
1774
            " [%s] (%d) %s (giving up)"
1775
            , print_endpoint(bind_ep).c_str()
1776
            , lep.device.c_str()
1777
            , ec.category().name(), ec.value(), ec.message().c_str());
1778
        }
1779
#endif
1780
0
        if (m_alerts.should_post<listen_failed_alert>())
1781
0
        {
1782
0
          m_alerts.emplace_alert<listen_failed_alert>(lep.device, bind_ep
1783
0
            , last_op, ec, sock_type);
1784
0
        }
1785
0
        ret->sock.reset();
1786
0
        return ret;
1787
0
      }
1788
1.83k
      ret->local_endpoint = ret->sock->local_endpoint(ec);
1789
1.83k
      last_op = operation_t::getname;
1790
1.83k
      if (ec)
1791
0
      {
1792
#ifndef TORRENT_DISABLE_LOGGING
1793
        if (should_log())
1794
        {
1795
          session_log("get_sockname failed on listen socket: %s"
1796
            , ec.message().c_str());
1797
        }
1798
#endif
1799
0
        if (m_alerts.should_post<listen_failed_alert>())
1800
0
        {
1801
0
          m_alerts.emplace_alert<listen_failed_alert>(lep.device, bind_ep
1802
0
            , last_op, ec, sock_type);
1803
0
        }
1804
0
        return ret;
1805
0
      }
1806
1807
1.83k
      TORRENT_ASSERT(ret->local_endpoint.port() == bind_ep.port()
1808
1.83k
        || bind_ep.port() == 0);
1809
1810
1.83k
      if (bind_ep.port() == 0) bind_ep = ret->local_endpoint;
1811
1812
1.83k
      ret->sock->listen(m_settings.get_int(settings_pack::listen_queue_size), ec);
1813
1.83k
      last_op = operation_t::sock_listen;
1814
1815
1.83k
      if (ec)
1816
0
      {
1817
#ifndef TORRENT_DISABLE_LOGGING
1818
        if (should_log())
1819
        {
1820
          session_log("cannot listen on interface \"%s\": %s"
1821
            , lep.device.c_str(), ec.message().c_str());
1822
        }
1823
#endif
1824
0
        if (m_alerts.should_post<listen_failed_alert>())
1825
0
        {
1826
0
          m_alerts.emplace_alert<listen_failed_alert>(lep.device, bind_ep
1827
0
            , last_op, ec, sock_type);
1828
0
        }
1829
0
        return ret;
1830
0
      }
1831
1.83k
    } // accept incoming
1832
1833
1.83k
    socket_type_t const udp_sock_type
1834
1.83k
      = (lep.ssl == transport::ssl)
1835
1.83k
      ? socket_type_t::utp_ssl
1836
1.83k
      : socket_type_t::utp;
1837
1.83k
    udp::endpoint udp_bind_ep(bind_ep.address(), bind_ep.port());
1838
1839
1.83k
    ret->udp_sock = std::make_shared<session_udp_socket>(m_io_context, ret);
1840
1.83k
    ret->udp_sock->sock.open(udp_bind_ep.protocol(), ec);
1841
1.83k
    if (ec)
1842
0
    {
1843
#ifndef TORRENT_DISABLE_LOGGING
1844
      if (should_log())
1845
      {
1846
        session_log("failed to open UDP socket: %s: %s"
1847
          , lep.device.c_str(), ec.message().c_str());
1848
      }
1849
#endif
1850
1851
0
      last_op = operation_t::sock_open;
1852
0
      if (m_alerts.should_post<listen_failed_alert>())
1853
0
        m_alerts.emplace_alert<listen_failed_alert>(lep.device
1854
0
          , bind_ep, last_op, ec, udp_sock_type);
1855
1856
0
      return ret;
1857
0
    }
1858
1859
1.83k
#if TORRENT_HAS_BINDTODEVICE
1860
1.83k
    if (!lep.device.empty())
1861
1.83k
    {
1862
1.83k
      bind_device(ret->udp_sock->sock, lep.device.c_str(), ec);
1863
#ifndef TORRENT_DISABLE_LOGGING
1864
      if (ec && should_log())
1865
      {
1866
        session_log("bind to device failed (device: %s): %s"
1867
          , lep.device.c_str(), ec.message().c_str());
1868
      }
1869
#endif // TORRENT_DISABLE_LOGGING
1870
1.83k
      ec.clear();
1871
1.83k
    }
1872
1.83k
#endif
1873
1.83k
    ret->udp_sock->sock.bind(udp_bind_ep, ec);
1874
1875
1.83k
    while (ec == error_code(error::address_in_use) && retries > 0)
1876
0
    {
1877
0
      TORRENT_ASSERT_VAL(ec, ec);
1878
#ifndef TORRENT_DISABLE_LOGGING
1879
      if (should_log())
1880
      {
1881
        session_log("failed to bind udp socket to: %s on device: %s :"
1882
          " [%s] (%d) %s (retries: %d)"
1883
          , print_endpoint(bind_ep).c_str()
1884
          , lep.device.c_str()
1885
          , ec.category().name(), ec.value(), ec.message().c_str()
1886
          , retries);
1887
      }
1888
#endif
1889
0
      ec.clear();
1890
0
      --retries;
1891
0
      udp_bind_ep.port(udp_bind_ep.port() + 1);
1892
0
      ret->udp_sock->sock.bind(udp_bind_ep, ec);
1893
0
    }
1894
1895
1.83k
    if (ec == error_code(error::address_in_use)
1896
1.83k
      && m_settings.get_bool(settings_pack::listen_system_port_fallback)
1897
1.83k
      && udp_bind_ep.port() != 0)
1898
0
    {
1899
      // instead of giving up, try let the OS pick a port
1900
0
      udp_bind_ep.port(0);
1901
0
      ec.clear();
1902
0
      ret->udp_sock->sock.bind(udp_bind_ep, ec);
1903
0
    }
1904
1905
1.83k
    last_op = operation_t::sock_bind;
1906
1.83k
    if (ec)
1907
0
    {
1908
#ifndef TORRENT_DISABLE_LOGGING
1909
      if (should_log())
1910
      {
1911
        session_log("failed to bind UDP socket: %s: %s"
1912
          , lep.device.c_str(), ec.message().c_str());
1913
      }
1914
#endif
1915
1916
0
      if (m_alerts.should_post<listen_failed_alert>())
1917
0
        m_alerts.emplace_alert<listen_failed_alert>(lep.device
1918
0
          , bind_ep, last_op, ec, udp_sock_type);
1919
1920
0
      return ret;
1921
0
    }
1922
1923
    // if we did not open a TCP listen socket, ret->local_endpoint was never
1924
    // initialized, so do that now, based on the UDP socket
1925
1.83k
    if (!(ret->flags & listen_socket_t::accept_incoming))
1926
0
    {
1927
0
      auto const udp_ep = ret->udp_sock->local_endpoint();
1928
0
      ret->local_endpoint = tcp::endpoint(udp_ep.address(), udp_ep.port());
1929
0
    }
1930
1931
1.83k
    ret->device = lep.device;
1932
1933
1.83k
    error_code err;
1934
1.83k
    set_socket_buffer_size(ret->udp_sock->sock, m_settings, err);
1935
1.83k
    if (err)
1936
0
    {
1937
0
      if (m_alerts.should_post<udp_error_alert>())
1938
0
        m_alerts.emplace_alert<udp_error_alert>(ret->udp_sock->sock.local_endpoint(ec)
1939
0
          , operation_t::alloc_recvbuf, err);
1940
0
    }
1941
1942
    // this call is necessary here because, unless the settings actually
1943
    // change after the session is up and listening, at no other point
1944
    // set_proxy_settings is called with the correct proxy configuration,
1945
    // internally, this method handle the SOCKS5's connection logic
1946
1.83k
    ret->udp_sock->sock.set_proxy_settings(proxy(), m_alerts, get_resolver()
1947
1.83k
      , settings().get_bool(settings_pack::socks5_udp_send_local_ep));
1948
1949
1.83k
    ADD_OUTSTANDING_ASYNC("session_impl::on_udp_packet");
1950
1.83k
    ret->udp_sock->sock.async_read(aux::make_handler([this, ret](error_code const& e)
1951
1.83k
      { this->on_udp_packet(ret->udp_sock, ret, ret->ssl, e); }
1952
1.83k
      , ret->udp_handler_storage, *this));
1953
1954
#ifndef TORRENT_DISABLE_LOGGING
1955
    if (should_log())
1956
    {
1957
      session_log(" listening on: %s TCP port: %d UDP port: %d"
1958
        , bind_ep.address().to_string().c_str()
1959
        , ret->tcp_external_port(), ret->udp_external_port());
1960
    }
1961
#endif
1962
1.83k
    return ret;
1963
1.83k
  }
1964
1965
  void session_impl::on_exception(std::exception const& e)
1966
0
  {
1967
0
    TORRENT_UNUSED(e);
1968
#ifndef TORRENT_DISABLE_LOGGING
1969
    session_log("FATAL SESSION ERROR [%s]", e.what());
1970
#endif
1971
0
    this->abort();
1972
0
  }
1973
1974
  void session_impl::on_error(error_code const& ec)
1975
0
  {
1976
0
    TORRENT_UNUSED(ec);
1977
#ifndef TORRENT_DISABLE_LOGGING
1978
    session_log("FATAL SESSION ERROR (%s : %d) [%s]"
1979
      , ec.category().name(), ec.value(), ec.message().c_str());
1980
#endif
1981
0
    this->abort();
1982
0
  }
1983
1984
  void session_impl::on_ip_change(error_code const& ec)
1985
0
  {
1986
#ifndef TORRENT_DISABLE_LOGGING
1987
    if (!ec)
1988
      session_log("received ip change from internal ip_notifier");
1989
    else
1990
      session_log("received error on_ip_change: %d, %s", ec.value(), ec.message().c_str());
1991
#endif
1992
0
    if (ec || m_abort || !m_ip_notifier) return;
1993
0
    m_ip_notifier->async_wait([this] (error_code const& e)
1994
0
      { wrap(&session_impl::on_ip_change, e); });
1995
0
    reopen_network_sockets({});
1996
0
  }
1997
1998
  // TODO: could this function be merged with expand_unspecified_addresses?
1999
  // right now both listen_endpoint_t and listen_interface_t are almost
2000
  // identical, maybe the latter could be removed too
2001
  void interface_to_endpoints(listen_interface_t const& iface
2002
    , listen_socket_flags_t flags
2003
    , span<ip_interface const> const ifs
2004
    , std::vector<listen_endpoint_t>& eps)
2005
1.83k
  {
2006
1.83k
    flags |= iface.local ? listen_socket_t::local_network : listen_socket_flags_t{};
2007
1.83k
    transport const ssl = iface.ssl ? transport::ssl : transport::plaintext;
2008
2009
    // First, check to see if it's an IP address
2010
1.83k
    error_code err;
2011
1.83k
    address const adr = make_address(iface.device.c_str(), err);
2012
1.83k
    if (!err)
2013
1.83k
    {
2014
1.83k
      eps.emplace_back(adr, iface.port, std::string{}, ssl, flags);
2015
1.83k
    }
2016
0
    else
2017
0
    {
2018
0
      flags |= listen_socket_t::was_expanded;
2019
2020
      // this is the case where device names a network device. We need to
2021
      // enumerate all IPs associated with this device
2022
0
      for (auto const& ipface : ifs)
2023
0
      {
2024
        // we're looking for a specific interface, and its address
2025
        // (which must be of the same family as the address we're
2026
        // connecting to)
2027
0
        if (iface.device != ipface.name) continue;
2028
2029
0
        bool const local = iface.local
2030
0
          || ipface.interface_address.is_loopback()
2031
0
          || is_link_local(ipface.interface_address);
2032
2033
0
        eps.emplace_back(ipface.interface_address, iface.port, iface.device
2034
0
          , ssl, flags | (local ? listen_socket_t::local_network : listen_socket_flags_t{}));
2035
0
      }
2036
0
    }
2037
1.83k
  }
2038
2039
  void session_impl::reopen_listen_sockets(bool const map_ports)
2040
1.83k
  {
2041
#ifndef TORRENT_DISABLE_LOGGING
2042
    session_log("reopen listen sockets");
2043
#endif
2044
2045
1.83k
    TORRENT_ASSERT(is_single_thread());
2046
2047
1.83k
    TORRENT_ASSERT(!m_abort);
2048
2049
1.83k
    error_code ec;
2050
2051
1.83k
    if (m_abort) return;
2052
2053
    // first build a list of endpoints we should be listening on
2054
    // we need to remove any unneeded sockets first to avoid the possibility
2055
    // of a new socket failing to bind due to a conflict with a stale socket
2056
1.83k
    std::vector<listen_endpoint_t> eps;
2057
2058
    // if we don't proxy peer connections, don't apply the special logic for
2059
    // proxies
2060
1.83k
    if (m_settings.get_int(settings_pack::proxy_type) != settings_pack::none
2061
1.83k
      && m_settings.get_bool(settings_pack::proxy_peer_connections))
2062
0
    {
2063
      // we will be able to accept incoming connections over UDP. so use
2064
      // one of the ports the user specified to use a consistent port
2065
      // across sessions. If the user did not specify any ports, pick one
2066
      // at random
2067
0
      int const port = m_listen_interfaces.empty()
2068
0
        ? int(random(63000) + 2000)
2069
0
        : m_listen_interfaces.front().port;
2070
0
      listen_endpoint_t ep(address_v4::any(), port, {}
2071
0
        , transport::plaintext, listen_socket_t::proxy);
2072
0
      eps.emplace_back(ep);
2073
0
    }
2074
1.83k
    else
2075
1.83k
    {
2076
1.83k
      std::vector<ip_interface> const ifs = enum_net_interfaces(m_io_context, ec);
2077
1.83k
      if (ec && m_alerts.should_post<listen_failed_alert>())
2078
0
      {
2079
0
        m_alerts.emplace_alert<listen_failed_alert>(""
2080
0
          , operation_t::enum_if, ec, socket_type_t::tcp);
2081
0
      }
2082
1.83k
      auto const routes = enum_routes(m_io_context, ec);
2083
1.83k
      if (ec && m_alerts.should_post<listen_failed_alert>())
2084
0
      {
2085
0
        m_alerts.emplace_alert<listen_failed_alert>(""
2086
0
          , operation_t::enum_route, ec, socket_type_t::tcp);
2087
0
      }
2088
2089
      // expand device names and populate eps
2090
1.83k
      for (auto const& iface : m_listen_interfaces)
2091
1.83k
      {
2092
#if !TORRENT_USE_SSL
2093
        if (iface.ssl)
2094
        {
2095
#ifndef TORRENT_DISABLE_LOGGING
2096
          session_log("attempted to listen ssl with no library support on device: \"%s\""
2097
            , iface.device.c_str());
2098
#endif
2099
          if (m_alerts.should_post<listen_failed_alert>())
2100
          {
2101
            m_alerts.emplace_alert<listen_failed_alert>(iface.device
2102
              , operation_t::sock_open
2103
              , boost::asio::error::operation_not_supported
2104
              , socket_type_t::tcp_ssl);
2105
          }
2106
          continue;
2107
        }
2108
#endif
2109
2110
        // now we have a device to bind to. This device may actually just be an
2111
        // IP address or a device name. In case it's a device name, we want to
2112
        // (potentially) end up binding a socket for each IP address associated
2113
        // with that device.
2114
1.83k
        interface_to_endpoints(iface, listen_socket_t::accept_incoming, ifs, eps);
2115
1.83k
      }
2116
2117
1.83k
      if (eps.empty())
2118
0
      {
2119
#ifndef TORRENT_DISABLE_LOGGING
2120
        session_log("no listen sockets");
2121
#endif
2122
0
      }
2123
2124
#if defined TORRENT_ANDROID && __ANDROID_API__ >= 24
2125
      // For Android API >= 24, enum_routes with the current NETLINK based
2126
      // implementation is unsupported (maybe in the future the operation
2127
      // will be restore using another implementation). If routes is empty,
2128
      // allow using unspecified address is a best effort approach that
2129
      // seems to work. The issue with this approach is with the DHTs,
2130
      // because for IPv6 this is not following BEP 32 and BEP 45. See:
2131
      // https://www.bittorrent.org/beps/bep_0032.html
2132
      // https://www.bittorrent.org/beps/bep_0045.html
2133
      if (!routes.empty()) expand_unspecified_address(ifs, routes, eps);
2134
#else
2135
1.83k
      expand_unspecified_address(ifs, routes, eps);
2136
1.83k
#endif
2137
1.83k
      expand_devices(ifs, eps);
2138
1.83k
    }
2139
2140
1.83k
    auto remove_iter = partition_listen_sockets(eps, m_listen_sockets);
2141
2142
1.83k
    while (remove_iter != m_listen_sockets.end())
2143
0
    {
2144
0
#ifndef TORRENT_DISABLE_DHT
2145
0
      if (m_dht)
2146
0
        m_dht->delete_socket(*remove_iter);
2147
0
#endif
2148
2149
#ifndef TORRENT_DISABLE_LOGGING
2150
      if (should_log())
2151
      {
2152
        session_log("closing listen socket for %s on device \"%s\""
2153
          , print_endpoint((*remove_iter)->local_endpoint).c_str()
2154
          , (*remove_iter)->device.c_str());
2155
      }
2156
#endif
2157
0
      if ((*remove_iter)->sock) (*remove_iter)->sock->close(ec);
2158
0
      if ((*remove_iter)->udp_sock) (*remove_iter)->udp_sock->sock.close();
2159
0
      if ((*remove_iter)->natpmp_mapper) (*remove_iter)->natpmp_mapper->close();
2160
0
      if ((*remove_iter)->upnp_mapper) (*remove_iter)->upnp_mapper->close();
2161
0
      if ((*remove_iter)->lsd) (*remove_iter)->lsd->close();
2162
0
      remove_iter = m_listen_sockets.erase(remove_iter);
2163
0
    }
2164
2165
    // all sockets in there stayed the same. Only sockets after this point are
2166
    // new and should post alerts
2167
1.83k
    int const existing_sockets = int(m_listen_sockets.size());
2168
2169
1.83k
    m_stats_counters.set_value(counters::has_incoming_connections
2170
1.83k
      , std::any_of(m_listen_sockets.begin(), m_listen_sockets.end()
2171
1.83k
        , [](std::shared_ptr<listen_socket_t> const& l)
2172
1.83k
        { return l->incoming_connection; }));
2173
2174
    // open new sockets on any endpoints that didn't match with
2175
    // an existing socket
2176
1.83k
    for (auto const& ep : eps)
2177
1.83k
#ifndef BOOST_NO_EXCEPTIONS
2178
1.83k
      try
2179
1.83k
#endif
2180
1.83k
    {
2181
1.83k
      std::shared_ptr<listen_socket_t> s = setup_listener(ep, ec);
2182
2183
1.83k
      if (!ec && (s->sock || s->udp_sock))
2184
1.83k
      {
2185
1.83k
        m_listen_sockets.emplace_back(s);
2186
2187
1.83k
#ifndef TORRENT_DISABLE_DHT
2188
1.83k
        if (m_dht
2189
1.83k
          && s->ssl != transport::ssl
2190
1.83k
          && !(s->flags & listen_socket_t::local_network))
2191
0
        {
2192
0
          m_dht->new_socket(m_listen_sockets.back());
2193
0
        }
2194
1.83k
#endif
2195
2196
1.83k
        TORRENT_ASSERT(bool(s->flags & listen_socket_t::accept_incoming) == bool(s->sock));
2197
1.83k
        if (s->sock) async_accept(s->sock, s->ssl);
2198
1.83k
      }
2199
1.83k
    }
2200
1.83k
#ifndef BOOST_NO_EXCEPTIONS
2201
1.83k
    catch (std::exception const& e)
2202
1.83k
    {
2203
0
      TORRENT_UNUSED(e);
2204
#ifndef TORRENT_DISABLE_LOGGING
2205
      if (should_log())
2206
      {
2207
        session_log("setup_listener(%s) device: %s failed: %s"
2208
          , print_endpoint(ep.addr, ep.port).c_str()
2209
          , ep.device.c_str()
2210
          , e.what());
2211
      }
2212
#endif // TORRENT_DISABLE_LOGGING
2213
0
    }
2214
1.83k
#endif // BOOST_NO_EXCEPTIONS
2215
2216
1.83k
    if (m_listen_sockets.empty())
2217
0
    {
2218
#ifndef TORRENT_DISABLE_LOGGING
2219
      session_log("giving up on binding listen sockets");
2220
#endif
2221
0
      return;
2222
0
    }
2223
2224
1.83k
    auto const new_sockets = span<std::shared_ptr<listen_socket_t>>(
2225
1.83k
      m_listen_sockets).subspan(existing_sockets);
2226
2227
    // now, send out listen_succeeded_alert for the listen sockets we are
2228
    // listening on
2229
1.83k
    if (m_alerts.should_post<listen_succeeded_alert>())
2230
1
    {
2231
1
      for (auto const& l : new_sockets)
2232
1
      {
2233
1
        error_code err;
2234
1
        if (l->sock)
2235
1
        {
2236
1
          tcp::endpoint const tcp_ep = l->sock->local_endpoint(err);
2237
1
          if (!err)
2238
1
          {
2239
1
            socket_type_t const socket_type
2240
1
              = l->ssl == transport::ssl
2241
1
              ? socket_type_t::tcp_ssl
2242
1
              : socket_type_t::tcp;
2243
2244
1
            m_alerts.emplace_alert<listen_succeeded_alert>(
2245
1
              tcp_ep, socket_type);
2246
1
          }
2247
1
        }
2248
2249
1
        if (l->udp_sock)
2250
1
        {
2251
1
          udp::endpoint const udp_ep = l->udp_sock->sock.local_endpoint(err);
2252
1
          if (!err && l->udp_sock->sock.is_open())
2253
1
          {
2254
1
            socket_type_t const socket_type
2255
1
              = l->ssl == transport::ssl
2256
1
              ? socket_type_t::utp_ssl
2257
1
              : socket_type_t::utp;
2258
2259
1
            m_alerts.emplace_alert<listen_succeeded_alert>(
2260
1
              udp_ep, socket_type);
2261
1
          }
2262
1
        }
2263
1
      }
2264
1
    }
2265
2266
1.83k
    if (m_settings.get_int(settings_pack::peer_dscp) != 0)
2267
1.83k
    {
2268
1.83k
      update_peer_dscp();
2269
1.83k
    }
2270
2271
1.83k
    ec.clear();
2272
2273
1.83k
    if (m_settings.get_bool(settings_pack::enable_natpmp))
2274
0
    {
2275
0
      for (auto const& s : new_sockets)
2276
0
        start_natpmp(s);
2277
0
    }
2278
2279
1.83k
    if (m_settings.get_bool(settings_pack::enable_upnp))
2280
0
    {
2281
0
      for (auto const& s : new_sockets)
2282
0
        start_upnp(s);
2283
0
    }
2284
2285
1.83k
    if (map_ports)
2286
0
    {
2287
0
      for (auto const& s : m_listen_sockets)
2288
0
        remap_ports(remap_natpmp_and_upnp, *s);
2289
0
    }
2290
1.83k
    else
2291
1.83k
    {
2292
      // new sockets need to map ports even if the caller did not request
2293
      // re-mapping
2294
1.83k
      for (auto const& s : new_sockets)
2295
1.83k
        remap_ports(remap_natpmp_and_upnp, *s);
2296
1.83k
    }
2297
2298
1.83k
    update_lsd();
2299
2300
1.83k
#if TORRENT_USE_I2P
2301
1.83k
    open_new_incoming_i2p_connection();
2302
1.83k
#endif
2303
2304
    // trackers that were not reachable, may have become reachable now.
2305
    // so clear the "disabled" flags to let them be tried one more time
2306
    // TODO: it would probably be better to do this by having a
2307
    // listen-socket "version" number that gets bumped. And instead of
2308
    // setting a bool to disable a tracker, we set the version number that
2309
    // it was disabled at. This change would affect the ABI in 1.2, so
2310
    // should be done in 2.0 or later
2311
1.83k
    for (auto& t : m_torrents)
2312
0
      t->enable_all_trackers();
2313
1.83k
  }
2314
2315
  void session_impl::reopen_network_sockets(reopen_network_flags_t const options)
2316
0
  {
2317
0
    reopen_listen_sockets(bool(options & session_handle::reopen_map_ports));
2318
0
  }
2319
2320
  namespace {
2321
    template <typename MapProtocol, typename ProtoType, typename EndpointType>
2322
    void map_port(MapProtocol& m, ProtoType protocol, EndpointType const& ep
2323
      , port_mapping_t& map_handle, std::string const& device)
2324
0
    {
2325
0
      if (map_handle != port_mapping_t{-1}) m.delete_mapping(map_handle);
2326
0
      map_handle = port_mapping_t{-1};
2327
2328
0
      address const addr = ep.address();
2329
      // with IPv4 the interface might be behind NAT so we can't skip them
2330
      // based on the scope of the local address
2331
0
      if (addr.is_v6() && is_local(addr))
2332
0
        return;
2333
2334
      // only update this mapping if we actually have a socket listening
2335
0
      if (ep != EndpointType())
2336
0
        map_handle = m.add_mapping(protocol, ep.port(), ep, device);
2337
0
    }
Unexecuted instantiation: session_impl.cpp:void libtorrent::aux::(anonymous namespace)::map_port<libtorrent::natpmp, libtorrent::portmap_protocol, boost::asio::ip::basic_endpoint<boost::asio::ip::tcp> >(libtorrent::natpmp&, libtorrent::portmap_protocol, boost::asio::ip::basic_endpoint<boost::asio::ip::tcp> const&, libtorrent::aux::strong_typedef<int, libtorrent::port_mapping_tag, void>&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
Unexecuted instantiation: session_impl.cpp:void libtorrent::aux::(anonymous namespace)::map_port<libtorrent::upnp, libtorrent::portmap_protocol, boost::asio::ip::basic_endpoint<boost::asio::ip::tcp> >(libtorrent::upnp&, libtorrent::portmap_protocol, boost::asio::ip::basic_endpoint<boost::asio::ip::tcp> const&, libtorrent::aux::strong_typedef<int, libtorrent::port_mapping_tag, void>&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&)
2338
  }
2339
2340
  void session_impl::remap_ports(remap_port_mask_t const mask
2341
    , listen_socket_t& s)
2342
1.83k
  {
2343
1.83k
    tcp::endpoint const tcp_ep = s.sock ? s.sock->local_endpoint() : tcp::endpoint();
2344
1.83k
    udp::endpoint const udp_ep = s.udp_sock ? s.udp_sock->sock.local_endpoint() : udp::endpoint();
2345
2346
1.83k
    if ((mask & remap_natpmp) && s.natpmp_mapper)
2347
0
    {
2348
0
      map_port(*s.natpmp_mapper, portmap_protocol::tcp, tcp_ep
2349
0
        , s.tcp_port_mapping[portmap_transport::natpmp].mapping, s.device);
2350
0
      map_port(*s.natpmp_mapper, portmap_protocol::udp, make_tcp(udp_ep)
2351
0
        , s.udp_port_mapping[portmap_transport::natpmp].mapping, s.device);
2352
0
    }
2353
1.83k
    if ((mask & remap_upnp) && s.upnp_mapper)
2354
0
    {
2355
0
      map_port(*s.upnp_mapper, portmap_protocol::tcp, tcp_ep
2356
0
        , s.tcp_port_mapping[portmap_transport::upnp].mapping, s.device);
2357
0
      map_port(*s.upnp_mapper, portmap_protocol::udp, make_tcp(udp_ep)
2358
0
        , s.udp_port_mapping[portmap_transport::upnp].mapping, s.device);
2359
0
    }
2360
1.83k
  }
2361
2362
  void session_impl::update_i2p_bridge()
2363
3.67k
  {
2364
    // we need this socket to be open before we
2365
    // can make name lookups for trackers for instance.
2366
    // pause the session now and resume it once we've
2367
    // established the i2p SAM connection
2368
3.67k
#if TORRENT_USE_I2P
2369
3.67k
    if (m_settings.get_str(settings_pack::i2p_hostname).empty())
2370
3.67k
    {
2371
3.67k
      error_code ec;
2372
3.67k
      m_i2p_conn.close(ec);
2373
3.67k
      return;
2374
3.67k
    }
2375
0
    TORRENT_ASSERT(!m_abort);
2376
0
    i2p_session_options session_options{
2377
0
      m_settings.get_int(settings_pack::i2p_inbound_quantity)
2378
0
      , m_settings.get_int(settings_pack::i2p_outbound_quantity)
2379
0
      , m_settings.get_int(settings_pack::i2p_inbound_length)
2380
0
      , m_settings.get_int(settings_pack::i2p_outbound_length)
2381
0
      , m_settings.get_int(settings_pack::i2p_inbound_length_variance)
2382
0
      , m_settings.get_int(settings_pack::i2p_outbound_length_variance)
2383
0
    };
2384
0
    m_i2p_conn.open(m_settings.get_str(settings_pack::i2p_hostname)
2385
0
      , m_settings.get_int(settings_pack::i2p_port)
2386
0
      , session_options
2387
0
      , std::bind(&session_impl::on_i2p_open, this, _1));
2388
0
#endif
2389
0
  }
2390
2391
#ifndef TORRENT_DISABLE_DHT
2392
  int session_impl::external_udp_port(address const& local_address) const
2393
0
  {
2394
0
    auto ls = std::find_if(m_listen_sockets.begin(), m_listen_sockets.end()
2395
0
      , [&](std::shared_ptr<listen_socket_t> const& e)
2396
0
    {
2397
0
      return e->local_endpoint.address() == local_address;
2398
0
    });
2399
2400
0
    if (ls != m_listen_sockets.end())
2401
0
      return (*ls)->udp_external_port();
2402
0
    else
2403
0
      return -1;
2404
0
  }
2405
#endif
2406
2407
#if TORRENT_USE_I2P
2408
  void session_impl::on_i2p_open(error_code const& ec)
2409
0
  {
2410
0
    if (ec)
2411
0
    {
2412
0
      if (m_alerts.should_post<i2p_alert>())
2413
0
        m_alerts.emplace_alert<i2p_alert>(ec);
2414
2415
#ifndef TORRENT_DISABLE_LOGGING
2416
      if (should_log())
2417
        session_log("i2p open failed (%d) %s", ec.value(), ec.message().c_str());
2418
#endif
2419
0
    }
2420
    // now that we have our i2p connection established
2421
    // it's OK to start torrents and use this socket to
2422
    // do i2p name lookups
2423
2424
0
    open_new_incoming_i2p_connection();
2425
0
  }
2426
2427
  void session_impl::open_new_incoming_i2p_connection()
2428
1.83k
  {
2429
1.83k
    if (m_abort) return;
2430
1.83k
    if (!m_i2p_conn.is_open()) return;
2431
2432
0
    if (m_i2p_listen_socket) return;
2433
0
    m_i2p_listen_socket.emplace(
2434
0
      instantiate_connection(m_io_context, m_i2p_conn.proxy()
2435
0
        , nullptr, nullptr, true, false));
2436
2437
0
    ADD_OUTSTANDING_ASYNC("session_impl::on_i2p_accept");
2438
0
    auto& s = boost::get<i2p_stream>(*m_i2p_listen_socket);
2439
0
    s.set_command(i2p_stream::cmd_accept);
2440
0
    s.set_session_id(m_i2p_conn.session_id());
2441
2442
0
    s.async_connect(tcp::endpoint()
2443
0
      , std::bind(&session_impl::on_i2p_accept, this, _1));
2444
0
  }
2445
2446
  void session_impl::on_i2p_accept(error_code const& e)
2447
0
  {
2448
0
    COMPLETE_ASYNC("session_impl::on_i2p_accept");
2449
0
    if (e == boost::asio::error::operation_aborted) return;
2450
0
    if (e)
2451
0
    {
2452
0
      if (m_alerts.should_post<listen_failed_alert>())
2453
0
      {
2454
0
        m_alerts.emplace_alert<listen_failed_alert>("i2p"
2455
0
          , operation_t::sock_accept
2456
0
          , e, socket_type_t::i2p);
2457
0
      }
2458
#ifndef TORRENT_DISABLE_LOGGING
2459
      if (should_log())
2460
        session_log("i2p SAM connection failure: %s", e.message().c_str());
2461
#endif
2462
0
      return;
2463
0
    }
2464
0
    incoming_connection(std::move(*m_i2p_listen_socket));
2465
0
    m_i2p_listen_socket.reset();
2466
0
    open_new_incoming_i2p_connection();
2467
0
  }
2468
#endif
2469
2470
  void session_impl::send_udp_packet_hostname(std::weak_ptr<utp_socket_interface> sock
2471
    , char const* hostname
2472
    , int const port
2473
    , span<char const> p
2474
    , error_code& ec
2475
    , udp_send_flags_t const flags)
2476
0
  {
2477
0
    auto si = sock.lock();
2478
0
    if (!si)
2479
0
    {
2480
0
      ec = boost::asio::error::bad_descriptor;
2481
0
      return;
2482
0
    }
2483
2484
0
    auto s = std::static_pointer_cast<aux::listen_socket_t>(si)->udp_sock;
2485
2486
0
    s->sock.send_hostname(hostname, port, p, ec, flags);
2487
2488
0
    if ((ec == error::would_block || ec == error::try_again)
2489
0
      && !s->write_blocked)
2490
0
    {
2491
0
      s->write_blocked = true;
2492
0
      ADD_OUTSTANDING_ASYNC("session_impl::on_udp_writeable");
2493
0
      s->sock.async_write(std::bind(&session_impl::on_udp_writeable
2494
0
        , this, s, _1));
2495
0
    }
2496
0
  }
2497
2498
  void session_impl::send_udp_packet(std::weak_ptr<utp_socket_interface> sock
2499
    , udp::endpoint const& ep
2500
    , span<char const> p
2501
    , error_code& ec
2502
    , udp_send_flags_t const flags)
2503
0
  {
2504
0
    auto si = sock.lock();
2505
0
    if (!si)
2506
0
    {
2507
0
      ec = boost::asio::error::bad_descriptor;
2508
0
      return;
2509
0
    }
2510
2511
0
    auto s = std::static_pointer_cast<aux::listen_socket_t>(si)->udp_sock;
2512
2513
    // the destination address family matching the local socket's address
2514
    // family does not hold for proxies that we talk to over IPv4 but can
2515
    // route to IPv6
2516
0
    TORRENT_ASSERT(s->sock.is_closed()
2517
0
      || s->sock.get_proxy_settings().type != settings_pack::none
2518
0
      || s->sock.local_endpoint().protocol() == ep.protocol());
2519
2520
0
    s->sock.send(ep, p, ec, flags);
2521
2522
0
    if ((ec == error::would_block || ec == error::try_again) && !s->write_blocked)
2523
0
    {
2524
0
      s->write_blocked = true;
2525
0
      ADD_OUTSTANDING_ASYNC("session_impl::on_udp_writeable");
2526
0
      s->sock.async_write(std::bind(&session_impl::on_udp_writeable
2527
0
        , this, s, _1));
2528
0
    }
2529
0
  }
2530
2531
  void session_impl::on_udp_writeable(std::weak_ptr<session_udp_socket> sock, error_code const& ec)
2532
0
  {
2533
0
    COMPLETE_ASYNC("session_impl::on_udp_writeable");
2534
0
    if (ec) return;
2535
2536
0
    auto s = sock.lock();
2537
0
    if (!s) return;
2538
2539
0
    s->write_blocked = false;
2540
2541
0
#ifdef TORRENT_SSL_PEERS
2542
0
    auto i = std::find_if(
2543
0
      m_listen_sockets.begin(), m_listen_sockets.end()
2544
0
      , [&s] (std::shared_ptr<listen_socket_t> const& ls) { return ls->udp_sock == s; });
2545
0
#endif
2546
2547
    // notify the utp socket manager it can start sending on the socket again
2548
0
    struct utp_socket_manager& mgr =
2549
0
#ifdef TORRENT_SSL_PEERS
2550
0
      (i != m_listen_sockets.end() && (*i)->ssl == transport::ssl) ? m_ssl_utp_socket_manager :
2551
0
#endif
2552
0
      m_utp_socket_manager;
2553
2554
0
    mgr.writable();
2555
0
  }
2556
2557
2558
  void session_impl::on_udp_packet(std::weak_ptr<session_udp_socket> socket
2559
    , std::weak_ptr<listen_socket_t> ls, transport const ssl, error_code const& ec)
2560
1.83k
  {
2561
1.83k
    COMPLETE_ASYNC("session_impl::on_udp_packet");
2562
1.83k
    if (ec)
2563
1.83k
    {
2564
1.83k
      std::shared_ptr<session_udp_socket> s = socket.lock();
2565
1.83k
      udp::endpoint ep;
2566
1.83k
      if (s) ep = s->local_endpoint();
2567
2568
      // don't bubble up operation aborted errors to the user
2569
1.83k
      if (ec != boost::asio::error::operation_aborted
2570
1.83k
        && ec != boost::asio::error::bad_descriptor
2571
1.83k
        && m_alerts.should_post<udp_error_alert>())
2572
0
      {
2573
0
        m_alerts.emplace_alert<udp_error_alert>(ep
2574
0
          , operation_t::sock_read, ec);
2575
0
      }
2576
2577
#ifndef TORRENT_DISABLE_LOGGING
2578
      if (should_log())
2579
      {
2580
        session_log("UDP error: %s (%d) %s"
2581
          , print_endpoint(ep).c_str(), ec.value(), ec.message().c_str());
2582
      }
2583
#endif
2584
1.83k
      return;
2585
1.83k
    }
2586
2587
0
    m_stats_counters.inc_stats_counter(counters::on_udp_counter);
2588
2589
0
    std::shared_ptr<session_udp_socket> s = socket.lock();
2590
0
    if (!s) return;
2591
2592
0
    struct utp_socket_manager& mgr =
2593
0
#ifdef TORRENT_SSL_PEERS
2594
0
      ssl == transport::ssl ? m_ssl_utp_socket_manager :
2595
0
#endif
2596
0
      m_utp_socket_manager;
2597
2598
0
    for (;;)
2599
0
    {
2600
0
      aux::array<udp_socket::packet, 50> p;
2601
0
      error_code err;
2602
0
      int const num_packets = s->sock.read(p, err);
2603
2604
0
      for (udp_socket::packet& packet : span<udp_socket::packet>(p).first(num_packets))
2605
0
      {
2606
0
        if (packet.error)
2607
0
        {
2608
          // TODO: 3 it would be neat if the utp socket manager would
2609
          // handle ICMP errors too
2610
2611
0
#ifndef TORRENT_DISABLE_DHT
2612
0
          if (m_dht)
2613
0
            m_dht->incoming_error(packet.error, packet.from);
2614
0
#endif
2615
2616
0
          m_tracker_manager.incoming_error(packet.error, packet.from);
2617
0
          continue;
2618
0
        }
2619
2620
0
        span<char const> const buf = packet.data;
2621
0
        if (!packet.hostname.empty())
2622
0
        {
2623
          // only the tracker manager supports receiving UDP packets
2624
          // from hostnames. If it won't handle it, no one else will
2625
          // either
2626
0
          m_tracker_manager.incoming_packet(packet.hostname, buf);
2627
0
          continue;
2628
0
        }
2629
2630
        // give the uTP socket manager first dibs on the packet. Presumably
2631
        // the majority of packets are uTP packets.
2632
0
        if (!mgr.incoming_packet(ls, packet.from, buf))
2633
0
        {
2634
          // if it wasn't a uTP packet, try the other users of the UDP
2635
          // socket
2636
0
          bool handled = false;
2637
0
#ifndef TORRENT_DISABLE_DHT
2638
0
          auto listen_socket = ls.lock();
2639
0
          if (m_dht && buf.size() > 20
2640
0
            && buf.front() == 'd'
2641
0
            && buf.back() == 'e'
2642
0
            && listen_socket)
2643
0
          {
2644
0
            handled = m_dht->incoming_packet(listen_socket, packet.from, buf);
2645
0
          }
2646
0
#endif
2647
2648
0
          if (!handled)
2649
0
          {
2650
0
            m_tracker_manager.incoming_packet(packet.from, buf);
2651
0
          }
2652
0
        }
2653
0
      }
2654
2655
0
      if (err == error::would_block || err == error::try_again)
2656
0
      {
2657
        // there are no more packets on the socket
2658
0
        break;
2659
0
      }
2660
2661
0
      if (err)
2662
0
      {
2663
0
        udp::endpoint const ep = s->local_endpoint();
2664
2665
0
        if (err != boost::asio::error::operation_aborted
2666
0
          && m_alerts.should_post<udp_error_alert>())
2667
0
          m_alerts.emplace_alert<udp_error_alert>(ep
2668
0
            , operation_t::sock_read, err);
2669
2670
#ifndef TORRENT_DISABLE_LOGGING
2671
        if (should_log())
2672
        {
2673
          session_log("UDP error: %s (%d) %s"
2674
            , print_endpoint(ep).c_str(), ec.value(), ec.message().c_str());
2675
        }
2676
#endif
2677
2678
        // any error other than these ones are considered fatal errors, and
2679
        // we won't read from the socket again
2680
0
        if (err != boost::asio::error::host_unreachable
2681
0
          && err != boost::asio::error::fault
2682
0
          && err != boost::asio::error::connection_reset
2683
0
          && err != boost::asio::error::connection_refused
2684
0
          && err != boost::asio::error::connection_aborted
2685
0
          && err != boost::asio::error::operation_aborted
2686
0
          && err != boost::asio::error::network_reset
2687
0
          && err != boost::asio::error::network_unreachable
2688
#ifdef _WIN32
2689
          // ERROR_MORE_DATA means the same thing as EMSGSIZE
2690
          && err != error_code(ERROR_MORE_DATA, system_category())
2691
          && err != error_code(ERROR_HOST_UNREACHABLE, system_category())
2692
          && err != error_code(ERROR_PORT_UNREACHABLE, system_category())
2693
          && err != error_code(ERROR_RETRY, system_category())
2694
          && err != error_code(ERROR_NETWORK_UNREACHABLE, system_category())
2695
          && err != error_code(ERROR_CONNECTION_REFUSED, system_category())
2696
          && err != error_code(ERROR_CONNECTION_ABORTED, system_category())
2697
#endif
2698
0
          && err != boost::asio::error::message_size)
2699
0
        {
2700
          // fatal errors. Don't try to read from this socket again
2701
0
          mgr.socket_drained();
2702
0
          return;
2703
0
        }
2704
        // non-fatal UDP errors get here, we should re-issue the read.
2705
0
        continue;
2706
0
      }
2707
0
    }
2708
2709
0
    mgr.socket_drained();
2710
2711
0
    ADD_OUTSTANDING_ASYNC("session_impl::on_udp_packet");
2712
0
    s->sock.async_read(make_handler([this, socket, ls, ssl](error_code const& e)
2713
0
      { this->on_udp_packet(std::move(socket), std::move(ls), ssl, e); }
2714
0
      , s->udp_handler_storage, *this));
2715
0
  }
2716
2717
  void session_impl::async_accept(std::shared_ptr<tcp::acceptor> const& listener
2718
    , transport const ssl)
2719
#ifndef BOOST_NO_EXCEPTIONS
2720
3.67k
  try
2721
3.67k
#endif
2722
3.67k
  {
2723
3.67k
    TORRENT_ASSERT(!m_abort);
2724
2725
3.67k
    std::weak_ptr<tcp::acceptor> ls(listener);
2726
3.67k
    m_stats_counters.inc_stats_counter(counters::num_outstanding_accept);
2727
3.67k
    ADD_OUTSTANDING_ASYNC("session_impl::on_accept_connection");
2728
3.67k
    listener->async_accept([this, ls, ssl] (error_code const& ec, true_tcp_socket s)
2729
3.67k
      { return wrap(&session_impl::on_accept_connection, std::move(s), ec, ls, ssl); });
2730
3.67k
  }
2731
3.67k
#ifndef BOOST_NO_EXCEPTIONS
2732
3.67k
  catch (system_error const& e) {
2733
0
    alerts().emplace_alert<session_error_alert>(e.code(), e.what());
2734
0
    pause();
2735
0
  } catch (std::exception const& e) {
2736
0
    alerts().emplace_alert<session_error_alert>(error_code(), e.what());
2737
0
    pause();
2738
0
  } catch (...) {
2739
0
    alerts().emplace_alert<session_error_alert>(error_code(), "unknown error");
2740
0
    pause();
2741
0
  }
2742
#endif
2743
2744
  void session_impl::on_accept_connection(true_tcp_socket s, error_code const& e
2745
    , std::weak_ptr<tcp::acceptor> listen_socket, transport const ssl)
2746
1.83k
  {
2747
1.83k
    COMPLETE_ASYNC("session_impl::on_accept_connection");
2748
1.83k
    m_stats_counters.inc_stats_counter(counters::on_accept_counter);
2749
1.83k
    m_stats_counters.inc_stats_counter(counters::num_outstanding_accept, -1);
2750
2751
1.83k
    TORRENT_ASSERT(is_single_thread());
2752
1.83k
    std::shared_ptr<tcp::acceptor> listener = listen_socket.lock();
2753
1.83k
    if (!listener) return;
2754
2755
1.83k
    if (e == boost::asio::error::operation_aborted) return;
2756
2757
0
    if (m_abort) return;
2758
2759
0
    error_code ec;
2760
0
    if (e)
2761
0
    {
2762
0
      tcp::endpoint const ep = listener->local_endpoint(ec);
2763
#ifndef TORRENT_DISABLE_LOGGING
2764
      if (should_log())
2765
      {
2766
        session_log("error accepting connection on '%s': %s"
2767
          , print_endpoint(ep).c_str(), e.message().c_str());
2768
      }
2769
#endif
2770
#ifdef TORRENT_WINDOWS
2771
      // Windows sometimes generates this error. It seems to be
2772
      // non-fatal and we have to do another async_accept.
2773
      if (e.value() == ERROR_SEM_TIMEOUT)
2774
      {
2775
        async_accept(listener, ssl);
2776
        return;
2777
      }
2778
#endif
2779
#ifdef TORRENT_BSD
2780
      // Leopard sometimes generates an "invalid argument" error. It seems to be
2781
      // non-fatal and we have to do another async_accept.
2782
      if (e.value() == EINVAL)
2783
      {
2784
        async_accept(listener, ssl);
2785
        return;
2786
      }
2787
#endif
2788
0
      if (e == boost::system::errc::too_many_files_open)
2789
0
      {
2790
        // if we failed to accept an incoming connection
2791
        // because we have too many files open, try again
2792
        // and lower the number of file descriptors used
2793
        // elsewhere.
2794
0
        if (m_settings.get_int(settings_pack::connections_limit) > 10)
2795
0
        {
2796
          // now, disconnect a random peer
2797
0
          auto const i = std::max_element(m_torrents.begin(), m_torrents.end()
2798
0
            , [](std::shared_ptr<torrent> const& lhs, std::shared_ptr<torrent> const& rhs)
2799
0
            { return lhs->num_peers() < rhs->num_peers(); });
2800
2801
0
          if (m_alerts.should_post<performance_alert>())
2802
0
            m_alerts.emplace_alert<performance_alert>(
2803
0
              torrent_handle(), performance_alert::too_few_file_descriptors);
2804
2805
0
          if (i != m_torrents.end())
2806
0
          {
2807
0
            (*i)->disconnect_peers(1, e);
2808
0
          }
2809
2810
0
          m_settings.set_int(settings_pack::connections_limit
2811
0
            , std::max(10, int(m_connections.size())));
2812
0
        }
2813
        // try again, but still alert the user of the problem
2814
0
        async_accept(listener, ssl);
2815
0
      }
2816
0
      if (m_alerts.should_post<listen_failed_alert>())
2817
0
      {
2818
0
        m_alerts.emplace_alert<listen_failed_alert>(ep.address().to_string()
2819
0
          , ep, operation_t::sock_accept, e
2820
0
          , ssl == transport::ssl ? socket_type_t::tcp_ssl : socket_type_t::tcp);
2821
0
      }
2822
0
      return;
2823
0
    }
2824
0
    async_accept(listener, ssl);
2825
2826
    // don't accept any connections from our local listen sockets if we're
2827
    // using a proxy. We should only accept peers via the proxy, never
2828
    // directly.
2829
    // This path is only for accepting incoming TCP sockets. The udp_socket
2830
    // class also restricts incoming packets based on proxy settings.
2831
0
    if (m_settings.get_int(settings_pack::proxy_type) != settings_pack::none
2832
0
      && m_settings.get_bool(settings_pack::proxy_peer_connections))
2833
0
      return;
2834
2835
0
    auto listen = std::find_if(m_listen_sockets.begin(), m_listen_sockets.end()
2836
0
      , [&listener](std::shared_ptr<listen_socket_t> const& l)
2837
0
    { return l->sock == listener; });
2838
0
    if (listen != m_listen_sockets.end())
2839
0
      (*listen)->incoming_connection = true;
2840
2841
0
    socket_type c = [&]{
2842
0
#ifdef TORRENT_SSL_PEERS
2843
0
      if (ssl == transport::ssl)
2844
0
      {
2845
        // accept connections initializing the SSL connection to use the peer
2846
        // ssl context. Since it has the servername callback set on it, we will
2847
        // switch away from this context into a specific torrent once we start
2848
        // handshaking
2849
0
        return socket_type(ssl_stream<tcp::socket>(tcp::socket(std::move(s)), m_peer_ssl_ctx));
2850
0
      }
2851
0
      else
2852
0
#endif
2853
0
      {
2854
0
        return socket_type(tcp::socket(std::move(s)));
2855
0
      }
2856
0
    }();
2857
2858
0
#ifdef TORRENT_SSL_PEERS
2859
0
    TORRENT_ASSERT((ssl == transport::ssl) == is_ssl(c));
2860
0
#endif
2861
2862
0
#ifdef TORRENT_SSL_PEERS
2863
0
    if (ssl == transport::ssl)
2864
0
    {
2865
0
      TORRENT_ASSERT(is_ssl(c));
2866
2867
      // save the socket so we can cancel the handshake
2868
      // TODO: this size need to be capped
2869
0
      auto iter = m_incoming_sockets.emplace(std::make_unique<socket_type>(std::move(c))).first;
2870
2871
0
      auto sock = iter->get();
2872
      // for SSL connections, incoming_connection() is called
2873
      // after the handshake is done
2874
0
      ADD_OUTSTANDING_ASYNC("session_impl::ssl_handshake");
2875
0
      boost::get<ssl_stream<tcp::socket>>(**iter).async_accept_handshake(
2876
0
        [this, sock] (error_code const& err) { ssl_handshake(err, sock); });
2877
0
    }
2878
0
    else
2879
0
#endif
2880
0
    {
2881
0
      incoming_connection(std::move(c));
2882
0
    }
2883
0
  }
2884
2885
#ifdef TORRENT_SSL_PEERS
2886
2887
  void session_impl::on_incoming_utp_ssl(socket_type s)
2888
0
  {
2889
0
    TORRENT_ASSERT(is_ssl(s));
2890
2891
    // save the socket so we can cancel the handshake
2892
2893
    // TODO: this size need to be capped
2894
0
    auto iter = m_incoming_sockets.emplace(std::make_unique<socket_type>(std::move(s))).first;
2895
0
    auto sock = iter->get();
2896
2897
    // for SSL connections, incoming_connection() is called
2898
    // after the handshake is done
2899
0
    ADD_OUTSTANDING_ASYNC("session_impl::ssl_handshake");
2900
0
    boost::get<ssl_stream<utp_stream>>(**iter).async_accept_handshake(
2901
0
      [this, sock] (error_code const& err) { ssl_handshake(err, sock); });
2902
0
  }
2903
2904
  // to test SSL connections, one can use this openssl command template:
2905
  //
2906
  // openssl s_client -cert <client-cert>.pem -key <client-private-key>.pem
2907
  //   -CAfile <torrent-cert>.pem  -debug -connect 127.0.0.1:4433 -tls1
2908
  //   -servername <hex-encoded-info-hash>
2909
2910
  void session_impl::ssl_handshake(error_code const& ec, socket_type* sock)
2911
0
  {
2912
0
    COMPLETE_ASYNC("session_impl::ssl_handshake");
2913
2914
0
    auto iter = m_incoming_sockets.find(sock);
2915
2916
    // this happens if the SSL connection is aborted because we're shutting
2917
    // down
2918
0
    if (iter == m_incoming_sockets.end()) return;
2919
2920
0
    socket_type s(std::move(**iter));
2921
0
    TORRENT_ASSERT(is_ssl(s));
2922
0
    m_incoming_sockets.erase(iter);
2923
2924
0
    error_code e;
2925
0
    tcp::endpoint endp = s.remote_endpoint(e);
2926
0
    if (e) return;
2927
2928
#ifndef TORRENT_DISABLE_LOGGING
2929
    if (should_log())
2930
    {
2931
      session_log(" *** peer SSL handshake done [ ip: %s ec: %s socket: %s ]"
2932
        , print_endpoint(endp).c_str(), ec.message().c_str(), socket_type_name(s));
2933
    }
2934
#endif
2935
2936
0
    if (ec)
2937
0
    {
2938
0
      if (m_alerts.should_post<peer_error_alert>())
2939
0
      {
2940
0
        m_alerts.emplace_alert<peer_error_alert>(torrent_handle(), endp
2941
0
          , peer_id(), operation_t::ssl_handshake, ec);
2942
0
      }
2943
0
      return;
2944
0
    }
2945
2946
0
    incoming_connection(std::move(s));
2947
0
  }
2948
2949
#endif // TORRENT_SSL_PEERS
2950
2951
  void session_impl::incoming_connection(socket_type s)
2952
0
  {
2953
0
    TORRENT_ASSERT(is_single_thread());
2954
2955
0
    if (m_abort)
2956
0
    {
2957
#ifndef TORRENT_DISABLE_LOGGING
2958
      session_log(" <== INCOMING CONNECTION [ ignored, aborting ]");
2959
#endif
2960
0
      return;
2961
0
    }
2962
2963
0
    if (m_paused)
2964
0
    {
2965
#ifndef TORRENT_DISABLE_LOGGING
2966
      session_log(" <== INCOMING CONNECTION [ ignored, paused ]");
2967
#endif
2968
0
      return;
2969
0
    }
2970
2971
0
    error_code ec;
2972
    // we got a connection request!
2973
0
    tcp::endpoint endp = s.remote_endpoint(ec);
2974
2975
0
    if (ec)
2976
0
    {
2977
#ifndef TORRENT_DISABLE_LOGGING
2978
      if (should_log())
2979
      {
2980
        session_log(" <== INCOMING CONNECTION [ rejected, could "
2981
          "not retrieve remote endpoint: %s ]"
2982
          , print_error(ec).c_str());
2983
      }
2984
#endif
2985
0
      return;
2986
0
    }
2987
2988
0
    if (!m_settings.get_bool(settings_pack::enable_incoming_utp)
2989
0
      && is_utp(s))
2990
0
    {
2991
#ifndef TORRENT_DISABLE_LOGGING
2992
      session_log("<== INCOMING CONNECTION [ rejected uTP connection ]");
2993
#endif
2994
0
      if (m_alerts.should_post<peer_blocked_alert>())
2995
0
        m_alerts.emplace_alert<peer_blocked_alert>(torrent_handle()
2996
0
          , endp, peer_blocked_alert::utp_disabled);
2997
0
      return;
2998
0
    }
2999
3000
0
    if (!m_settings.get_bool(settings_pack::enable_incoming_tcp)
3001
0
      && boost::get<tcp::socket>(&s))
3002
0
    {
3003
#ifndef TORRENT_DISABLE_LOGGING
3004
      session_log("<== INCOMING CONNECTION [ rejected TCP connection ]");
3005
#endif
3006
0
      if (m_alerts.should_post<peer_blocked_alert>())
3007
0
        m_alerts.emplace_alert<peer_blocked_alert>(torrent_handle()
3008
0
          , endp, peer_blocked_alert::tcp_disabled);
3009
0
      return;
3010
0
    }
3011
3012
    // if there are outgoing interfaces specified, verify this
3013
    // peer is correctly bound to one of them
3014
0
    if (!m_outgoing_interfaces.empty())
3015
0
    {
3016
0
      tcp::endpoint local = s.local_endpoint(ec);
3017
0
      if (ec)
3018
0
      {
3019
#ifndef TORRENT_DISABLE_LOGGING
3020
        if (should_log())
3021
        {
3022
          session_log("<== INCOMING CONNECTION [ rejected connection: %s ]"
3023
            , print_error(ec).c_str());
3024
        }
3025
#endif
3026
0
        return;
3027
0
      }
3028
3029
0
      if (!verify_incoming_interface(local.address()))
3030
0
      {
3031
#ifndef TORRENT_DISABLE_LOGGING
3032
        if (should_log())
3033
        {
3034
          session_log("<== INCOMING CONNECTION [ rejected, local interface has incoming connections disabled: %s ]"
3035
            , local.address().to_string().c_str());
3036
        }
3037
#endif
3038
0
        if (m_alerts.should_post<peer_blocked_alert>())
3039
0
          m_alerts.emplace_alert<peer_blocked_alert>(torrent_handle()
3040
0
            , endp, peer_blocked_alert::invalid_local_interface);
3041
0
        return;
3042
0
      }
3043
0
      if (!verify_bound_address(local.address(), is_utp(s), ec))
3044
0
      {
3045
0
        if (ec)
3046
0
        {
3047
#ifndef TORRENT_DISABLE_LOGGING
3048
          if (should_log())
3049
          {
3050
            session_log("<== INCOMING CONNECTION [ rejected, not allowed local interface: %s ]"
3051
              , print_error(ec).c_str());
3052
          }
3053
#endif
3054
0
          return;
3055
0
        }
3056
3057
#ifndef TORRENT_DISABLE_LOGGING
3058
        if (should_log())
3059
        {
3060
          session_log("<== INCOMING CONNECTION [ rejected, not allowed local interface: %s ]"
3061
            , local.address().to_string().c_str());
3062
        }
3063
#endif
3064
0
        if (m_alerts.should_post<peer_blocked_alert>())
3065
0
          m_alerts.emplace_alert<peer_blocked_alert>(torrent_handle()
3066
0
            , endp, peer_blocked_alert::invalid_local_interface);
3067
0
        return;
3068
0
      }
3069
0
    }
3070
3071
    // local addresses do not count, since it's likely
3072
    // coming from our own client through local service discovery
3073
    // and it does not reflect whether or not a router is open
3074
    // for incoming connections or not.
3075
0
    if (!is_local(endp.address()))
3076
0
      m_stats_counters.set_value(counters::has_incoming_connections, 1);
3077
3078
    // this filter is ignored if a single torrent
3079
    // is set to ignore the filter, since this peer might be
3080
    // for that torrent
3081
0
    if (m_stats_counters[counters::non_filter_torrents] == 0
3082
0
      && m_ip_filter
3083
0
      && (m_ip_filter->access(endp.address()) & ip_filter::blocked))
3084
0
    {
3085
#ifndef TORRENT_DISABLE_LOGGING
3086
      session_log("<== INCOMING CONNECTION [ filtered blocked ip ]");
3087
#endif
3088
0
      if (m_alerts.should_post<peer_blocked_alert>())
3089
0
        m_alerts.emplace_alert<peer_blocked_alert>(torrent_handle()
3090
0
          , endp, peer_blocked_alert::ip_filter);
3091
0
      return;
3092
0
    }
3093
3094
0
    bool want_on_unknown_torrent = false;
3095
0
#ifndef TORRENT_DISABLE_EXTENSIONS
3096
0
    want_on_unknown_torrent = !m_ses_extensions[plugins_unknown_torrent_idx].empty();
3097
0
#endif
3098
3099
    // check if we have any active torrents
3100
    // or if there is an extension that wants on_unknown_torrent
3101
    // if we don't reject the connection
3102
0
    if (m_torrents.empty() && !want_on_unknown_torrent)
3103
0
    {
3104
#ifndef TORRENT_DISABLE_LOGGING
3105
      session_log("<== INCOMING CONNECTION [ rejected, there are no torrents ]");
3106
#endif
3107
0
      return;
3108
0
    }
3109
3110
    // figure out which peer classes this is connections has,
3111
    // to get connection_limit_factor
3112
0
    peer_class_set pcs;
3113
0
    set_peer_classes(&pcs, endp.address(), socket_type_idx(s));
3114
0
    int connection_limit_factor = 0;
3115
0
    for (int i = 0; i < pcs.num_classes(); ++i)
3116
0
    {
3117
0
      peer_class_t pc = pcs.class_at(i);
3118
0
      if (m_classes.at(pc) == nullptr) continue;
3119
0
      int f = m_classes.at(pc)->connection_limit_factor;
3120
0
      if (connection_limit_factor < f) connection_limit_factor = f;
3121
0
    }
3122
0
    if (connection_limit_factor == 0) connection_limit_factor = 100;
3123
3124
0
    std::int64_t limit = m_settings.get_int(settings_pack::connections_limit);
3125
0
    limit = limit * 100 / connection_limit_factor;
3126
3127
    // don't allow more connections than the max setting
3128
    // weighed by the peer class' setting
3129
0
    bool reject = num_connections() >= limit + m_settings.get_int(settings_pack::connections_slack);
3130
3131
0
    if (reject)
3132
0
    {
3133
0
      if (m_alerts.should_post<peer_disconnected_alert>())
3134
0
      {
3135
0
        m_alerts.emplace_alert<peer_disconnected_alert>(torrent_handle(), endp, peer_id()
3136
0
            , operation_t::bittorrent, socket_type_idx(s)
3137
0
            , error_code(errors::too_many_connections)
3138
0
            , close_reason_t::none);
3139
0
      }
3140
#ifndef TORRENT_DISABLE_LOGGING
3141
      if (should_log())
3142
      {
3143
        session_log("<== INCOMING CONNECTION [ connections limit exceeded, conns: %d, limit: %d, slack: %d ]"
3144
          , num_connections(), m_settings.get_int(settings_pack::connections_limit)
3145
          , m_settings.get_int(settings_pack::connections_slack));
3146
      }
3147
#endif
3148
0
      return;
3149
0
    }
3150
3151
    // if we don't have any active torrents, there's no
3152
    // point in accepting this connection. If, however,
3153
    // the setting to start up queued torrents when they
3154
    // get an incoming connection is enabled or if there is
3155
    // an extension that wants on_unknown_torrent, we cannot
3156
    // perform this check.
3157
0
    if (!m_settings.get_bool(settings_pack::incoming_starts_queued_torrents) && !want_on_unknown_torrent)
3158
0
    {
3159
0
      bool has_active_torrent = std::any_of(m_torrents.begin(), m_torrents.end()
3160
0
        , [](std::shared_ptr<torrent> const& i)
3161
0
        { return !i->is_torrent_paused(); });
3162
0
      if (!has_active_torrent)
3163
0
      {
3164
#ifndef TORRENT_DISABLE_LOGGING
3165
        session_log("<== INCOMING CONNECTION [ rejected, no active torrents ]");
3166
#endif
3167
0
        return;
3168
0
      }
3169
0
    }
3170
3171
0
    m_stats_counters.inc_stats_counter(counters::incoming_connections);
3172
3173
0
    if (m_alerts.should_post<incoming_connection_alert>())
3174
0
      m_alerts.emplace_alert<incoming_connection_alert>(socket_type_idx(s), endp);
3175
3176
0
    peer_connection_args pack{
3177
0
      this
3178
0
      , &m_settings
3179
0
      , &m_stats_counters
3180
0
      , m_disk_thread.get()
3181
0
      , &m_io_context
3182
0
      , std::weak_ptr<torrent>()
3183
0
      , std::move(s)
3184
0
      , endp
3185
0
      , nullptr
3186
0
      , aux::generate_peer_id(m_settings)
3187
0
    };
3188
3189
0
    std::shared_ptr<peer_connection> c
3190
0
      = std::make_shared<bt_peer_connection>(pack);
3191
3192
0
    if (!c->is_disconnecting())
3193
0
    {
3194
      // in case we've exceeded the limit, let this peer know that
3195
      // as soon as it's received the handshake, it needs to either
3196
      // disconnect or pick another peer to disconnect
3197
0
      if (num_connections() >= limit)
3198
0
        c->peer_exceeds_limit();
3199
3200
0
      TORRENT_ASSERT(!c->m_in_constructor);
3201
      // removing a peer may not throw an exception, so prepare for this
3202
      // connection to be added to the undead peers now.
3203
0
      m_undead_peers.reserve(m_undead_peers.size() + m_connections.size() + 1);
3204
0
      m_connections.insert(c);
3205
0
      c->start();
3206
0
    }
3207
0
  }
3208
3209
  void session_impl::close_connection(peer_connection* p) noexcept
3210
0
  {
3211
0
    TORRENT_ASSERT(is_single_thread());
3212
0
    std::shared_ptr<peer_connection> sp(p->self());
3213
3214
0
    TORRENT_ASSERT(p->is_disconnecting());
3215
3216
0
    auto const i = m_connections.find(sp);
3217
    // make sure the next disk peer round-robin cursor stays valid
3218
0
    if (i != m_connections.end())
3219
0
    {
3220
0
      m_connections.erase(i);
3221
3222
0
      TORRENT_ASSERT(std::find(m_undead_peers.begin()
3223
0
        , m_undead_peers.end(), sp) == m_undead_peers.end());
3224
3225
      // someone else is holding a reference, it's important that
3226
      // it's destructed from the network thread. Make sure the
3227
      // last reference is held by the network thread.
3228
0
      TORRENT_ASSERT_VAL(m_undead_peers.capacity() > m_undead_peers.size()
3229
0
        , m_undead_peers.capacity());
3230
0
      if (sp.use_count() > 2)
3231
0
        m_undead_peers.push_back(sp);
3232
0
    }
3233
0
  }
3234
3235
#if TORRENT_ABI_VERSION == 1
3236
  peer_id session_impl::deprecated_get_peer_id() const
3237
0
  {
3238
0
    return aux::generate_peer_id(m_settings);
3239
0
  }
3240
#endif
3241
3242
  int session_impl::next_port() const
3243
0
  {
3244
0
    int start = m_settings.get_int(settings_pack::outgoing_port);
3245
0
    int num = m_settings.get_int(settings_pack::num_outgoing_ports);
3246
0
    std::pair<int, int> out_ports(start, start + num);
3247
0
    if (m_next_port < out_ports.first || m_next_port > out_ports.second)
3248
0
      m_next_port = out_ports.first;
3249
3250
0
    int port = m_next_port;
3251
0
    ++m_next_port;
3252
0
    if (m_next_port > out_ports.second) m_next_port = out_ports.first;
3253
#ifndef TORRENT_DISABLE_LOGGING
3254
    session_log(" *** BINDING OUTGOING CONNECTION [ port: %d ]", port);
3255
#endif
3256
0
    return port;
3257
0
  }
3258
3259
  int session_impl::rate_limit(peer_class_t c, int channel) const
3260
2
  {
3261
2
    TORRENT_ASSERT(channel >= 0 && channel <= 1);
3262
2
    if (channel < 0 || channel > 1) return 0;
3263
3264
2
    peer_class const* pc = m_classes.at(c);
3265
2
    if (pc == nullptr) return 0;
3266
2
    return pc->channel[channel].throttle();
3267
2
  }
3268
3269
  int session_impl::upload_rate_limit(peer_class_t c) const
3270
1
  {
3271
1
    return rate_limit(c, peer_connection::upload_channel);
3272
1
  }
3273
3274
  int session_impl::download_rate_limit(peer_class_t c) const
3275
1
  {
3276
1
    return rate_limit(c, peer_connection::download_channel);
3277
1
  }
3278
3279
  void session_impl::set_rate_limit(peer_class_t c, int channel, int limit)
3280
7.34k
  {
3281
7.34k
    TORRENT_ASSERT(is_single_thread());
3282
7.34k
    TORRENT_ASSERT(limit >= -1);
3283
7.34k
    TORRENT_ASSERT(channel >= 0 && channel <= 1);
3284
3285
7.34k
    if (channel < 0 || channel > 1) return;
3286
3287
7.34k
    peer_class* pc = m_classes.at(c);
3288
7.34k
    if (pc == nullptr) return;
3289
7.34k
    if (limit <= 0) limit = 0;
3290
0
    else limit = std::min(limit, std::numeric_limits<int>::max() - 1);
3291
7.34k
    pc->channel[channel].throttle(limit);
3292
7.34k
  }
3293
3294
  void session_impl::set_upload_rate_limit(peer_class_t c, int limit)
3295
3.67k
  {
3296
3.67k
    set_rate_limit(c, peer_connection::upload_channel, limit);
3297
3.67k
  }
3298
3299
  void session_impl::set_download_rate_limit(peer_class_t c, int limit)
3300
3.67k
  {
3301
3.67k
    set_rate_limit(c, peer_connection::download_channel, limit);
3302
3.67k
  }
3303
3304
#if TORRENT_USE_ASSERTS
3305
  bool session_impl::has_peer(peer_connection const* p) const
3306
0
  {
3307
0
    TORRENT_ASSERT(is_single_thread());
3308
0
    return std::any_of(m_connections.begin(), m_connections.end()
3309
0
      , [p] (std::shared_ptr<peer_connection> const& pr)
3310
0
      { return pr.get() == p; });
3311
0
  }
3312
3313
  bool session_impl::any_torrent_has_peer(peer_connection const* p) const
3314
0
  {
3315
0
    for (auto& pe : m_torrents)
3316
0
      if (pe->has_peer(p)) return true;
3317
0
    return false;
3318
0
  }
3319
3320
  bool session_impl::verify_queue_position(torrent const* t, queue_position_t const pos)
3321
0
  {
3322
0
    return m_download_queue.end_index() > pos && m_download_queue[pos] == t;
3323
0
  }
3324
#endif
3325
3326
  void session_impl::sent_bytes(int bytes_payload, int bytes_protocol)
3327
0
  {
3328
0
    TORRENT_ASSERT(bytes_payload >= 0);
3329
0
    TORRENT_ASSERT(bytes_protocol >= 0);
3330
0
    m_stats_counters.inc_stats_counter(counters::sent_bytes
3331
0
      , bytes_payload + bytes_protocol);
3332
0
    m_stats_counters.inc_stats_counter(counters::sent_payload_bytes
3333
0
      , bytes_payload);
3334
3335
0
    m_stat.sent_bytes(bytes_payload, bytes_protocol);
3336
0
  }
3337
3338
  void session_impl::received_bytes(int bytes_payload, int bytes_protocol)
3339
0
  {
3340
0
    TORRENT_ASSERT(bytes_payload >= 0);
3341
0
    TORRENT_ASSERT(bytes_protocol >= 0);
3342
0
    m_stats_counters.inc_stats_counter(counters::recv_bytes
3343
0
      , bytes_payload + bytes_protocol);
3344
0
    m_stats_counters.inc_stats_counter(counters::recv_payload_bytes
3345
0
      , bytes_payload);
3346
3347
0
    m_stat.received_bytes(bytes_payload, bytes_protocol);
3348
0
  }
3349
3350
  void session_impl::trancieve_ip_packet(int bytes, bool ipv6)
3351
0
  {
3352
0
    TORRENT_ASSERT(bytes >= 0);
3353
    // one TCP/IP packet header for the packet
3354
    // sent or received, and one for the ACK
3355
    // The IPv4 header is 20 bytes
3356
    // and IPv6 header is 40 bytes
3357
0
    int const header = (ipv6 ? 40 : 20) + 20;
3358
0
    int const mtu = 1500;
3359
0
    int const packet_size = mtu - header;
3360
0
    int const overhead = std::max(1, (bytes + packet_size - 1) / packet_size) * header;
3361
0
    m_stats_counters.inc_stats_counter(counters::sent_ip_overhead_bytes
3362
0
      , overhead);
3363
0
    m_stats_counters.inc_stats_counter(counters::recv_ip_overhead_bytes
3364
0
      , overhead);
3365
3366
0
    m_stat.trancieve_ip_packet(bytes, ipv6);
3367
0
  }
3368
3369
  void session_impl::sent_syn(bool ipv6)
3370
0
  {
3371
0
    int const overhead = ipv6 ? 60 : 40;
3372
0
    m_stats_counters.inc_stats_counter(counters::sent_ip_overhead_bytes
3373
0
      , overhead);
3374
3375
0
    m_stat.sent_syn(ipv6);
3376
0
  }
3377
3378
  void session_impl::received_synack(bool ipv6)
3379
0
  {
3380
0
    int const overhead = ipv6 ? 60 : 40;
3381
0
    m_stats_counters.inc_stats_counter(counters::sent_ip_overhead_bytes
3382
0
      , overhead);
3383
0
    m_stats_counters.inc_stats_counter(counters::recv_ip_overhead_bytes
3384
0
      , overhead);
3385
3386
0
    m_stat.received_synack(ipv6);
3387
0
  }
3388
3389
  void session_impl::on_tick(error_code const& e)
3390
1.83k
  {
3391
1.83k
    COMPLETE_ASYNC("session_impl::on_tick");
3392
1.83k
    m_stats_counters.inc_stats_counter(counters::on_tick_counter);
3393
3394
1.83k
    TORRENT_ASSERT(is_single_thread());
3395
3396
1.83k
    time_point const now = aux::time_now();
3397
3398
    // remove undead peers that only have this list as their reference keeping them alive
3399
1.83k
    if (!m_undead_peers.empty())
3400
0
    {
3401
0
      auto const remove_it = std::remove_if(m_undead_peers.begin(), m_undead_peers.end()
3402
0
        , [](std::shared_ptr<peer_connection>& ptr) { return ptr.use_count() == 1; });
3403
0
      m_undead_peers.erase(remove_it, m_undead_peers.end());
3404
0
      if (m_undead_peers.empty())
3405
0
      {
3406
        // we just removed our last "undead" peer (i.e. a peer connection
3407
        // that had some external reference to it). It's now safe to
3408
        // shut-down
3409
0
        if (m_abort)
3410
0
        {
3411
0
          post(m_io_context, make_handler([this] { abort_stage2(); }
3412
0
            , m_abort_handler_storage, *this));
3413
0
        }
3414
0
      }
3415
0
    }
3416
3417
// too expensive
3418
//    INVARIANT_CHECK;
3419
3420
    // we have to keep ticking the utp socket manager
3421
    // until they're all closed
3422
    // we also have to keep updating the aux time while
3423
    // there are outstanding announces
3424
1.83k
    if (m_abort)
3425
1.83k
    {
3426
1.83k
      if (m_utp_socket_manager.num_sockets() == 0
3427
1.83k
#ifdef TORRENT_SSL_PEERS
3428
1.83k
        && m_ssl_utp_socket_manager.num_sockets() == 0
3429
1.83k
#endif
3430
1.83k
        && m_undead_peers.empty()
3431
1.83k
        && m_tracker_manager.empty())
3432
1.83k
      {
3433
        // this is where shutdown completes. We won't issue another
3434
        // on_tick()
3435
1.83k
        return;
3436
1.83k
      }
3437
#if defined TORRENT_ASIO_DEBUGGING
3438
      std::fprintf(stderr, "uTP sockets: %d ssl-uTP sockets: %d undead-peers left: %d\n"
3439
        , m_utp_socket_manager.num_sockets()
3440
#ifdef TORRENT_SSL_PEERS
3441
        , m_ssl_utp_socket_manager.num_sockets()
3442
#else
3443
        , 0
3444
#endif
3445
        , int(m_undead_peers.size()));
3446
#endif
3447
1.83k
    }
3448
3449
2
    if (e && e != boost::asio::error::operation_aborted)
3450
0
    {
3451
#ifndef TORRENT_DISABLE_LOGGING
3452
      if (should_log())
3453
        session_log("*** TICK TIMER FAILED %s", e.message().c_str());
3454
#endif
3455
0
      std::abort();
3456
0
    }
3457
3458
2
    ADD_OUTSTANDING_ASYNC("session_impl::on_tick");
3459
2
    milliseconds const tick_interval(m_abort ? 100 : m_settings.get_int(settings_pack::tick_interval));
3460
2
    m_timer.expires_at(now + tick_interval);
3461
2
    m_timer.async_wait(aux::make_handler([this](error_code const& err)
3462
2
    { wrap(&session_impl::on_tick, err); }, m_tick_handler_storage, *this));
3463
3464
2
    m_download_rate.update_quotas(now - m_last_tick);
3465
2
    m_upload_rate.update_quotas(now - m_last_tick);
3466
3467
2
    m_last_tick = now;
3468
3469
2
    m_utp_socket_manager.tick(now);
3470
2
#ifdef TORRENT_SSL_PEERS
3471
2
    m_ssl_utp_socket_manager.tick(now);
3472
2
#endif
3473
3474
    // only tick the following once per second
3475
2
    if (now - m_last_second_tick < seconds(1)) return;
3476
3477
1
#ifndef TORRENT_DISABLE_DHT
3478
1
    if (m_dht
3479
1
      && m_dht_interval_update_torrents < 40
3480
1
      && m_dht_interval_update_torrents != int(m_torrents.size()))
3481
0
      update_dht_announce_interval();
3482
1
#endif
3483
3484
1
    m_utp_socket_manager.decay();
3485
1
#ifdef TORRENT_SSL_PEERS
3486
1
    m_ssl_utp_socket_manager.decay();
3487
1
#endif
3488
3489
1
    int const tick_interval_ms = aux::numeric_cast<int>(total_milliseconds(now - m_last_second_tick));
3490
1
    m_last_second_tick = now;
3491
3492
1
    std::int32_t const stime = session_time();
3493
1
    if (stime > 65000)
3494
0
    {
3495
      // we're getting close to the point where our timestamps
3496
      // in torrent_peer are wrapping. We need to step all counters back
3497
      // four hours. This means that any timestamp that refers to a time
3498
      // more than 18.2 - 4 = 14.2 hours ago, will be incremented to refer to
3499
      // 14.2 hours ago.
3500
3501
0
      m_created += hours(4);
3502
3503
0
      constexpr int four_hours = 60 * 60 * 4;
3504
0
      for (auto& i : m_torrents)
3505
0
      {
3506
0
        i->step_session_time(four_hours);
3507
0
      }
3508
0
    }
3509
3510
1
#ifndef TORRENT_DISABLE_EXTENSIONS
3511
1
    for (auto& ext : m_ses_extensions[plugins_tick_idx])
3512
0
    {
3513
0
      ext->on_tick();
3514
0
    }
3515
1
#endif
3516
3517
    // don't do any of the following while we're shutting down
3518
1
    if (m_abort) return;
3519
3520
1
    switch (m_settings.get_int(settings_pack::mixed_mode_algorithm))
3521
1
    {
3522
0
      case settings_pack::prefer_tcp:
3523
0
        set_upload_rate_limit(m_tcp_peer_class, 0);
3524
0
        set_download_rate_limit(m_tcp_peer_class, 0);
3525
0
        break;
3526
1
      case settings_pack::peer_proportional:
3527
1
        {
3528
1
          int num_peers[2][2] = {{0, 0}, {0, 0}};
3529
1
          for (auto const& i : m_connections)
3530
0
          {
3531
0
            peer_connection& p = *i;
3532
0
            if (p.in_handshake()) continue;
3533
0
            int protocol = 0;
3534
0
            if (is_utp(p.get_socket())) protocol = 1;
3535
3536
0
            if (p.download_queue().size() > 1
3537
0
              && p.m_channel_state[peer_connection::download_channel] & peer_info::bw_network)
3538
0
              ++num_peers[protocol][peer_connection::download_channel];
3539
0
            if (!p.upload_queue().empty()
3540
0
              && p.m_channel_state[peer_connection::upload_channel] & peer_info::bw_network)
3541
0
              ++num_peers[protocol][peer_connection::upload_channel];
3542
0
          }
3543
3544
1
          int const stat_rate[] = {m_stat.upload_rate(), m_stat.download_rate() };
3545
          // never throttle below this
3546
1
          int lower_limit[] = {5000, 30000};
3547
3548
3
          for (int i = 0; i < 2; ++i)
3549
2
          {
3550
            // if there are no uTP peers, don't throttle TCP
3551
2
            int const total_peers = num_peers[0][i] + num_peers[1][i];
3552
2
            if (num_peers[1][i] == 0 || total_peers < 5)
3553
2
            {
3554
2
              set_rate_limit(m_tcp_peer_class, i, 0);
3555
2
            }
3556
0
            else
3557
0
            {
3558
0
              if (num_peers[0][i] == 0) num_peers[0][i] = 1;
3559
              // this are 64 bits since it's multiplied by the number
3560
              // of peers, which otherwise might overflow an int
3561
0
              std::int64_t rate = stat_rate[i];
3562
0
              int const limit = std::max(int(rate * num_peers[0][i] * 4 / total_peers), lower_limit[i]);
3563
0
              set_rate_limit(m_tcp_peer_class, i, limit);
3564
0
            }
3565
2
          }
3566
1
        }
3567
1
        break;
3568
1
    }
3569
3570
    // --------------------------------------------------------------
3571
    // auto managed torrent
3572
    // --------------------------------------------------------------
3573
1
    if (!m_paused) m_auto_manage_time_scaler--;
3574
1
    if (m_auto_manage_time_scaler < 0)
3575
1
    {
3576
1
      m_auto_manage_time_scaler = settings().get_int(settings_pack::auto_manage_interval);
3577
1
      recalculate_auto_managed_torrents();
3578
1
    }
3579
3580
    // --------------------------------------------------------------
3581
    // check for incoming connections that might have timed out
3582
    // --------------------------------------------------------------
3583
3584
1
    for (auto i = m_connections.begin(); i != m_connections.end();)
3585
0
    {
3586
0
      peer_connection* p = (*i).get();
3587
0
      ++i;
3588
      // ignore connections that already have a torrent, since they
3589
      // are ticked through the torrents' second_tick
3590
0
      if (!p->associated_torrent().expired()) continue;
3591
3592
      // TODO: have a separate list for these connections, instead of having to loop through all of them
3593
0
      int timeout = m_settings.get_int(settings_pack::handshake_timeout);
3594
0
#if TORRENT_USE_I2P
3595
0
      timeout *= is_i2p(p->get_socket()) ? 4 : 1;
3596
0
#endif
3597
0
      if (m_last_tick - p->connected_time () > seconds(timeout))
3598
0
        p->disconnect(errors::timed_out, operation_t::bittorrent);
3599
0
    }
3600
3601
    // --------------------------------------------------------------
3602
    // second_tick every torrent (that wants it)
3603
    // --------------------------------------------------------------
3604
3605
#if TORRENT_DEBUG_STREAMING > 0
3606
    std::printf("\033[2J\033[0;0H");
3607
#endif
3608
3609
1
    aux::vector<torrent*>& want_tick = m_torrent_lists[torrent_want_tick];
3610
2
    for (int i = 0; i < int(want_tick.size()); ++i)
3611
1
    {
3612
1
      torrent& t = *want_tick[i];
3613
1
      TORRENT_ASSERT(t.want_tick());
3614
1
      TORRENT_ASSERT(!t.is_aborted());
3615
3616
1
      t.second_tick(tick_interval_ms);
3617
3618
      // if the call to second_tick caused the torrent
3619
      // to no longer want to be ticked (i.e. it was
3620
      // removed from the list) we need to back up the counter
3621
      // to not miss the torrent after it
3622
1
      if (!t.want_tick()) --i;
3623
1
    }
3624
3625
    // TODO: this should apply to all bandwidth channels
3626
1
    if (m_settings.get_bool(settings_pack::rate_limit_ip_overhead))
3627
1
    {
3628
1
      int const up_limit = upload_rate_limit(m_global_class);
3629
1
      int const down_limit = download_rate_limit(m_global_class);
3630
3631
1
      if (down_limit > 0
3632
1
        && m_stat.download_ip_overhead() >= down_limit
3633
1
        && m_alerts.should_post<performance_alert>())
3634
0
      {
3635
0
        m_alerts.emplace_alert<performance_alert>(torrent_handle()
3636
0
          , performance_alert::download_limit_too_low);
3637
0
      }
3638
3639
1
      if (up_limit > 0
3640
1
        && m_stat.upload_ip_overhead() >= up_limit
3641
1
        && m_alerts.should_post<performance_alert>())
3642
0
      {
3643
0
        m_alerts.emplace_alert<performance_alert>(torrent_handle()
3644
0
          , performance_alert::upload_limit_too_low);
3645
0
      }
3646
1
    }
3647
3648
1
#if TORRENT_ABI_VERSION == 1
3649
1
    m_peak_up_rate = std::max(m_stat.upload_rate(), m_peak_up_rate);
3650
1
#endif
3651
3652
1
    m_stat.second_tick(tick_interval_ms);
3653
3654
    // --------------------------------------------------------------
3655
    // scrape paused torrents that are auto managed
3656
    // (unless the session is paused)
3657
    // --------------------------------------------------------------
3658
1
    if (!m_paused)
3659
1
    {
3660
1
      INVARIANT_CHECK;
3661
1
      --m_auto_scrape_time_scaler;
3662
1
      if (m_auto_scrape_time_scaler <= 0)
3663
0
      {
3664
0
        aux::vector<torrent*>& want_scrape = m_torrent_lists[torrent_want_scrape];
3665
0
        m_auto_scrape_time_scaler = m_settings.get_int(settings_pack::auto_scrape_interval)
3666
0
          / std::max(1, int(want_scrape.size()));
3667
0
        if (m_auto_scrape_time_scaler < m_settings.get_int(settings_pack::auto_scrape_min_interval))
3668
0
          m_auto_scrape_time_scaler = m_settings.get_int(settings_pack::auto_scrape_min_interval);
3669
3670
0
        if (!want_scrape.empty() && !m_abort)
3671
0
        {
3672
0
          if (m_next_scrape_torrent >= int(want_scrape.size()))
3673
0
            m_next_scrape_torrent = 0;
3674
3675
0
          torrent& t = *want_scrape[m_next_scrape_torrent];
3676
0
          TORRENT_ASSERT(t.is_paused() && t.is_auto_managed());
3677
3678
          // false means it's not triggered by the user, but automatically
3679
          // by libtorrent
3680
0
          t.scrape_tracker(-1, false);
3681
3682
0
          ++m_next_scrape_torrent;
3683
0
          if (m_next_scrape_torrent >= int(want_scrape.size()))
3684
0
            m_next_scrape_torrent = 0;
3685
3686
0
        }
3687
0
      }
3688
1
    }
3689
3690
    // --------------------------------------------------------------
3691
    // connect new peers
3692
    // --------------------------------------------------------------
3693
3694
1
    try_connect_more_peers();
3695
3696
    // --------------------------------------------------------------
3697
    // unchoke set calculations
3698
    // --------------------------------------------------------------
3699
1
    m_unchoke_time_scaler--;
3700
1
    if (m_unchoke_time_scaler <= 0 && !m_connections.empty())
3701
0
    {
3702
0
      m_unchoke_time_scaler = settings().get_int(settings_pack::unchoke_interval);
3703
0
      recalculate_unchoke_slots();
3704
0
    }
3705
3706
    // --------------------------------------------------------------
3707
    // optimistic unchoke calculation
3708
    // --------------------------------------------------------------
3709
1
    m_optimistic_unchoke_time_scaler--;
3710
1
    if (m_optimistic_unchoke_time_scaler <= 0)
3711
1
    {
3712
1
      m_optimistic_unchoke_time_scaler
3713
1
        = settings().get_int(settings_pack::optimistic_unchoke_interval);
3714
1
      recalculate_optimistic_unchoke_slots();
3715
1
    }
3716
3717
    // --------------------------------------------------------------
3718
    // disconnect peers when we have too many
3719
    // --------------------------------------------------------------
3720
1
    --m_disconnect_time_scaler;
3721
1
    if (m_disconnect_time_scaler <= 0)
3722
0
    {
3723
0
      m_disconnect_time_scaler = m_settings.get_int(settings_pack::peer_turnover_interval);
3724
3725
      // if the connections_limit is too low, the disconnect
3726
      // logic is disabled, since it is too disruptive
3727
0
      if (m_settings.get_int(settings_pack::connections_limit) > 5)
3728
0
      {
3729
0
        int const limit = std::min(m_settings.get_int(settings_pack::connections_limit)
3730
0
          , std::numeric_limits<int>::max() / 100);
3731
0
        int const cutoff = std::min(m_settings.get_int(settings_pack::peer_turnover_cutoff), 100);
3732
0
        if (num_connections() >= limit * cutoff / 100 && !m_torrents.empty())
3733
0
        {
3734
          // every 90 seconds, disconnect the worst peers
3735
          // if we have reached the connection limit
3736
0
          auto const i = std::max_element(m_torrents.begin(), m_torrents.end()
3737
0
            , [] (std::shared_ptr<torrent> const& lhs, std::shared_ptr<torrent> const& rhs)
3738
0
            { return lhs->num_peers() < rhs->num_peers(); });
3739
3740
0
          TORRENT_ASSERT(i != m_torrents.end());
3741
0
          int const peers_to_disconnect = std::min(std::max(
3742
0
            (*i)->num_peers() * m_settings.get_int(settings_pack::peer_turnover) / 100, 1)
3743
0
            , (*i)->num_connect_candidates());
3744
0
          (*i)->disconnect_peers(peers_to_disconnect
3745
0
            , error_code(errors::optimistic_disconnect));
3746
0
        }
3747
0
        else
3748
0
        {
3749
          // if we haven't reached the global max. see if any torrent
3750
          // has reached its local limit
3751
0
          for (auto const& t : m_torrents)
3752
0
          {
3753
            // this disconnect logic is disabled for torrents with
3754
            // too low connection limit
3755
0
            int const max = std::min(t->max_connections()
3756
0
              , std::numeric_limits<int>::max() / 100);
3757
0
            if (t->num_peers() < max * cutoff / 100 || max < 6)
3758
0
              continue;
3759
3760
0
            int const peers_to_disconnect = std::min(std::max(t->num_peers()
3761
0
              * m_settings.get_int(settings_pack::peer_turnover) / 100, 1)
3762
0
              , t->num_connect_candidates());
3763
0
            t->disconnect_peers(peers_to_disconnect, errors::optimistic_disconnect);
3764
0
          }
3765
0
        }
3766
0
      }
3767
0
    }
3768
1
  }
3769
3770
  void session_impl::received_buffer(int s)
3771
0
  {
3772
0
    int index = std::min(aux::log2p1(std::uint32_t(s >> 3)), 17);
3773
0
    m_stats_counters.inc_stats_counter(counters::socket_recv_size3 + index);
3774
0
  }
3775
3776
  void session_impl::sent_buffer(int s)
3777
0
  {
3778
0
    int index = std::min(aux::log2p1(std::uint32_t(s >> 3)), 17);
3779
0
    m_stats_counters.inc_stats_counter(counters::socket_send_size3 + index);
3780
0
  }
3781
3782
  void session_impl::prioritize_connections(std::weak_ptr<torrent> t)
3783
0
  {
3784
0
    m_prio_torrents.emplace_back(t, 10);
3785
0
  }
3786
3787
#ifndef TORRENT_DISABLE_DHT
3788
3789
  void session_impl::add_dht_node(udp::endpoint const& n)
3790
0
  {
3791
0
    TORRENT_ASSERT(is_single_thread());
3792
0
    if (m_dht)
3793
0
      m_dht->add_node(n);
3794
0
    else if (m_dht_nodes.size() >= 200)
3795
0
      m_dht_nodes[random(std::uint32_t(m_dht_nodes.size() - 1))] = n;
3796
0
    else
3797
0
      m_dht_nodes.push_back(n);
3798
0
  }
3799
3800
  bool session_impl::has_dht() const
3801
0
  {
3802
0
    return m_dht.get() != nullptr;
3803
0
  }
3804
3805
  void session_impl::prioritize_dht(std::weak_ptr<torrent> t)
3806
0
  {
3807
0
    TORRENT_ASSERT(!m_abort);
3808
0
    if (m_abort) return;
3809
3810
0
    TORRENT_ASSERT(m_dht);
3811
0
    m_dht_torrents.push_back(t);
3812
#ifndef TORRENT_DISABLE_LOGGING
3813
    std::shared_ptr<torrent> tor = t.lock();
3814
    if (tor && should_log())
3815
      session_log("prioritizing DHT announce: \"%s\"", tor->name().c_str());
3816
#endif
3817
    // trigger a DHT announce right away if we just added a new torrent and
3818
    // there's no back-log. in the timer handler, as long as there are more
3819
    // high priority torrents to be announced to the DHT, it will keep the
3820
    // timer interval short until all torrents have been announced.
3821
0
    if (m_dht_torrents.size() == 1)
3822
0
    {
3823
0
      ADD_OUTSTANDING_ASYNC("session_impl::on_dht_announce");
3824
0
      m_dht_announce_timer.expires_after(seconds(0));
3825
0
      m_dht_announce_timer.async_wait([this](error_code const& err) {
3826
0
        wrap(&session_impl::on_dht_announce, err); });
3827
0
    }
3828
0
  }
3829
3830
  void session_impl::on_dht_announce(error_code const& e)
3831
0
  {
3832
0
    COMPLETE_ASYNC("session_impl::on_dht_announce");
3833
0
    TORRENT_ASSERT(is_single_thread());
3834
0
    if (e)
3835
0
    {
3836
#ifndef TORRENT_DISABLE_LOGGING
3837
      if (should_log())
3838
      {
3839
        session_log("aborting DHT announce timer (%d): %s"
3840
          , e.value(), e.message().c_str());
3841
      }
3842
#endif
3843
0
      return;
3844
0
    }
3845
3846
0
    if (m_abort)
3847
0
    {
3848
#ifndef TORRENT_DISABLE_LOGGING
3849
      session_log("aborting DHT announce timer: m_abort set");
3850
#endif
3851
0
      return;
3852
0
    }
3853
3854
0
    if (!m_dht)
3855
0
    {
3856
0
      m_dht_torrents.clear();
3857
0
      return;
3858
0
    }
3859
3860
0
    TORRENT_ASSERT(m_dht);
3861
3862
0
    update_dht_announce_interval();
3863
3864
0
    if (!m_dht_torrents.empty())
3865
0
    {
3866
0
      std::shared_ptr<torrent> t;
3867
0
      do
3868
0
      {
3869
0
        t = m_dht_torrents.front().lock();
3870
0
        m_dht_torrents.pop_front();
3871
0
      } while (!t && !m_dht_torrents.empty());
3872
3873
0
      if (t)
3874
0
      {
3875
0
        t->dht_announce();
3876
0
        return;
3877
0
      }
3878
0
    }
3879
0
    if (m_torrents.empty()) return;
3880
3881
0
    if (m_next_dht_torrent >= m_torrents.size())
3882
0
      m_next_dht_torrent = 0;
3883
0
    m_torrents[m_next_dht_torrent]->dht_announce();
3884
    // TODO: 2 make a list for torrents that want to be announced on the DHT so we
3885
    // don't have to loop over all torrents, just to find the ones that want to announce
3886
0
    ++m_next_dht_torrent;
3887
0
    if (m_next_dht_torrent >= m_torrents.size())
3888
0
      m_next_dht_torrent = 0;
3889
0
  }
3890
#endif
3891
3892
  void session_impl::on_lsd_announce(error_code const& e)
3893
1.83k
  {
3894
1.83k
    COMPLETE_ASYNC("session_impl::on_lsd_announce");
3895
1.83k
    m_stats_counters.inc_stats_counter(counters::on_lsd_counter);
3896
1.83k
    TORRENT_ASSERT(is_single_thread());
3897
1.83k
    if (e) return;
3898
3899
0
    if (m_abort) return;
3900
3901
0
    ADD_OUTSTANDING_ASYNC("session_impl::on_lsd_announce");
3902
    // announce on local network every 5 minutes
3903
0
    int const delay = std::max(m_settings.get_int(settings_pack::local_service_announce_interval)
3904
0
      / std::max(int(m_torrents.size()), 1), 1);
3905
0
    m_lsd_announce_timer.expires_after(seconds(delay));
3906
0
    m_lsd_announce_timer.async_wait([this](error_code const& err) {
3907
0
      wrap(&session_impl::on_lsd_announce, err); });
3908
3909
0
    if (m_torrents.empty()) return;
3910
3911
0
    if (m_next_lsd_torrent >= m_torrents.size())
3912
0
      m_next_lsd_torrent = 0;
3913
0
    m_torrents[m_next_lsd_torrent]->lsd_announce();
3914
0
    ++m_next_lsd_torrent;
3915
0
    if (m_next_lsd_torrent >= m_torrents.size())
3916
0
      m_next_lsd_torrent = 0;
3917
0
  }
3918
3919
  void session_impl::auto_manage_checking_torrents(std::vector<torrent*>& list
3920
    , int& limit)
3921
1
  {
3922
1
    for (auto& t : list)
3923
0
    {
3924
0
      TORRENT_ASSERT(t->state() == torrent_status::checking_files);
3925
0
      TORRENT_ASSERT(t->is_auto_managed());
3926
0
      if (limit <= 0)
3927
0
      {
3928
0
        t->pause();
3929
0
      }
3930
0
      else
3931
0
      {
3932
0
        t->resume();
3933
0
        if (!t->should_check_files()) continue;
3934
0
        t->start_checking();
3935
0
        --limit;
3936
0
      }
3937
0
    }
3938
1
  }
3939
3940
  void session_impl::auto_manage_torrents(std::vector<torrent*>& list
3941
    , int& dht_limit, int& tracker_limit
3942
    , int& lsd_limit, int& hard_limit, int type_limit)
3943
2
  {
3944
2
    for (auto& t : list)
3945
1
    {
3946
1
      TORRENT_ASSERT(t->state() != torrent_status::checking_files);
3947
3948
      // inactive torrents don't count (and if you configured them to do so,
3949
      // the torrent won't say it's inactive)
3950
1
      if (hard_limit > 0 && t->is_inactive())
3951
0
      {
3952
0
        t->set_announce_to_dht(--dht_limit >= 0);
3953
0
        t->set_announce_to_trackers(--tracker_limit >= 0);
3954
0
        t->set_announce_to_lsd(--lsd_limit >= 0);
3955
3956
0
        --hard_limit;
3957
#ifndef TORRENT_DISABLE_LOGGING
3958
        if (t->is_torrent_paused())
3959
          t->log_to_all_peers("auto manager starting (inactive) torrent");
3960
#endif
3961
0
        t->set_paused(false);
3962
0
        continue;
3963
0
      }
3964
3965
1
      if (type_limit > 0 && hard_limit > 0)
3966
1
      {
3967
1
        t->set_announce_to_dht(--dht_limit >= 0);
3968
1
        t->set_announce_to_trackers(--tracker_limit >= 0);
3969
1
        t->set_announce_to_lsd(--lsd_limit >= 0);
3970
3971
1
        --hard_limit;
3972
1
        --type_limit;
3973
#ifndef TORRENT_DISABLE_LOGGING
3974
        if (t->is_torrent_paused())
3975
          t->log_to_all_peers("auto manager starting torrent");
3976
#endif
3977
1
        t->set_paused(false);
3978
1
        continue;
3979
1
      }
3980
3981
#ifndef TORRENT_DISABLE_LOGGING
3982
      if (!t->is_torrent_paused())
3983
        t->log_to_all_peers("auto manager pausing torrent");
3984
#endif
3985
      // use graceful pause for auto-managed torrents
3986
0
      t->set_paused(true, torrent_handle::graceful_pause
3987
0
        | torrent_handle::clear_disk_cache);
3988
0
      t->set_announce_to_dht(false);
3989
0
      t->set_announce_to_trackers(false);
3990
0
      t->set_announce_to_lsd(false);
3991
0
    }
3992
2
  }
3993
3994
  int session_impl::get_int_setting(int n) const
3995
3.67k
  {
3996
3.67k
    int const v = settings().get_int(n);
3997
3.67k
    if (v < 0) return std::numeric_limits<int>::max();
3998
3.67k
    return v;
3999
3.67k
  }
4000
4001
  void session_impl::recalculate_auto_managed_torrents()
4002
1
  {
4003
1
    INVARIANT_CHECK;
4004
4005
1
    m_last_auto_manage = time_now();
4006
1
    m_need_auto_manage = false;
4007
4008
1
    if (m_paused) return;
4009
4010
    // make copies of the lists of torrents that we want to consider for auto
4011
    // management. We need copies because they will be sorted.
4012
1
    std::vector<torrent*> checking
4013
1
      = torrent_list(session_interface::torrent_checking_auto_managed);
4014
1
    std::vector<torrent*> downloaders
4015
1
      = torrent_list(session_interface::torrent_downloading_auto_managed);
4016
1
    std::vector<torrent*> seeds
4017
1
      = torrent_list(session_interface::torrent_seeding_auto_managed);
4018
4019
    // these counters are set to the number of torrents
4020
    // of each kind we're allowed to have active
4021
1
    int downloading_limit = get_int_setting(settings_pack::active_downloads);
4022
1
    int seeding_limit = get_int_setting(settings_pack::active_seeds);
4023
1
    int checking_limit = get_int_setting(settings_pack::active_checking);
4024
1
    int dht_limit = get_int_setting(settings_pack::active_dht_limit);
4025
1
    int tracker_limit = get_int_setting(settings_pack::active_tracker_limit);
4026
1
    int lsd_limit = get_int_setting(settings_pack::active_lsd_limit);
4027
1
    int hard_limit = get_int_setting(settings_pack::active_limit);
4028
4029
    // if hard_limit is <= 0, all torrents in these lists should be paused.
4030
    // The order is not relevant
4031
1
    if (hard_limit > 0)
4032
1
    {
4033
      // we only need to sort the first n torrents here, where n is the number
4034
      // of checking torrents we allow. The rest of the list is still used to
4035
      // make sure the remaining torrents are paused, but their order is not
4036
      // relevant
4037
1
      std::partial_sort(checking.begin(), checking.begin() +
4038
1
        std::min(checking_limit, int(checking.size())), checking.end()
4039
1
        , [](torrent const* lhs, torrent const* rhs)
4040
1
        { return lhs->sequence_number() < rhs->sequence_number(); });
4041
4042
1
      std::partial_sort(downloaders.begin(), downloaders.begin() +
4043
1
        std::min(hard_limit, int(downloaders.size())), downloaders.end()
4044
1
        , [](torrent const* lhs, torrent const* rhs)
4045
1
        { return lhs->sequence_number() < rhs->sequence_number(); });
4046
4047
1
      std::partial_sort(seeds.begin(), seeds.begin() +
4048
1
        std::min(hard_limit, int(seeds.size())), seeds.end()
4049
1
        , [this](torrent const* lhs, torrent const* rhs)
4050
1
        { return lhs->seed_rank(m_settings) > rhs->seed_rank(m_settings); });
4051
1
    }
4052
4053
1
    auto_manage_checking_torrents(checking, checking_limit);
4054
4055
1
    if (settings().get_bool(settings_pack::auto_manage_prefer_seeds))
4056
0
    {
4057
0
      auto_manage_torrents(seeds, dht_limit, tracker_limit, lsd_limit
4058
0
        , hard_limit, seeding_limit);
4059
0
      auto_manage_torrents(downloaders, dht_limit, tracker_limit, lsd_limit
4060
0
        , hard_limit, downloading_limit);
4061
0
    }
4062
1
    else
4063
1
    {
4064
1
      auto_manage_torrents(downloaders, dht_limit, tracker_limit, lsd_limit
4065
1
        , hard_limit, downloading_limit);
4066
1
      auto_manage_torrents(seeds, dht_limit, tracker_limit, lsd_limit
4067
1
        , hard_limit, seeding_limit);
4068
1
    }
4069
1
  }
4070
4071
  namespace {
4072
#ifndef TORRENT_DISABLE_EXTENSIONS
4073
    uint64_t const priority_undetermined = std::numeric_limits<uint64_t>::max() - 1;
4074
#endif
4075
4076
    struct opt_unchoke_candidate
4077
    {
4078
      explicit opt_unchoke_candidate(std::shared_ptr<peer_connection> const* tp)
4079
0
        : peer(tp)
4080
0
      {}
4081
4082
      std::shared_ptr<peer_connection> const* peer;
4083
#ifndef TORRENT_DISABLE_EXTENSIONS
4084
      // this is mutable because comparison functors passed to std::partial_sort
4085
      // are not supposed to modify the elements they are sorting. Here the mutation
4086
      // being applied is idempotent so it should not pose a problem.
4087
      mutable uint64_t ext_priority = priority_undetermined;
4088
#endif
4089
    };
4090
4091
    struct last_optimistic_unchoke_cmp
4092
    {
4093
#ifndef TORRENT_DISABLE_EXTENSIONS
4094
      explicit last_optimistic_unchoke_cmp(std::vector<std::shared_ptr<plugin>>& ps)
4095
1
        : plugins(ps)
4096
1
      {}
4097
4098
      std::vector<std::shared_ptr<plugin>>& plugins;
4099
#endif
4100
4101
      uint64_t get_ext_priority(opt_unchoke_candidate const& peer) const
4102
0
      {
4103
0
#ifndef TORRENT_DISABLE_EXTENSIONS
4104
0
        if (peer.ext_priority == priority_undetermined)
4105
0
        {
4106
0
          peer.ext_priority = std::numeric_limits<uint64_t>::max();
4107
0
          for (auto& e : plugins)
4108
0
          {
4109
0
            uint64_t const priority = e->get_unchoke_priority(peer_connection_handle(*peer.peer));
4110
0
            peer.ext_priority = std::min(priority, peer.ext_priority);
4111
0
          }
4112
0
        }
4113
0
        return peer.ext_priority;
4114
#else
4115
        TORRENT_UNUSED(peer);
4116
        return std::numeric_limits<uint64_t>::max();
4117
#endif
4118
0
      }
4119
4120
      bool operator()(opt_unchoke_candidate const& l
4121
        , opt_unchoke_candidate const& r) const
4122
0
      {
4123
0
        torrent_peer const* pil = (*l.peer)->peer_info_struct();
4124
0
        torrent_peer const* pir = (*r.peer)->peer_info_struct();
4125
0
        if (pil->last_optimistically_unchoked
4126
0
          != pir->last_optimistically_unchoked)
4127
0
        {
4128
0
          return pil->last_optimistically_unchoked
4129
0
            < pir->last_optimistically_unchoked;
4130
0
        }
4131
0
        else
4132
0
        {
4133
0
          return get_ext_priority(l) < get_ext_priority(r);
4134
0
        }
4135
0
      }
4136
    };
4137
  }
4138
4139
  void session_impl::recalculate_optimistic_unchoke_slots()
4140
1
  {
4141
1
    INVARIANT_CHECK;
4142
4143
1
    TORRENT_ASSERT(is_single_thread());
4144
1
    if (m_stats_counters[counters::num_unchoke_slots] == 0) return;
4145
4146
    // if we unchoke everyone, skip this logic
4147
1
    if (settings().get_int(settings_pack::choking_algorithm) == settings_pack::fixed_slots_choker
4148
1
      && settings().get_int(settings_pack::unchoke_slots_limit) < 0)
4149
0
      return;
4150
4151
1
    std::vector<opt_unchoke_candidate> opt_unchoke;
4152
4153
    // collect the currently optimistically unchoked peers here, so we can
4154
    // choke them when we've found new optimistic unchoke candidates.
4155
1
    std::vector<torrent_peer*> prev_opt_unchoke;
4156
4157
    // TODO: 3 it would probably make sense to have a separate list of peers
4158
    // that are eligible for optimistic unchoke, similar to the torrents
4159
    // perhaps this could even iterate over the pool allocators of
4160
    // torrent_peer objects. It could probably be done in a single pass and
4161
    // collect the n best candidates. maybe just a queue of peers would make
4162
    // even more sense, just pick the next peer in the queue for unchoking. It
4163
    // would be O(1).
4164
1
    for (auto& i : m_connections)
4165
0
    {
4166
0
      peer_connection* const p = i.get();
4167
0
      TORRENT_ASSERT(p);
4168
0
      torrent_peer* pi = p->peer_info_struct();
4169
0
      if (!pi) continue;
4170
0
      if (pi->web_seed) continue;
4171
4172
0
      if (pi->optimistically_unchoked)
4173
0
      {
4174
0
        prev_opt_unchoke.push_back(pi);
4175
0
      }
4176
4177
0
      torrent const* t = p->associated_torrent().lock().get();
4178
0
      if (!t) continue;
4179
4180
      // TODO: 3 peers should know whether their torrent is paused or not,
4181
      // instead of having to ask it over and over again
4182
0
      if (t->is_paused()) continue;
4183
4184
0
      if (!p->is_connecting()
4185
0
        && !p->is_disconnecting()
4186
0
        && p->is_peer_interested()
4187
0
        && t->free_upload_slots()
4188
0
        && (p->is_choked() || pi->optimistically_unchoked)
4189
0
        && !p->ignore_unchoke_slots()
4190
0
        && t->valid_metadata())
4191
0
      {
4192
0
        opt_unchoke.emplace_back(&i);
4193
0
      }
4194
0
    }
4195
4196
    // find the peers that has been waiting the longest to be optimistically
4197
    // unchoked
4198
4199
1
    int num_opt_unchoke = m_settings.get_int(settings_pack::num_optimistic_unchoke_slots);
4200
1
    int const allowed_unchoke_slots = int(m_stats_counters[counters::num_unchoke_slots]);
4201
1
    if (num_opt_unchoke == 0) num_opt_unchoke = std::max(1, allowed_unchoke_slots / 5);
4202
1
    if (num_opt_unchoke > int(opt_unchoke.size())) num_opt_unchoke =
4203
1
      int(opt_unchoke.size());
4204
4205
    // find the n best optimistic unchoke candidates
4206
1
    std::partial_sort(opt_unchoke.begin()
4207
1
      , opt_unchoke.begin() + num_opt_unchoke
4208
1
      , opt_unchoke.end()
4209
1
#ifndef TORRENT_DISABLE_EXTENSIONS
4210
1
      , last_optimistic_unchoke_cmp(m_ses_extensions[plugins_optimistic_unchoke_idx])
4211
#else
4212
      , last_optimistic_unchoke_cmp()
4213
#endif
4214
1
      );
4215
4216
    // unchoke the first num_opt_unchoke peers in the candidate set
4217
    // and make sure that the others are choked
4218
1
    auto opt_unchoke_end = opt_unchoke.begin()
4219
1
      + num_opt_unchoke;
4220
4221
1
    for (auto i = opt_unchoke.begin(); i != opt_unchoke_end; ++i)
4222
0
    {
4223
0
      torrent_peer* pi = (*i->peer)->peer_info_struct();
4224
0
      auto* const p = static_cast<peer_connection*>(pi->connection);
4225
0
      if (pi->optimistically_unchoked)
4226
0
      {
4227
#ifndef TORRENT_DISABLE_LOGGING
4228
          p->peer_log(peer_log_alert::info, "OPTIMISTIC UNCHOKE"
4229
            , "already unchoked | session-time: %d"
4230
            , pi->last_optimistically_unchoked);
4231
#endif
4232
0
        TORRENT_ASSERT(!pi->connection->is_choked());
4233
        // remove this peer from prev_opt_unchoke, to prevent us from
4234
        // choking it later. This peer gets another round of optimistic
4235
        // unchoke
4236
0
        auto const existing =
4237
0
          std::find(prev_opt_unchoke.begin(), prev_opt_unchoke.end(), pi);
4238
0
        TORRENT_ASSERT(existing != prev_opt_unchoke.end());
4239
0
        prev_opt_unchoke.erase(existing);
4240
0
      }
4241
0
      else
4242
0
      {
4243
0
        TORRENT_ASSERT(p->is_choked());
4244
0
        std::shared_ptr<torrent> t = p->associated_torrent().lock();
4245
0
        bool ret = t->unchoke_peer(*p, true);
4246
0
        TORRENT_ASSERT(ret);
4247
0
        if (ret)
4248
0
        {
4249
0
          pi->optimistically_unchoked = true;
4250
0
          m_stats_counters.inc_stats_counter(counters::num_peers_up_unchoked_optimistic);
4251
0
          pi->last_optimistically_unchoked = std::uint16_t(session_time());
4252
#ifndef TORRENT_DISABLE_LOGGING
4253
          p->peer_log(peer_log_alert::info, "OPTIMISTIC UNCHOKE"
4254
            , "session-time: %d", pi->last_optimistically_unchoked);
4255
#endif
4256
0
        }
4257
0
      }
4258
0
    }
4259
4260
    // now, choke all the previous optimistically unchoked peers
4261
1
    for (torrent_peer* pi : prev_opt_unchoke)
4262
0
    {
4263
0
      TORRENT_ASSERT(pi->optimistically_unchoked);
4264
0
      auto* const p = static_cast<peer_connection*>(pi->connection);
4265
0
      std::shared_ptr<torrent> t = p->associated_torrent().lock();
4266
0
      pi->optimistically_unchoked = false;
4267
0
      m_stats_counters.inc_stats_counter(counters::num_peers_up_unchoked_optimistic, -1);
4268
0
      t->choke_peer(*p);
4269
0
    }
4270
4271
    // if we have too many unchoked peers now, we need to trigger the regular
4272
    // choking logic to choke some
4273
1
    if (m_stats_counters[counters::num_unchoke_slots]
4274
1
      < m_stats_counters[counters::num_peers_up_unchoked_all])
4275
0
    {
4276
0
      m_unchoke_time_scaler = 0;
4277
0
    }
4278
1
  }
4279
4280
  void session_impl::try_connect_more_peers()
4281
1
  {
4282
1
    if (m_abort) return;
4283
4284
1
    if (num_connections() >= m_settings.get_int(settings_pack::connections_limit))
4285
0
      return;
4286
4287
    // this is the maximum number of connections we will
4288
    // attempt this tick
4289
1
    int max_connections = m_settings.get_int(settings_pack::connection_speed);
4290
4291
    // this loop will "hand out" connection_speed to the torrents, in a round
4292
    // robin fashion, so that every torrent is equally likely to connect to a
4293
    // peer
4294
4295
    // boost connections are connections made by torrent connection
4296
    // boost, which are done immediately on a tracker response. These
4297
    // connections needs to be deducted from the regular connection attempt
4298
    // quota for this tick
4299
1
    if (m_boost_connections > 0)
4300
0
    {
4301
0
      if (m_boost_connections > max_connections)
4302
0
      {
4303
0
        m_boost_connections -= max_connections;
4304
0
        max_connections = 0;
4305
0
      }
4306
0
      else
4307
0
      {
4308
0
        max_connections -= m_boost_connections;
4309
0
        m_boost_connections = 0;
4310
0
      }
4311
0
    }
4312
4313
    // zero connections speeds are allowed, we just won't make any connections
4314
1
    if (max_connections <= 0) return;
4315
4316
    // TODO: use a lower limit than m_settings.connections_limit
4317
    // to allocate the to 10% or so of connection slots for incoming
4318
    // connections
4319
    // cap this at max - 1, since we may add one below
4320
1
    int const limit = std::min(m_settings.get_int(settings_pack::connections_limit)
4321
1
      - num_connections(), std::numeric_limits<int>::max() - 1);
4322
4323
    // this logic is here to smooth out the number of new connection
4324
    // attempts over time, to prevent connecting a large number of
4325
    // sockets, wait 10 seconds, and then try again
4326
1
    if (m_settings.get_bool(settings_pack::smooth_connects) && max_connections > (limit+1) / 2)
4327
0
      max_connections = (limit + 1) / 2;
4328
4329
1
    aux::vector<torrent*>& want_peers_download = m_torrent_lists[torrent_want_peers_download];
4330
1
    aux::vector<torrent*>& want_peers_finished = m_torrent_lists[torrent_want_peers_finished];
4331
4332
    // if no torrent want any peers, just return
4333
1
    if (want_peers_download.empty() && want_peers_finished.empty()) return;
4334
4335
    // if we don't have any connection attempt quota, return
4336
0
    if (max_connections <= 0) return;
4337
4338
0
    int steps_since_last_connect = 0;
4339
0
    int const num_torrents = int(want_peers_finished.size() + want_peers_download.size());
4340
0
    for (;;)
4341
0
    {
4342
0
      if (m_next_downloading_connect_torrent >= int(want_peers_download.size()))
4343
0
        m_next_downloading_connect_torrent = 0;
4344
4345
0
      if (m_next_finished_connect_torrent >= int(want_peers_finished.size()))
4346
0
        m_next_finished_connect_torrent = 0;
4347
4348
0
      torrent* t = nullptr;
4349
      // there are prioritized torrents. Pick one of those
4350
0
      while (!m_prio_torrents.empty())
4351
0
      {
4352
0
        t = m_prio_torrents.front().first.lock().get();
4353
0
        --m_prio_torrents.front().second;
4354
0
        if (m_prio_torrents.front().second > 0
4355
0
          && t != nullptr
4356
0
          && t->want_peers()) break;
4357
0
        m_prio_torrents.pop_front();
4358
0
        t = nullptr;
4359
0
      }
4360
4361
0
      if (t == nullptr)
4362
0
      {
4363
0
        if ((m_download_connect_attempts >= m_settings.get_int(
4364
0
            settings_pack::connect_seed_every_n_download)
4365
0
          && !want_peers_finished.empty())
4366
0
            || want_peers_download.empty())
4367
0
        {
4368
          // pick a finished torrent to give a peer to
4369
0
          t = want_peers_finished[m_next_finished_connect_torrent];
4370
0
          TORRENT_ASSERT(t->want_peers_finished());
4371
0
          m_download_connect_attempts = 0;
4372
0
          ++m_next_finished_connect_torrent;
4373
0
        }
4374
0
        else
4375
0
        {
4376
          // pick a downloading torrent to give a peer to
4377
0
          t = want_peers_download[m_next_downloading_connect_torrent];
4378
0
          TORRENT_ASSERT(t->want_peers_download());
4379
0
          ++m_download_connect_attempts;
4380
0
          ++m_next_downloading_connect_torrent;
4381
0
        }
4382
0
      }
4383
4384
0
      TORRENT_ASSERT(t->want_peers());
4385
0
      TORRENT_ASSERT(!t->is_torrent_paused());
4386
4387
0
      if (t->try_connect_peer())
4388
0
      {
4389
0
        --max_connections;
4390
0
        steps_since_last_connect = 0;
4391
0
        m_stats_counters.inc_stats_counter(counters::connection_attempts);
4392
0
      }
4393
4394
0
      ++steps_since_last_connect;
4395
4396
      // if there are no more free connection slots, abort
4397
0
      if (max_connections == 0) return;
4398
      // there are no more torrents that want peers
4399
0
      if (want_peers_download.empty() && want_peers_finished.empty()) break;
4400
      // if we have gone a whole loop without
4401
      // handing out a single connection, break
4402
0
      if (steps_since_last_connect > num_torrents + 1) break;
4403
      // maintain the global limit on number of connections
4404
0
      if (num_connections() >= m_settings.get_int(settings_pack::connections_limit)) break;
4405
0
    }
4406
0
  }
4407
4408
  void session_impl::recalculate_unchoke_slots()
4409
1.83k
  {
4410
1.83k
    TORRENT_ASSERT(is_single_thread());
4411
4412
1.83k
    time_point const now = aux::time_now();
4413
1.83k
    time_duration const unchoke_interval = now - m_last_choke;
4414
1.83k
    m_last_choke = now;
4415
4416
    // if we unchoke everyone, skip this logic
4417
1.83k
    if (settings().get_int(settings_pack::choking_algorithm) == settings_pack::fixed_slots_choker
4418
1.83k
      && settings().get_int(settings_pack::unchoke_slots_limit) < 0)
4419
0
    {
4420
0
      m_stats_counters.set_value(counters::num_unchoke_slots, std::numeric_limits<int>::max());
4421
0
      return;
4422
0
    }
4423
4424
    // build list of all peers that are
4425
    // unchokable.
4426
    // TODO: 3 there should be a pre-calculated list of all peers eligible for
4427
    // unchoking
4428
1.83k
    std::vector<peer_connection*> peers;
4429
1.83k
    for (auto i = m_connections.begin(); i != m_connections.end();)
4430
0
    {
4431
0
      std::shared_ptr<peer_connection> p = *i;
4432
0
      TORRENT_ASSERT(p);
4433
0
      ++i;
4434
0
      torrent* const t = p->associated_torrent().lock().get();
4435
0
      torrent_peer* const pi = p->peer_info_struct();
4436
4437
0
      if (p->ignore_unchoke_slots() || t == nullptr || pi == nullptr
4438
0
        || pi->web_seed || t->is_paused())
4439
0
      {
4440
0
        p->reset_choke_counters();
4441
0
        continue;
4442
0
      }
4443
4444
0
      if (!p->is_peer_interested()
4445
0
        || p->is_disconnecting()
4446
0
        || p->is_connecting())
4447
0
      {
4448
        // this peer is not unchokable. So, if it's unchoked
4449
        // already, make sure to choke it.
4450
0
        if (p->is_choked())
4451
0
        {
4452
0
          p->reset_choke_counters();
4453
0
          continue;
4454
0
        }
4455
0
        if (pi && pi->optimistically_unchoked)
4456
0
        {
4457
0
          m_stats_counters.inc_stats_counter(counters::num_peers_up_unchoked_optimistic, -1);
4458
0
          pi->optimistically_unchoked = false;
4459
          // force a new optimistic unchoke
4460
0
          m_optimistic_unchoke_time_scaler = 0;
4461
          // TODO: post a message to have this happen
4462
          // immediately instead of waiting for the next tick
4463
0
        }
4464
0
        t->choke_peer(*p);
4465
0
        p->reset_choke_counters();
4466
0
        continue;
4467
0
      }
4468
4469
0
      peers.push_back(p.get());
4470
0
    }
4471
4472
1.83k
    int const allowed_upload_slots = unchoke_sort(peers
4473
1.83k
      , unchoke_interval, m_settings);
4474
4475
1.83k
    if (m_settings.get_int(settings_pack::choking_algorithm) == settings_pack::fixed_slots_choker)
4476
1.83k
    {
4477
1.83k
      int const upload_slots = get_int_setting(settings_pack::unchoke_slots_limit);
4478
1.83k
      m_stats_counters.set_value(counters::num_unchoke_slots, upload_slots);
4479
1.83k
    }
4480
0
    else
4481
0
    {
4482
0
      m_stats_counters.set_value(counters::num_unchoke_slots
4483
0
        , allowed_upload_slots);
4484
0
    }
4485
4486
#ifndef TORRENT_DISABLE_LOGGING
4487
    if (should_log())
4488
    {
4489
      session_log("RECALCULATE UNCHOKE SLOTS: [ peers: %d "
4490
        "eligible-peers: %d"
4491
        " allowed-slots: %d ]"
4492
        , int(m_connections.size())
4493
        , int(peers.size())
4494
        , allowed_upload_slots);
4495
    }
4496
#endif
4497
4498
1.83k
    int const unchoked_counter_optimistic
4499
1.83k
      = int(m_stats_counters[counters::num_peers_up_unchoked_optimistic]);
4500
1.83k
    int const num_opt_unchoke = (unchoked_counter_optimistic == 0)
4501
1.83k
      ? std::max(1, allowed_upload_slots / 5) : unchoked_counter_optimistic;
4502
4503
1.83k
    int unchoke_set_size = allowed_upload_slots - num_opt_unchoke;
4504
4505
    // go through all the peers and unchoke the first ones and choke
4506
    // all the other ones.
4507
1.83k
    for (auto p : peers)
4508
0
    {
4509
0
      TORRENT_ASSERT(p != nullptr);
4510
0
      TORRENT_ASSERT(!p->ignore_unchoke_slots());
4511
4512
      // this will update the m_uploaded_at_last_unchoke
4513
0
      p->reset_choke_counters();
4514
4515
0
      torrent* t = p->associated_torrent().lock().get();
4516
0
      TORRENT_ASSERT(t);
4517
4518
0
      if (unchoke_set_size > 0)
4519
0
      {
4520
        // yes, this peer should be unchoked
4521
0
        if (p->is_choked())
4522
0
        {
4523
0
          if (!t->unchoke_peer(*p))
4524
0
            continue;
4525
0
        }
4526
4527
0
        --unchoke_set_size;
4528
4529
0
        TORRENT_ASSERT(p->peer_info_struct());
4530
0
        if (p->peer_info_struct()->optimistically_unchoked)
4531
0
        {
4532
          // force a new optimistic unchoke
4533
          // since this one just got promoted into the
4534
          // proper unchoke set
4535
0
          m_optimistic_unchoke_time_scaler = 0;
4536
0
          p->peer_info_struct()->optimistically_unchoked = false;
4537
0
          m_stats_counters.inc_stats_counter(counters::num_peers_up_unchoked_optimistic, -1);
4538
0
        }
4539
0
      }
4540
0
      else
4541
0
      {
4542
        // no, this peer should be choked
4543
0
        TORRENT_ASSERT(p->peer_info_struct());
4544
0
        if (!p->is_choked() && !p->peer_info_struct()->optimistically_unchoked)
4545
0
          t->choke_peer(*p);
4546
0
      }
4547
0
    }
4548
1.83k
  }
4549
4550
  std::shared_ptr<torrent> session_impl::delay_load_torrent(info_hash_t const& info_hash
4551
    , peer_connection* pc)
4552
0
  {
4553
0
#ifndef TORRENT_DISABLE_EXTENSIONS
4554
0
    for (auto& e : m_ses_extensions[plugins_all_idx])
4555
0
    {
4556
0
      add_torrent_params p;
4557
0
      if (e->on_unknown_torrent(info_hash, peer_connection_handle(pc->self()), p))
4558
0
      {
4559
0
        error_code ec;
4560
0
        torrent_handle handle = add_torrent(std::move(p), ec);
4561
4562
0
        return handle.native_handle();
4563
0
      }
4564
0
    }
4565
#else
4566
    TORRENT_UNUSED(pc);
4567
    TORRENT_UNUSED(info_hash);
4568
#endif
4569
0
    return std::shared_ptr<torrent>();
4570
0
  }
4571
4572
  // the return value from this function is valid only as long as the
4573
  // session is locked!
4574
  std::weak_ptr<torrent> session_impl::find_torrent(info_hash_t const& info_hash) const
4575
1.83k
  {
4576
1.83k
    TORRENT_ASSERT(is_single_thread());
4577
4578
1.83k
    torrent* i = nullptr;
4579
1.83k
    info_hash.for_each([&](sha1_hash const& ih, protocol_version)
4580
3.67k
    {
4581
3.67k
      if (i == nullptr) i = m_torrents.find(ih);
4582
3.67k
    });
4583
#if TORRENT_USE_INVARIANT_CHECKS
4584
    for (auto const& te : m_torrents)
4585
    {
4586
      TORRENT_ASSERT(te);
4587
    }
4588
#endif
4589
1.83k
    if (i != nullptr) return i->shared_from_this();
4590
1.83k
    return std::weak_ptr<torrent>();
4591
1.83k
  }
4592
4593
  void session_impl::insert_torrent(info_hash_t const& ih, std::shared_ptr<torrent> const& t)
4594
1.83k
  {
4595
1.83k
    m_torrents.insert(ih, t);
4596
1.83k
    t->added();
4597
1.83k
  }
4598
4599
  void session_impl::update_torrent_info_hash(std::shared_ptr<torrent> const& t
4600
    , info_hash_t const& old_ih)
4601
0
  {
4602
0
    m_torrents.erase(old_ih);
4603
0
    m_torrents.insert(t->info_hash(), t);
4604
0
  }
4605
4606
  void session_impl::set_queue_position(torrent* me, queue_position_t p)
4607
3.81k
  {
4608
3.81k
    queue_position_t const current_pos = me->queue_position();
4609
3.81k
    if (current_pos == p) return;
4610
4611
3.10k
    if (p >= queue_position_t{0} && current_pos == no_pos)
4612
1.55k
    {
4613
      // we're inserting the torrent into the download queue
4614
1.55k
      queue_position_t const last = m_download_queue.end_index();
4615
1.55k
      if (p >= last)
4616
1.55k
      {
4617
1.55k
        m_download_queue.push_back(me);
4618
1.55k
        me->set_queue_position_impl(last);
4619
1.55k
      }
4620
0
      else
4621
0
      {
4622
0
        m_download_queue.insert(m_download_queue.begin() + static_cast<int>(p), me);
4623
0
        for (queue_position_t i = p; i < m_download_queue.end_index(); ++i)
4624
0
        {
4625
0
          m_download_queue[i]->set_queue_position_impl(i);
4626
0
        }
4627
0
      }
4628
1.55k
    }
4629
1.55k
    else if (p < queue_position_t{})
4630
1.55k
    {
4631
      // we're removing the torrent from the download queue
4632
1.55k
      TORRENT_ASSERT(current_pos >= queue_position_t{0});
4633
1.55k
      TORRENT_ASSERT(p == no_pos);
4634
1.55k
      TORRENT_ASSERT(m_download_queue[current_pos] == me);
4635
1.55k
      m_download_queue.erase(m_download_queue.begin() + static_cast<int>(current_pos));
4636
1.55k
      me->set_queue_position_impl(no_pos);
4637
1.55k
      for (queue_position_t i = current_pos; i < m_download_queue.end_index(); ++i)
4638
0
      {
4639
0
        m_download_queue[i]->set_queue_position_impl(i);
4640
0
      }
4641
1.55k
    }
4642
0
    else if (p < current_pos)
4643
0
    {
4644
      // we're moving the torrent up the queue
4645
0
      torrent* tmp = me;
4646
0
      for (queue_position_t i = p; i <= current_pos; ++i)
4647
0
      {
4648
0
        std::swap(m_download_queue[i], tmp);
4649
0
        m_download_queue[i]->set_queue_position_impl(i);
4650
0
      }
4651
0
      TORRENT_ASSERT(tmp == me);
4652
0
    }
4653
0
    else if (p > current_pos)
4654
0
    {
4655
      // we're moving the torrent down the queue
4656
0
      p = std::min(p, prev(m_download_queue.end_index()));
4657
0
      for (queue_position_t i = current_pos; i < p; ++i)
4658
0
      {
4659
0
        m_download_queue[i] = m_download_queue[next(i)];
4660
0
        m_download_queue[i]->set_queue_position_impl(i);
4661
0
      }
4662
0
      m_download_queue[p] = me;
4663
0
      me->set_queue_position_impl(p);
4664
0
    }
4665
4666
3.10k
    trigger_auto_manage();
4667
3.10k
  }
4668
4669
#if !defined TORRENT_DISABLE_ENCRYPTION
4670
  torrent const* session_impl::find_encrypted_torrent(sha1_hash const& info_hash
4671
    , sha1_hash const& xor_mask)
4672
0
  {
4673
0
    sha1_hash obfuscated = info_hash;
4674
0
    obfuscated ^= xor_mask;
4675
4676
0
    return m_torrents.find_obfuscated(obfuscated);
4677
0
  }
4678
#endif
4679
4680
#ifndef TORRENT_DISABLE_MUTABLE_TORRENTS
4681
  std::vector<std::shared_ptr<torrent>> session_impl::find_collection(
4682
    std::string const& collection) const
4683
0
  {
4684
0
    std::vector<std::shared_ptr<torrent>> ret;
4685
0
    for (auto const& t : m_torrents)
4686
0
    {
4687
0
      if (!t) continue;
4688
0
      std::vector<std::string> const& c = t->torrent_file().collections();
4689
0
      if (std::find(c.begin(), c.end(), collection) == c.end()) continue;
4690
0
      ret.push_back(t);
4691
0
    }
4692
0
    return ret;
4693
0
  }
4694
#endif //TORRENT_DISABLE_MUTABLE_TORRENTS
4695
4696
  namespace {
4697
4698
  // returns true if lhs is a better disconnect candidate than rhs
4699
  bool compare_disconnect_torrent(std::shared_ptr<torrent> const& lhs
4700
    , std::shared_ptr<torrent> const& rhs)
4701
0
  {
4702
    // a torrent with 0 peers is never a good disconnect candidate
4703
    // since there's nothing to disconnect
4704
0
    if ((lhs->num_peers() == 0) != (rhs->num_peers() == 0))
4705
0
      return lhs->num_peers() != 0;
4706
4707
    // other than that, always prefer to disconnect peers from finished torrents
4708
    // in order to not harm downloading ones
4709
0
    if (lhs->is_finished() != rhs->is_finished())
4710
0
      return lhs->is_finished();
4711
4712
0
    return lhs->num_peers() > rhs->num_peers();
4713
0
  }
4714
4715
  } // anonymous namespace
4716
4717
  std::weak_ptr<torrent> session_impl::find_disconnect_candidate_torrent() const
4718
0
  {
4719
0
    auto const i = std::min_element(m_torrents.begin(), m_torrents.end()
4720
0
      , &compare_disconnect_torrent);
4721
4722
0
    TORRENT_ASSERT(i != m_torrents.end());
4723
0
    if (i == m_torrents.end()) return std::shared_ptr<torrent>();
4724
4725
0
    return *i;
4726
0
  }
4727
4728
#ifndef TORRENT_DISABLE_LOGGING
4729
  bool session_impl::should_log() const
4730
  {
4731
    return m_alerts.should_post<log_alert>();
4732
  }
4733
4734
  TORRENT_FORMAT(2,3)
4735
  void session_impl::session_log(char const* fmt, ...) const noexcept try
4736
  {
4737
    if (!m_alerts.should_post<log_alert>()) return;
4738
4739
    va_list v;
4740
    va_start(v, fmt);
4741
    m_alerts.emplace_alert<log_alert>(fmt, v);
4742
    va_end(v);
4743
  }
4744
  catch (std::exception const&) {}
4745
#endif
4746
4747
  void session_impl::get_torrent_status(std::vector<torrent_status>* ret
4748
    , std::function<bool(torrent_status const&)> const& pred
4749
    , status_flags_t const flags) const
4750
0
  {
4751
0
    for (auto const& t : m_torrents)
4752
0
    {
4753
0
      if (t->is_aborted()) continue;
4754
0
      torrent_status st;
4755
0
      t->status(&st, flags);
4756
0
      if (!pred(st)) continue;
4757
0
      ret->push_back(std::move(st));
4758
0
    }
4759
0
  }
4760
4761
  void session_impl::refresh_torrent_status(std::vector<torrent_status>* ret
4762
    , status_flags_t const flags) const
4763
0
  {
4764
0
    for (auto& st : *ret)
4765
0
    {
4766
0
      auto t = st.handle.m_torrent.lock();
4767
0
      if (!t) continue;
4768
0
      t->status(&st, flags);
4769
0
    }
4770
0
  }
4771
4772
  void session_impl::post_torrent_updates(status_flags_t const flags)
4773
0
  {
4774
0
    INVARIANT_CHECK;
4775
4776
0
    TORRENT_ASSERT(is_single_thread());
4777
4778
0
    std::vector<torrent*>& state_updates
4779
0
      = m_torrent_lists[aux::session_impl::torrent_state_updates];
4780
4781
0
#if TORRENT_USE_ASSERTS
4782
0
    m_posting_torrent_updates = true;
4783
0
#endif
4784
4785
0
    std::vector<torrent_status> status;
4786
0
    status.reserve(state_updates.size());
4787
4788
    // TODO: it might be a nice feature here to limit the number of torrents
4789
    // to send in a single update. By just posting the first n torrents, they
4790
    // would nicely be round-robined because the torrent lists are always
4791
    // pushed back. Perhaps the status_update_alert could even have a fixed
4792
    // array of n entries rather than a vector, to further improve memory
4793
    // locality.
4794
0
    for (auto& t : state_updates)
4795
0
    {
4796
0
      TORRENT_ASSERT(t->m_links[aux::session_impl::torrent_state_updates].in_list());
4797
0
      status.emplace_back();
4798
      // querying accurate download counters may require
4799
      // the torrent to be loaded. Loading a torrent, and evicting another
4800
      // one will lead to calling state_updated(), which screws with
4801
      // this list while we're working on it, and break things
4802
0
      t->status(&status.back(), flags);
4803
0
      t->clear_in_state_update();
4804
0
    }
4805
0
    state_updates.clear();
4806
4807
0
#if TORRENT_USE_ASSERTS
4808
0
    m_posting_torrent_updates = false;
4809
0
#endif
4810
4811
0
    m_alerts.emplace_alert<state_update_alert>(std::move(status));
4812
0
  }
4813
4814
  void session_impl::post_session_stats()
4815
0
  {
4816
0
    if (!m_posted_stats_header)
4817
0
    {
4818
0
      m_posted_stats_header = true;
4819
0
      m_alerts.emplace_alert<session_stats_header_alert>();
4820
0
    }
4821
0
    m_disk_thread->update_stats_counters(m_stats_counters);
4822
4823
0
#ifndef TORRENT_DISABLE_DHT
4824
0
    if (m_dht)
4825
0
      m_dht->update_stats_counters(m_stats_counters);
4826
0
#endif
4827
4828
0
    m_stats_counters.set_value(counters::limiter_up_queue
4829
0
      , m_upload_rate.queue_size());
4830
0
    m_stats_counters.set_value(counters::limiter_down_queue
4831
0
      , m_download_rate.queue_size());
4832
4833
0
    m_stats_counters.set_value(counters::limiter_up_bytes
4834
0
      , m_upload_rate.queued_bytes());
4835
0
    m_stats_counters.set_value(counters::limiter_down_bytes
4836
0
      , m_download_rate.queued_bytes());
4837
4838
0
    m_alerts.emplace_alert<session_stats_alert>(m_stats_counters);
4839
0
  }
4840
4841
  void session_impl::post_dht_stats()
4842
0
  {
4843
0
#ifndef TORRENT_DISABLE_DHT
4844
0
    std::vector<dht::dht_status> dht_stats;
4845
0
    if (m_dht)
4846
0
      dht_stats = m_dht->dht_status();
4847
4848
0
    if (dht_stats.empty())
4849
0
    {
4850
      // for backwards compatibility, still post an empty alert if we don't
4851
      // have any active DHT nodes
4852
0
      m_alerts.emplace_alert<dht_stats_alert>(std::vector<dht_routing_bucket>{}
4853
0
        , std::vector<dht_lookup>{}, dht::node_id{}, udp::endpoint{});
4854
0
    }
4855
0
    else
4856
0
    {
4857
0
      for (auto& s : dht_stats)
4858
0
      {
4859
0
        m_alerts.emplace_alert<dht_stats_alert>(
4860
0
          std::move(s.table), std::move(s.requests)
4861
0
          , s.our_id, s.local_endpoint);
4862
0
      }
4863
0
    }
4864
0
#endif
4865
0
  }
4866
4867
  std::vector<torrent_handle> session_impl::get_torrents() const
4868
0
  {
4869
0
    std::vector<torrent_handle> ret;
4870
4871
0
    for (auto const& i : m_torrents)
4872
0
    {
4873
0
      if (i->is_aborted()) continue;
4874
0
      ret.push_back(torrent_handle(i));
4875
0
    }
4876
0
    return ret;
4877
0
  }
4878
4879
  torrent_handle session_impl::find_torrent_handle(info_hash_t const& info_hash)
4880
0
  {
4881
0
    return torrent_handle(find_torrent(info_hash));
4882
0
  }
4883
4884
  void session_impl::async_add_torrent(add_torrent_params* params)
4885
1.83k
  {
4886
1.83k
    std::unique_ptr<add_torrent_params> holder(params);
4887
1.83k
    error_code ec;
4888
1.83k
    add_torrent(std::move(*params), ec);
4889
1.83k
  }
4890
4891
#ifndef TORRENT_DISABLE_EXTENSIONS
4892
  void session_impl::add_extensions_to_torrent(
4893
    std::shared_ptr<torrent> const& torrent_ptr, client_data_t const userdata)
4894
1.83k
  {
4895
1.83k
    for (auto& e : m_ses_extensions[plugins_all_idx])
4896
5.50k
    {
4897
5.50k
      std::shared_ptr<torrent_plugin> tp(e->new_torrent(
4898
5.50k
        torrent_ptr->get_handle(), userdata));
4899
5.50k
      if (tp) torrent_ptr->add_extension(std::move(tp));
4900
5.50k
    }
4901
1.83k
  }
4902
#endif
4903
4904
  torrent_handle session_impl::add_torrent(add_torrent_params&& params
4905
    , error_code& ec)
4906
1.83k
  {
4907
1.83k
    std::shared_ptr<torrent> torrent_ptr;
4908
4909
    // in case there's an error, make sure to abort the torrent before leaving
4910
    // the scope
4911
1.83k
    auto abort_torrent = aux::scope_end([&]{ if (torrent_ptr) torrent_ptr->abort(); });
4912
4913
    // copy the most important fields from params to pass back in the
4914
    // add_torrent_alert
4915
1.83k
    add_torrent_params alert_params;
4916
1.83k
    alert_params.flags = params.flags;
4917
1.83k
    alert_params.ti = params.ti;
4918
1.83k
    alert_params.name = params.name;
4919
1.83k
    alert_params.save_path = params.save_path;
4920
1.83k
    alert_params.userdata = params.userdata;
4921
1.83k
    alert_params.trackerid = params.trackerid;
4922
4923
1.83k
#ifndef TORRENT_DISABLE_EXTENSIONS
4924
1.83k
    auto extensions = std::move(params.extensions);
4925
1.83k
    auto const userdata = params.userdata;
4926
1.83k
#endif
4927
4928
1.83k
    auto const flags = params.flags;
4929
4930
1.83k
    info_hash_t info_hash;
4931
1.83k
    bool added;
4932
1.83k
    std::tie(torrent_ptr, info_hash, added) = add_torrent_impl(std::move(params), ec);
4933
4934
1.83k
    alert_params.info_hashes = info_hash;
4935
4936
1.83k
    torrent_handle handle(torrent_ptr);
4937
4938
1.83k
    if (!torrent_ptr)
4939
0
    {
4940
0
      m_alerts.emplace_alert<add_torrent_alert>(handle, std::move(alert_params), ec);
4941
0
      return handle;
4942
0
    }
4943
4944
1.83k
    TORRENT_ASSERT(info_hash.has_v1() || info_hash.has_v2());
4945
4946
1.83k
#if TORRENT_ABI_VERSION == 1
4947
1.83k
    if (m_alerts.should_post<torrent_added_alert>())
4948
1
      m_alerts.emplace_alert<torrent_added_alert>(handle);
4949
1.83k
#endif
4950
4951
    // if this was an existing torrent, we can't start it again, or add
4952
    // another set of plugins etc. we're done
4953
1.83k
    if (!added)
4954
0
    {
4955
0
      abort_torrent.disarm();
4956
0
      m_alerts.emplace_alert<add_torrent_alert>(handle, std::move(alert_params), ec);
4957
0
      return handle;
4958
0
    }
4959
4960
1.83k
    torrent_ptr->set_ip_filter(m_ip_filter);
4961
1.83k
    torrent_ptr->start();
4962
4963
1.83k
#ifndef TORRENT_DISABLE_EXTENSIONS
4964
1.83k
    for (auto& ext : extensions)
4965
0
    {
4966
0
      std::shared_ptr<torrent_plugin> tp(ext(handle, userdata));
4967
0
      if (tp) torrent_ptr->add_extension(std::move(tp));
4968
0
    }
4969
4970
1.83k
    add_extensions_to_torrent(torrent_ptr, userdata);
4971
1.83k
#endif
4972
4973
1.83k
    TORRENT_ASSERT(info_hash == torrent_ptr->torrent_file().info_hashes());
4974
1.83k
    insert_torrent(info_hash, torrent_ptr);
4975
4976
1.83k
        m_alerts.emplace_alert<add_torrent_alert>(handle, std::move(alert_params), ec);
4977
4978
    // once we successfully add the torrent, we can disarm the abort action
4979
1.83k
    abort_torrent.disarm();
4980
4981
    // recalculate auto-managed torrents sooner (or put it off)
4982
    // if another torrent will be added within one second from now
4983
    // we want to put it off again anyway. So that while we're adding
4984
    // a boat load of torrents, we postpone the recalculation until
4985
    // we're done adding them all (since it's kind of an expensive operation)
4986
1.83k
    if (flags & torrent_flags::auto_managed)
4987
703
    {
4988
703
      const int max_downloading = settings().get_int(settings_pack::active_downloads);
4989
703
      const int max_seeds = settings().get_int(settings_pack::active_seeds);
4990
703
      const int max_active = settings().get_int(settings_pack::active_limit);
4991
4992
703
      const int num_downloading
4993
703
      = int(torrent_list(session_interface::torrent_downloading_auto_managed).size());
4994
703
      const int num_seeds
4995
703
      = int(torrent_list(session_interface::torrent_seeding_auto_managed).size());
4996
703
      const int num_active = num_downloading + num_seeds;
4997
4998
      // there's no point in triggering the auto manage logic early if we
4999
      // don't have a reason to believe anything will change. It's kind of
5000
      // expensive.
5001
703
      if ((num_downloading < max_downloading
5002
703
        || num_seeds < max_seeds)
5003
703
        && num_active < max_active)
5004
703
      {
5005
703
        trigger_auto_manage();
5006
703
      }
5007
703
    }
5008
5009
1.83k
    return handle;
5010
1.83k
  }
5011
5012
  std::tuple<std::shared_ptr<torrent>, info_hash_t, bool>
5013
  session_impl::add_torrent_impl(add_torrent_params&& params, error_code& ec)
5014
1.83k
  {
5015
1.83k
    TORRENT_ASSERT(!params.save_path.empty());
5016
5017
1.83k
    using ptr_t = std::shared_ptr<torrent>;
5018
1.83k
    using ret_t = std::tuple<std::shared_ptr<torrent>, info_hash_t, bool>;
5019
5020
1.83k
#if TORRENT_ABI_VERSION == 1
5021
1.83k
    if (string_begins_no_case("magnet:", params.url.c_str()))
5022
0
    {
5023
0
      parse_magnet_uri(params.url, params, ec);
5024
0
      if (ec) return ret_t{ptr_t(), params.info_hashes, false};
5025
0
      params.url.clear();
5026
0
    }
5027
1.83k
#endif
5028
5029
1.83k
    if (params.ti && !params.ti->is_valid())
5030
0
    {
5031
0
      ec = errors::no_metadata;
5032
0
      return ret_t{ptr_t(), params.info_hashes, false};
5033
0
    }
5034
5035
1.83k
    if (params.ti && params.ti->is_valid() && params.ti->num_files() == 0)
5036
0
    {
5037
0
      ec = errors::no_files_in_torrent;
5038
0
      return ret_t{ptr_t(), params.info_hashes, false};
5039
0
    }
5040
5041
1.83k
    if (params.ti
5042
1.83k
      && ((params.info_hashes.has_v1() && params.info_hashes.v1 != params.ti->info_hashes().v1)
5043
1.83k
        || (params.info_hashes.has_v2() && params.info_hashes.v2 != params.ti->info_hashes().v2)
5044
1.83k
      ))
5045
0
    {
5046
0
      ec = errors::mismatching_info_hash;
5047
0
      return ret_t{ptr_t(), params.info_hashes, false};
5048
0
    }
5049
5050
1.83k
#ifndef TORRENT_DISABLE_DHT
5051
    // add params.dht_nodes to the DHT, if enabled
5052
1.83k
    for (auto const& n : params.dht_nodes)
5053
0
      add_dht_node_name(n);
5054
5055
1.83k
    if (params.ti)
5056
1.83k
    {
5057
1.83k
      for (auto const& n : params.ti->nodes())
5058
0
        add_dht_node_name(n);
5059
1.83k
    }
5060
1.83k
#endif
5061
5062
1.83k
    INVARIANT_CHECK;
5063
5064
1.83k
    if (is_aborted())
5065
0
    {
5066
0
      ec = errors::session_is_closing;
5067
0
      return ret_t{ptr_t(), params.info_hashes, false};
5068
0
    }
5069
5070
    // figure out the info hash of the torrent and make sure
5071
    // params.info_hashes is set correctly
5072
1.83k
    if (params.ti)
5073
1.83k
    {
5074
1.83k
      params.info_hashes = params.ti->info_hashes();
5075
1.83k
#if TORRENT_ABI_VERSION < 3
5076
1.83k
      params.info_hash = params.info_hashes.get_best();
5077
1.83k
#endif
5078
1.83k
    }
5079
5080
1.83k
    if (!params.info_hashes.has_v1() && !params.info_hashes.has_v2())
5081
0
    {
5082
0
      ec = errors::missing_info_hash_in_uri;
5083
0
      return ret_t{ptr_t(), params.info_hashes, false};
5084
0
    }
5085
5086
    // is the torrent already active?
5087
1.83k
    std::shared_ptr<torrent> torrent_ptr = find_torrent(params.info_hashes).lock();
5088
5089
1.83k
    if (torrent_ptr)
5090
0
    {
5091
0
      if (!(params.flags & torrent_flags::duplicate_is_error))
5092
0
        return ret_t{std::move(torrent_ptr), params.info_hashes, false};
5093
5094
0
      ec = errors::duplicate_torrent;
5095
0
      return ret_t{ptr_t(), params.info_hashes, false};
5096
0
    }
5097
5098
    // make sure we have enough memory in the torrent lists up-front,
5099
    // since when torrents changes states, we cannot allocate memory that
5100
    // might fail.
5101
1.83k
    size_t const num_torrents = m_torrents.size();
5102
1.83k
    for (auto& l : m_torrent_lists)
5103
14.6k
    {
5104
14.6k
      l.reserve(num_torrents + 1);
5105
14.6k
    }
5106
5107
1.83k
    try
5108
1.83k
    {
5109
1.83k
      torrent_ptr = std::make_shared<torrent>(*this, m_paused, std::move(params));
5110
1.83k
      torrent_ptr->set_queue_position(m_download_queue.end_index());
5111
1.83k
    }
5112
1.83k
    catch (system_error const& e)
5113
1.83k
    {
5114
0
      ec = e.code();
5115
0
      return ret_t{ptr_t(), params.info_hashes, false};
5116
0
    }
5117
5118
    // it's fine to copy this moved-from info_hash_t object, since its move
5119
    // construction is just a copy.
5120
1.83k
    return ret_t{std::move(torrent_ptr), params.info_hashes, true};
5121
1.83k
  }
5122
5123
  void session_impl::update_outgoing_interfaces()
5124
1.83k
  {
5125
1.83k
    std::string const net_interfaces = m_settings.get_str(settings_pack::outgoing_interfaces);
5126
5127
    // declared in string_util.hpp
5128
1.83k
    parse_comma_separated_string(net_interfaces, m_outgoing_interfaces);
5129
5130
#ifndef TORRENT_DISABLE_LOGGING
5131
    if (!net_interfaces.empty() && m_outgoing_interfaces.empty())
5132
    {
5133
      session_log("ERROR: failed to parse outgoing interface list: %s"
5134
        , net_interfaces.c_str());
5135
    }
5136
#endif
5137
1.83k
  }
5138
5139
  tcp::endpoint session_impl::bind_outgoing_socket(socket_type& s
5140
    , address const& remote_address, error_code& ec) const
5141
0
  {
5142
0
    tcp::endpoint bind_ep(address_v4(), 0);
5143
0
    if (m_settings.get_int(settings_pack::outgoing_port) > 0)
5144
0
    {
5145
#ifdef TORRENT_WINDOWS
5146
      s.set_option(exclusive_address_use(true), ec);
5147
#else
5148
0
      s.set_option(tcp::acceptor::reuse_address(true), ec);
5149
0
#endif
5150
      // ignore errors because the underlying socket may not
5151
      // be opened yet. This happens when we're routing through
5152
      // a proxy. In that case, we don't yet know the address of
5153
      // the proxy server, and more importantly, we don't know
5154
      // the address family of its address. This means we can't
5155
      // open the socket yet. The socks abstraction layer defers
5156
      // opening it.
5157
0
      ec.clear();
5158
0
      bind_ep.port(std::uint16_t(next_port()));
5159
0
    }
5160
5161
0
    if (is_utp(s))
5162
0
    {
5163
      // TODO: factor out this logic into a separate function for unit
5164
      // testing
5165
5166
0
      utp_socket_impl* impl = nullptr;
5167
0
      transport ssl = transport::plaintext;
5168
0
#if TORRENT_USE_SSL
5169
0
      if (boost::get<ssl_stream<utp_stream>>(&s) != nullptr)
5170
0
      {
5171
0
        impl = boost::get<ssl_stream<utp_stream>>(s).next_layer().get_impl();
5172
0
        ssl = transport::ssl;
5173
0
      }
5174
0
      else
5175
0
#endif
5176
0
        impl = boost::get<utp_stream>(s).get_impl();
5177
5178
0
      std::vector<std::shared_ptr<listen_socket_t>> with_gateways;
5179
0
      std::shared_ptr<listen_socket_t> match;
5180
0
      for (auto& ls : m_listen_sockets)
5181
0
      {
5182
        // this is almost, but not quite, like can_route()
5183
0
        if (!(ls->flags & listen_socket_t::proxy)
5184
0
          && is_v4(ls->local_endpoint) != remote_address.is_v4())
5185
0
          continue;
5186
0
        if (ls->ssl != ssl) continue;
5187
0
        if (!(ls->flags & listen_socket_t::local_network))
5188
0
          with_gateways.push_back(ls);
5189
5190
0
        if (ls->flags & listen_socket_t::proxy
5191
0
          || match_addr_mask(ls->local_endpoint.address(), remote_address, ls->netmask))
5192
0
        {
5193
          // is this better than the previous match?
5194
0
          match = ls;
5195
0
        }
5196
0
      }
5197
0
      if (!match && !with_gateways.empty())
5198
0
        match = with_gateways[random(std::uint32_t(with_gateways.size() - 1))];
5199
5200
0
      if (match)
5201
0
      {
5202
0
        impl->m_sock = match;
5203
0
        return match->local_endpoint;
5204
0
      }
5205
0
      ec.assign(boost::system::errc::not_supported, generic_category());
5206
0
      return {};
5207
0
    }
5208
5209
0
    if (!m_outgoing_interfaces.empty())
5210
0
    {
5211
0
      if (m_interface_index >= m_outgoing_interfaces.size()) m_interface_index = 0;
5212
0
      std::string const& ifname = m_outgoing_interfaces[m_interface_index++];
5213
5214
0
      bind_ep.address(bind_socket_to_device(m_io_context, s
5215
0
        , remote_address.is_v4() ? tcp::v4() : tcp::v6()
5216
0
        , ifname.c_str(), bind_ep.port(), ec));
5217
0
      return bind_ep;
5218
0
    }
5219
5220
    // if we're not binding to a specific interface, bind
5221
    // to the same protocol family as the target endpoint
5222
0
    if (bind_ep.address().is_unspecified())
5223
0
    {
5224
0
      if (remote_address.is_v6())
5225
0
        bind_ep.address(address_v6::any());
5226
0
      else
5227
0
        bind_ep.address(address_v4::any());
5228
0
    }
5229
5230
0
    s.bind(bind_ep, ec);
5231
0
    return bind_ep;
5232
0
  }
5233
5234
  // verify that ``addr``s interface allows incoming connections
5235
  bool session_impl::verify_incoming_interface(address const& addr)
5236
0
  {
5237
0
    auto const iter = std::find_if(m_listen_sockets.begin(), m_listen_sockets.end()
5238
0
      , [&addr](std::shared_ptr<listen_socket_t> const& s)
5239
0
      { return s->local_endpoint.address() == addr; });
5240
0
    return iter == m_listen_sockets.end()
5241
0
      ? false
5242
0
      : bool((*iter)->flags & listen_socket_t::accept_incoming);
5243
0
  }
5244
5245
  // verify that the given local address satisfies the requirements of
5246
  // the outgoing interfaces. i.e. that one of the allowed outgoing
5247
  // interfaces has this address. For uTP sockets, which are all backed
5248
  // by an unconnected udp socket, we won't be able to tell what local
5249
  // address is used for this peer's packets, in that case, just make
5250
  // sure one of the allowed interfaces exists and maybe that it's the
5251
  // default route. For systems that have SO_BINDTODEVICE, it should be
5252
  // enough to just know that one of the devices exist
5253
  bool session_impl::verify_bound_address(address const& addr, bool utp
5254
    , error_code& ec)
5255
0
  {
5256
0
    TORRENT_UNUSED(utp);
5257
5258
    // we have specific outgoing interfaces specified. Make sure the
5259
    // local endpoint for this socket is bound to one of the allowed
5260
    // interfaces. the list can be a mixture of interfaces and IP
5261
    // addresses.
5262
0
    for (auto const& s : m_outgoing_interfaces)
5263
0
    {
5264
0
      error_code err;
5265
0
      address const ip = make_address(s.c_str(), err);
5266
0
      if (err) continue;
5267
0
      if (ip == addr) return true;
5268
0
    }
5269
5270
    // we didn't find the address as an IP in the interface list. Now,
5271
    // resolve which device (if any) has this IP address.
5272
0
    std::string const device = device_for_address(addr, m_io_context, ec);
5273
0
    if (ec) return false;
5274
5275
    // if no device was found to have this address, we fail
5276
0
    if (device.empty()) return false;
5277
5278
0
    return std::any_of(m_outgoing_interfaces.begin(), m_outgoing_interfaces.end()
5279
0
      , [&device](std::string const& s) { return s == device; });
5280
0
  }
5281
5282
  bool session_impl::has_lsd() const
5283
198
  {
5284
198
    return std::any_of(m_listen_sockets.begin(), m_listen_sockets.end()
5285
198
      , [](std::shared_ptr<listen_socket_t> const& s) { return bool(s->lsd); });
5286
198
  }
5287
5288
  void session_impl::remove_torrent(const torrent_handle& h
5289
    , remove_flags_t const options)
5290
0
  {
5291
0
    INVARIANT_CHECK;
5292
5293
0
    std::shared_ptr<torrent> tptr = h.m_torrent.lock();
5294
0
    if (!tptr) return;
5295
0
    if (!tptr->is_added()) return;
5296
5297
0
    remove_torrent_impl(tptr, options);
5298
5299
0
    tptr->abort();
5300
0
  }
5301
5302
  void session_impl::remove_torrent_impl(std::shared_ptr<torrent> tptr
5303
    , remove_flags_t const options)
5304
0
  {
5305
0
    m_torrents.erase(tptr->info_hash());
5306
5307
0
    torrent& t = *tptr;
5308
0
    if (options)
5309
0
    {
5310
0
      if (!t.delete_files(options))
5311
0
      {
5312
0
        if (m_alerts.should_post<torrent_delete_failed_alert>())
5313
0
          m_alerts.emplace_alert<torrent_delete_failed_alert>(t.get_handle()
5314
0
            , error_code(), t.torrent_file().info_hashes());
5315
0
      }
5316
0
    }
5317
5318
0
    tptr->update_gauge();
5319
0
    tptr->removed();
5320
5321
0
#ifndef TORRENT_DISABLE_DHT
5322
0
    if (m_next_dht_torrent == m_torrents.size())
5323
0
      m_next_dht_torrent = 0;
5324
0
#endif
5325
0
    if (m_next_lsd_torrent == m_torrents.size())
5326
0
      m_next_lsd_torrent = 0;
5327
5328
    // this torrent may open up a slot for a queued torrent
5329
0
    trigger_auto_manage();
5330
0
  }
5331
5332
#if TORRENT_ABI_VERSION == 1
5333
5334
  void session_impl::update_ssl_listen()
5335
1.83k
  {
5336
1.83k
    INVARIANT_CHECK;
5337
5338
    // this function maps the previous functionality of just setting the ssl
5339
    // listen port in order to enable the ssl listen sockets, to the new
5340
    // mechanism where SSL sockets are specified in listen_interfaces.
5341
1.83k
    std::vector<std::string> ignore;
5342
1.83k
    auto current_ifaces = parse_listen_interfaces(
5343
1.83k
      m_settings.get_str(settings_pack::listen_interfaces), ignore);
5344
    // these are the current interfaces we have, first remove all the SSL
5345
    // interfaces
5346
1.83k
    current_ifaces.erase(std::remove_if(current_ifaces.begin(), current_ifaces.end()
5347
1.83k
      , std::bind(&listen_interface_t::ssl, _1)), current_ifaces.end());
5348
5349
1.83k
    int const ssl_listen_port = m_settings.get_int(settings_pack::ssl_listen);
5350
5351
    // setting a port of 0 means to disable listening on SSL, so just update
5352
    // the interface list with the new list, and we're done
5353
1.83k
    if (ssl_listen_port == 0)
5354
1.83k
    {
5355
1.83k
      m_settings.set_str(settings_pack::listen_interfaces
5356
1.83k
        , print_listen_interfaces(current_ifaces));
5357
1.83k
      return;
5358
1.83k
    }
5359
5360
0
    std::vector<listen_interface_t> new_ifaces;
5361
0
    std::transform(current_ifaces.begin(), current_ifaces.end()
5362
0
      , std::back_inserter(new_ifaces), [](listen_interface_t in)
5363
0
      { in.ssl = true; return in; });
5364
5365
0
    current_ifaces.insert(current_ifaces.end(), new_ifaces.begin(), new_ifaces.end());
5366
5367
0
    m_settings.set_str(settings_pack::listen_interfaces
5368
0
      , print_listen_interfaces(current_ifaces));
5369
0
  }
5370
#endif // TORRENT_ABI_VERSION
5371
5372
  void session_impl::update_listen_interfaces()
5373
1.83k
  {
5374
1.83k
    INVARIANT_CHECK;
5375
5376
1.83k
    std::string const net_interfaces = m_settings.get_str(settings_pack::listen_interfaces);
5377
1.83k
    std::vector<std::string> err;
5378
1.83k
    m_listen_interfaces = parse_listen_interfaces(net_interfaces, err);
5379
5380
1.83k
    for (auto const& e : err)
5381
0
    {
5382
0
      m_alerts.emplace_alert<listen_failed_alert>(e, lt::address{}, 0
5383
0
        , operation_t::parse_address, errors::invalid_port, lt::socket_type_t::tcp);
5384
0
    }
5385
5386
#ifndef TORRENT_DISABLE_LOGGING
5387
    if (should_log())
5388
    {
5389
      session_log("update listen interfaces: %s", net_interfaces.c_str());
5390
      session_log("parsed listen interfaces count: %d, ifaces: %s"
5391
        , int(m_listen_interfaces.size())
5392
        , print_listen_interfaces(m_listen_interfaces).c_str());
5393
    }
5394
#endif
5395
1.83k
  }
5396
5397
  void session_impl::update_privileged_ports()
5398
1.83k
  {
5399
1.83k
    if (m_settings.get_bool(settings_pack::no_connect_privileged_ports))
5400
0
    {
5401
      // Close connections whose endpoint is filtered
5402
      // by the new setting
5403
0
      for (auto const& t : m_torrents)
5404
0
        t->privileged_port_updated();
5405
0
    }
5406
1.83k
  }
5407
5408
  void session_impl::update_auto_sequential()
5409
1.83k
  {
5410
1.83k
    for (auto& i : m_torrents)
5411
0
      i->update_auto_sequential();
5412
1.83k
  }
5413
5414
  void session_impl::update_max_failcount()
5415
1.83k
  {
5416
1.83k
    for (auto& i : m_torrents)
5417
0
      i->update_max_failcount();
5418
1.83k
  }
5419
5420
  void session_impl::update_resolver_cache_timeout()
5421
1.83k
  {
5422
1.83k
    int const timeout = m_settings.get_int(settings_pack::resolver_cache_timeout);
5423
1.83k
    m_host_resolver.set_cache_timeout(seconds(timeout));
5424
1.83k
  }
5425
5426
  void session_impl::update_proxy()
5427
9.18k
  {
5428
9.18k
    for (auto& i : m_listen_sockets)
5429
0
      i->udp_sock->sock.set_proxy_settings(proxy(), m_alerts, get_resolver()
5430
0
        , settings().get_bool(settings_pack::socks5_udp_send_local_ep));
5431
9.18k
  }
5432
5433
  void session_impl::update_ip_notifier()
5434
1.83k
  {
5435
1.83k
    if (m_settings.get_bool(settings_pack::enable_ip_notifier))
5436
0
      start_ip_notifier();
5437
1.83k
    else
5438
1.83k
      stop_ip_notifier();
5439
1.83k
  }
5440
5441
  void session_impl::update_upnp()
5442
1.83k
  {
5443
1.83k
    if (m_settings.get_bool(settings_pack::enable_upnp))
5444
0
      start_upnp();
5445
1.83k
    else
5446
1.83k
      stop_upnp();
5447
1.83k
  }
5448
5449
  void session_impl::update_natpmp()
5450
1.83k
  {
5451
1.83k
    if (m_settings.get_bool(settings_pack::enable_natpmp))
5452
0
      start_natpmp();
5453
1.83k
    else
5454
1.83k
      stop_natpmp();
5455
1.83k
  }
5456
5457
  void session_impl::update_lsd()
5458
3.67k
  {
5459
3.67k
    if (m_settings.get_bool(settings_pack::enable_lsd))
5460
0
      start_lsd();
5461
3.67k
    else
5462
3.67k
      stop_lsd();
5463
3.67k
  }
5464
5465
  void session_impl::update_dht()
5466
1.83k
  {
5467
1.83k
#ifndef TORRENT_DISABLE_DHT
5468
1.83k
    if (m_settings.get_bool(settings_pack::enable_dht))
5469
0
    {
5470
0
      if (!m_settings.get_str(settings_pack::dht_bootstrap_nodes).empty()
5471
0
        && m_dht_router_nodes.empty())
5472
0
      {
5473
        // if we have bootstrap nodes configured, make sure we initiate host
5474
        // name lookups. once these complete, the DHT will be started.
5475
        // they are tracked by m_outstanding_router_lookups
5476
0
        update_dht_bootstrap_nodes();
5477
0
      }
5478
0
      else
5479
0
      {
5480
0
        start_dht();
5481
0
      }
5482
0
    }
5483
1.83k
    else
5484
1.83k
      stop_dht();
5485
1.83k
#endif
5486
1.83k
  }
5487
5488
  void session_impl::update_dht_bootstrap_nodes()
5489
1.83k
  {
5490
1.83k
#ifndef TORRENT_DISABLE_DHT
5491
1.83k
    if (!m_settings.get_bool(settings_pack::enable_dht)) return;
5492
5493
0
    std::string const& node_list = m_settings.get_str(settings_pack::dht_bootstrap_nodes);
5494
0
    std::vector<std::pair<std::string, int>> nodes;
5495
0
    parse_comma_separated_string_port(node_list, nodes);
5496
5497
#ifndef TORRENT_DISABLE_LOGGING
5498
    if (!node_list.empty() && nodes.empty())
5499
    {
5500
      session_log("ERROR: failed to parse DHT bootstrap list: %s", node_list.c_str());
5501
    }
5502
#endif
5503
0
    for (auto const& n : nodes)
5504
0
      add_dht_router(n);
5505
0
#endif
5506
0
  }
5507
5508
  void session_impl::update_count_slow()
5509
1.83k
  {
5510
1.83k
    error_code ec;
5511
1.83k
    for (auto const& tp : m_torrents)
5512
0
    {
5513
0
      tp->on_inactivity_tick(ec);
5514
0
    }
5515
1.83k
  }
5516
5517
  // TODO: 2 this function should be removed and users need to deal with the
5518
  // more generic case of having multiple listen ports
5519
  std::uint16_t session_impl::listen_port() const
5520
0
  {
5521
0
    return listen_port(nullptr);
5522
0
  }
5523
5524
  std::uint16_t session_impl::listen_port(listen_socket_t* sock) const
5525
0
  {
5526
0
    if (m_listen_sockets.empty()) return 0;
5527
0
    if (sock)
5528
0
    {
5529
      // if we're using a proxy, we won't be able to accept any TCP
5530
      // connections. Not even uTP connections via the port we know about.
5531
      // The DHT may use the implied port to make it work, but the port we
5532
      // announce here has no relevance for that.
5533
0
      if (sock->flags & listen_socket_t::proxy)
5534
0
        return 0;
5535
5536
0
      if (!(sock->flags & listen_socket_t::accept_incoming))
5537
0
        return 0;
5538
5539
0
      return std::uint16_t(sock->tcp_external_port());
5540
0
    }
5541
5542
0
#ifdef TORRENT_SSL_PEERS
5543
0
    for (auto const& s : m_listen_sockets)
5544
0
    {
5545
0
      if (!(s->flags & listen_socket_t::accept_incoming)) continue;
5546
0
      if (s->ssl == transport::plaintext)
5547
0
        return std::uint16_t(s->tcp_external_port());
5548
0
    }
5549
0
    return 0;
5550
#else
5551
    sock = m_listen_sockets.front().get();
5552
    if (!(sock->flags & listen_socket_t::accept_incoming)) return 0;
5553
    return std::uint16_t(sock->tcp_external_port());
5554
#endif
5555
0
  }
5556
5557
  // TODO: 2 this function should be removed and users need to deal with the
5558
  // more generic case of having multiple ssl ports
5559
  std::uint16_t session_impl::ssl_listen_port() const
5560
0
  {
5561
0
    return ssl_listen_port(nullptr);
5562
0
  }
5563
5564
  std::uint16_t session_impl::ssl_listen_port(listen_socket_t* sock) const
5565
0
  {
5566
0
#ifdef TORRENT_SSL_PEERS
5567
0
    if (sock)
5568
0
    {
5569
0
      if (!(sock->flags & listen_socket_t::accept_incoming)) return 0;
5570
0
      return std::uint16_t(sock->tcp_external_port());
5571
0
    }
5572
5573
0
    if (m_settings.get_int(settings_pack::proxy_type) != settings_pack::none
5574
0
      && m_settings.get_bool(settings_pack::proxy_peer_connections))
5575
0
      return 0;
5576
5577
0
    for (auto const& s : m_listen_sockets)
5578
0
    {
5579
0
      if (!(s->flags & listen_socket_t::accept_incoming)) continue;
5580
0
      if (s->ssl == transport::ssl)
5581
0
        return std::uint16_t(s->tcp_external_port());
5582
0
    }
5583
#else
5584
    TORRENT_UNUSED(sock);
5585
#endif
5586
0
    return 0;
5587
0
  }
5588
5589
  int session_impl::get_listen_port(transport const ssl, aux::listen_socket_handle const& s)
5590
0
  {
5591
0
    auto socket = s.get();
5592
0
    if (socket->ssl != ssl)
5593
0
    {
5594
0
      auto alt_socket = std::find_if(m_listen_sockets.begin(), m_listen_sockets.end()
5595
0
        , [&](std::shared_ptr<listen_socket_t> const& e)
5596
0
      {
5597
0
        return e->ssl == ssl
5598
0
          && e->external_address.external_address()
5599
0
            == socket->external_address.external_address();
5600
0
      });
5601
0
      if (alt_socket != m_listen_sockets.end())
5602
0
        socket = alt_socket->get();
5603
0
    }
5604
0
    return socket->udp_external_port();
5605
0
  }
5606
5607
  int session_impl::listen_port(transport const ssl, address const& local_addr)
5608
0
  {
5609
0
    auto socket = std::find_if(m_listen_sockets.begin(), m_listen_sockets.end()
5610
0
      , [&](std::shared_ptr<listen_socket_t> const& e)
5611
0
    {
5612
0
      if (!(e->flags & listen_socket_t::accept_incoming)) return false;
5613
0
      auto const& listen_addr = e->external_address.external_address();
5614
0
      return e->ssl == ssl
5615
0
        && (listen_addr == local_addr
5616
0
          || (listen_addr.is_v4() == local_addr.is_v4() && listen_addr.is_unspecified()));
5617
0
    });
5618
0
    if (socket != m_listen_sockets.end())
5619
0
      return (*socket)->tcp_external_port();
5620
0
    return 0;
5621
0
  }
5622
5623
  void session_impl::announce_lsd(sha1_hash const& ih, int port)
5624
0
  {
5625
    // use internal listen port for local peers
5626
0
    for (auto const& s : m_listen_sockets)
5627
0
    {
5628
0
      if (s->lsd) s->lsd->announce(ih, port);
5629
0
    }
5630
0
  }
5631
5632
  void session_impl::on_lsd_peer(tcp::endpoint const& peer, sha1_hash const& ih)
5633
0
  {
5634
0
    m_stats_counters.inc_stats_counter(counters::on_lsd_peer_counter);
5635
0
    TORRENT_ASSERT(is_single_thread());
5636
5637
0
    INVARIANT_CHECK;
5638
5639
0
    std::shared_ptr<torrent> t = find_torrent(info_hash_t(ih)).lock();
5640
0
    if (!t) return;
5641
    // don't add peers from lsd to private torrents
5642
0
    if (t->torrent_file().priv() || (t->torrent_file().is_i2p()
5643
0
      && !m_settings.get_bool(settings_pack::allow_i2p_mixed))) return;
5644
5645
0
    protocol_version const v = ih == t->torrent_file().info_hashes().v1
5646
0
      ? protocol_version::V1 : protocol_version::V2;
5647
5648
0
    t->add_peer(peer, peer_info::lsd, v == protocol_version::V2 ? pex_lt_v2 : pex_flags_t(0));
5649
#ifndef TORRENT_DISABLE_LOGGING
5650
    if (should_log())
5651
    {
5652
      t->debug_log("lsd add_peer() [ %s ]"
5653
        , peer.address().to_string().c_str());
5654
    }
5655
#endif
5656
0
    t->do_connect_boost();
5657
5658
0
    if (m_alerts.should_post<lsd_peer_alert>())
5659
0
      m_alerts.emplace_alert<lsd_peer_alert>(t->get_handle(), peer);
5660
0
  }
5661
5662
  void session_impl::start_natpmp(std::shared_ptr<aux::listen_socket_t> const& s)
5663
0
  {
5664
    // don't create mappings for local IPv6 addresses
5665
    // they can't be reached from outside of the local network anyways
5666
0
    if (is_v6(s->local_endpoint) && is_local(s->local_endpoint.address()))
5667
0
      return;
5668
5669
0
    if (!s->natpmp_mapper
5670
0
      && !(s->flags & listen_socket_t::local_network)
5671
0
      && !(s->flags & listen_socket_t::proxy))
5672
0
    {
5673
      // the natpmp constructor may fail and call the callbacks
5674
      // into the session_impl.
5675
0
      s->natpmp_mapper = std::make_shared<natpmp>(m_io_context, *this, listen_socket_handle(s));
5676
0
      ip_interface ip;
5677
0
      ip.interface_address = s->local_endpoint.address();
5678
0
      ip.netmask = s->netmask;
5679
0
      std::strncpy(ip.name, s->device.c_str(), sizeof(ip.name) - 1);
5680
0
      ip.name[sizeof(ip.name) - 1] = '\0';
5681
0
      s->natpmp_mapper->start(ip);
5682
0
    }
5683
0
  }
5684
5685
  void session_impl::on_port_mapping(port_mapping_t const mapping
5686
    , address const& external_ip, int port
5687
    , portmap_protocol const proto, error_code const& ec
5688
    , portmap_transport const transport
5689
    , listen_socket_handle const& ls)
5690
0
  {
5691
0
    TORRENT_ASSERT(is_single_thread());
5692
5693
0
    listen_socket_t* listen_socket = ls.get();
5694
5695
    // NOTE: don't assume that if ec != 0, the rest of the logic
5696
    // is not necessary, the ports still need to be set, in other
5697
    // words, don't early return without careful review of the
5698
    // remaining logic
5699
0
    if (ec && m_alerts.should_post<portmap_error_alert>())
5700
0
    {
5701
0
      m_alerts.emplace_alert<portmap_error_alert>(mapping
5702
0
        , transport, ec, listen_socket ? listen_socket->local_endpoint.address() : address());
5703
0
    }
5704
5705
0
    if (!listen_socket) return;
5706
5707
0
    if (!ec && !external_ip.is_unspecified())
5708
0
    {
5709
      // TODO: 1 report the proper address of the router as the source IP of
5710
      // this vote of our external address, instead of the empty address
5711
0
      listen_socket->external_address.cast_vote(external_ip, source_router, address());
5712
0
    }
5713
5714
    // need to check whether this mapping is for one of session ports (it could also be a user mapping)
5715
0
    if ((proto == portmap_protocol::tcp) && (listen_socket->tcp_port_mapping[transport].mapping == mapping))
5716
0
      listen_socket->tcp_port_mapping[transport].port = port;
5717
0
    else if ((proto == portmap_protocol::udp) && (listen_socket->udp_port_mapping[transport].mapping == mapping))
5718
0
      listen_socket->udp_port_mapping[transport].port = port;
5719
5720
0
    if (!ec && m_alerts.should_post<portmap_alert>())
5721
0
    {
5722
0
      m_alerts.emplace_alert<portmap_alert>(mapping, port
5723
0
        , transport, proto, listen_socket->local_endpoint.address());
5724
0
    }
5725
0
  }
5726
5727
#if TORRENT_ABI_VERSION == 1
5728
  session_status session_impl::status() const
5729
0
  {
5730
//    INVARIANT_CHECK;
5731
0
    TORRENT_ASSERT(is_single_thread());
5732
5733
0
    session_status s;
5734
5735
0
    s.optimistic_unchoke_counter = m_optimistic_unchoke_time_scaler;
5736
0
    s.unchoke_counter = m_unchoke_time_scaler;
5737
0
    s.num_dead_peers = int(m_undead_peers.size());
5738
5739
0
    s.num_peers = int(m_stats_counters[counters::num_peers_connected]);
5740
0
    s.num_unchoked = int(m_stats_counters[counters::num_peers_up_unchoked_all]);
5741
0
    s.allowed_upload_slots = int(m_stats_counters[counters::num_unchoke_slots]);
5742
5743
0
    s.num_torrents
5744
0
      = int(m_stats_counters[counters::num_checking_torrents]
5745
0
      + m_stats_counters[counters::num_stopped_torrents]
5746
0
      + m_stats_counters[counters::num_queued_seeding_torrents]
5747
0
      + m_stats_counters[counters::num_queued_download_torrents]
5748
0
      + m_stats_counters[counters::num_upload_only_torrents]
5749
0
      + m_stats_counters[counters::num_downloading_torrents]
5750
0
      + m_stats_counters[counters::num_seeding_torrents]
5751
0
      + m_stats_counters[counters::num_error_torrents]);
5752
5753
0
    s.num_paused_torrents
5754
0
      = int(m_stats_counters[counters::num_stopped_torrents]
5755
0
      + m_stats_counters[counters::num_error_torrents]
5756
0
      + m_stats_counters[counters::num_queued_seeding_torrents]
5757
0
      + m_stats_counters[counters::num_queued_download_torrents]);
5758
5759
0
    s.total_redundant_bytes = m_stats_counters[counters::recv_redundant_bytes];
5760
0
    s.total_failed_bytes = m_stats_counters[counters::recv_failed_bytes];
5761
5762
0
    s.up_bandwidth_queue = int(m_stats_counters[counters::limiter_up_queue]);
5763
0
    s.down_bandwidth_queue = int(m_stats_counters[counters::limiter_down_queue]);
5764
5765
0
    s.up_bandwidth_bytes_queue = int(m_stats_counters[counters::limiter_up_bytes]);
5766
0
    s.down_bandwidth_bytes_queue = int(m_stats_counters[counters::limiter_down_bytes]);
5767
5768
0
    s.disk_write_queue = int(m_stats_counters[counters::num_peers_down_disk]);
5769
0
    s.disk_read_queue = int(m_stats_counters[counters::num_peers_up_disk]);
5770
5771
0
    s.has_incoming_connections = m_stats_counters[counters::has_incoming_connections] != 0;
5772
5773
    // total
5774
0
    s.download_rate = m_stat.download_rate();
5775
0
    s.total_upload = m_stat.total_upload();
5776
0
    s.upload_rate = m_stat.upload_rate();
5777
0
    s.total_download = m_stat.total_download();
5778
5779
    // payload
5780
0
    s.payload_download_rate = m_stat.transfer_rate(stat::download_payload);
5781
0
    s.total_payload_download = m_stat.total_transfer(stat::download_payload);
5782
0
    s.payload_upload_rate = m_stat.transfer_rate(stat::upload_payload);
5783
0
    s.total_payload_upload = m_stat.total_transfer(stat::upload_payload);
5784
5785
    // IP-overhead
5786
0
    s.ip_overhead_download_rate = m_stat.transfer_rate(stat::download_ip_protocol);
5787
0
    s.total_ip_overhead_download = m_stats_counters[counters::recv_ip_overhead_bytes];
5788
0
    s.ip_overhead_upload_rate = m_stat.transfer_rate(stat::upload_ip_protocol);
5789
0
    s.total_ip_overhead_upload = m_stats_counters[counters::sent_ip_overhead_bytes];
5790
5791
    // tracker
5792
0
    s.total_tracker_download = m_stats_counters[counters::recv_tracker_bytes];
5793
0
    s.total_tracker_upload = m_stats_counters[counters::sent_tracker_bytes];
5794
5795
    // dht
5796
0
    s.total_dht_download = m_stats_counters[counters::dht_bytes_in];
5797
0
    s.total_dht_upload = m_stats_counters[counters::dht_bytes_out];
5798
5799
    // deprecated
5800
0
    s.tracker_download_rate = 0;
5801
0
    s.tracker_upload_rate = 0;
5802
0
    s.dht_download_rate = 0;
5803
0
    s.dht_upload_rate = 0;
5804
5805
0
#ifndef TORRENT_DISABLE_DHT
5806
0
    if (m_dht)
5807
0
    {
5808
0
      m_dht->dht_status(s);
5809
0
    }
5810
0
    else
5811
0
#endif
5812
0
    {
5813
0
      s.dht_nodes = 0;
5814
0
      s.dht_node_cache = 0;
5815
0
      s.dht_torrents = 0;
5816
0
      s.dht_global_nodes = 0;
5817
0
      s.dht_total_allocations = 0;
5818
0
    }
5819
5820
0
    s.utp_stats.packet_loss = std::uint64_t(m_stats_counters[counters::utp_packet_loss]);
5821
0
    s.utp_stats.timeout = std::uint64_t(m_stats_counters[counters::utp_timeout]);
5822
0
    s.utp_stats.packets_in = std::uint64_t(m_stats_counters[counters::utp_packets_in]);
5823
0
    s.utp_stats.packets_out = std::uint64_t(m_stats_counters[counters::utp_packets_out]);
5824
0
    s.utp_stats.fast_retransmit = std::uint64_t(m_stats_counters[counters::utp_fast_retransmit]);
5825
0
    s.utp_stats.packet_resend = std::uint64_t(m_stats_counters[counters::utp_packet_resend]);
5826
0
    s.utp_stats.samples_above_target = std::uint64_t(m_stats_counters[counters::utp_samples_above_target]);
5827
0
    s.utp_stats.samples_below_target = std::uint64_t(m_stats_counters[counters::utp_samples_below_target]);
5828
0
    s.utp_stats.payload_pkts_in = std::uint64_t(m_stats_counters[counters::utp_payload_pkts_in]);
5829
0
    s.utp_stats.payload_pkts_out = std::uint64_t(m_stats_counters[counters::utp_payload_pkts_out]);
5830
0
    s.utp_stats.invalid_pkts_in = std::uint64_t(m_stats_counters[counters::utp_invalid_pkts_in]);
5831
0
    s.utp_stats.redundant_pkts_in = std::uint64_t(m_stats_counters[counters::utp_redundant_pkts_in]);
5832
5833
0
    s.utp_stats.num_idle = int(m_stats_counters[counters::num_utp_idle]);
5834
0
    s.utp_stats.num_syn_sent = int(m_stats_counters[counters::num_utp_syn_sent]);
5835
0
    s.utp_stats.num_connected = int(m_stats_counters[counters::num_utp_connected]);
5836
0
    s.utp_stats.num_fin_sent = int(m_stats_counters[counters::num_utp_fin_sent]);
5837
0
    s.utp_stats.num_close_wait = int(m_stats_counters[counters::num_utp_close_wait]);
5838
5839
    // this loop is potentially expensive. It could be optimized by
5840
    // simply keeping a global counter
5841
0
    s.peerlist_size = std::accumulate(m_torrents.begin(), m_torrents.end(), 0
5842
0
      , [](int const acc, std::shared_ptr<torrent> const& t)
5843
0
      { return acc + t->num_known_peers(); });
5844
5845
0
    return s;
5846
0
  }
5847
#endif // TORRENT_ABI_VERSION
5848
5849
#ifndef TORRENT_DISABLE_DHT
5850
5851
  void session_impl::start_dht()
5852
0
  {
5853
0
    INVARIANT_CHECK;
5854
5855
0
    stop_dht();
5856
5857
0
    if (!m_settings.get_bool(settings_pack::enable_dht)) return;
5858
5859
    // postpone starting the DHT if we're still resolving the DHT router
5860
0
    if (m_outstanding_router_lookups > 0)
5861
0
    {
5862
#ifndef TORRENT_DISABLE_LOGGING
5863
      session_log("not starting DHT, outstanding router lookups: %d"
5864
        , m_outstanding_router_lookups);
5865
#endif
5866
0
      return;
5867
0
    }
5868
5869
0
    if (m_abort)
5870
0
    {
5871
#ifndef TORRENT_DISABLE_LOGGING
5872
      session_log("not starting DHT, aborting");
5873
#endif
5874
0
      return;
5875
0
    }
5876
5877
#ifndef TORRENT_DISABLE_LOGGING
5878
    session_log("starting DHT, running: %s, router lookups: %d"
5879
      , m_dht ? "true" : "false", m_outstanding_router_lookups);
5880
#endif
5881
5882
    // TODO: refactor, move the storage to dht_tracker
5883
0
    m_dht_storage = m_dht_storage_constructor(m_settings);
5884
0
    m_dht = std::make_shared<dht::dht_tracker>(
5885
0
      static_cast<dht::dht_observer*>(this)
5886
0
      , m_io_context
5887
0
      , [this](aux::listen_socket_handle const& sock
5888
0
        , udp::endpoint const& ep
5889
0
        , span<char const> p
5890
0
        , error_code& ec
5891
0
        , udp_send_flags_t const flags)
5892
0
        { send_udp_packet_listen(sock, ep, p, ec, flags); }
5893
0
      , m_settings
5894
0
      , m_stats_counters
5895
0
      , *m_dht_storage
5896
0
      , std::move(m_dht_state));
5897
5898
0
    for (auto& s : m_listen_sockets)
5899
0
    {
5900
0
      if (s->ssl != transport::ssl
5901
0
        && !(s->flags & listen_socket_t::local_network))
5902
0
      {
5903
0
        m_dht->new_socket(s);
5904
0
      }
5905
0
    }
5906
5907
0
    for (auto const& n : m_dht_router_nodes)
5908
0
    {
5909
0
      m_dht->add_router_node(n);
5910
0
    }
5911
5912
0
    for (auto const& n : m_dht_nodes)
5913
0
    {
5914
0
      m_dht->add_node(n);
5915
0
    }
5916
0
    m_dht_nodes.clear();
5917
0
    m_dht_nodes.shrink_to_fit();
5918
5919
0
    auto cb = [this](
5920
0
      std::vector<std::pair<dht::node_entry, std::string>> const&)
5921
0
    {
5922
0
      if (m_alerts.should_post<dht_bootstrap_alert>())
5923
0
        m_alerts.emplace_alert<dht_bootstrap_alert>();
5924
0
    };
5925
5926
0
    m_dht->start(cb);
5927
0
  }
5928
5929
  void session_impl::stop_dht()
5930
3.67k
  {
5931
#ifndef TORRENT_DISABLE_LOGGING
5932
    session_log("about to stop DHT, running: %s", m_dht ? "true" : "false");
5933
#endif
5934
5935
3.67k
    if (m_dht)
5936
0
    {
5937
0
      m_dht->stop();
5938
0
      m_dht.reset();
5939
0
    }
5940
5941
3.67k
    m_dht_storage.reset();
5942
3.67k
  }
5943
5944
#if TORRENT_ABI_VERSION <= 2
5945
  void session_impl::set_dht_settings(dht::dht_settings const& settings)
5946
0
  {
5947
0
#ifndef TORRENT_DISABLE_DHT
5948
0
#define SET_BOOL(name) m_settings.set_bool(settings_pack::dht_ ## name, settings.name)
5949
0
#define SET_INT(name) m_settings.set_int(settings_pack::dht_ ## name, settings.name)
5950
5951
0
    SET_INT(max_peers_reply);
5952
0
    SET_INT(search_branching);
5953
0
    SET_INT(max_fail_count);
5954
0
    SET_INT(max_torrents);
5955
0
    SET_INT(max_dht_items);
5956
0
    SET_INT(max_peers);
5957
0
    SET_INT(max_torrent_search_reply);
5958
0
    SET_BOOL(restrict_routing_ips);
5959
0
    SET_BOOL(restrict_search_ips);
5960
0
    SET_BOOL(extended_routing_table);
5961
0
    SET_BOOL(aggressive_lookups);
5962
0
    SET_BOOL(privacy_lookups);
5963
0
    SET_BOOL(enforce_node_id);
5964
0
    SET_BOOL(ignore_dark_internet);
5965
0
    SET_INT(block_timeout);
5966
0
    SET_INT(block_ratelimit);
5967
0
    SET_BOOL(read_only);
5968
0
    SET_INT(item_lifetime);
5969
0
    SET_INT(upload_rate_limit);
5970
0
    SET_INT(sample_infohashes_interval);
5971
0
    SET_INT(max_infohashes_sample_count);
5972
0
#undef SET_BOOL
5973
0
#undef SET_INT
5974
0
    update_dht_upload_rate_limit();
5975
0
#endif
5976
0
  }
5977
5978
  dht::dht_settings session_impl::get_dht_settings() const
5979
0
  {
5980
0
    dht::dht_settings sett;
5981
0
#ifndef TORRENT_DISABLE_DHT
5982
0
#define SET_BOOL(name) \
5983
0
    sett.name = m_settings.get_bool( settings_pack::dht_ ## name )
5984
0
#define SET_INT(name) \
5985
0
    sett.name = m_settings.get_int( settings_pack::dht_ ## name )
5986
5987
0
    SET_INT(max_peers_reply);
5988
0
    SET_INT(search_branching);
5989
0
    SET_INT(max_fail_count);
5990
0
    SET_INT(max_torrents);
5991
0
    SET_INT(max_dht_items);
5992
0
    SET_INT(max_peers);
5993
0
    SET_INT(max_torrent_search_reply);
5994
0
    SET_BOOL(restrict_routing_ips);
5995
0
    SET_BOOL(restrict_search_ips);
5996
0
    SET_BOOL(extended_routing_table);
5997
0
    SET_BOOL(aggressive_lookups);
5998
0
    SET_BOOL(privacy_lookups);
5999
0
    SET_BOOL(enforce_node_id);
6000
0
    SET_BOOL(ignore_dark_internet);
6001
0
    SET_INT(block_timeout);
6002
0
    SET_INT(block_ratelimit);
6003
0
    SET_BOOL(read_only);
6004
0
    SET_INT(item_lifetime);
6005
0
    SET_INT(upload_rate_limit);
6006
0
    SET_INT(sample_infohashes_interval);
6007
0
    SET_INT(max_infohashes_sample_count);
6008
0
#undef SET_BOOL
6009
0
#undef SET_INT
6010
0
#endif
6011
0
    return sett;
6012
0
  }
6013
#endif
6014
6015
  void session_impl::set_dht_state(dht::dht_state&& state)
6016
1.83k
  {
6017
1.83k
    m_dht_state = std::move(state);
6018
1.83k
  }
6019
6020
  void session_impl::set_dht_storage(dht::dht_storage_constructor_type sc)
6021
1.83k
  {
6022
1.83k
    m_dht_storage_constructor = std::move(sc);
6023
1.83k
  }
6024
6025
#if TORRENT_ABI_VERSION == 1
6026
  entry session_impl::dht_state() const
6027
0
  {
6028
0
    return m_dht ? dht::save_dht_state(m_dht->state()) : entry();
6029
0
  }
6030
6031
  void session_impl::start_dht_deprecated(entry const& startup_state)
6032
0
  {
6033
0
    m_settings.set_bool(settings_pack::enable_dht, true);
6034
0
    std::vector<char> tmp;
6035
0
    bencode(std::back_inserter(tmp), startup_state);
6036
6037
0
    bdecode_node e;
6038
0
    error_code ec;
6039
0
    if (tmp.empty() || bdecode(&tmp[0], &tmp[0] + tmp.size(), e, ec) != 0)
6040
0
      return;
6041
0
    m_dht_state = dht::read_dht_state(e);
6042
0
    start_dht();
6043
0
  }
6044
#endif
6045
6046
  void session_impl::add_dht_node_name(std::pair<std::string, int> const& node)
6047
0
  {
6048
0
    ADD_OUTSTANDING_ASYNC("session_impl::on_dht_name_lookup");
6049
0
    m_host_resolver.async_resolve(node.first, resolver::abort_on_shutdown
6050
0
      , std::bind(&session_impl::on_dht_name_lookup
6051
0
        , this, _1, _2, node.second));
6052
0
  }
6053
6054
  void session_impl::on_dht_name_lookup(error_code const& e
6055
    , std::vector<address> const& addresses, int port)
6056
0
  {
6057
0
    COMPLETE_ASYNC("session_impl::on_dht_name_lookup");
6058
6059
0
    if (e)
6060
0
    {
6061
0
      if (m_alerts.should_post<dht_error_alert>())
6062
0
        m_alerts.emplace_alert<dht_error_alert>(
6063
0
          operation_t::hostname_lookup, e);
6064
0
      return;
6065
0
    }
6066
6067
0
    for (auto const& addr : addresses)
6068
0
    {
6069
0
      udp::endpoint ep(addr, std::uint16_t(port));
6070
0
      add_dht_node(ep);
6071
0
    }
6072
0
  }
6073
6074
  void session_impl::add_dht_router(std::pair<std::string, int> const& node)
6075
0
  {
6076
0
    ADD_OUTSTANDING_ASYNC("session_impl::on_dht_router_name_lookup");
6077
0
    ++m_outstanding_router_lookups;
6078
0
    m_host_resolver.async_resolve(node.first, resolver::abort_on_shutdown
6079
0
      , std::bind(&session_impl::on_dht_router_name_lookup
6080
0
        , this, _1, _2, node.second));
6081
0
  }
6082
6083
  void session_impl::on_dht_router_name_lookup(error_code const& e
6084
    , std::vector<address> const& addresses, int port)
6085
0
  {
6086
0
    COMPLETE_ASYNC("session_impl::on_dht_router_name_lookup");
6087
0
    --m_outstanding_router_lookups;
6088
6089
0
    if (e)
6090
0
    {
6091
0
      if (m_alerts.should_post<dht_error_alert>())
6092
0
        m_alerts.emplace_alert<dht_error_alert>(
6093
0
          operation_t::hostname_lookup, e);
6094
6095
0
      if (m_outstanding_router_lookups == 0) start_dht();
6096
0
      return;
6097
0
    }
6098
6099
6100
0
    for (auto const& addr : addresses)
6101
0
    {
6102
      // router nodes should be added before the DHT is started (and bootstrapped)
6103
0
      udp::endpoint ep(addr, std::uint16_t(port));
6104
0
      if (m_dht) m_dht->add_router_node(ep);
6105
0
      m_dht_router_nodes.push_back(ep);
6106
0
    }
6107
6108
0
    if (m_outstanding_router_lookups == 0) start_dht();
6109
0
  }
6110
6111
  // callback for dht_immutable_get
6112
  void session_impl::get_immutable_callback(sha1_hash target
6113
    , dht::item const& i)
6114
0
  {
6115
0
    TORRENT_ASSERT(!i.is_mutable());
6116
0
    m_alerts.emplace_alert<dht_immutable_item_alert>(target, i.value());
6117
0
  }
6118
6119
  void session_impl::dht_get_immutable_item(sha1_hash const& target)
6120
0
  {
6121
0
    if (!m_dht) return;
6122
0
    m_dht->get_item(target, std::bind(&session_impl::get_immutable_callback
6123
0
      , this, target, _1));
6124
0
  }
6125
6126
  // callback for dht_mutable_get
6127
  void session_impl::get_mutable_callback(dht::item const& i
6128
    , bool const authoritative)
6129
0
  {
6130
0
    TORRENT_ASSERT(i.is_mutable());
6131
0
    m_alerts.emplace_alert<dht_mutable_item_alert>(i.pk().bytes
6132
0
      , i.sig().bytes, i.seq().value
6133
0
      , i.salt(), i.value(), authoritative);
6134
0
  }
6135
6136
  // key is a 32-byte binary string, the public key to look up.
6137
  // the salt is optional
6138
  // TODO: 3 use public_key here instead of std::array
6139
  void session_impl::dht_get_mutable_item(std::array<char, 32> key
6140
    , std::string salt)
6141
0
  {
6142
0
    if (!m_dht) return;
6143
0
    m_dht->get_item(dht::public_key(key.data()), std::bind(&session_impl::get_mutable_callback
6144
0
      , this, _1, _2), std::move(salt));
6145
0
  }
6146
6147
  namespace {
6148
6149
    void on_dht_put_immutable_item(aux::alert_manager& alerts, sha1_hash target, int num)
6150
0
    {
6151
0
      if (alerts.should_post<dht_put_alert>())
6152
0
        alerts.emplace_alert<dht_put_alert>(target, num);
6153
0
    }
6154
6155
    void on_dht_put_mutable_item(aux::alert_manager& alerts, dht::item const& i, int num)
6156
0
    {
6157
0
      if (alerts.should_post<dht_put_alert>())
6158
0
      {
6159
0
        dht::signature const sig = i.sig();
6160
0
        dht::public_key const pk = i.pk();
6161
0
        dht::sequence_number const seq = i.seq();
6162
0
        std::string salt = i.salt();
6163
0
        alerts.emplace_alert<dht_put_alert>(pk.bytes, sig.bytes
6164
0
          , std::move(salt), seq.value, num);
6165
0
      }
6166
0
    }
6167
6168
    void put_mutable_callback(dht::item& i
6169
      , std::function<void(entry&, std::array<char, 64>&
6170
        , std::int64_t&, std::string const&)> cb)
6171
0
    {
6172
0
      entry value = i.value();
6173
0
      dht::signature sig = i.sig();
6174
0
      dht::public_key pk = i.pk();
6175
0
      dht::sequence_number seq = i.seq();
6176
0
      std::string salt = i.salt();
6177
0
      cb(value, sig.bytes, seq.value, salt);
6178
0
      i.assign(std::move(value), salt, seq, pk, sig);
6179
0
    }
6180
6181
    void on_dht_get_peers(aux::alert_manager& alerts, sha1_hash info_hash, std::vector<tcp::endpoint> const& peers)
6182
0
    {
6183
0
      if (alerts.should_post<dht_get_peers_reply_alert>())
6184
0
        alerts.emplace_alert<dht_get_peers_reply_alert>(info_hash, peers);
6185
0
    }
6186
6187
    void on_direct_response(aux::alert_manager& alerts, client_data_t userdata, dht::msg const& msg)
6188
0
    {
6189
0
      if (msg.message.type() == bdecode_node::none_t)
6190
0
        alerts.emplace_alert<dht_direct_response_alert>(userdata, msg.addr);
6191
0
      else
6192
0
        alerts.emplace_alert<dht_direct_response_alert>(userdata, msg.addr, msg.message);
6193
0
    }
6194
6195
  } // anonymous namespace
6196
6197
  void session_impl::dht_put_immutable_item(entry const& data, sha1_hash target)
6198
0
  {
6199
0
    if (!m_dht) return;
6200
0
    m_dht->put_item(data, std::bind(&on_dht_put_immutable_item, std::ref(m_alerts)
6201
0
      , target, _1));
6202
0
  }
6203
6204
  void session_impl::dht_put_mutable_item(std::array<char, 32> key
6205
    , std::function<void(entry&, std::array<char,64>&
6206
    , std::int64_t&, std::string const&)> cb
6207
    , std::string salt)
6208
0
  {
6209
0
    if (!m_dht) return;
6210
0
    m_dht->put_item(dht::public_key(key.data())
6211
0
      , std::bind(&on_dht_put_mutable_item, std::ref(m_alerts), _1, _2)
6212
0
      , std::bind(&put_mutable_callback, _1, std::move(cb)), salt);
6213
0
  }
6214
6215
  void session_impl::dht_get_peers(sha1_hash const& info_hash)
6216
0
  {
6217
0
    if (!m_dht) return;
6218
0
    m_dht->get_peers(info_hash, std::bind(&on_dht_get_peers, std::ref(m_alerts), info_hash, _1));
6219
0
  }
6220
6221
  void session_impl::dht_announce(sha1_hash const& info_hash, int port, dht::announce_flags_t const flags)
6222
0
  {
6223
0
    if (!m_dht) return;
6224
0
    m_dht->announce(info_hash, port, flags, std::bind(&on_dht_get_peers, std::ref(m_alerts), info_hash, _1));
6225
0
  }
6226
6227
  void session_impl::dht_live_nodes(sha1_hash const& nid)
6228
0
  {
6229
0
    if (!m_dht) return;
6230
0
    auto nodes = m_dht->live_nodes(nid);
6231
0
    m_alerts.emplace_alert<dht_live_nodes_alert>(nid, nodes);
6232
0
  }
6233
6234
  void session_impl::dht_sample_infohashes(udp::endpoint const& ep, sha1_hash const& target)
6235
0
  {
6236
0
    if (!m_dht) return;
6237
0
    m_dht->sample_infohashes(ep, target, [this, ep](sha1_hash const& nid
6238
0
      , time_duration const interval
6239
0
      , int const num, std::vector<sha1_hash> samples
6240
0
      , std::vector<std::pair<sha1_hash, udp::endpoint>> nodes)
6241
0
    {
6242
0
      m_alerts.emplace_alert<dht_sample_infohashes_alert>(nid
6243
0
        , ep, interval, num, std::move(samples), std::move(nodes));
6244
0
    });
6245
0
  }
6246
6247
  void session_impl::dht_direct_request(udp::endpoint const& ep, entry& e, client_data_t userdata)
6248
0
  {
6249
0
    if (!m_dht) return;
6250
0
    m_dht->direct_request(ep, e, std::bind(&on_direct_response, std::ref(m_alerts), userdata, _1));
6251
0
  }
6252
6253
#endif
6254
6255
  bool session_impl::is_listening() const
6256
0
  {
6257
0
    return !m_listen_sockets.empty();
6258
0
  }
6259
6260
  session_impl::~session_impl()
6261
1.83k
  {
6262
    // since we're destructing the session, no more alerts will make it out to
6263
    // the user. So stop posting them now
6264
1.83k
    m_alerts.set_alert_mask({});
6265
1.83k
    m_alerts.set_notify_function({});
6266
6267
    // this is not allowed to be the network thread!
6268
//    TORRENT_ASSERT(is_not_thread());
6269
// TODO: asserts that no outstanding async operations are still in flight
6270
6271
    // this can happen if we end the io_context run loop with an exception
6272
1.83k
    m_connections.clear();
6273
1.83k
    for (auto& t : m_torrents)
6274
0
    {
6275
0
      t->panic();
6276
0
      t->abort();
6277
0
    }
6278
1.83k
    m_torrents.clear();
6279
6280
    // this has probably been called already, but in case of sudden
6281
    // termination through an exception, it may not have been done
6282
1.83k
    abort_stage2();
6283
6284
#if defined TORRENT_ASIO_DEBUGGING
6285
    FILE* f = fopen("wakeups.log", "w+");
6286
    if (f != nullptr)
6287
    {
6288
      time_point m = min_time();
6289
      if (!_wakeups.empty()) m = _wakeups[0].timestamp;
6290
      time_point prev = m;
6291
      std::uint64_t prev_csw = 0;
6292
      if (!_wakeups.empty()) prev_csw = _wakeups[0].context_switches;
6293
      std::fprintf(f, "abs. time\trel. time\tctx switch\tidle-wakeup\toperation\n");
6294
      for (wakeup_t const& w : _wakeups)
6295
      {
6296
        bool const idle_wakeup = w.context_switches > prev_csw;
6297
        std::fprintf(f, "%" PRId64 "\t%" PRId64 "\t%" PRId64 "\t%c\t%s\n"
6298
          , total_microseconds(w.timestamp - m)
6299
          , total_microseconds(w.timestamp - prev)
6300
          , w.context_switches
6301
          , idle_wakeup ? '*' : '.'
6302
          , w.operation);
6303
        prev = w.timestamp;
6304
        prev_csw = w.context_switches;
6305
      }
6306
      fclose(f);
6307
    }
6308
#endif
6309
1.83k
  }
6310
6311
#if TORRENT_ABI_VERSION == 1
6312
  int session_impl::max_connections() const
6313
0
  {
6314
0
    return m_settings.get_int(settings_pack::connections_limit);
6315
0
  }
6316
6317
  int session_impl::max_uploads() const
6318
0
  {
6319
0
    return m_settings.get_int(settings_pack::unchoke_slots_limit);
6320
0
  }
6321
6322
  void session_impl::set_local_download_rate_limit(int bytes_per_second)
6323
0
  {
6324
0
    INVARIANT_CHECK;
6325
0
    settings_pack p;
6326
0
    p.set_int(settings_pack::local_download_rate_limit, bytes_per_second);
6327
0
    apply_settings_pack_impl(p);
6328
0
  }
6329
6330
  void session_impl::set_local_upload_rate_limit(int bytes_per_second)
6331
0
  {
6332
0
    INVARIANT_CHECK;
6333
0
    settings_pack p;
6334
0
    p.set_int(settings_pack::local_upload_rate_limit, bytes_per_second);
6335
0
    apply_settings_pack_impl(p);
6336
0
  }
6337
6338
  void session_impl::set_download_rate_limit_depr(int bytes_per_second)
6339
0
  {
6340
0
    INVARIANT_CHECK;
6341
0
    settings_pack p;
6342
0
    p.set_int(settings_pack::download_rate_limit, bytes_per_second);
6343
0
    apply_settings_pack_impl(p);
6344
0
  }
6345
6346
  void session_impl::set_upload_rate_limit_depr(int bytes_per_second)
6347
0
  {
6348
0
    INVARIANT_CHECK;
6349
0
    settings_pack p;
6350
0
    p.set_int(settings_pack::upload_rate_limit, bytes_per_second);
6351
0
    apply_settings_pack_impl(p);
6352
0
  }
6353
6354
  void session_impl::set_max_connections(int limit)
6355
0
  {
6356
0
    INVARIANT_CHECK;
6357
0
    settings_pack p;
6358
0
    p.set_int(settings_pack::connections_limit, limit);
6359
0
    apply_settings_pack_impl(p);
6360
0
  }
6361
6362
  void session_impl::set_max_uploads(int limit)
6363
0
  {
6364
0
    INVARIANT_CHECK;
6365
0
    settings_pack p;
6366
0
    p.set_int(settings_pack::unchoke_slots_limit, limit);
6367
0
    apply_settings_pack_impl(p);
6368
0
  }
6369
6370
  int session_impl::local_upload_rate_limit() const
6371
0
  {
6372
0
    return upload_rate_limit(m_local_peer_class);
6373
0
  }
6374
6375
  int session_impl::local_download_rate_limit() const
6376
0
  {
6377
0
    return download_rate_limit(m_local_peer_class);
6378
0
  }
6379
6380
  int session_impl::upload_rate_limit_depr() const
6381
0
  {
6382
0
    return upload_rate_limit(m_global_class);
6383
0
  }
6384
6385
  int session_impl::download_rate_limit_depr() const
6386
0
  {
6387
0
    return download_rate_limit(m_global_class);
6388
0
  }
6389
#endif // DEPRECATE
6390
6391
6392
  // TODO: 2 this should be factored into the udp socket, so we only have the
6393
  // code once
6394
  void session_impl::update_peer_dscp()
6395
3.67k
  {
6396
3.67k
    int const value = m_settings.get_int(settings_pack::peer_dscp);
6397
3.67k
    for (auto const& l : m_listen_sockets)
6398
1.83k
    {
6399
1.83k
      if (l->sock)
6400
1.83k
      {
6401
1.83k
        error_code ec;
6402
1.83k
        set_traffic_class(*l->sock, value, ec);
6403
6404
#ifndef TORRENT_DISABLE_LOGGING
6405
        if (should_log())
6406
        {
6407
          session_log(">>> SET_DSCP [ tcp (%s %d) value: %x e: %s ]"
6408
            , l->sock->local_endpoint().address().to_string().c_str()
6409
            , l->sock->local_endpoint().port(), std::uint32_t(value), ec.message().c_str());
6410
        }
6411
#endif
6412
1.83k
      }
6413
6414
1.83k
      if (l->udp_sock)
6415
1.83k
      {
6416
1.83k
        error_code ec;
6417
1.83k
        set_traffic_class(l->udp_sock->sock, value, ec);
6418
6419
#ifndef TORRENT_DISABLE_LOGGING
6420
        if (should_log())
6421
        {
6422
          session_log(">>> SET_DSCP [ udp (%s %d) value: %x e: %s ]"
6423
            , l->udp_sock->sock.local_endpoint().address().to_string().c_str()
6424
            , l->udp_sock->sock.local_port()
6425
            , std::uint32_t(value), ec.message().c_str());
6426
        }
6427
#endif
6428
1.83k
      }
6429
1.83k
    }
6430
3.67k
  }
6431
6432
  void session_impl::update_user_agent()
6433
1.83k
  {
6434
    // replace all occurrences of '\n' with ' '.
6435
1.83k
    std::string agent = m_settings.get_str(settings_pack::user_agent);
6436
1.83k
    std::string::iterator i = agent.begin();
6437
1.83k
    while ((i = std::find(i, agent.end(), '\n'))
6438
1.83k
      != agent.end())
6439
0
      *i = ' ';
6440
1.83k
    m_settings.set_str(settings_pack::user_agent, agent);
6441
1.83k
  }
6442
6443
  void session_impl::update_unchoke_limit()
6444
1.83k
  {
6445
1.83k
    int const allowed_upload_slots = get_int_setting(settings_pack::unchoke_slots_limit);
6446
6447
1.83k
    m_stats_counters.set_value(counters::num_unchoke_slots
6448
1.83k
      , allowed_upload_slots);
6449
6450
1.83k
    if (m_settings.get_int(settings_pack::num_optimistic_unchoke_slots)
6451
1.83k
      >= allowed_upload_slots / 2)
6452
0
    {
6453
0
      if (m_alerts.should_post<performance_alert>())
6454
0
        m_alerts.emplace_alert<performance_alert>(torrent_handle()
6455
0
          , performance_alert::too_many_optimistic_unchoke_slots);
6456
0
    }
6457
6458
1.83k
    if (settings().get_int(settings_pack::choking_algorithm) != settings_pack::fixed_slots_choker)
6459
0
      return;
6460
6461
1.83k
    if (allowed_upload_slots == std::numeric_limits<int>::max())
6462
0
    {
6463
      // this means we're not applying upload slot limits, unchoke
6464
      // everyone
6465
0
      for (auto const& p : m_connections)
6466
0
      {
6467
0
        if (p->is_disconnecting()
6468
0
          || p->is_connecting()
6469
0
          || !p->is_choked()
6470
0
          || p->in_handshake()
6471
0
          || p->ignore_unchoke_slots()
6472
0
          )
6473
0
          continue;
6474
6475
0
        auto const t = p->associated_torrent().lock();
6476
0
        t->unchoke_peer(*p);
6477
0
      }
6478
0
    }
6479
1.83k
    else
6480
1.83k
    {
6481
      // trigger recalculating unchoke slots
6482
1.83k
      m_unchoke_time_scaler = 0;
6483
1.83k
    }
6484
1.83k
  }
6485
6486
  void session_impl::update_connection_speed()
6487
1.83k
  {
6488
1.83k
    if (m_settings.get_int(settings_pack::connection_speed) < 0)
6489
0
      m_settings.set_int(settings_pack::connection_speed, 200);
6490
1.83k
  }
6491
6492
  void session_impl::update_alert_queue_size()
6493
1.83k
  {
6494
1.83k
    m_alerts.set_alert_queue_size_limit(m_settings.get_int(settings_pack::alert_queue_size));
6495
1.83k
  }
6496
6497
  bool session_impl::preemptive_unchoke() const
6498
0
  {
6499
0
    if (settings().get_int(settings_pack::choking_algorithm) != settings_pack::fixed_slots_choker) return false;
6500
0
    return m_stats_counters[counters::num_peers_up_unchoked]
6501
0
      < m_stats_counters[counters::num_unchoke_slots]
6502
0
      || m_settings.get_int(settings_pack::unchoke_slots_limit) < 0;
6503
0
  }
6504
6505
  void session_impl::update_dht_upload_rate_limit()
6506
1.83k
  {
6507
1.83k
#ifndef TORRENT_DISABLE_DHT
6508
1.83k
    if (m_settings.get_int(settings_pack::dht_upload_rate_limit) > std::numeric_limits<int>::max() / 3)
6509
0
    {
6510
0
      m_settings.set_int(settings_pack::dht_upload_rate_limit, std::numeric_limits<int>::max() / 3);
6511
0
    }
6512
1.83k
#endif
6513
1.83k
  }
6514
6515
  void session_impl::update_disk_threads()
6516
3.67k
  {
6517
3.67k
    if (m_settings.get_int(settings_pack::aio_threads) < 0)
6518
0
      m_settings.set_int(settings_pack::aio_threads, 0);
6519
3.67k
    if (m_settings.get_int(settings_pack::hashing_threads) < 0)
6520
0
      m_settings.set_int(settings_pack::hashing_threads, 0);
6521
3.67k
  }
6522
6523
  void session_impl::update_report_web_seed_downloads()
6524
1.83k
  {
6525
    // if this flag changed, update all web seed connections
6526
1.83k
    bool report = m_settings.get_bool(settings_pack::report_web_seed_downloads);
6527
1.83k
    for (auto const& c : m_connections)
6528
0
    {
6529
0
      connection_type const type = c->type();
6530
0
      if (type == connection_type::url_seed
6531
0
        || type == connection_type::http_seed)
6532
0
        c->ignore_stats(!report);
6533
0
    }
6534
1.83k
  }
6535
6536
  void session_impl::trigger_auto_manage()
6537
13.7k
  {
6538
13.7k
    if (m_pending_auto_manage || m_abort) return;
6539
6540
    // we recalculated auto-managed torrents less than a second ago,
6541
    // put it off one second.
6542
12.6k
    if (time_now() - m_last_auto_manage < seconds(1))
6543
12.6k
    {
6544
12.6k
      m_auto_manage_time_scaler = 0;
6545
12.6k
      return;
6546
12.6k
    }
6547
0
    m_pending_auto_manage = true;
6548
0
    m_need_auto_manage = true;
6549
6550
0
    post(m_io_context, [this]{ wrap(&session_impl::on_trigger_auto_manage); });
6551
0
  }
6552
6553
  void session_impl::on_trigger_auto_manage()
6554
0
  {
6555
0
    TORRENT_ASSERT(m_pending_auto_manage);
6556
0
    if (!m_need_auto_manage || m_abort)
6557
0
    {
6558
0
      m_pending_auto_manage = false;
6559
0
      return;
6560
0
    }
6561
    // don't clear m_pending_auto_manage until after we've
6562
    // recalculated the auto managed torrents. The auto-managed
6563
    // logic may trigger another auto-managed event otherwise
6564
0
    recalculate_auto_managed_torrents();
6565
0
    m_pending_auto_manage = false;
6566
0
  }
6567
6568
  void session_impl::update_socket_buffer_size()
6569
3.67k
  {
6570
3.67k
    for (auto const& l : m_listen_sockets)
6571
0
    {
6572
0
      error_code ec;
6573
0
      set_socket_buffer_size(l->udp_sock->sock, m_settings, ec);
6574
#ifndef TORRENT_DISABLE_LOGGING
6575
      if (ec && should_log())
6576
      {
6577
        session_log("listen socket buffer size [ udp %s:%d ] %s"
6578
          , l->udp_sock->sock.local_endpoint().address().to_string().c_str()
6579
          , l->udp_sock->sock.local_port(), print_error(ec).c_str());
6580
      }
6581
#endif
6582
0
      ec.clear();
6583
0
      set_socket_buffer_size(*l->sock, m_settings, ec);
6584
#ifndef TORRENT_DISABLE_LOGGING
6585
      if (ec && should_log())
6586
      {
6587
        session_log("listen socket buffer size [ tcp %s:%d] %s"
6588
          , l->sock->local_endpoint().address().to_string().c_str()
6589
          , l->sock->local_endpoint().port(), print_error(ec).c_str());
6590
      }
6591
#endif
6592
0
    }
6593
3.67k
  }
6594
6595
  void session_impl::update_dht_announce_interval()
6596
1.83k
  {
6597
1.83k
#ifndef TORRENT_DISABLE_DHT
6598
1.83k
    if (!m_dht)
6599
1.83k
    {
6600
#ifndef TORRENT_DISABLE_LOGGING
6601
      session_log("not starting DHT announce timer: m_dht == nullptr");
6602
#endif
6603
1.83k
      return;
6604
1.83k
    }
6605
6606
0
    m_dht_interval_update_torrents = int(m_torrents.size());
6607
6608
0
    if (m_abort)
6609
0
    {
6610
#ifndef TORRENT_DISABLE_LOGGING
6611
      session_log("not starting DHT announce timer: m_abort set");
6612
#endif
6613
0
      return;
6614
0
    }
6615
6616
0
    ADD_OUTSTANDING_ASYNC("session_impl::on_dht_announce");
6617
0
    int delay = std::max(1000 * m_settings.get_int(settings_pack::dht_announce_interval)
6618
0
      / std::max(int(m_torrents.size()), 1), 1);
6619
6620
0
    if (!m_dht_torrents.empty())
6621
0
    {
6622
      // we have prioritized torrents that need
6623
      // an initial DHT announce. Don't wait too long
6624
      // until we announce those.
6625
0
      delay = std::min(4000, delay);
6626
0
    }
6627
6628
0
    m_dht_announce_timer.expires_after(milliseconds(delay));
6629
0
    m_dht_announce_timer.async_wait([this](error_code const& e) {
6630
0
      wrap(&session_impl::on_dht_announce, e); });
6631
0
#endif
6632
0
  }
6633
6634
#if TORRENT_ABI_VERSION == 1
6635
  void session_impl::update_local_download_rate()
6636
1.83k
  {
6637
1.83k
    if (m_settings.get_int(settings_pack::local_download_rate_limit) < 0)
6638
0
      m_settings.set_int(settings_pack::local_download_rate_limit, 0);
6639
1.83k
    set_download_rate_limit(m_local_peer_class
6640
1.83k
      , m_settings.get_int(settings_pack::local_download_rate_limit));
6641
1.83k
  }
6642
6643
  void session_impl::update_local_upload_rate()
6644
1.83k
  {
6645
1.83k
    if (m_settings.get_int(settings_pack::local_upload_rate_limit) < 0)
6646
0
      m_settings.set_int(settings_pack::local_upload_rate_limit, 0);
6647
1.83k
    set_upload_rate_limit(m_local_peer_class
6648
1.83k
      , m_settings.get_int(settings_pack::local_upload_rate_limit));
6649
1.83k
  }
6650
#endif
6651
6652
  void session_impl::update_download_rate()
6653
1.83k
  {
6654
1.83k
    if (m_settings.get_int(settings_pack::download_rate_limit) < 0)
6655
0
      m_settings.set_int(settings_pack::download_rate_limit, 0);
6656
1.83k
    set_download_rate_limit(m_global_class
6657
1.83k
      , m_settings.get_int(settings_pack::download_rate_limit));
6658
1.83k
  }
6659
6660
  void session_impl::update_upload_rate()
6661
1.83k
  {
6662
1.83k
    if (m_settings.get_int(settings_pack::upload_rate_limit) < 0)
6663
0
      m_settings.set_int(settings_pack::upload_rate_limit, 0);
6664
1.83k
    set_upload_rate_limit(m_global_class
6665
1.83k
      , m_settings.get_int(settings_pack::upload_rate_limit));
6666
1.83k
  }
6667
6668
  void session_impl::update_connections_limit()
6669
1.83k
  {
6670
1.83k
    int limit = m_settings.get_int(settings_pack::connections_limit);
6671
6672
1.83k
    if (limit <= 0) limit = max_open_files();
6673
6674
1.83k
    m_settings.set_int(settings_pack::connections_limit, limit);
6675
6676
1.83k
    if (num_connections() > m_settings.get_int(settings_pack::connections_limit)
6677
1.83k
      && !m_torrents.empty())
6678
0
    {
6679
      // if we have more connections that we're allowed, disconnect
6680
      // peers from the torrents so that they are all as even as possible
6681
6682
0
      int to_disconnect = num_connections() - m_settings.get_int(settings_pack::connections_limit);
6683
6684
0
      int last_average = 0;
6685
0
      int average = m_settings.get_int(settings_pack::connections_limit) / int(m_torrents.size());
6686
6687
      // the number of slots that are unused by torrents
6688
0
      int extra = m_settings.get_int(settings_pack::connections_limit) % int(m_torrents.size());
6689
6690
      // run 3 iterations of this, then we're probably close enough
6691
0
      for (int iter = 0; iter < 4; ++iter)
6692
0
      {
6693
        // the number of torrents that are above average
6694
0
        int num_above = 0;
6695
0
        for (auto const& t : m_torrents)
6696
0
        {
6697
0
          int const num = t->num_peers();
6698
0
          if (num <= last_average) continue;
6699
0
          if (num > average) ++num_above;
6700
0
          if (num < average) extra += average - num;
6701
0
        }
6702
6703
        // distribute extra among the torrents that are above average
6704
0
        if (num_above == 0) num_above = 1;
6705
0
        last_average = average;
6706
0
        average += extra / num_above;
6707
0
        if (extra == 0) break;
6708
        // save the remainder for the next iteration
6709
0
        extra = extra % num_above;
6710
0
      }
6711
6712
0
      for (auto const& t : m_torrents)
6713
0
      {
6714
0
        int const num = t->num_peers();
6715
0
        if (num <= average) continue;
6716
6717
        // distribute the remainder
6718
0
        int my_average = average;
6719
0
        if (extra > 0)
6720
0
        {
6721
0
          ++my_average;
6722
0
          --extra;
6723
0
        }
6724
6725
0
        int const disconnect = std::min(to_disconnect, num - my_average);
6726
0
        to_disconnect -= disconnect;
6727
0
        t->disconnect_peers(disconnect, errors::too_many_connections);
6728
0
      }
6729
0
    }
6730
1.83k
  }
6731
6732
  void session_impl::update_alert_mask()
6733
1.83k
  {
6734
1.83k
    m_alerts.set_alert_mask(alert_category_t(
6735
1.83k
      static_cast<std::uint32_t>(m_settings.get_int(settings_pack::alert_mask))));
6736
1.83k
  }
6737
6738
  void session_impl::update_validate_https()
6739
1.83k
  {
6740
1.83k
#if TORRENT_USE_SSL
6741
1.83k
    auto const flags = m_settings.get_bool(settings_pack::validate_https_trackers)
6742
1.83k
      ? ssl::context::verify_peer
6743
1.83k
        | ssl::context::verify_fail_if_no_peer_cert
6744
1.83k
        | ssl::context::verify_client_once
6745
1.83k
      : ssl::context::verify_none;
6746
1.83k
    error_code ec;
6747
1.83k
    m_ssl_ctx.set_verify_mode(flags, ec);
6748
6749
#ifndef TORRENT_DISABLE_LOGGING
6750
    if (ec) session_log("SSL set_verify_mode failed: %s", ec.message().c_str());
6751
#endif
6752
1.83k
#endif
6753
1.83k
  }
6754
6755
  void session_impl::pop_alerts(std::vector<alert*>* alerts)
6756
3
  {
6757
3
    m_alerts.get_all(*alerts);
6758
3
  }
6759
6760
#if TORRENT_ABI_VERSION == 1
6761
  void session_impl::update_rate_limit_utp()
6762
1.83k
  {
6763
1.83k
    if (m_settings.get_bool(settings_pack::rate_limit_utp))
6764
1.83k
    {
6765
      // allow the global or local peer class to limit uTP peers
6766
1.83k
      m_peer_class_type_filter.allow(peer_class_type_filter::utp_socket
6767
1.83k
        , m_global_class);
6768
1.83k
      m_peer_class_type_filter.allow(peer_class_type_filter::ssl_utp_socket
6769
1.83k
        , m_global_class);
6770
1.83k
    }
6771
0
    else
6772
0
    {
6773
      // don't add the global or local peer class to limit uTP peers
6774
0
      m_peer_class_type_filter.disallow(peer_class_type_filter::utp_socket
6775
0
        , m_global_class);
6776
0
      m_peer_class_type_filter.disallow(peer_class_type_filter::ssl_utp_socket
6777
0
        , m_global_class);
6778
0
    }
6779
1.83k
  }
6780
6781
  void session_impl::update_ignore_rate_limits_on_local_network()
6782
1.83k
  {
6783
1.83k
    init_peer_class_filter(
6784
1.83k
      m_settings.get_bool(settings_pack::ignore_limits_on_local_network));
6785
1.83k
  }
6786
6787
  // this function is called on the user's thread
6788
  // not the network thread
6789
  void session_impl::pop_alerts()
6790
0
  {
6791
    // if we don't have any alerts in our local cache, we have to ask
6792
    // the alert_manager for more. It will swap our vector with its and
6793
    // destruct eny left-over alerts in there.
6794
0
    if (m_alert_pointer_pos >= int(m_alert_pointers.size()))
6795
0
    {
6796
0
      pop_alerts(&m_alert_pointers);
6797
0
      m_alert_pointer_pos = 0;
6798
0
    }
6799
0
  }
6800
6801
  alert const* session_impl::pop_alert()
6802
0
  {
6803
0
    if (m_alert_pointer_pos >= int(m_alert_pointers.size()))
6804
0
    {
6805
0
      pop_alerts();
6806
0
      if (m_alert_pointers.empty())
6807
0
        return nullptr;
6808
0
    }
6809
6810
0
    if (m_alert_pointers.empty()) return nullptr;
6811
6812
    // clone here to be backwards compatible, to make the client delete the
6813
    // alert object
6814
0
    return m_alert_pointers[m_alert_pointer_pos++];
6815
0
  }
6816
6817
#endif
6818
6819
  alert* session_impl::wait_for_alert(time_duration max_wait)
6820
3
  {
6821
3
    return m_alerts.wait_for_alert(max_wait);
6822
3
  }
6823
6824
#if TORRENT_ABI_VERSION == 1
6825
  std::size_t session_impl::set_alert_queue_size_limit(std::size_t queue_size_limit_)
6826
0
  {
6827
0
    m_settings.set_int(settings_pack::alert_queue_size, int(queue_size_limit_));
6828
0
    return std::size_t(m_alerts.set_alert_queue_size_limit(int(queue_size_limit_)));
6829
0
  }
6830
#endif
6831
6832
  void session_impl::start_ip_notifier()
6833
0
  {
6834
0
    INVARIANT_CHECK;
6835
6836
0
    if (m_ip_notifier) return;
6837
6838
0
    m_ip_notifier = create_ip_notifier(m_io_context);
6839
0
    m_ip_notifier->async_wait([this](error_code const& e)
6840
0
      { wrap(&session_impl::on_ip_change, e); });
6841
0
  }
6842
6843
  void session_impl::start_lsd()
6844
0
  {
6845
0
    INVARIANT_CHECK;
6846
6847
0
    for (auto& s : m_listen_sockets)
6848
0
    {
6849
      // we're not looking for local peers when we're using a proxy. We
6850
      // want all traffic to go through the proxy
6851
0
      if (s->flags & listen_socket_t::proxy) continue;
6852
0
      if (s->lsd) continue;
6853
0
      s->lsd = std::make_shared<lsd>(m_io_context, *this, s->local_endpoint.address()
6854
0
        , s->netmask);
6855
0
      error_code ec;
6856
0
      s->lsd->start(ec);
6857
0
      if (ec)
6858
0
      {
6859
0
        if (m_alerts.should_post<lsd_error_alert>())
6860
0
          m_alerts.emplace_alert<lsd_error_alert>(ec, s->local_endpoint.address());
6861
0
        s->lsd.reset();
6862
0
      }
6863
0
    }
6864
0
  }
6865
6866
  void session_impl::start_natpmp()
6867
0
  {
6868
0
    INVARIANT_CHECK;
6869
0
    for (auto& s : m_listen_sockets)
6870
0
    {
6871
0
      start_natpmp(s);
6872
0
      remap_ports(remap_natpmp, *s);
6873
0
    }
6874
0
  }
6875
6876
  void session_impl::start_upnp()
6877
0
  {
6878
0
    INVARIANT_CHECK;
6879
0
    for (auto const& s : m_listen_sockets)
6880
0
    {
6881
0
      start_upnp(s);
6882
0
      remap_ports(remap_upnp, *s);
6883
0
    }
6884
0
  }
6885
6886
  void session_impl::start_upnp(std::shared_ptr<aux::listen_socket_t> const& s)
6887
0
  {
6888
    // until we support SSDP over an IPv6 network (
6889
    // https://en.wikipedia.org/wiki/Simple_Service_Discovery_Protocol )
6890
    // there's no point in starting upnp on one.
6891
0
    if (is_v6(s->local_endpoint))
6892
0
      return;
6893
6894
    // there's no point in starting the UPnP mapper for a network that isn't
6895
    // connected to the internet. The whole point is to forward ports through
6896
    // the gateway
6897
0
    if ((s->flags & listen_socket_t::local_network)
6898
0
      || (s->flags & listen_socket_t::proxy))
6899
0
      return;
6900
6901
0
    if (!s->upnp_mapper)
6902
0
    {
6903
      // the upnp constructor may fail and call the callbacks
6904
      // into the session_impl.
6905
0
      s->upnp_mapper = std::make_shared<upnp>(m_io_context, m_settings
6906
0
        , *this, s->local_endpoint.address().to_v4(), s->netmask.to_v4(), s->device
6907
0
        , listen_socket_handle(s));
6908
0
      s->upnp_mapper->start();
6909
0
    }
6910
0
  }
6911
6912
  std::vector<port_mapping_t> session_impl::add_port_mapping(portmap_protocol const t
6913
    , int const external_port
6914
    , int const local_port)
6915
0
  {
6916
0
    std::vector<port_mapping_t> ret;
6917
0
    for (auto& s : m_listen_sockets)
6918
0
    {
6919
0
      tcp::endpoint const ep{s->local_endpoint.address(), static_cast<std::uint16_t>(local_port)};
6920
0
      if (s->upnp_mapper) ret.push_back(s->upnp_mapper->add_mapping(
6921
0
        t, external_port, ep, s->device));
6922
0
      if (s->natpmp_mapper) ret.push_back(s->natpmp_mapper->add_mapping(
6923
0
        t, external_port, ep, s->device));
6924
0
    }
6925
0
    return ret;
6926
0
  }
6927
6928
  void session_impl::delete_port_mapping(port_mapping_t handle)
6929
0
  {
6930
0
    for (auto& s : m_listen_sockets)
6931
0
    {
6932
0
      if (s->upnp_mapper) s->upnp_mapper->delete_mapping(handle);
6933
0
      if (s->natpmp_mapper) s->natpmp_mapper->delete_mapping(handle);
6934
0
    }
6935
0
  }
6936
6937
  void session_impl::stop_ip_notifier()
6938
3.67k
  {
6939
3.67k
    if (!m_ip_notifier) return;
6940
6941
0
    m_ip_notifier->cancel();
6942
0
    m_ip_notifier.reset();
6943
0
  }
6944
6945
  void session_impl::stop_lsd()
6946
5.50k
  {
6947
5.50k
    for (auto& s : m_listen_sockets)
6948
3.67k
    {
6949
3.67k
      if (!s->lsd) continue;
6950
0
      s->lsd->close();
6951
0
      s->lsd.reset();
6952
0
    }
6953
5.50k
  }
6954
6955
  void session_impl::stop_natpmp()
6956
3.67k
  {
6957
3.67k
    for (auto& s : m_listen_sockets)
6958
1.83k
    {
6959
1.83k
      s->tcp_port_mapping[portmap_transport::natpmp] = listen_port_mapping();
6960
1.83k
      s->udp_port_mapping[portmap_transport::natpmp] = listen_port_mapping();
6961
1.83k
      if (!s->natpmp_mapper) continue;
6962
0
      s->natpmp_mapper->close();
6963
0
      s->natpmp_mapper.reset();
6964
0
    }
6965
3.67k
  }
6966
6967
  void session_impl::stop_upnp()
6968
3.67k
  {
6969
3.67k
    for (auto& s : m_listen_sockets)
6970
1.83k
    {
6971
1.83k
      if (!s->upnp_mapper) continue;
6972
0
      s->tcp_port_mapping[portmap_transport::upnp] = listen_port_mapping();
6973
0
      s->udp_port_mapping[portmap_transport::upnp] = listen_port_mapping();
6974
0
      s->upnp_mapper->close();
6975
0
      s->upnp_mapper.reset();
6976
0
    }
6977
3.67k
  }
6978
6979
  external_ip session_impl::external_address() const
6980
0
  {
6981
0
    address ips[2][2];
6982
6983
    // take the first IP we find which matches each category
6984
0
    for (auto const& i : m_listen_sockets)
6985
0
    {
6986
0
      address external_addr = i->external_address.external_address();
6987
0
      if (ips[0][external_addr.is_v6()] == address())
6988
0
        ips[0][external_addr.is_v6()] = external_addr;
6989
0
      address local_addr = i->local_endpoint.address();
6990
0
      if (ips[is_local(local_addr)][local_addr.is_v6()] == address())
6991
0
        ips[is_local(local_addr)][local_addr.is_v6()] = local_addr;
6992
0
    }
6993
6994
0
    return {ips[1][0], ips[0][0], ips[1][1], ips[0][1]};
6995
0
  }
6996
6997
  // this is the DHT observer version. DHT is the implied source
6998
  void session_impl::set_external_address(aux::listen_socket_handle const& iface
6999
    , address const& ip, address const& source)
7000
0
  {
7001
0
    auto i = iface.m_sock.lock();
7002
0
    TORRENT_ASSERT(i);
7003
0
    if (!i) return;
7004
0
    set_external_address(i, ip, source_dht, source);
7005
0
  }
7006
7007
  void session_impl::get_peers(sha1_hash const& ih)
7008
0
  {
7009
0
    if (!m_alerts.should_post<dht_get_peers_alert>()) return;
7010
0
    m_alerts.emplace_alert<dht_get_peers_alert>(ih);
7011
0
  }
7012
7013
  void session_impl::announce(sha1_hash const& ih, address const& addr
7014
    , int port)
7015
0
  {
7016
0
    if (!m_alerts.should_post<dht_announce_alert>()) return;
7017
0
    m_alerts.emplace_alert<dht_announce_alert>(addr, port, ih);
7018
0
  }
7019
7020
  void session_impl::outgoing_get_peers(sha1_hash const& target
7021
    , sha1_hash const& sent_target, udp::endpoint const& ep)
7022
0
  {
7023
0
    if (!m_alerts.should_post<dht_outgoing_get_peers_alert>()) return;
7024
0
    m_alerts.emplace_alert<dht_outgoing_get_peers_alert>(target, sent_target, ep);
7025
0
  }
7026
7027
#ifndef TORRENT_DISABLE_LOGGING
7028
  bool session_impl::should_log(module_t) const
7029
  {
7030
    return m_alerts.should_post<dht_log_alert>();
7031
  }
7032
7033
  TORRENT_FORMAT(3,4)
7034
  void session_impl::log(module_t m, char const* fmt, ...)
7035
  {
7036
    if (!m_alerts.should_post<dht_log_alert>()) return;
7037
7038
    va_list v;
7039
    va_start(v, fmt);
7040
    m_alerts.emplace_alert<dht_log_alert>(
7041
      static_cast<dht_log_alert::dht_module_t>(m), fmt, v);
7042
    va_end(v);
7043
  }
7044
7045
  void session_impl::log_packet(message_direction_t dir, span<char const> pkt
7046
    , udp::endpoint const& node)
7047
  {
7048
    if (!m_alerts.should_post<dht_pkt_alert>()) return;
7049
7050
    dht_pkt_alert::direction_t d = dir == dht::dht_logger::incoming_message
7051
      ? dht_pkt_alert::incoming : dht_pkt_alert::outgoing;
7052
7053
    m_alerts.emplace_alert<dht_pkt_alert>(pkt, d, node);
7054
  }
7055
7056
  bool session_impl::should_log_portmap(portmap_transport) const
7057
  {
7058
    return m_alerts.should_post<portmap_log_alert>();
7059
  }
7060
7061
  void session_impl::log_portmap(portmap_transport transport, char const* msg
7062
    , listen_socket_handle const& ls) const
7063
  {
7064
    listen_socket_t const* listen_socket = ls.get();
7065
    if (m_alerts.should_post<portmap_log_alert>())
7066
      m_alerts.emplace_alert<portmap_log_alert>(transport, msg
7067
        , listen_socket ? listen_socket->local_endpoint.address() : address());
7068
  }
7069
7070
  bool session_impl::should_log_lsd() const
7071
  {
7072
    return m_alerts.should_post<log_alert>();
7073
  }
7074
7075
  void session_impl::log_lsd(char const* msg) const
7076
  {
7077
    if (m_alerts.should_post<log_alert>())
7078
      m_alerts.emplace_alert<log_alert>(msg);
7079
  }
7080
#endif
7081
7082
  bool session_impl::on_dht_request(string_view query
7083
    , dht::msg const& request, entry& response)
7084
0
  {
7085
0
#ifndef TORRENT_DISABLE_EXTENSIONS
7086
0
    for (auto const& ext : m_ses_extensions[plugins_dht_request_idx])
7087
0
    {
7088
0
      if (ext->on_dht_request(query
7089
0
        , request.addr, request.message, response))
7090
0
        return true;
7091
0
    }
7092
#else
7093
    TORRENT_UNUSED(query);
7094
    TORRENT_UNUSED(request);
7095
    TORRENT_UNUSED(response);
7096
#endif
7097
0
    return false;
7098
0
  }
7099
7100
  void session_impl::set_external_address(
7101
    tcp::endpoint const& local_endpoint, address const& ip
7102
    , ip_source_t const source_type, address const& source)
7103
0
  {
7104
0
    auto sock = std::find_if(m_listen_sockets.begin(), m_listen_sockets.end()
7105
0
      , [&](std::shared_ptr<listen_socket_t> const& v)
7106
0
      { return v->local_endpoint.address() == local_endpoint.address(); });
7107
7108
0
    if (sock != m_listen_sockets.end())
7109
0
      set_external_address(*sock, ip, source_type, source);
7110
0
  }
7111
7112
  void session_impl::set_external_address(std::shared_ptr<listen_socket_t> const& sock
7113
    , address const& ip, ip_source_t const source_type, address const& source)
7114
0
  {
7115
0
    if (!sock->external_address.cast_vote(ip, source_type, source)) return;
7116
7117
#ifndef TORRENT_DISABLE_LOGGING
7118
    if (should_log())
7119
    {
7120
      session_log("external address updated for %s [ new-ip: %s type: %d last-voter: %s ]"
7121
        , sock->device.empty() ? print_endpoint(sock->local_endpoint).c_str() : sock->device.c_str()
7122
        , print_address(ip).c_str()
7123
        , static_cast<std::uint8_t>(source_type)
7124
        , print_address(source).c_str());
7125
    }
7126
#endif
7127
7128
0
    if (m_alerts.should_post<external_ip_alert>())
7129
0
      m_alerts.emplace_alert<external_ip_alert>(ip);
7130
7131
0
    for (auto const& t : m_torrents)
7132
0
    {
7133
0
      t->new_external_ip();
7134
0
    }
7135
7136
    // since we have a new external IP now, we need to
7137
    // restart the DHT with a new node ID
7138
7139
0
#ifndef TORRENT_DISABLE_DHT
7140
0
    if (m_dht) m_dht->update_node_id(sock);
7141
0
#endif
7142
0
  }
7143
7144
#if TORRENT_USE_INVARIANT_CHECKS
7145
  void session_impl::check_invariant() const
7146
  {
7147
    TORRENT_ASSERT(is_single_thread());
7148
7149
    if (m_settings.get_int(settings_pack::unchoke_slots_limit) < 0
7150
      && m_settings.get_int(settings_pack::choking_algorithm) == settings_pack::fixed_slots_choker)
7151
      TORRENT_ASSERT(m_stats_counters[counters::num_unchoke_slots] == std::numeric_limits<int>::max());
7152
7153
#ifndef TORRENT_EXPENSIVE_INVARIANT_CHECKS
7154
    // this can get expensive when there are a lot of torrents
7155
    if (m_download_queue.size() < 500)
7156
#endif
7157
    {
7158
      for (torrent_list_index_t l{}; l != m_torrent_lists.end_index(); ++l)
7159
      {
7160
        std::vector<torrent*> const& list = m_torrent_lists[l];
7161
        for (auto const& i : list)
7162
        {
7163
          TORRENT_ASSERT(i->m_links[l].in_list());
7164
        }
7165
7166
        queue_position_t idx{};
7167
        for (auto t : m_download_queue)
7168
        {
7169
          TORRENT_ASSERT(t->queue_position() == idx);
7170
          ++idx;
7171
        }
7172
      }
7173
    }
7174
7175
    int const num_gauges = counters::num_error_torrents - counters::num_checking_torrents + 1;
7176
    aux::array<int, num_gauges> torrent_state_gauges;
7177
    torrent_state_gauges.fill(0);
7178
7179
#if defined TORRENT_EXPENSIVE_INVARIANT_CHECKS
7180
    std::unordered_set<queue_position_t> unique;
7181
#endif
7182
7183
    int num_active_downloading = 0;
7184
    int num_active_finished = 0;
7185
    int total_downloaders = 0;
7186
    for (auto const& tor : m_torrents)
7187
    {
7188
      std::shared_ptr<torrent> const& t = tor;
7189
      if (t->want_peers_download()) ++num_active_downloading;
7190
      if (t->want_peers_finished()) ++num_active_finished;
7191
      TORRENT_ASSERT(!(t->want_peers_download() && t->want_peers_finished()));
7192
7193
      int const state = t->current_stats_state() - counters::num_checking_torrents;
7194
      if (state != torrent::no_gauge_state)
7195
      {
7196
        ++torrent_state_gauges[state];
7197
      }
7198
7199
      queue_position_t const pos = t->queue_position();
7200
      if (pos < queue_position_t{})
7201
      {
7202
        TORRENT_ASSERT(pos == no_pos);
7203
        continue;
7204
      }
7205
      ++total_downloaders;
7206
7207
#if defined TORRENT_EXPENSIVE_INVARIANT_CHECKS
7208
      unique.insert(t->queue_position());
7209
#endif
7210
    }
7211
7212
    for (int i = 0, j = counters::num_checking_torrents;
7213
      j < counters::num_error_torrents + 1; ++i, ++j)
7214
    {
7215
      TORRENT_ASSERT(torrent_state_gauges[i] == m_stats_counters[j]);
7216
    }
7217
7218
#if defined TORRENT_EXPENSIVE_INVARIANT_CHECKS
7219
    TORRENT_ASSERT(int(unique.size()) == total_downloaders);
7220
#endif
7221
    TORRENT_ASSERT(num_active_downloading == int(m_torrent_lists[torrent_want_peers_download].size()));
7222
    TORRENT_ASSERT(num_active_finished == int(m_torrent_lists[torrent_want_peers_finished].size()));
7223
7224
    std::unordered_set<peer_connection*> unique_peers;
7225
7226
    int unchokes = 0;
7227
    int unchokes_all = 0;
7228
    int num_optimistic = 0;
7229
    int disk_queue[2] = {0, 0};
7230
    for (auto const& p : m_connections)
7231
    {
7232
      TORRENT_ASSERT(p);
7233
      if (p->is_disconnecting()) continue;
7234
7235
      std::shared_ptr<torrent> t = p->associated_torrent().lock();
7236
      TORRENT_ASSERT(unique_peers.find(p.get()) == unique_peers.end());
7237
      unique_peers.insert(p.get());
7238
7239
      if (p->m_channel_state[0] & peer_info::bw_disk) ++disk_queue[0];
7240
      if (p->m_channel_state[1] & peer_info::bw_disk) ++disk_queue[1];
7241
7242
      if (p->ignore_unchoke_slots())
7243
      {
7244
        if (!p->is_choked()) ++unchokes_all;
7245
        continue;
7246
      }
7247
      if (!p->is_choked())
7248
      {
7249
        ++unchokes;
7250
        ++unchokes_all;
7251
      }
7252
7253
      if (p->peer_info_struct()
7254
        && p->peer_info_struct()->optimistically_unchoked)
7255
      {
7256
        ++num_optimistic;
7257
        TORRENT_ASSERT(!p->is_choked());
7258
      }
7259
    }
7260
7261
    for (auto const& p : m_undead_peers)
7262
    {
7263
      if (p->ignore_unchoke_slots())
7264
      {
7265
        if (!p->is_choked()) ++unchokes_all;
7266
        continue;
7267
      }
7268
      if (!p->is_choked())
7269
      {
7270
        ++unchokes_all;
7271
        ++unchokes;
7272
      }
7273
7274
      if (p->peer_info_struct()
7275
        && p->peer_info_struct()->optimistically_unchoked)
7276
      {
7277
        ++num_optimistic;
7278
        TORRENT_ASSERT(!p->is_choked());
7279
      }
7280
    }
7281
7282
    TORRENT_ASSERT(disk_queue[peer_connection::download_channel]
7283
      == m_stats_counters[counters::num_peers_down_disk]);
7284
    TORRENT_ASSERT(disk_queue[peer_connection::upload_channel]
7285
      == m_stats_counters[counters::num_peers_up_disk]);
7286
7287
    if (m_settings.get_int(settings_pack::num_optimistic_unchoke_slots))
7288
    {
7289
      TORRENT_ASSERT(num_optimistic <= m_settings.get_int(
7290
        settings_pack::num_optimistic_unchoke_slots));
7291
    }
7292
7293
    int const unchoked_counter_all = int(m_stats_counters[counters::num_peers_up_unchoked_all]);
7294
    int const unchoked_counter = int(m_stats_counters[counters::num_peers_up_unchoked]);
7295
    int const unchoked_counter_optimistic
7296
      = int(m_stats_counters[counters::num_peers_up_unchoked_optimistic]);
7297
7298
    TORRENT_ASSERT_VAL(unchoked_counter_all == unchokes_all, unchokes_all);
7299
    TORRENT_ASSERT_VAL(unchoked_counter == unchokes, unchokes);
7300
    TORRENT_ASSERT_VAL(unchoked_counter_optimistic == num_optimistic, num_optimistic);
7301
7302
    for (auto const& te : m_torrents)
7303
    {
7304
      TORRENT_ASSERT(te);
7305
    }
7306
  }
7307
#endif // TORRENT_USE_INVARIANT_CHECKS
7308
7309
#ifndef TORRENT_DISABLE_LOGGING
7310
    tracker_logger::tracker_logger(session_interface& ses): m_ses(ses) {}
7311
    void tracker_logger::tracker_warning(tracker_request const&
7312
      , std::string const& str)
7313
    {
7314
      debug_log("*** tracker warning: %s", str.c_str());
7315
    }
7316
7317
    void tracker_logger::tracker_response(tracker_request const&
7318
      , libtorrent::address const& tracker_ip
7319
      , std::list<address> const& tracker_ips
7320
      , struct tracker_response const& resp)
7321
    {
7322
      TORRENT_UNUSED(tracker_ips);
7323
      debug_log("TRACKER RESPONSE\n"
7324
        "interval: %d\n"
7325
        "external ip: %s\n"
7326
        "we connected to: %s\n"
7327
        "peers:"
7328
        , resp.interval.count()
7329
        , print_address(resp.external_ip).c_str()
7330
        , print_address(tracker_ip).c_str());
7331
7332
      for (auto const& p : resp.peers)
7333
      {
7334
        debug_log("  %16s %5d %s", p.hostname.c_str(), p.port
7335
          , p.pid.is_all_zeros() ? "" : to_hex(p.pid).c_str());
7336
      }
7337
      for (auto const& p : resp.peers4)
7338
      {
7339
        debug_log("  %s:%d", print_address(address_v4(p.ip)).c_str(), p.port);
7340
      }
7341
      for (auto const& p : resp.peers6)
7342
      {
7343
        debug_log("  [%s]:%d", print_address(address_v6(p.ip)).c_str(), p.port);
7344
      }
7345
    }
7346
7347
    void tracker_logger::tracker_request_error(tracker_request const&
7348
      , error_code const& ec, operation_t const op, std::string const& str
7349
      , seconds32 const retry_interval)
7350
    {
7351
      TORRENT_UNUSED(retry_interval);
7352
      debug_log("*** tracker error: [%s] %s %s"
7353
        , operation_name(op), ec.message().c_str(), str.c_str());
7354
    }
7355
7356
    bool tracker_logger::should_log() const
7357
    {
7358
      return m_ses.alerts().should_post<log_alert>();
7359
    }
7360
7361
    void tracker_logger::debug_log(const char* fmt, ...) const noexcept try
7362
    {
7363
      if (!m_ses.alerts().should_post<log_alert>()) return;
7364
7365
      va_list v;
7366
      va_start(v, fmt);
7367
      m_ses.alerts().emplace_alert<log_alert>(fmt, v);
7368
      va_end(v);
7369
    }
7370
    catch (std::exception const&) {}
7371
#endif // TORRENT_DISABLE_LOGGING
7372
}}