1 /* 2 3 Copyright (c) 2012-2018, Arvid Norberg 4 All rights reserved. 5 6 Redistribution and use in source and binary forms, with or without 7 modification, are permitted provided that the following conditions 8 are met: 9 10 * Redistributions of source code must retain the above copyright 11 notice, this list of conditions and the following disclaimer. 12 * Redistributions in binary form must reproduce the above copyright 13 notice, this list of conditions and the following disclaimer in 14 the documentation and/or other materials provided with the distribution. 15 * Neither the name of the author nor the names of its 16 contributors may be used to endorse or promote products derived 17 from this software without specific prior written permission. 18 19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 POSSIBILITY OF SUCH DAMAGE. 30 31 */ 32 33 #include "libtorrent/config.hpp" 34 #include "libtorrent/assert.hpp" 35 #include "libtorrent/settings_pack.hpp" 36 #include "libtorrent/aux_/session_impl.hpp" 37 #include "libtorrent/aux_/array.hpp" 38 #include "libtorrent/aux_/session_settings.hpp" 39 40 #include <algorithm> 41 42 namespace { 43 44 template <class T> compare_first(std::pair<std::uint16_t,T> const & lhs,std::pair<std::uint16_t,T> const & rhs)45 bool compare_first(std::pair<std::uint16_t, T> const& lhs 46 , std::pair<std::uint16_t, T> const& rhs) 47 { 48 return lhs.first < rhs.first; 49 } 50 51 template <class T> insort_replace(std::vector<std::pair<std::uint16_t,T>> & c,std::pair<std::uint16_t,T> v)52 void insort_replace(std::vector<std::pair<std::uint16_t, T>>& c, std::pair<std::uint16_t, T> v) 53 { 54 auto i = std::lower_bound(c.begin(), c.end(), v, &compare_first<T>); 55 if (i != c.end() && i->first == v.first) i->second = std::move(v.second); 56 else c.emplace(i, std::move(v)); 57 } 58 59 // return the string, unless it's null, in which case the empty string is 60 // returned ensure_string(char const * str)61 char const* ensure_string(char const* str) 62 { return str == nullptr ? "" : str; } 63 } 64 65 namespace libtorrent { 66 67 struct str_setting_entry_t 68 { 69 // the name of this setting. used for serialization and deserialization 70 char const* name; 71 // if present, this function is called when the setting is changed 72 void (aux::session_impl::*fun)(); 73 char const *default_value; 74 }; 75 76 struct int_setting_entry_t 77 { 78 // the name of this setting. used for serialization and deserialization 79 char const* name; 80 // if present, this function is called when the setting is changed 81 void (aux::session_impl::*fun)(); 82 int default_value; 83 }; 84 85 struct bool_setting_entry_t 86 { 87 // the name of this setting. used for serialization and deserialization 88 char const* name; 89 // if present, this function is called when the setting is changed 90 void (aux::session_impl::*fun)(); 91 bool default_value; 92 }; 93 94 95 #define SET(name, default_value, fun) { #name, fun, default_value } 96 97 #if TORRENT_ABI_VERSION == 1 98 #define DEPRECATED_SET(name, default_value, fun) { #name, fun, default_value } 99 #define DEPRECATED_SET_STR(name, default_value, fun) { #name, fun, default_value } 100 #else 101 #define DEPRECATED_SET(name, default_value, fun) { "", nullptr, 0 } 102 #define DEPRECATED_SET_STR(name, default_value, fun) { "", nullptr, nullptr } 103 #endif 104 105 #ifdef TORRENT_WINDOWS 106 constexpr int CLOSE_FILE_INTERVAL = 120; 107 #else 108 constexpr int CLOSE_FILE_INTERVAL = 0; 109 #endif 110 111 namespace { 112 113 using aux::session_impl; 114 115 aux::array<str_setting_entry_t, settings_pack::num_string_settings> const str_settings 116 ({{ 117 SET(user_agent, "libtorrent/" LIBTORRENT_VERSION, &session_impl::update_user_agent), 118 SET(announce_ip, nullptr, nullptr), 119 DEPRECATED_SET_STR(mmap_cache, nullptr, nullptr), 120 SET(handshake_client_version, nullptr, nullptr), 121 SET(outgoing_interfaces, "", &session_impl::update_outgoing_interfaces), 122 SET(listen_interfaces, "0.0.0.0:6881,[::]:6881", &session_impl::update_listen_interfaces), 123 SET(proxy_hostname, "", &session_impl::update_proxy), 124 SET(proxy_username, "", &session_impl::update_proxy), 125 SET(proxy_password, "", &session_impl::update_proxy), 126 SET(i2p_hostname, "", &session_impl::update_i2p_bridge), 127 SET(peer_fingerprint, "-LT12E0-", nullptr), 128 SET(dht_bootstrap_nodes, "dht.libtorrent.org:25401", &session_impl::update_dht_bootstrap_nodes) 129 }}); 130 131 aux::array<bool_setting_entry_t, settings_pack::num_bool_settings> const bool_settings 132 ({{ 133 SET(allow_multiple_connections_per_ip, false, nullptr), 134 DEPRECATED_SET(ignore_limits_on_local_network, true, &session_impl::update_ignore_rate_limits_on_local_network), 135 SET(send_redundant_have, true, nullptr), 136 DEPRECATED_SET(lazy_bitfields, false, nullptr), 137 SET(use_dht_as_fallback, false, nullptr), 138 SET(upnp_ignore_nonrouters, false, nullptr), 139 SET(use_parole_mode, true, nullptr), 140 SET(use_read_cache, true, nullptr), 141 DEPRECATED_SET(use_write_cache, true, nullptr), 142 DEPRECATED_SET(dont_flush_write_cache, false, nullptr), 143 #ifdef TORRENT_WINDOWS 144 // the emulation of preadv/pwritev uses overlapped reads/writes to be able 145 // to issue them all back to back. However, it appears windows fail to 146 // merge them. At least for people reporting performance issues in 147 // qBittorrent 148 SET(coalesce_reads, true, nullptr), 149 SET(coalesce_writes, true, nullptr), 150 #else 151 SET(coalesce_reads, false, nullptr), 152 SET(coalesce_writes, false, nullptr), 153 #endif 154 SET(auto_manage_prefer_seeds, false, nullptr), 155 SET(dont_count_slow_torrents, true, &session_impl::update_count_slow), 156 SET(close_redundant_connections, true, nullptr), 157 SET(prioritize_partial_pieces, false, nullptr), 158 SET(rate_limit_ip_overhead, true, nullptr), 159 SET(announce_to_all_trackers, false, nullptr), 160 SET(announce_to_all_tiers, false, nullptr), 161 SET(prefer_udp_trackers, true, nullptr), 162 DEPRECATED_SET(strict_super_seeding, false, nullptr), 163 DEPRECATED_SET(lock_disk_cache, false, nullptr), 164 SET(disable_hash_checks, false, nullptr), 165 SET(allow_i2p_mixed, false, nullptr), 166 DEPRECATED_SET(low_prio_disk, true, nullptr), 167 SET(volatile_read_cache, false, nullptr), 168 DEPRECATED_SET(guided_read_cache, false, nullptr), 169 SET(no_atime_storage, true, nullptr), 170 SET(incoming_starts_queued_torrents, false, nullptr), 171 SET(report_true_downloaded, false, nullptr), 172 SET(strict_end_game_mode, true, nullptr), 173 DEPRECATED_SET(broadcast_lsd, true, nullptr), 174 SET(enable_outgoing_utp, true, nullptr), 175 SET(enable_incoming_utp, true, nullptr), 176 SET(enable_outgoing_tcp, true, nullptr), 177 SET(enable_incoming_tcp, true, nullptr), 178 SET(ignore_resume_timestamps, false, nullptr), 179 SET(no_recheck_incomplete_resume, false, nullptr), 180 SET(anonymous_mode, false, nullptr), 181 SET(report_web_seed_downloads, true, &session_impl::update_report_web_seed_downloads), 182 DEPRECATED_SET(rate_limit_utp, true, &session_impl::update_rate_limit_utp), 183 DEPRECATED_SET(announce_double_nat, false, nullptr), 184 SET(seeding_outgoing_connections, true, nullptr), 185 SET(no_connect_privileged_ports, false, &session_impl::update_privileged_ports), 186 SET(smooth_connects, true, nullptr), 187 SET(always_send_user_agent, false, nullptr), 188 SET(apply_ip_filter_to_trackers, true, nullptr), 189 DEPRECATED_SET(use_disk_read_ahead, true, nullptr), 190 DEPRECATED_SET(lock_files, false, nullptr), 191 DEPRECATED_SET(contiguous_recv_buffer, true, nullptr), 192 SET(ban_web_seeds, true, nullptr), 193 SET(allow_partial_disk_writes, true, nullptr), 194 DEPRECATED_SET(force_proxy, false, nullptr), 195 SET(support_share_mode, true, nullptr), 196 SET(support_merkle_torrents, true, nullptr), 197 SET(report_redundant_bytes, true, nullptr), 198 SET(listen_system_port_fallback, true, nullptr), 199 DEPRECATED_SET(use_disk_cache_pool, false, nullptr), 200 SET(announce_crypto_support, true, nullptr), 201 SET(enable_upnp, true, &session_impl::update_upnp), 202 SET(enable_natpmp, true, &session_impl::update_natpmp), 203 SET(enable_lsd, true, &session_impl::update_lsd), 204 SET(enable_dht, true, &session_impl::update_dht), 205 SET(prefer_rc4, false, nullptr), 206 SET(proxy_hostnames, true, nullptr), 207 SET(proxy_peer_connections, true, nullptr), 208 SET(auto_sequential, true, &session_impl::update_auto_sequential), 209 SET(proxy_tracker_connections, true, nullptr), 210 SET(enable_ip_notifier, true, &session_impl::update_ip_notifier), 211 SET(dht_prefer_verified_node_ids, true, &session_impl::update_dht_settings), 212 SET(piece_extent_affinity, false, nullptr), 213 SET(validate_https_trackers, true, &session_impl::update_validate_https), 214 SET(ssrf_mitigation, true, nullptr), 215 SET(allow_idna, false, nullptr), 216 }}); 217 218 aux::array<int_setting_entry_t, settings_pack::num_int_settings> const int_settings 219 ({{ 220 SET(tracker_completion_timeout, 30, nullptr), 221 SET(tracker_receive_timeout, 10, nullptr), 222 SET(stop_tracker_timeout, 5, nullptr), 223 SET(tracker_maximum_response_length, 1024*1024, nullptr), 224 SET(piece_timeout, 20, nullptr), 225 SET(request_timeout, 60, nullptr), 226 SET(request_queue_time, 3, nullptr), 227 SET(max_allowed_in_request_queue, 500, nullptr), 228 SET(max_out_request_queue, 500, nullptr), 229 SET(whole_pieces_threshold, 20, nullptr), 230 SET(peer_timeout, 120, nullptr), 231 SET(urlseed_timeout, 20, nullptr), 232 SET(urlseed_pipeline_size, 5, nullptr), 233 SET(urlseed_wait_retry, 30, nullptr), 234 SET(file_pool_size, 40, nullptr), 235 SET(max_failcount, 3, &session_impl::update_max_failcount), 236 SET(min_reconnect_time, 60, nullptr), 237 SET(peer_connect_timeout, 15, nullptr), 238 SET(connection_speed, 30, &session_impl::update_connection_speed), 239 SET(inactivity_timeout, 600, nullptr), 240 SET(unchoke_interval, 15, nullptr), 241 SET(optimistic_unchoke_interval, 30, nullptr), 242 SET(num_want, 200, nullptr), 243 SET(initial_picker_threshold, 4, nullptr), 244 SET(allowed_fast_set_size, 5, nullptr), 245 SET(suggest_mode, settings_pack::no_piece_suggestions, nullptr), 246 SET(max_queued_disk_bytes, 1024 * 1024, &session_impl::update_queued_disk_bytes), 247 SET(handshake_timeout, 10, nullptr), 248 SET(send_buffer_low_watermark, 10 * 1024, nullptr), 249 SET(send_buffer_watermark, 500 * 1024, nullptr), 250 SET(send_buffer_watermark_factor, 50, nullptr), 251 SET(choking_algorithm, settings_pack::fixed_slots_choker, nullptr), 252 SET(seed_choking_algorithm, settings_pack::round_robin, nullptr), 253 SET(cache_size, 2048, nullptr), 254 DEPRECATED_SET(cache_buffer_chunk_size, 0, nullptr), 255 SET(cache_expiry, 300, nullptr), 256 SET(disk_io_write_mode, settings_pack::enable_os_cache, nullptr), 257 SET(disk_io_read_mode, settings_pack::enable_os_cache, nullptr), 258 SET(outgoing_port, 0, nullptr), 259 SET(num_outgoing_ports, 0, nullptr), 260 SET(peer_tos, 0x20, &session_impl::update_peer_tos), 261 SET(active_downloads, 3, &session_impl::trigger_auto_manage), 262 SET(active_seeds, 5, &session_impl::trigger_auto_manage), 263 SET(active_checking, 1, &session_impl::trigger_auto_manage), 264 SET(active_dht_limit, 88, nullptr), 265 SET(active_tracker_limit, 1600, nullptr), 266 SET(active_lsd_limit, 60, nullptr), 267 SET(active_limit, 500, &session_impl::trigger_auto_manage), 268 DEPRECATED_SET(active_loaded_limit, 0, &session_impl::trigger_auto_manage), 269 SET(auto_manage_interval, 30, nullptr), 270 SET(seed_time_limit, 24 * 60 * 60, nullptr), 271 SET(auto_scrape_interval, 1800, nullptr), 272 SET(auto_scrape_min_interval, 300, nullptr), 273 SET(max_peerlist_size, 3000, nullptr), 274 SET(max_paused_peerlist_size, 1000, nullptr), 275 SET(min_announce_interval, 5 * 60, nullptr), 276 SET(auto_manage_startup, 60, nullptr), 277 SET(seeding_piece_quota, 20, nullptr), 278 // TODO: deprecate this 279 SET(max_rejects, 50, nullptr), 280 SET(recv_socket_buffer_size, 0, &session_impl::update_socket_buffer_size), 281 SET(send_socket_buffer_size, 0, &session_impl::update_socket_buffer_size), 282 SET(max_peer_recv_buffer_size, 2 * 1024 * 1024, nullptr), 283 DEPRECATED_SET(file_checks_delay_per_block, 0, nullptr), 284 SET(read_cache_line_size, 32, nullptr), 285 SET(write_cache_line_size, 16, nullptr), 286 SET(optimistic_disk_retry, 10 * 60, nullptr), 287 SET(max_suggest_pieces, 16, nullptr), 288 SET(local_service_announce_interval, 5 * 60, nullptr), 289 SET(dht_announce_interval, 15 * 60, &session_impl::update_dht_announce_interval), 290 SET(udp_tracker_token_expiry, 60, nullptr), 291 DEPRECATED_SET(default_cache_min_age, 1, nullptr), 292 SET(num_optimistic_unchoke_slots, 0, nullptr), 293 SET(default_est_reciprocation_rate, 16000, nullptr), 294 SET(increase_est_reciprocation_rate, 20, nullptr), 295 SET(decrease_est_reciprocation_rate, 3, nullptr), 296 SET(max_pex_peers, 50, nullptr), 297 SET(tick_interval, 500, nullptr), 298 SET(share_mode_target, 3, nullptr), 299 SET(upload_rate_limit, 0, &session_impl::update_upload_rate), 300 SET(download_rate_limit, 0, &session_impl::update_download_rate), 301 DEPRECATED_SET(local_upload_rate_limit, 0, &session_impl::update_local_upload_rate), 302 DEPRECATED_SET(local_download_rate_limit, 0, &session_impl::update_local_download_rate), 303 SET(dht_upload_rate_limit, 8000, &session_impl::update_dht_upload_rate_limit), 304 SET(unchoke_slots_limit, 8, &session_impl::update_unchoke_limit), 305 DEPRECATED_SET(half_open_limit, 0, nullptr), 306 SET(connections_limit, 200, &session_impl::update_connections_limit), 307 SET(connections_slack, 10, nullptr), 308 SET(utp_target_delay, 100, nullptr), 309 SET(utp_gain_factor, 3000, nullptr), 310 SET(utp_min_timeout, 500, nullptr), 311 SET(utp_syn_resends, 2, nullptr), 312 SET(utp_fin_resends, 2, nullptr), 313 SET(utp_num_resends, 3, nullptr), 314 SET(utp_connect_timeout, 3000, nullptr), 315 SET(utp_delayed_ack, 0, nullptr), 316 SET(utp_loss_multiplier, 50, nullptr), 317 SET(mixed_mode_algorithm, settings_pack::peer_proportional, nullptr), 318 SET(listen_queue_size, 5, nullptr), 319 SET(torrent_connect_boost, 30, nullptr), 320 SET(alert_queue_size, 1000, &session_impl::update_alert_queue_size), 321 SET(max_metadata_size, 3 * 1024 * 10240, nullptr), 322 DEPRECATED_SET(hashing_threads, 1, nullptr), 323 SET(checking_mem_usage, 1024, nullptr), 324 SET(predictive_piece_announce, 0, nullptr), 325 SET(aio_threads, 4, &session_impl::update_disk_threads), 326 DEPRECATED_SET(aio_max, 300, nullptr), 327 DEPRECATED_SET(network_threads, 0, nullptr), 328 DEPRECATED_SET(ssl_listen, 0, &session_impl::update_ssl_listen), 329 SET(tracker_backoff, 250, nullptr), 330 SET(share_ratio_limit, 200, nullptr), 331 SET(seed_time_ratio_limit, 700, nullptr), 332 SET(peer_turnover, 4, nullptr), 333 SET(peer_turnover_cutoff, 90, nullptr), 334 SET(peer_turnover_interval, 300, nullptr), 335 SET(connect_seed_every_n_download, 10, nullptr), 336 SET(max_http_recv_buffer_size, 4*1024*204, nullptr), 337 SET(max_retry_port_bind, 10, nullptr), 338 SET(alert_mask, int(static_cast<std::uint32_t>(alert_category::error)), &session_impl::update_alert_mask), 339 SET(out_enc_policy, settings_pack::pe_enabled, nullptr), 340 SET(in_enc_policy, settings_pack::pe_enabled, nullptr), 341 SET(allowed_enc_level, settings_pack::pe_both, nullptr), 342 SET(inactive_down_rate, 2048, nullptr), 343 SET(inactive_up_rate, 2048, nullptr), 344 SET(proxy_type, settings_pack::none, &session_impl::update_proxy), 345 SET(proxy_port, 0, &session_impl::update_proxy), 346 SET(i2p_port, 0, &session_impl::update_i2p_bridge), 347 SET(cache_size_volatile, 256, nullptr), 348 SET(urlseed_max_request_bytes, 16 * 1024 * 1024, nullptr), 349 SET(web_seed_name_lookup_retry, 1800, nullptr), 350 SET(close_file_interval, CLOSE_FILE_INTERVAL, nullptr), 351 SET(utp_cwnd_reduce_timer, 100, nullptr), 352 SET(max_web_seed_connections, 3, nullptr), 353 SET(resolver_cache_timeout, 1200, &session_impl::update_resolver_cache_timeout), 354 SET(send_not_sent_low_watermark, 16384, nullptr), 355 SET(rate_choker_initial_threshold, 1024, nullptr), 356 SET(upnp_lease_duration, 3600, nullptr), 357 SET(max_concurrent_http_announces, 50, nullptr), 358 }}); 359 360 #undef SET 361 #undef DEPRECATED_SET 362 363 } // anonymous namespace 364 setting_by_name(string_view const key)365 int setting_by_name(string_view const key) 366 { 367 for (int k = 0; k < str_settings.end_index(); ++k) 368 { 369 if (key != str_settings[k].name) continue; 370 return settings_pack::string_type_base + k; 371 } 372 for (int k = 0; k < int_settings.end_index(); ++k) 373 { 374 if (key != int_settings[k].name) continue; 375 return settings_pack::int_type_base + k; 376 } 377 for (int k = 0; k < bool_settings.end_index(); ++k) 378 { 379 if (key != bool_settings[k].name) continue; 380 return settings_pack::bool_type_base + k; 381 } 382 return -1; 383 } 384 name_for_setting(int s)385 char const* name_for_setting(int s) 386 { 387 switch (s & settings_pack::type_mask) 388 { 389 case settings_pack::string_type_base: 390 return str_settings[s - settings_pack::string_type_base].name; 391 case settings_pack::int_type_base: 392 return int_settings[s - settings_pack::int_type_base].name; 393 case settings_pack::bool_type_base: 394 return bool_settings[s - settings_pack::bool_type_base].name; 395 } 396 return ""; 397 } 398 load_pack_from_dict(bdecode_node const & settings)399 settings_pack load_pack_from_dict(bdecode_node const& settings) 400 { 401 settings_pack pack; 402 403 for (int i = 0; i < settings.dict_size(); ++i) 404 { 405 string_view key; 406 bdecode_node val; 407 std::tie(key, val) = settings.dict_at(i); 408 switch (val.type()) 409 { 410 case bdecode_node::dict_t: 411 case bdecode_node::list_t: 412 continue; 413 case bdecode_node::int_t: 414 { 415 bool found = false; 416 for (int k = 0; k < int_settings.end_index(); ++k) 417 { 418 if (key != int_settings[k].name) continue; 419 pack.set_int(settings_pack::int_type_base | k, int(val.int_value())); 420 found = true; 421 break; 422 } 423 if (found) continue; 424 for (int k = 0; k < bool_settings.end_index(); ++k) 425 { 426 if (key != bool_settings[k].name) continue; 427 pack.set_bool(settings_pack::bool_type_base | k, val.int_value() != 0); 428 break; 429 } 430 } 431 break; 432 case bdecode_node::string_t: 433 for (int k = 0; k < str_settings.end_index(); ++k) 434 { 435 if (key != str_settings[k].name) continue; 436 pack.set_str(settings_pack::string_type_base + k, val.string_value().to_string()); 437 break; 438 } 439 break; 440 case bdecode_node::none_t: 441 break; 442 } 443 } 444 return pack; 445 } 446 save_settings_to_dict(aux::session_settings const & sett,entry::dictionary_type & out)447 void save_settings_to_dict(aux::session_settings const& sett, entry::dictionary_type& out) 448 { 449 sett.bulk_get([&out](aux::session_settings_single_thread const& s) 450 { 451 // loop over all settings that differ from default 452 for (int i = 0; i < settings_pack::num_string_settings; ++i) 453 { 454 if (ensure_string(str_settings[i].default_value) == s.get_str(i | settings_pack::string_type_base)) continue; 455 out[str_settings[i].name] = s.get_str(i | settings_pack::string_type_base); 456 } 457 458 for (int i = 0; i < settings_pack::num_int_settings; ++i) 459 { 460 if (int_settings[i].default_value == s.get_int(i | settings_pack::int_type_base)) continue; 461 out[int_settings[i].name] = s.get_int(i | settings_pack::int_type_base); 462 } 463 464 for (int i = 0; i < settings_pack::num_bool_settings; ++i) 465 { 466 if (bool_settings[i].default_value == s.get_bool(i | settings_pack::bool_type_base)) continue; 467 out[bool_settings[i].name] = s.get_bool(i | settings_pack::bool_type_base); 468 } 469 }); 470 } 471 run_all_updates(aux::session_impl & ses)472 void run_all_updates(aux::session_impl& ses) 473 { 474 using fun_t = void (aux::session_impl::*)(); 475 for (int i = 0; i < settings_pack::num_string_settings; ++i) 476 { 477 fun_t const& f = str_settings[i].fun; 478 if (f) (ses.*f)(); 479 } 480 481 for (int i = 0; i < settings_pack::num_int_settings; ++i) 482 { 483 fun_t const& f = int_settings[i].fun; 484 if (f) (ses.*f)(); 485 } 486 487 for (int i = 0; i < settings_pack::num_bool_settings; ++i) 488 { 489 fun_t const& f = bool_settings[i].fun; 490 if (f) (ses.*f)(); 491 } 492 } 493 initialize_default_settings(aux::session_settings_single_thread & s)494 void initialize_default_settings(aux::session_settings_single_thread& s) 495 { 496 for (int i = 0; i < settings_pack::num_string_settings; ++i) 497 { 498 if (str_settings[i].default_value == nullptr) continue; 499 s.set_str(settings_pack::string_type_base | i, str_settings[i].default_value); 500 TORRENT_ASSERT(s.get_str(settings_pack::string_type_base + i) == str_settings[i].default_value); 501 } 502 503 for (int i = 0; i < settings_pack::num_int_settings; ++i) 504 { 505 s.set_int(settings_pack::int_type_base | i, int_settings[i].default_value); 506 TORRENT_ASSERT(s.get_int(settings_pack::int_type_base + i) == int_settings[i].default_value); 507 } 508 509 for (int i = 0; i < settings_pack::num_bool_settings; ++i) 510 { 511 s.set_bool(settings_pack::bool_type_base | i, bool_settings[i].default_value); 512 TORRENT_ASSERT(s.get_bool(settings_pack::bool_type_base + i) == bool_settings[i].default_value); 513 } 514 } 515 default_settings()516 settings_pack default_settings() 517 { 518 settings_pack ret; 519 // TODO: it would be nice to reserve() these vectors up front 520 for (int i = 0; i < settings_pack::num_string_settings; ++i) 521 { 522 if (str_settings[i].default_value == nullptr) continue; 523 ret.set_str(settings_pack::string_type_base + i, str_settings[i].default_value); 524 } 525 526 for (int i = 0; i < settings_pack::num_int_settings; ++i) 527 { 528 ret.set_int(settings_pack::int_type_base + i, int_settings[i].default_value); 529 } 530 531 for (int i = 0; i < settings_pack::num_bool_settings; ++i) 532 { 533 ret.set_bool(settings_pack::bool_type_base + i, bool_settings[i].default_value); 534 } 535 return ret; 536 } 537 default_int_value(int const name)538 int default_int_value(int const name) 539 { 540 TORRENT_ASSERT((name & settings_pack::type_mask) == settings_pack::int_type_base); 541 return int_settings[name - settings_pack::int_type_base].default_value; 542 } 543 apply_pack(settings_pack const * pack,aux::session_settings & sett,aux::session_impl * ses)544 void apply_pack(settings_pack const* pack, aux::session_settings& sett 545 , aux::session_impl* ses) 546 { 547 using fun_t = void (aux::session_impl::*)(); 548 std::vector<fun_t> callbacks; 549 550 sett.bulk_set([&](aux::session_settings_single_thread& s) 551 { 552 apply_pack_impl(pack, s, ses ? &callbacks : nullptr); 553 }); 554 555 // call the callbacks once all the settings have been applied, and 556 // only once per callback 557 for (auto const& f : callbacks) 558 { 559 (ses->*f)(); 560 } 561 } 562 apply_pack_impl(settings_pack const * pack,aux::session_settings_single_thread & sett,std::vector<void (aux::session_impl::*)()> * callbacks)563 void apply_pack_impl(settings_pack const* pack, aux::session_settings_single_thread& sett 564 , std::vector<void(aux::session_impl::*)()>* callbacks) 565 { 566 for (auto const& p : pack->m_strings) 567 { 568 // disregard setting indices that are not string types 569 if ((p.first & settings_pack::type_mask) != settings_pack::string_type_base) 570 continue; 571 572 // ignore settings that are out of bounds 573 int const index = p.first & settings_pack::index_mask; 574 TORRENT_ASSERT_PRECOND(index >= 0 && index < settings_pack::num_string_settings); 575 if (index < 0 || index >= settings_pack::num_string_settings) 576 continue; 577 578 // if the value did not change, don't call the update callback 579 if (sett.get_str(p.first) == p.second) continue; 580 581 sett.set_str(p.first, p.second); 582 str_setting_entry_t const& sa = str_settings[index]; 583 584 if (sa.fun && callbacks 585 && std::find(callbacks->begin(), callbacks->end(), sa.fun) == callbacks->end()) 586 callbacks->push_back(sa.fun); 587 } 588 589 for (auto const& p : pack->m_ints) 590 { 591 // disregard setting indices that are not int types 592 if ((p.first & settings_pack::type_mask) != settings_pack::int_type_base) 593 continue; 594 595 // ignore settings that are out of bounds 596 int const index = p.first & settings_pack::index_mask; 597 TORRENT_ASSERT_PRECOND(index >= 0 && index < settings_pack::num_int_settings); 598 if (index < 0 || index >= settings_pack::num_int_settings) 599 continue; 600 601 // if the value did not change, don't call the update callback 602 if (sett.get_int(p.first) == p.second) continue; 603 604 sett.set_int(p.first, p.second); 605 int_setting_entry_t const& sa = int_settings[index]; 606 if (sa.fun && callbacks 607 && std::find(callbacks->begin(), callbacks->end(), sa.fun) == callbacks->end()) 608 callbacks->push_back(sa.fun); 609 } 610 611 for (auto const& p : pack->m_bools) 612 { 613 // disregard setting indices that are not bool types 614 if ((p.first & settings_pack::type_mask) != settings_pack::bool_type_base) 615 continue; 616 617 // ignore settings that are out of bounds 618 int const index = p.first & settings_pack::index_mask; 619 TORRENT_ASSERT_PRECOND(index >= 0 && index < settings_pack::num_bool_settings); 620 if (index < 0 || index >= settings_pack::num_bool_settings) 621 continue; 622 623 // if the value did not change, don't call the update callback 624 if (sett.get_bool(p.first) == p.second) continue; 625 626 sett.set_bool(p.first, p.second); 627 bool_setting_entry_t const& sa = bool_settings[index]; 628 if (sa.fun && callbacks 629 && std::find(callbacks->begin(), callbacks->end(), sa.fun) == callbacks->end()) 630 callbacks->push_back(sa.fun); 631 } 632 } 633 set_str(int const name,std::string val)634 void settings_pack::set_str(int const name, std::string val) 635 { 636 TORRENT_ASSERT((name & type_mask) == string_type_base); 637 if ((name & type_mask) != string_type_base) return; 638 std::pair<std::uint16_t, std::string> v(aux::numeric_cast<std::uint16_t>(name), std::move(val)); 639 insort_replace(m_strings, std::move(v)); 640 } 641 set_int(int const name,int const val)642 void settings_pack::set_int(int const name, int const val) 643 { 644 TORRENT_ASSERT((name & type_mask) == int_type_base); 645 if ((name & type_mask) != int_type_base) return; 646 std::pair<std::uint16_t, int> v(aux::numeric_cast<std::uint16_t>(name), val); 647 insort_replace(m_ints, v); 648 } 649 set_bool(int const name,bool const val)650 void settings_pack::set_bool(int const name, bool const val) 651 { 652 TORRENT_ASSERT((name & type_mask) == bool_type_base); 653 if ((name & type_mask) != bool_type_base) return; 654 std::pair<std::uint16_t, bool> v(aux::numeric_cast<std::uint16_t>(name), val); 655 insort_replace(m_bools, v); 656 } 657 has_val(int const name) const658 bool settings_pack::has_val(int const name) const 659 { 660 switch (name & type_mask) 661 { 662 case string_type_base: 663 { 664 // this is an optimization. If the settings pack is complete, 665 // i.e. has every key, we don't need to search, it's just a lookup 666 if (m_strings.size() == settings_pack::num_string_settings) 667 return true; 668 std::pair<std::uint16_t, std::string> v(aux::numeric_cast<std::uint16_t>(name), std::string()); 669 auto i = std::lower_bound(m_strings.begin(), m_strings.end(), v 670 , &compare_first<std::string>); 671 return i != m_strings.end() && i->first == name; 672 } 673 case int_type_base: 674 { 675 // this is an optimization. If the settings pack is complete, 676 // i.e. has every key, we don't need to search, it's just a lookup 677 if (m_ints.size() == settings_pack::num_int_settings) 678 return true; 679 std::pair<std::uint16_t, int> v(aux::numeric_cast<std::uint16_t>(name), 0); 680 auto i = std::lower_bound(m_ints.begin(), m_ints.end(), v 681 , &compare_first<int>); 682 return i != m_ints.end() && i->first == name; 683 } 684 case bool_type_base: 685 { 686 // this is an optimization. If the settings pack is complete, 687 // i.e. has every key, we don't need to search, it's just a lookup 688 if (m_bools.size() == settings_pack::num_bool_settings) 689 return true; 690 std::pair<std::uint16_t, bool> v(aux::numeric_cast<std::uint16_t>(name), false); 691 auto i = std::lower_bound(m_bools.begin(), m_bools.end(), v 692 , &compare_first<bool>); 693 return i != m_bools.end() && i->first == name; 694 } 695 } 696 TORRENT_ASSERT_FAIL(); 697 return false; 698 } 699 get_str(int name) const700 std::string const& settings_pack::get_str(int name) const 701 { 702 static std::string const empty; 703 TORRENT_ASSERT((name & type_mask) == string_type_base); 704 if ((name & type_mask) != string_type_base) return empty; 705 706 // this is an optimization. If the settings pack is complete, 707 // i.e. has every key, we don't need to search, it's just a lookup 708 if (m_strings.size() == settings_pack::num_string_settings) 709 { 710 TORRENT_ASSERT(m_strings[name & index_mask].first == name); 711 return m_strings[name & index_mask].second; 712 } 713 std::pair<std::uint16_t, std::string> v(aux::numeric_cast<std::uint16_t>(name), std::string()); 714 auto i = std::lower_bound(m_strings.begin(), m_strings.end(), v 715 , &compare_first<std::string>); 716 if (i != m_strings.end() && i->first == name) return i->second; 717 return empty; 718 } 719 get_int(int name) const720 int settings_pack::get_int(int name) const 721 { 722 TORRENT_ASSERT((name & type_mask) == int_type_base); 723 if ((name & type_mask) != int_type_base) return 0; 724 725 // this is an optimization. If the settings pack is complete, 726 // i.e. has every key, we don't need to search, it's just a lookup 727 if (m_ints.size() == settings_pack::num_int_settings) 728 { 729 TORRENT_ASSERT(m_ints[name & index_mask].first == name); 730 return m_ints[name & index_mask].second; 731 } 732 std::pair<std::uint16_t, int> v(aux::numeric_cast<std::uint16_t>(name), 0); 733 auto i = std::lower_bound(m_ints.begin(), m_ints.end(), v 734 , &compare_first<int>); 735 if (i != m_ints.end() && i->first == name) return i->second; 736 return 0; 737 } 738 get_bool(int name) const739 bool settings_pack::get_bool(int name) const 740 { 741 TORRENT_ASSERT((name & type_mask) == bool_type_base); 742 if ((name & type_mask) != bool_type_base) return false; 743 744 // this is an optimization. If the settings pack is complete, 745 // i.e. has every key, we don't need to search, it's just a lookup 746 if (m_bools.size() == settings_pack::num_bool_settings) 747 { 748 TORRENT_ASSERT(m_bools[name & index_mask].first == name); 749 return m_bools[name & index_mask].second; 750 } 751 std::pair<std::uint16_t, bool> v(aux::numeric_cast<std::uint16_t>(name), false); 752 auto i = std::lower_bound(m_bools.begin(), m_bools.end(), v 753 , &compare_first<bool>); 754 if (i != m_bools.end() && i->first == name) return i->second; 755 return false; 756 } 757 clear()758 void settings_pack::clear() 759 { 760 m_strings.clear(); 761 m_ints.clear(); 762 m_bools.clear(); 763 } 764 clear(int const name)765 void settings_pack::clear(int const name) 766 { 767 switch (name & type_mask) 768 { 769 case string_type_base: 770 { 771 std::pair<std::uint16_t, std::string> v(aux::numeric_cast<std::uint16_t>(name), std::string()); 772 auto const i = std::lower_bound(m_strings.begin(), m_strings.end() 773 , v, &compare_first<std::string>); 774 if (i != m_strings.end() && i->first == name) m_strings.erase(i); 775 break; 776 } 777 case int_type_base: 778 { 779 std::pair<std::uint16_t, int> v(aux::numeric_cast<std::uint16_t>(name), 0); 780 auto const i = std::lower_bound(m_ints.begin(), m_ints.end() 781 , v, &compare_first<int>); 782 if (i != m_ints.end() && i->first == name) m_ints.erase(i); 783 break; 784 } 785 case bool_type_base: 786 { 787 std::pair<std::uint16_t, bool> v(aux::numeric_cast<std::uint16_t>(name), false); 788 auto const i = std::lower_bound(m_bools.begin(), m_bools.end() 789 , v, &compare_first<bool>); 790 if (i != m_bools.end() && i->first == name) m_bools.erase(i); 791 break; 792 } 793 } 794 } 795 } 796