From 71f5510d627da5518bdc710d3e6589eb7c0a7d83 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Sat, 6 Aug 2016 13:18:48 -0400 Subject: [PATCH] =?UTF-8?q?make=20the=20random=20function=20produce=20prop?= =?UTF-8?q?er=20random=20distributions,=20based=20o=E2=80=A6=20(#981)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit make the random function produce proper random distributions, based on uniform_int_distribution of C++11. also clean up piece_picker's priority_range to return two results instead of taking pointers to out-parameters. fix recent pe-crypto regression exposed by this change --- include/libtorrent/bt_peer_connection.hpp | 8 --- include/libtorrent/entry.hpp | 2 +- include/libtorrent/pe_crypto.hpp | 2 + include/libtorrent/piece_picker.hpp | 2 +- include/libtorrent/random.hpp | 4 +- simulation/setup_dht.cpp | 8 +-- simulation/test_dht.cpp | 4 +- src/bt_peer_connection.cpp | 62 +++++++++++++---------- src/ip_voter.cpp | 3 +- src/kademlia/dht_storage.cpp | 33 ++++++++---- src/kademlia/node.cpp | 6 +-- src/kademlia/node_id.cpp | 16 +++--- src/kademlia/rpc_manager.cpp | 2 +- src/kademlia/traversal_algorithm.cpp | 6 +-- src/lsd.cpp | 2 +- src/pe_crypto.cpp | 19 ++++++- src/peer_list.cpp | 4 +- src/piece_picker.cpp | 36 ++++++------- src/random.cpp | 18 +++---- src/session_impl.cpp | 2 +- src/smart_ban.cpp | 2 +- src/string_util.cpp | 2 +- src/torrent.cpp | 8 +-- src/udp_tracker_connection.cpp | 4 +- src/upnp.cpp | 2 +- src/ut_metadata.cpp | 2 +- src/utp_socket_manager.cpp | 2 +- src/utp_stream.cpp | 6 +-- test/main.cpp | 4 +- test/setup_transfer.cpp | 10 ++-- test/swarm_suite.cpp | 2 +- test/test_dht_storage.cpp | 4 +- test/test_privacy.cpp | 4 +- test/test_random.cpp | 2 +- test/test_read_resume.cpp | 2 +- test/test_resume.cpp | 2 +- 36 files changed, 163 insertions(+), 134 deletions(-) diff --git a/include/libtorrent/bt_peer_connection.hpp b/include/libtorrent/bt_peer_connection.hpp index d1aabeb1d..4bb53f348 100644 --- a/include/libtorrent/bt_peer_connection.hpp +++ b/include/libtorrent/bt_peer_connection.hpp @@ -324,14 +324,6 @@ private: read_packet }; -#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS) - enum - { - handshake_len = 68, - dh_key_len = 96 - }; -#endif - // state of on_receive. one of the enums in state_t std::uint8_t m_state; diff --git a/include/libtorrent/entry.hpp b/include/libtorrent/entry.hpp index 3755646a9..d1225afb0 100644 --- a/include/libtorrent/entry.hpp +++ b/include/libtorrent/entry.hpp @@ -94,7 +94,7 @@ namespace libtorrent // to a list). The definition doesn't mention such a limit though. typedef std::map dictionary_type; typedef std::string string_type; - typedef std::list list_type; + typedef std::vector list_type; typedef std::int64_t integer_type; typedef std::vector preformatted_type; diff --git a/include/libtorrent/pe_crypto.hpp b/include/libtorrent/pe_crypto.hpp index 933ffd46d..d01d6ecda 100644 --- a/include/libtorrent/pe_crypto.hpp +++ b/include/libtorrent/pe_crypto.hpp @@ -58,6 +58,8 @@ namespace libtorrent using key_t = mp::number>; + std::array export_key(key_t const& k); + // RC4 state from libtomcrypt struct rc4 { int x, y; diff --git a/include/libtorrent/piece_picker.hpp b/include/libtorrent/piece_picker.hpp index 1dec06e55..39548d5ce 100644 --- a/include/libtorrent/piece_picker.hpp +++ b/include/libtorrent/piece_picker.hpp @@ -716,7 +716,7 @@ namespace libtorrent // fills in the range [start, end) of pieces in // m_pieces that have priority 'prio' - void priority_range(int prio, int* start, int* end); + std::pair priority_range(int prio); // adds the piece 'index' to m_pieces void add(int index); diff --git a/include/libtorrent/random.hpp b/include/libtorrent/random.hpp index 0f66e103f..6bb8c5736 100644 --- a/include/libtorrent/random.hpp +++ b/include/libtorrent/random.hpp @@ -35,6 +35,6 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { - std::uint32_t TORRENT_EXTRA_EXPORT random(); - std::uint32_t TORRENT_EXTRA_EXPORT randint(int i); + std::uint32_t TORRENT_EXTRA_EXPORT random(std::uint32_t max); + std::uint32_t TORRENT_EXTRA_EXPORT randint(std::uint32_t one_past_end); } diff --git a/simulation/setup_dht.cpp b/simulation/setup_dht.cpp index 9563d5561..a6568d68f 100644 --- a/simulation/setup_dht.cpp +++ b/simulation/setup_dht.cpp @@ -61,13 +61,13 @@ namespace { // this is the IP address assigned to node 'idx' asio::ip::address addr_from_int(int /* idx */) { - return asio::ip::address_v4(lt::random()); + return rand_v4(); } asio::ip::address addr6_from_int(int /* idx */) { asio::ip::address_v6::bytes_type bytes; - for (uint8_t& b : bytes) b = uint8_t(lt::random()); + for (uint8_t& b : bytes) b = uint8_t(lt::random(0xff)); return asio::ip::address_v6(bytes); } @@ -217,7 +217,7 @@ struct dht_node final : lt::dht::udp_socket_interface // there are no more slots in this bucket, just move ont if (nodes_per_bucket[bucket] == 0) continue; --nodes_per_bucket[bucket]; - bool const added = dht().m_table.node_seen(n.first, n.second, (lt::random() % 300) + 10); + bool const added = dht().m_table.node_seen(n.first, n.second, lt::random(300) + 10); TEST_CHECK(added); if (m_add_dead_nodes) { @@ -226,7 +226,7 @@ struct dht_node final : lt::dht::udp_socket_interface dht::node_id target = dht::generate_random_id() & ~mask; target |= id & mask; dht().m_table.node_seen(target, rand_udp_ep(m_ipv6 ? rand_v6 : rand_v4) - , (lt::random() % 300) + 10); + , lt::random(300) + 10); } } /* diff --git a/simulation/test_dht.cpp b/simulation/test_dht.cpp index b7235af5d..97a669289 100644 --- a/simulation/test_dht.cpp +++ b/simulation/test_dht.cpp @@ -143,8 +143,8 @@ TORRENT_TEST(dht_bootstrap) { ses.post_session_stats(); std::printf("depth: %d nodes: %d\n", routing_table_depth, num_nodes); - TEST_CHECK(routing_table_depth >= 9); - TEST_CHECK(num_nodes >= 115); + TEST_CHECK(routing_table_depth >= 8); + TEST_CHECK(num_nodes >= 110); dht.stop(); return true; } diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index 8687edcc1..93ae0f336 100644 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -42,12 +42,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #include -// for backwards compatibility with boost < 1.60 which was before export_bits -// and import_bits were introduced -#if BOOST_VERSION < 106000 -#include "libtorrent/aux_/cppint_import_export.hpp" -#endif - #include "libtorrent/aux_/disable_warnings_pop.hpp" #ifndef TORRENT_DISABLE_LOGGING @@ -88,6 +82,12 @@ namespace libtorrent #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS) namespace { + enum + { + handshake_len = 68, + dh_key_len = 96 + }; + // stream key (info hash of attached torrent) // secret is the DH shared secret // initializes m_enc_handler @@ -102,8 +102,7 @@ namespace libtorrent // outgoing connection : hash ('keyA',S,SKEY) // incoming connection : hash ('keyB',S,SKEY) - std::array secret_buf; - mp::export_bits(secret, reinterpret_cast(secret_buf.data()), 8); + std::array const secret_buf = export_key(secret); if (outgoing) h.update(keyA); else h.update(keyB); h.update(secret_buf); @@ -486,8 +485,7 @@ namespace libtorrent #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS) namespace { - char random_byte() - { return random() & 0xff; } + char random_byte() { return random(0xff); } } void bt_peer_connection::write_pe1_2_dhkey() @@ -511,7 +509,7 @@ namespace libtorrent return; } - int const pad_size = random() % 512; + int const pad_size = random(512); #ifndef TORRENT_DISABLE_LOGGING peer_log(peer_log_alert::info, "ENCRYPTION", "pad size: %d", pad_size); @@ -521,8 +519,8 @@ namespace libtorrent char* ptr = msg; int const buf_size = dh_key_len + pad_size; - mp::export_bits(m_dh_key_exchange->get_local_key() - , reinterpret_cast(ptr), 8); + std::array const local_key = export_key(m_dh_key_exchange->get_local_key()); + memcpy(ptr, local_key.data(), dh_key_len); ptr += dh_key_len; std::generate(ptr, ptr + pad_size, random_byte); @@ -548,10 +546,9 @@ namespace libtorrent hasher h; sha1_hash const& info_hash = t->torrent_file().info_hash(); key_t const secret_key = m_dh_key_exchange->get_secret(); - std::array secret; - mp::export_bits(secret_key, reinterpret_cast(secret.data()), 8); + std::array const secret = export_key(secret_key); - int pad_size = random() % 512; + int const pad_size = random(512); // synchash,skeyhash,vc,crypto_provide,len(pad),pad,len(ia) char msg[20 + 20 + 8 + 4 + 2 + 512 + 2]; @@ -566,6 +563,12 @@ namespace libtorrent std::memcpy(ptr, sync_hash.data(), 20); ptr += 20; +#ifndef TORRENT_DISABLE_LOGGING + peer_log(peer_log_alert::info, "ENCRYPTION" + , "writing synchash %s secret: %s" + , aux::to_hex(sync_hash).c_str() + , aux::to_hex(secret).c_str()); +#endif static char const req2[4] = {'r', 'e', 'q', '2'}; // stream key obfuscated hash [ hash('req2',SKEY) xor hash('req3',S) ] @@ -591,13 +594,13 @@ namespace libtorrent m_dh_key_exchange.reset(); // secret should be invalid at this point // write the verification constant and crypto field - int encrypt_size = sizeof(msg) - 512 + pad_size - 40; - - std::uint8_t crypto_provide = m_settings.get_int(settings_pack::allowed_enc_level); + int const encrypt_size = sizeof(msg) - 512 + pad_size - 40; // this is an invalid setting, but let's just make the best of the situation - if ((crypto_provide & settings_pack::pe_both) == 0) - crypto_provide = settings_pack::pe_both; + int const enc_level = m_settings.get_int(settings_pack::allowed_enc_level); + std::uint8_t const crypto_provide = ((enc_level & settings_pack::pe_both) == 0) + ? settings_pack::pe_both + : enc_level; #ifndef TORRENT_DISABLE_LOGGING char const* level[] = {"plaintext", "rc4", "plaintext rc4"}; @@ -621,7 +624,7 @@ namespace libtorrent TORRENT_ASSERT(crypto_select == 0x02 || crypto_select == 0x01); TORRENT_ASSERT(!m_sent_handshake); - int const pad_size = random() % 512; + int const pad_size = random(512); int const buf_size = 8 + 4 + 2 + pad_size; char msg[512 + 8 + 4 + 2]; @@ -669,7 +672,6 @@ namespace libtorrent detail::write_uint32(crypto_field, write_buf); detail::write_uint16(pad_size, write_buf); // len (pad) - // fill pad with zeroes std::generate(write_buf, write_buf + pad_size, random_byte); write_buf += pad_size; @@ -678,6 +680,7 @@ namespace libtorrent detail::write_uint16(handshake_len, write_buf); // len(IA) } + // TODO: 3 use span instead of (pointer,len) pairs int bt_peer_connection::get_syncoffset(char const* src, int const src_size , char const* target, int const target_size) const { @@ -809,7 +812,7 @@ namespace libtorrent // in anonymous mode, every peer connection // has a unique peer-id for (int i = 0; i < 20; ++i) - m_our_peer_id[i] = random() & 0xff; + m_our_peer_id[i] = random(0xff); } std::memcpy(ptr, m_our_peer_id.data(), 20); @@ -2637,12 +2640,17 @@ namespace libtorrent static char const req1[4] = {'r', 'e', 'q', '1'}; // compute synchash (hash('req1',S)) - std::array buffer; - mp::export_bits(m_dh_key_exchange->get_secret() - , reinterpret_cast(buffer.data()), 8); + std::array const buffer = export_key(m_dh_key_exchange->get_secret()); hasher h(req1); h.update(buffer); m_sync_hash.reset(new sha1_hash(h.final())); + +#ifndef TORRENT_DISABLE_LOGGING + peer_log(peer_log_alert::info, "ENCRYPTION" + , "looking for synchash %s secret: %s" + , aux::to_hex(*m_sync_hash).c_str() + , aux::to_hex(buffer).c_str()); +#endif } int const syncoffset = get_syncoffset(m_sync_hash->data(), 20 diff --git a/src/ip_voter.cpp b/src/ip_voter.cpp index c5bec1f2f..d807d4e8b 100644 --- a/src/ip_voter.cpp +++ b/src/ip_voter.cpp @@ -125,8 +125,7 @@ namespace libtorrent if (m_external_addresses.size() > 40) { - if (random() % 100 < 50) - return maybe_rotate(); + if (random(1)) return maybe_rotate(); // use stable sort here to maintain the fifo-order // of the entries with the same number of votes diff --git a/src/kademlia/dht_storage.cpp b/src/kademlia/dht_storage.cpp index bcaa589af..4cd7e3af7 100644 --- a/src/kademlia/dht_storage.cpp +++ b/src/kademlia/dht_storage.cpp @@ -236,20 +236,35 @@ namespace // max_peers_reply should probably be specified in bytes if (!v.peers.empty() && v.peers.begin()->addr.protocol() == tcp::v6()) max /= 4; - int num = (std::min)(int(v.peers.size()), max); + // we're picking "to_pick" from a list of "num" at random. + int const to_pick = (std::min)(int(v.peers.size()), max); std::set::const_iterator iter = v.peers.begin(); entry::list_type& pe = peers["values"].list(); - std::string endpoint; - for (int t = 0, m = 0; m < num && iter != v.peers.end(); ++iter, ++t) + for (int t = 0, m = 0; m < to_pick && iter != v.peers.end(); ++iter) { - if ((random() / float(UINT_MAX + 1.f)) * (num - t) >= num - m) continue; + // if the node asking for peers is a seed, skip seeds from the + // peer list if (noseed && iter->seed) continue; - endpoint.resize(18); - std::string::iterator out = endpoint.begin(); + + ++t; + std::string* str; + if (t <= to_pick) + { + pe.push_back(entry()); + str = &pe.back().string(); + } + else + { + // maybe replace an item we've already picked + if (random(t-1) >= to_pick) continue; + str = &pe[random(to_pick - 1)].string(); + } + + str->resize(18); + std::string::iterator out = str->begin(); write_endpoint(iter->addr, out); - endpoint.resize(out - endpoint.begin()); - pe.push_back(entry(endpoint)); + str->resize(out - str->begin()); ++m; } @@ -316,7 +331,7 @@ namespace { // when we're at capacity, there's a 50/50 chance of dropping the // announcing peer or an existing peer - if (random() & 1) return; + if (random(1)) return; i = v->peers.lower_bound(peer); if (i == v->peers.end()) --i; v->peers.erase(i++); diff --git a/src/kademlia/node.cpp b/src/kademlia/node.cpp index fdf47d47d..8623dbf45 100644 --- a/src/kademlia/node.cpp +++ b/src/kademlia/node.cpp @@ -117,8 +117,8 @@ node::node(udp proto, udp_socket_interface* sock , m_counters(cnt) , m_storage(storage) { - m_secret[0] = random(); - m_secret[1] = random(); + m_secret[0] = random(0xffffffff); + m_secret[1] = random(0xffffffff); } node::~node() = default; @@ -242,7 +242,7 @@ int node::bucket_size(int bucket) void node::new_write_key() { m_secret[1] = m_secret[0]; - m_secret[0] = random(); + m_secret[0] = random(0xffffffff); } void node::unreachable(udp::endpoint const& ep) diff --git a/src/kademlia/node_id.cpp b/src/kademlia/node_id.cpp index 987f35758..dd75b5d85 100644 --- a/src/kademlia/node_id.cpp +++ b/src/kademlia/node_id.cpp @@ -132,9 +132,9 @@ node_id generate_id_impl(address const& ip_, std::uint32_t r) id[0] = (c >> 24) & 0xff; id[1] = (c >> 16) & 0xff; - id[2] = ((c >> 8) & 0xf8) | (random() & 0x7); + id[2] = ((c >> 8) & 0xf8) | random(0x7); - for (int i = 3; i < 19; ++i) id[i] = random() & 0xff; + for (int i = 3; i < 19; ++i) id[i] = random(0xff); id[19] = r & 0xff; return id; @@ -144,14 +144,14 @@ static std::uint32_t secret = 0; void make_id_secret(node_id& in) { - if (secret == 0) secret = (random() % 0xfffffffe) + 1; + if (secret == 0) secret = random(0xfffffffe) + 1; - std::uint32_t rand = random(); + std::uint32_t const rand = random(0xffffffff); // generate the last 4 bytes as a "signature" of the previous 4 bytes. This // lets us verify whether a hash came from this function or not in the future. - hasher h(reinterpret_cast(&secret), 4); - h.update(reinterpret_cast(&rand), 4); + hasher h(reinterpret_cast(&secret), 4); + h.update(reinterpret_cast(&rand), 4); sha1_hash const secret_hash = h.final(); memcpy(&in[20-4], &secret_hash[0], 4); memcpy(&in[20-8], &rand, 4); @@ -160,7 +160,7 @@ void make_id_secret(node_id& in) node_id generate_random_id() { char r[20]; - for (int i = 0; i < 20; ++i) r[i] = random() & 0xff; + for (int i = 0; i < 20; ++i) r[i] = random(0xff); return hasher(r, 20).final(); } @@ -195,7 +195,7 @@ bool verify_id(node_id const& nid, address const& source_ip) node_id generate_id(address const& ip) { - return generate_id_impl(ip, random()); + return generate_id_impl(ip, random(0xffffffff)); } bool matching_prefix(node_entry const& n, int mask, int prefix, int bucket_index) diff --git a/src/kademlia/rpc_manager.cpp b/src/kademlia/rpc_manager.cpp index 1921b3f38..e939121a5 100644 --- a/src/kademlia/rpc_manager.cpp +++ b/src/kademlia/rpc_manager.cpp @@ -461,7 +461,7 @@ bool rpc_manager::invoke(entry& e, udp::endpoint target_addr std::string transaction_id; transaction_id.resize(2); char* out = &transaction_id[0]; - int tid = (random() ^ (random() << 5)) & 0xffff; + int tid = random(0x7fff); io::write_uint16(tid, out); e["t"] = transaction_id; diff --git a/src/kademlia/traversal_algorithm.cpp b/src/kademlia/traversal_algorithm.cpp index c5269ea2a..dfdc8d80e 100644 --- a/src/kademlia/traversal_algorithm.cpp +++ b/src/kademlia/traversal_algorithm.cpp @@ -158,7 +158,7 @@ void traversal_algorithm::add_entry(node_id const& id, udp::endpoint addr, unsig { address_v6::bytes_type addr_bytes = o->target_addr().to_v6().to_bytes(); address_v6::bytes_type::const_iterator prefix_it = addr_bytes.begin(); - std::uint64_t prefix6 = detail::read_uint64(prefix_it); + std::uint64_t const prefix6 = detail::read_uint64(prefix_it); if (m_peer6_prefixes.insert(prefix6).second) goto add_result; @@ -167,8 +167,8 @@ void traversal_algorithm::add_entry(node_id const& id, udp::endpoint addr, unsig #endif { // mask the lower octet - std::uint32_t prefix4 = o->target_addr().to_v4().to_ulong(); - prefix4 &= 0xffffff00; + std::uint32_t const prefix4 + = o->target_addr().to_v4().to_ulong() & 0xffffff00; if (m_peer4_prefixes.insert(prefix4).second) goto add_result; diff --git a/src/lsd.cpp b/src/lsd.cpp index 29d479831..c730b27d9 100644 --- a/src/lsd.cpp +++ b/src/lsd.cpp @@ -91,7 +91,7 @@ lsd::lsd(io_service& ios, peer_callback_t const& cb , m_log_cb(log) #endif , m_broadcast_timer(ios) - , m_cookie((random() ^ boost::uintptr_t(this)) & 0x7fffffff) + , m_cookie((random(0x7fffffff) ^ boost::uintptr_t(this)) & 0x7fffffff) , m_disabled(false) #if TORRENT_USE_IPV6 , m_disabled6(false) diff --git a/src/pe_crypto.cpp b/src/pe_crypto.cpp index b51aee35e..8acfe08ae 100644 --- a/src/pe_crypto.cpp +++ b/src/pe_crypto.cpp @@ -66,11 +66,28 @@ namespace libtorrent ("0xFFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485B576625E7EC6F44C42E9A63A36210000000000090563"); } + std::array export_key(key_t const& k) + { + std::array ret; + std::uint8_t* begin = reinterpret_cast(ret.data()); + std::uint8_t* end = mp::export_bits(k, begin, 8); + + // TODO: it would be nice to be able to export to a fixed width field, so + // we wouldn't have to shift it later + if (end < begin + 96) + { + int const len = end - begin; + memmove(begin + 96 - len, begin, len); + memset(begin, 0, 96 - len); + } + return ret; + } + // Set the prime P and the generator, generate local public key dh_key_exchange::dh_key_exchange() { std::array random_key; - for (auto& i : random_key) i = random(); + for (auto& i : random_key) i = random(0xff); // create local key (random) mp::import_bits(m_dh_local_secret, random_key.begin(), random_key.end()); diff --git a/src/peer_list.cpp b/src/peer_list.cpp index 0db7c9918..39cf74cd4 100644 --- a/src/peer_list.cpp +++ b/src/peer_list.cpp @@ -346,7 +346,7 @@ namespace libtorrent if (m_finished != state->is_finished) recalculate_connect_candidates(state); - int round_robin = random() % m_peers.size(); + int round_robin = random(std::uint32_t(m_peers.size()-1)); int low_watermark = max_peerlist_size * 95 / 100; if (low_watermark == max_peerlist_size) --low_watermark; @@ -361,7 +361,7 @@ namespace libtorrent torrent_peer& pe = *m_peers[round_robin]; TORRENT_ASSERT(pe.in_use); - int current = round_robin; + int const current = round_robin; if (is_erase_candidate(pe) && (erase_candidate == -1 diff --git a/src/piece_picker.cpp b/src/piece_picker.cpp index ab5729916..a9bf5abb6 100644 --- a/src/piece_picker.cpp +++ b/src/piece_picker.cpp @@ -773,15 +773,15 @@ namespace libtorrent return std::make_pair(min_availability + m_seeds, fraction_part * 1000 / num_pieces); } - void piece_picker::priority_range(int prio, int* start, int* end) + std::pair piece_picker::priority_range(int prio) { TORRENT_ASSERT(prio >= 0); - TORRENT_ASSERT(prio < int(m_priority_boundaries.size()) - || m_dirty); - if (prio == 0) *start = 0; - else *start = m_priority_boundaries[prio - 1]; - *end = m_priority_boundaries[prio]; - TORRENT_ASSERT(*start <= *end); + TORRENT_ASSERT(prio < int(m_priority_boundaries.size()) || m_dirty); + std::pair const ret{ + prio == 0 ? 0 : m_priority_boundaries[prio-1] + , m_priority_boundaries[prio]}; + TORRENT_ASSERT(ret.first <= ret.second); + return ret; } void piece_picker::add(int index) @@ -802,11 +802,10 @@ namespace libtorrent TORRENT_ASSERT(int(m_priority_boundaries.size()) >= priority); - int range_start, range_end; - priority_range(priority, &range_start, &range_end); - int new_index; - if (range_end == range_start) new_index = range_start; - else new_index = random() % (range_end - range_start + 1) + range_start; + auto range = priority_range(priority); + int new_index = (range.second == range.first) + ? range.first + : random(range.second - range.first) + range.first; #ifdef TORRENT_PICKER_LOG std::cerr << "[" << this << "] " << "add " << index << " (" << priority << ")" << std::endl; @@ -1028,10 +1027,8 @@ namespace libtorrent TORRENT_ASSERT(elem_index < int(m_pieces.size())); TORRENT_ASSERT(m_piece_map[m_pieces[elem_index]].priority(this) == priority); - int range_start, range_end; - priority_range(priority, &range_start, &range_end); - TORRENT_ASSERT(range_start < range_end); - int other_index = random() % (range_end - range_start) + range_start; + auto const range = priority_range(priority); + int const other_index = random(range.second - range.first - 1) + range.first; if (other_index == elem_index) return; @@ -2206,7 +2203,7 @@ namespace libtorrent // we're not using rarest first (only for the first // bucket, since that's where the currently downloading // pieces are) - int start_piece = random() % m_piece_map.size(); + int const start_piece = int(random(std::uint32_t(m_piece_map.size()-1))); int piece = start_piece; while (num_blocks > 0) @@ -2385,7 +2382,7 @@ get_out: while (partials_size > 0) { pc.inc_stats_counter(counters::piece_picker_busy_loops); - int piece = random() % partials_size; + int piece = random(partials_size-1); downloading_piece const* dp = partials[piece]; TORRENT_ASSERT(pieces[dp->index]); TORRENT_ASSERT(piece_priority(dp->index) > 0); @@ -2409,8 +2406,7 @@ get_out: if (!temp.empty()) { ret |= picker_log_alert::end_game; - - interesting_blocks.push_back(temp[random() % temp.size()]); + interesting_blocks.push_back(temp[random(std::uint32_t(temp.size()) - 1)]); --num_blocks; break; } diff --git a/src/random.cpp b/src/random.cpp index 2fbea6b64..9fbcb9324 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -43,31 +43,31 @@ namespace libtorrent #ifdef TORRENT_BUILD_SIMULATOR - std::uint32_t random() + std::uint32_t random(std::uint32_t max) { // make sure random numbers are deterministic. Seed with a fixed number - static mt19937 random_engine(4040); - return uniform_int_distribution(0 - , (std::numeric_limits::max)())(random_engine); + static mt19937 random_engine(0x82daf973); + return uniform_int_distribution(0, max)(random_engine); } #else - std::uint32_t random() + std::uint32_t random(std::uint32_t max) { // TODO: versions prior to msvc-14 (visual studio 2015) do // not generate thread safe initialization of statics static random_device dev; static mt19937 random_engine(dev()); - return uniform_int_distribution(0 - , (std::numeric_limits::max)())(random_engine); + return uniform_int_distribution(0, max)(random_engine); } #endif // TORRENT_BUILD_SIMULATOR - std::uint32_t randint(int i) + + std::uint32_t randint(std::uint32_t one_past_end) { - return random() % i; + return random(one_past_end - 1); } + } diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 4233f38eb..38e8b7741 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -2038,7 +2038,7 @@ namespace aux { socks5_stream& s = *m_socks_listen_socket->get(); m_socks_listen_port = listen_port(); - if (m_socks_listen_port == 0) m_socks_listen_port = 2000 + random() % 60000; + if (m_socks_listen_port == 0) m_socks_listen_port = 2000 + random(60000); s.async_listen(tcp::endpoint(address_v4::any(), m_socks_listen_port) , std::bind(&session_impl::on_socks_listen, this , m_socks_listen_socket, _1)); diff --git a/src/smart_ban.cpp b/src/smart_ban.cpp index be9dcbc77..fa8c5ae9b 100644 --- a/src/smart_ban.cpp +++ b/src/smart_ban.cpp @@ -78,7 +78,7 @@ namespace { explicit smart_ban_plugin(torrent& t) : m_torrent(t) - , m_salt(random()) + , m_salt(random(0xffffffff)) {} void on_piece_pass(int p) override diff --git a/src/string_util.cpp b/src/string_util.cpp index 3031bb40a..45457dcfa 100644 --- a/src/string_util.cpp +++ b/src/string_util.cpp @@ -143,7 +143,7 @@ namespace libtorrent // the random number while (begin != end) - *begin++ = printable[random() % (sizeof(printable)-1)]; + *begin++ = printable[random(sizeof(printable)-2)]; } char* allocate_string_copy(char const* str) diff --git a/src/torrent.cpp b/src/torrent.cpp index b9e03dffe..6ce8c3897 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -1363,7 +1363,7 @@ namespace libtorrent { // schedule a disk tick in 2 minutes or so if (m_storage_tick != 0) return; - m_storage_tick = 120 + (random() % 60); + m_storage_tick = 120 + random(60); update_want_tick(); } @@ -1415,7 +1415,7 @@ namespace libtorrent { if (j->ret && m_storage_tick == 0) { - m_storage_tick = 120 + (random() % 20); + m_storage_tick = 120 + random(20); update_want_tick(); } } @@ -4709,7 +4709,7 @@ namespace libtorrent } if (avail_vec.empty()) return -1; - return avail_vec[random() % avail_vec.size()]; + return avail_vec[random(avail_vec.size() - 1)]; } void torrent::on_files_deleted(disk_io_job const* j) @@ -9713,7 +9713,7 @@ namespace libtorrent return; // now, pick one of the rarest pieces to download - int const pick = random() % rarest_pieces.size(); + int const pick = random(rarest_pieces.size() - 1); bool const was_finished = is_finished(); m_picker->set_piece_priority(rarest_pieces[pick], 1); update_gauge(); diff --git a/src/udp_tracker_connection.cpp b/src/udp_tracker_connection.cpp index ec2dbca07..ea8848050 100644 --- a/src/udp_tracker_connection.cpp +++ b/src/udp_tracker_connection.cpp @@ -443,9 +443,7 @@ namespace libtorrent std::uint32_t new_tid; // don't use 0, because that has special meaning (unintialized) - do { - new_tid = random(); - } while (new_tid == 0); + new_tid = random(0xfffffffe) + 1; if (m_transaction_id != 0) m_man.update_transaction_id(shared_from_this(), new_tid); diff --git a/src/upnp.cpp b/src/upnp.cpp index bb2deccdc..47e7afe4f 100644 --- a/src/upnp.cpp +++ b/src/upnp.cpp @@ -1365,7 +1365,7 @@ void upnp::on_upnp_map_response(error_code const& e // some routers return 501 action failed, instead of 716 // The external port conflicts with another mapping // pick a random port - m.external_port = 40000 + (random() % 10000); + m.external_port = 40000 + random(10000); m.action = mapping_t::action_add; ++m.failcount; update_map(d, mapping); diff --git a/src/ut_metadata.cpp b/src/ut_metadata.cpp index 55d7e0c7c..10101c703 100644 --- a/src/ut_metadata.cpp +++ b/src/ut_metadata.cpp @@ -471,7 +471,7 @@ namespace libtorrent { namespace void failed_hash_check(time_point const& now) { - m_request_limit = now + seconds(20 + (std::int64_t(random()) * 50) / UINT_MAX); + m_request_limit = now + seconds(20 + random(50)); } private: diff --git a/src/utp_socket_manager.cpp b/src/utp_socket_manager.cpp index b59710a19..c22ec3b19 100644 --- a/src/utp_socket_manager.cpp +++ b/src/utp_socket_manager.cpp @@ -338,7 +338,7 @@ namespace libtorrent } else { - send_id = random() & 0xffff; + send_id = random(0xffff); recv_id = send_id - 1; } utp_socket_impl* impl = construct_utp_impl(recv_id, send_id, str, this); diff --git a/src/utp_stream.cpp b/src/utp_stream.cpp index afef633c7..3b01d2520 100644 --- a/src/utp_stream.cpp +++ b/src/utp_stream.cpp @@ -1356,7 +1356,7 @@ void utp_socket_impl::send_syn() { INVARIANT_CHECK; - m_seq_nr = random() & 0xffff; + m_seq_nr = random(0xffff); m_acked_seq_nr = (m_seq_nr - 1) & ACK_MASK; m_loss_seq_nr = m_acked_seq_nr; m_ack_nr = 0; @@ -1476,7 +1476,7 @@ void utp_socket_impl::send_reset(utp_header const* ph) h.connection_id = m_send_id; h.timestamp_difference_microseconds = m_reply_micro; h.wnd_size = 0; - h.seq_nr = random() & 0xffff; + h.seq_nr = random(0xffff); h.ack_nr = ph->seq_nr; time_point now = clock_type::now(); h.timestamp_microseconds = std::uint32_t( @@ -3091,7 +3091,7 @@ bool utp_socket_impl::incoming_packet(span buf m_port = ep.port(); m_ack_nr = ph->seq_nr; - m_seq_nr = random() & 0xffff; + m_seq_nr = random(0xffff); m_acked_seq_nr = (m_seq_nr - 1) & ACK_MASK; m_loss_seq_nr = m_acked_seq_nr; m_fast_resend_seq_nr = m_seq_nr; diff --git a/test/main.cpp b/test/main.cpp index c5cde7148..817fa91ba 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -46,6 +46,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/assert.hpp" #include "libtorrent/file.hpp" +#include "libtorrent/random.hpp" #include #ifdef _WIN32 @@ -322,7 +323,8 @@ EXPORT int main(int argc, char const* argv[]) #else chdir(dir); #endif - std::fprintf(stderr, "test: %s\ncwd = \"%s\"\n", executable, test_dir.c_str()); + std::fprintf(stderr, "test: %s\ncwd = \"%s\"\nrnd: %x\n" + , executable, test_dir.c_str(), libtorrent::random(0xffffffff)); int total_failures = 0; diff --git a/test/setup_transfer.cpp b/test/setup_transfer.cpp index 2c7683f01..611af2e9d 100644 --- a/test/setup_transfer.cpp +++ b/test/setup_transfer.cpp @@ -100,7 +100,7 @@ sha1_hash rand_hash() { sha1_hash ret; for (int i = 0; i < 20; ++i) - ret[i] = boost::uint8_t(lt::random() & 0xff); + ret[i] = boost::uint8_t(lt::random(0xff)); return ret; } @@ -109,7 +109,7 @@ address rand_v6() { address_v6::bytes_type bytes; for (int i = 0; i < int(bytes.size()); ++i) - bytes[i] = boost::uint8_t(lt::random() & 0xff); + bytes[i] = boost::uint8_t(lt::random(0xff)); return address_v6(bytes); } #endif @@ -533,7 +533,7 @@ int start_proxy(int proxy_type) if (i->second.type == proxy_type) { return i->first; } } - int port = 2000 + (lt::random() % 6000); + int port = 2000 + lt::random(6000); error_code ec; io_service ios; @@ -601,7 +601,7 @@ boost::shared_ptr clone_ptr(boost::shared_ptr const& ptr) } unsigned char random_byte() -{ return lt::random() & 0xff; } +{ return lt::random(0xff); } std::vector generate_piece(int const idx, int const piece_size) { @@ -958,7 +958,7 @@ pid_type web_server_pid = 0; int start_web_server(bool ssl, bool chunked_encoding, bool keepalive) { - int port = 2000 + (lt::random() % 6000); + int port = 2000 + lt::random(6000); error_code ec; io_service ios; diff --git a/test/swarm_suite.cpp b/test/swarm_suite.cpp index cffde32e8..e9dc7992b 100644 --- a/test/swarm_suite.cpp +++ b/test/swarm_suite.cpp @@ -99,7 +99,7 @@ void test_swarm(int flags) // three peers before finishing. float rate_limit = 100000; - int port = lt::random() % 100; + int port = lt::random(100); char iface[50]; std::snprintf(iface, sizeof(iface), "0.0.0.0:480%02d", port); pack.set_int(settings_pack::upload_rate_limit, int(rate_limit)); diff --git a/test/test_dht_storage.cpp b/test/test_dht_storage.cpp index 8b29beb84..745debcac 100644 --- a/test/test_dht_storage.cpp +++ b/test/test_dht_storage.cpp @@ -254,7 +254,7 @@ TORRENT_TEST(peer_limit) for (int i = 0; i < 200; ++i) { - s->announce_peer(n1, tcp::endpoint(rand_v4(), lt::random()) + s->announce_peer(n1, tcp::endpoint(rand_v4(), lt::random(0xffff)) , "torrent_name", false); dht_storage_counters cnt = s->counters(); TEST_CHECK(cnt.peers <= 42); @@ -271,7 +271,7 @@ TORRENT_TEST(torrent_limit) for (int i = 0; i < 200; ++i) { - s->announce_peer(rand_hash(), tcp::endpoint(rand_v4(), lt::random()) + s->announce_peer(rand_hash(), tcp::endpoint(rand_v4(), lt::random(0xffff)) , "", false); dht_storage_counters cnt = s->counters(); TEST_CHECK(cnt.torrents <= 42); diff --git a/test/test_privacy.cpp b/test/test_privacy.cpp index 3e68d29c7..84c4808e7 100644 --- a/test/test_privacy.cpp +++ b/test/test_privacy.cpp @@ -116,10 +116,10 @@ session_proxy test_proxy(settings_pack::proxy_type_t proxy_type, int flags) // since multiple sessions may exist simultaneously (because of the // pipelining of the tests) they actually need to use different ports - static int listen_port = 10000 + libtorrent::random() % 50000; + static int listen_port = 10000 + libtorrent::random(50000); char iface[200]; std::snprintf(iface, sizeof(iface), "127.0.0.1:%d", listen_port); - listen_port += (libtorrent::random() % 10) + 1; + listen_port += libtorrent::random(10) + 1; sett.set_str(settings_pack::listen_interfaces, iface); // if we don't do this, the peer connection test diff --git a/test/test_random.cpp b/test/test_random.cpp index d7566e442..25b16d053 100644 --- a/test/test_random.cpp +++ b/test/test_random.cpp @@ -48,7 +48,7 @@ TORRENT_TEST(random) for (int i = 0; i < repetitions; ++i) { - std::uint32_t val = libtorrent::random(); + std::uint32_t val = libtorrent::random(0xffffffff); val >>= byte * 8; ++buckets[val & 0xff]; } diff --git a/test/test_read_resume.cpp b/test/test_read_resume.cpp index ec8386aba..d83e6ca55 100644 --- a/test/test_read_resume.cpp +++ b/test/test_read_resume.cpp @@ -182,7 +182,7 @@ boost::shared_ptr generate_torrent() for (int i = 0; i < num; ++i) { sha1_hash ph; - for (int k = 0; k < 20; ++k) ph[k] = lt::random(); + for (int k = 0; k < 20; ++k) ph[k] = lt::random(0xff); t.set_hash(i, ph); } diff --git a/test/test_resume.cpp b/test/test_resume.cpp index 8657a4b62..e809e8d13 100644 --- a/test/test_resume.cpp +++ b/test/test_resume.cpp @@ -65,7 +65,7 @@ boost::shared_ptr generate_torrent() for (int i = 0; i < num; ++i) { sha1_hash ph; - for (int k = 0; k < 20; ++k) ph[k] = lt::random(); + for (int k = 0; k < 20; ++k) ph[k] = lt::random(0xff); t.set_hash(i, ph); }