diff --git a/Jamfile b/Jamfile index 8244fdb36..acf99127a 100755 --- a/Jamfile +++ b/Jamfile @@ -179,11 +179,13 @@ rule linking ( properties * ) result += BOOST_ALL_DYN_LINK ; result += /boost/system//boost_system/static/BOOST_ALL_DYN_LINK ; result += /boost/chrono//boost_chrono/static/BOOST_ALL_DYN_LINK ; + result += /boost/random//boost_random/static/BOOST_ALL_DYN_LINK ; } else { result += /boost/system//boost_system/static ; result += /boost/chrono//boost_chrono/static ; + result += /boost/chrono//boost_random/static ; } if gcc in $(properties) && shared in $(properties) @@ -196,6 +198,7 @@ rule linking ( properties * ) { result += /boost/system//boost_system/shared ; result += /boost/chrono//boost_chrono/shared ; + result += /boost/chrono//boost_random/shared ; } result += $(BOOST_ROOT) BOOST_ALL_NO_LIB @@ -207,6 +210,7 @@ rule linking ( properties * ) { result += boost_system ; result += boost_chrono ; + result += boost_random ; # on mac the boost headers are installed in # a directory that isn't automatically accessable @@ -487,6 +491,10 @@ lib boost_chrono : : darwin boost_chrono-mt $(boost-library-sea lib boost_chrono : : solaris boost_chrono $(boost-library-search-path) ; lib boost_chrono : : boost_chrono ; +lib boost_random : : darwin boost_random-mt $(boost-library-search-path) ; +lib boost_random : : solaris boost_random $(boost-library-search-path) ; +lib boost_random : : boost_random ; + # openssl on linux/bsd/macos etc. lib gcrypt : : gcrypt shared /opt/local/lib ; lib z : : shared z /usr/lib ; diff --git a/build_dist.sh b/build_dist.sh index be654f39a..dbbe7651d 100755 --- a/build_dist.sh +++ b/build_dist.sh @@ -18,6 +18,6 @@ rm -f bindings/python/Makefile bindings/python/Makefile.in chmod a-x docs/*.rst docs/*.htm* src/*.cpp include/libtorrent/*.hpp ./autotool.sh -./configure --enable-python-binding --enable-examples=yes --enable-encryption --enable-tests=yes --with-boost-system=mt --with-boost-python=mt --enable-tests +./configure --enable-python-binding --enable-examples=yes --enable-encryption --enable-tests=yes --with-boost-system=mt --with-boost-chrono=mt --with-boost-random=mt --with-boost-python=mt --enable-tests make V=1 -j8 check distcheck diff --git a/configure.ac b/configure.ac index 0cfa40e35..61212fc78 100644 --- a/configure.ac +++ b/configure.ac @@ -119,12 +119,20 @@ AC_CACHE_CHECK([for __attribute__((visibility("hidden")))], AS_ECHO AS_ECHO "Checking for boost libraries:" -AX_BOOST_BASE([1.36]) +AX_BOOST_BASE([1.47]) AX_BOOST_SYSTEM() AS_IF([test -z "$BOOST_SYSTEM_LIB"], [AC_MSG_ERROR(Boost.System library not found. Try using --with-boost-system=lib)]) +AX_BOOST_CHRONO() +AS_IF([test -z "$BOOST_CHRONO_LIB"], + [AC_MSG_ERROR(Boost.Chrono library not found. Try using --with-boost-chrono=lib)]) + +AX_BOOST_RANDOM() +AS_IF([test -z "$BOOST_RANDOM_LIB"], + [AC_MSG_ERROR(Boost.Random library not found. Try using --with-boost-random=lib)]) + CPPFLAGS="$BOOST_CPPFLAGS $CPPFLAGS" LDFLAGS="$BOOST_LDFLAGS $LDFLAGS" @@ -747,6 +755,8 @@ Boost libraries: CPPFlags: ${BOOST_CPPFLAGS} LDFlags: ${BOOST_LDFLAGS} boost.system: ${BOOST_SYSTEM_LIB} + boost.chrono: ${BOOST_CHRONO_LIB} + boost.random: ${BOOST_RANDOM_LIB} END AS_IF([test "x$ARG_ENABLE_PYTHON_BINDING" = "xyes"], [ diff --git a/examples/Makefile.am b/examples/Makefile.am index b08fe5b4e..e863f2dd4 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,5 +1,6 @@ example_programs = \ client_test \ + stats_counters \ dump_torrent \ make_torrent \ simple_client \ diff --git a/include/libtorrent/Makefile.am b/include/libtorrent/Makefile.am index 9018eda99..6220aad95 100644 --- a/include/libtorrent/Makefile.am +++ b/include/libtorrent/Makefile.am @@ -102,7 +102,6 @@ nobase_include_HEADERS = \ platform_util.hpp \ policy.hpp \ proxy_base.hpp \ - ptime.hpp \ puff.hpp \ random.hpp \ resolver.hpp \ diff --git a/include/libtorrent/random.hpp b/include/libtorrent/random.hpp index b31e8f335..90ed7a1e5 100644 --- a/include/libtorrent/random.hpp +++ b/include/libtorrent/random.hpp @@ -35,6 +35,5 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { - void random_seed(boost::uint32_t v); boost::uint32_t TORRENT_EXTRA_EXPORT random(); } diff --git a/m4/ax_boost_chrono.m4 b/m4/ax_boost_chrono.m4 new file mode 100644 index 000000000..5d065e240 --- /dev/null +++ b/m4/ax_boost_chrono.m4 @@ -0,0 +1,119 @@ +# =========================================================================== +# http://www.gnu.org/software/autoconf-archive/ax_boost_chrono.html +# =========================================================================== +# +# SYNOPSIS +# +# AX_BOOST_CHRONO +# +# DESCRIPTION +# +# Test for System library from the Boost C++ libraries. The macro requires +# a preceding call to AX_BOOST_BASE. Further documentation is available at +# . +# +# This macro calls: +# +# AC_SUBST(BOOST_CHRONO_LIB) +# +# And sets: +# +# HAVE_BOOST_CHRONO +# +# LICENSE +# +# Copyright (c) 2012 Xiyue Deng +# +# Copying and distribution of this file, with or without modification, are +# permitted in any medium without royalty provided the copyright notice +# and this notice are preserved. This file is offered as-is, without any +# warranty. + +#serial 1 + +AC_DEFUN([AX_BOOST_CHRONO], +[ + AC_ARG_WITH([boost-chrono], + AS_HELP_STRING([--with-boost-chrono@<:@=special-lib@:>@], + [use the Chrono library from boost - it is possible to specify a certain library for the linker + e.g. --with-boost-chrono=boost_chrono-gcc-mt ]), + [ + if test "$withval" = "no"; then + want_boost="no" + elif test "$withval" = "yes"; then + want_boost="yes" + ax_boost_user_chrono_lib="" + else + want_boost="yes" + ax_boost_user_chrono_lib="$withval" + fi + ], + [want_boost="yes"] + ) + + if test "x$want_boost" = "xyes"; then + AC_REQUIRE([AC_PROG_CC]) + AC_REQUIRE([AC_CANONICAL_BUILD]) + CPPFLAGS_SAVED="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS" + export CPPFLAGS + + LDFLAGS_SAVED="$LDFLAGS" + LDFLAGS="$LDFLAGS $BOOST_LDFLAGS" + export LDFLAGS + + AC_CACHE_CHECK(whether the Boost::Chrono library is available, + ax_cv_boost_chrono, + [AC_LANG_PUSH([C++]) + CXXFLAGS_SAVE=$CXXFLAGS + + AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[@%:@include ]], + [[boost::chrono::system_clock::time_point time;]])], + ax_cv_boost_chrono=yes, ax_cv_boost_chrono=no) + CXXFLAGS=$CXXFLAGS_SAVE + AC_LANG_POP([C++]) + ]) + if test "x$ax_cv_boost_chrono" = "xyes"; then + AC_SUBST(BOOST_CPPFLAGS) + + AC_DEFINE(HAVE_BOOST_CHRONO,,[define if the Boost::Chrono library is available]) + BOOSTLIBDIR=`echo $BOOST_LDFLAGS | sed -e 's/@<:@^\/@:>@*//'` + + LDFLAGS_SAVE=$LDFLAGS + if test "x$ax_boost_user_chrono_lib" = "x"; then + for libextension in `ls $BOOSTLIBDIR/libboost_chrono*.so* $BOOSTLIBDIR/libboost_chrono*.dylib* $BOOSTLIBDIR/libboost_chrono*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^lib\(boost_chrono.*\)\.so.*$;\1;' -e 's;^lib\(boost_chrono.*\)\.dylib.*$;\1;' -e 's;^lib\(boost_chrono.*\)\.a.*$;\1;'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_CHRONO_LIB="-l$ax_lib"; AC_SUBST(BOOST_CHRONO_LIB) link_chrono="yes"; break], + [link_chrono="no"]) + done + if test "x$link_chrono" != "xyes"; then + for libextension in `ls $BOOSTLIBDIR/boost_chrono*.dll* $BOOSTLIBDIR/boost_chrono*.a* 2>/dev/null | sed 's,.*/,,' | sed -e 's;^\(boost_chrono.*\)\.dll.*$;\1;' -e 's;^\(boost_chrono.*\)\.a.*$;\1;'` ; do + ax_lib=${libextension} + AC_CHECK_LIB($ax_lib, exit, + [BOOST_CHRONO_LIB="-l$ax_lib"; AC_SUBST(BOOST_CHRONO_LIB) link_chrono="yes"; break], + [link_chrono="no"]) + done + fi + + else + for ax_lib in $ax_boost_user_chrono_lib boost_chrono-$ax_boost_user_chrono_lib; do + AC_CHECK_LIB($ax_lib, exit, + [BOOST_CHRONO_LIB="-l$ax_lib"; AC_SUBST(BOOST_CHRONO_LIB) link_chrono="yes"; break], + [link_chrono="no"]) + done + + fi + if test "x$ax_lib" = "x"; then + AC_MSG_ERROR(Could not find a version of the library!) + fi + if test "x$link_chrono" = "xno"; then + AC_MSG_ERROR(Could not link against $ax_lib !) + fi + fi + + CPPFLAGS="$CPPFLAGS_SAVED" + LDFLAGS="$LDFLAGS_SAVED" + fi +]) + diff --git a/src/block_cache.cpp b/src/block_cache.cpp index f75849337..98753db6f 100644 --- a/src/block_cache.cpp +++ b/src/block_cache.cpp @@ -44,6 +44,10 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert_dispatcher.hpp" #include "libtorrent/performance_counters.hpp" +#ifdef TORRENT_DEBUG +#include "libtorrent/random.hpp" +#endif + #if TORRENT_USE_PURGABLE_CONTROL #include // see comments at: @@ -1201,7 +1205,7 @@ void block_cache::insert_blocks(cached_piece_entry* pe, int block, file::iovec_t VM_PURGABLE_SET_STATE, &state); #ifdef TORRENT_DEBUG - // if ((rand() % 200) == 0) ret = 1; +// if ((random() % 200) == 0) ret = 1; #endif if (ret != KERN_SUCCESS || (state & VM_PURGABLE_EMPTY)) { @@ -1250,7 +1254,7 @@ bool block_cache::inc_block_refcount(cached_piece_entry* pe, int block, int reas VM_PURGABLE_SET_STATE, &state); #ifdef TORRENT_DEBUG -// if ((rand() % 200) == 0) ret = 1; +// if ((random() % 200) == 0) ret = 1; #endif if (ret != KERN_SUCCESS || (state & VM_PURGABLE_EMPTY)) { @@ -1312,7 +1316,7 @@ void block_cache::dec_block_refcount(cached_piece_entry* pe, int block, int reas VM_PURGABLE_SET_STATE, &state); #ifdef TORRENT_DEBUG -// if ((rand() % 200) == 0) ret = 1; +// if ((random() % 200) == 0) ret = 1; #endif if (ret != KERN_SUCCESS || (state & VM_PURGABLE_EMPTY)) { diff --git a/src/kademlia/node.cpp b/src/kademlia/node.cpp index c8de239dd..d8b6c33be 100644 --- a/src/kademlia/node.cpp +++ b/src/kademlia/node.cpp @@ -112,7 +112,7 @@ node_impl::node_impl(alert_dispatcher* alert_disp , m_counters(cnt) { m_secret[0] = random(); - m_secret[1] = std::rand(); + m_secret[1] = random(); } bool node_impl::verify_token(std::string const& token, char const* info_hash diff --git a/src/random.cpp b/src/random.cpp index f8698441c..0e6d61753 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -33,40 +33,21 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/config.hpp" #include "libtorrent/random.hpp" #include "libtorrent/assert.hpp" +#include +#include +#include namespace libtorrent { - - namespace - { - boost::uint32_t x = 123456789; -#ifdef TORRENT_USE_ASSERTS - bool seeded = false; -#endif - } - - void random_seed(boost::uint32_t v) - { - x = v; -#ifdef TORRENT_USE_ASSERTS - seeded = true; -#endif - } - - // this is an xorshift random number generator - // see: http://en.wikipedia.org/wiki/Xorshift boost::uint32_t random() { - TORRENT_ASSERT(seeded); + using boost::random::random_device; + using boost::random::mt19937; + using boost::random::uniform_int_distribution; - static boost::uint32_t y = 362436069; - static boost::uint32_t z = 521288629; - static boost::uint32_t w = 88675123; - boost::uint32_t t; - - t = x ^ (x << 11); - x = y; y = z; z = w; - return w = w ^ (w >> 19) ^ (t ^ (t >> 8)); + static random_device dev; + static mt19937 random_engine(dev()); + return uniform_int_distribution(0, UINT_MAX)(random_engine); } } diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 4a0bc8cd4..53acff6d7 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -313,14 +313,6 @@ namespace aux { } #endif // TORRENT_STATS - struct seed_random_generator - { - seed_random_generator() - { - random_seed((unsigned int)((time_now().time_since_epoch().count()) & 0xffffffff)); - } - }; - void session_impl::init_peer_class_filter(bool unlimited_local) { // set the default peer_class_filter to use the local peer class @@ -543,8 +535,6 @@ namespace aux { TORRENT_ASSERT_VAL(!ec, ec); // ---- generate a peer id ---- - static seed_random_generator seeder; - std::string print = cl_fprint.to_string(); TORRENT_ASSERT_VAL(print.length() <= 20, print.length()); @@ -1852,8 +1842,8 @@ namespace aux { { #ifdef TORRENT_DEBUG // make it obvious that the return value is undefined - ret.upload_limit = rand(); - ret.download_limit = rand(); + ret.upload_limit = random(); + ret.download_limit = random(); ret.label.resize(20); url_random(&ret.label[0], &ret.label[0] + 20); ret.ignore_unchoke_slots = false; diff --git a/src/torrent.cpp b/src/torrent.cpp index 0905ffa67..c8b289454 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -1623,7 +1623,7 @@ namespace libtorrent SSL_CTX_set_cert_store(ssl_ctx, cert_store); #if 0 char filename[100]; - snprintf(filename, sizeof(filename), "/tmp/%d.pem", rand()); + snprintf(filename, sizeof(filename), "/tmp/%u.pem", random()); FILE* f = fopen(filename, "w+"); fwrite(cert.c_str(), cert.size(), 1, f); fclose(f); diff --git a/src/utp_stream.cpp b/src/utp_stream.cpp index d8d3cdf8c..ae7a579af 100644 --- a/src/utp_stream.cpp +++ b/src/utp_stream.cpp @@ -1899,7 +1899,7 @@ bool utp_socket_impl::send_pkt(int flags) error_code ec; #ifdef TORRENT_DEBUG // simulate 1% packet loss -// if ((rand() % 100) > 0) +// if ((random() % 100) > 0) #endif m_sm->send_packet(udp::endpoint(m_remote_address, m_port) , (char const*)h, p->size, ec diff --git a/test/Jamfile b/test/Jamfile index 022de4f56..9ad2e9847 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -90,6 +90,7 @@ feature.compose valgrind : "valgrind --tool=memcheck test-suite libtorrent : [ run test_socket_io.cpp ] + [ run test_random.cpp ] [ run test_utf8.cpp ] [ run test_gzip.cpp ] [ run test_bitfield.cpp ] diff --git a/test/test_dht.cpp b/test/test_dht.cpp index cf26e2bdd..9ca783a62 100644 --- a/test/test_dht.cpp +++ b/test/test_dht.cpp @@ -434,8 +434,6 @@ bool get_item_cb(dht::item& i) // TODO: 3 test obfuscated_get_peers int test_main() { - random_seed(time_now_hires().time_since_epoch().count()); - dht_settings sett; sett.max_torrents = 4; sett.max_dht_items = 4; diff --git a/test/test_pe_crypto.cpp b/test/test_pe_crypto.cpp index 9cbd635de..d3e79b05d 100644 --- a/test/test_pe_crypto.cpp +++ b/test/test_pe_crypto.cpp @@ -182,8 +182,6 @@ int test_main() const int repcount = 128; #endif - random_seed(time_now_hires().time_since_epoch().count()); - for (int rep = 0; rep < repcount; ++rep) { dh_key_exchange DH1, DH2; diff --git a/test/test_piece_picker.cpp b/test/test_piece_picker.cpp index f64e87c9d..3d9dce41b 100644 --- a/test/test_piece_picker.cpp +++ b/test/test_piece_picker.cpp @@ -271,8 +271,6 @@ int test_pick(boost::shared_ptr const& p, int options = piece_pick int test_main() { - random_seed(time_now_hires().time_since_epoch().count()); - tcp::endpoint endp; piece_picker::downloading_piece st; #if TORRENT_USE_ASSERTS diff --git a/test/test_policy.cpp b/test/test_policy.cpp index bccc697fe..af8992a19 100644 --- a/test/test_policy.cpp +++ b/test/test_policy.cpp @@ -133,8 +133,6 @@ private: int test_main() { - random_seed(time_now_hires().time_since_epoch().count()); - torrent_peer_allocator allocator; external_ip ext_ip; diff --git a/test/test_random.cpp b/test/test_random.cpp new file mode 100644 index 000000000..da6e964bf --- /dev/null +++ b/test/test_random.cpp @@ -0,0 +1,67 @@ +/* + +Copyright (c) 2014, Arvid Norberg +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the distribution. + * Neither the name of the author nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include "test.hpp" +#include "setup_transfer.hpp" +#include "random.hpp" + +using namespace libtorrent; + +int test_main() +{ + + const int repetitions = 200000; + + for (int byte = 0; byte < 4; ++byte) + { + int buckets[256]; + memset(buckets, 0, sizeof(buckets)); + + for (int i = 0; i < repetitions; ++i) + { + boost::uint32_t val = libtorrent::random(); + val >>= byte * 8; + ++buckets[val & 0xff]; + } + + for (int i = 0; i < 256; ++i) + { + const int expected = repetitions / 256; + // expect each bucket to be within 15% of the expected value + fprintf(stderr, "%d: %f\n", i, float(buckets[i] - expected) * 100.f / expected); + TEST_CHECK(abs(buckets[i] - expected) < expected / 6); + } + } + + return 0; +} +