diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index ad5837e18..694f71853 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -422,7 +422,10 @@ namespace libtorrent #endif torrent_handle add_torrent(add_torrent_params const&, error_code& ec); - boost::shared_ptr add_torrent_impl(add_torrent_params& p, error_code& ec); + // second return value is true if the torrent was added and false if an + // existing one was found. + std::pair, bool> + add_torrent_impl(add_torrent_params& p, error_code& ec); void async_add_torrent(add_torrent_params* params); void on_async_load_torrent(disk_io_job const* j); diff --git a/include/libtorrent/socks5_stream.hpp b/include/libtorrent/socks5_stream.hpp index ffa375eab..a8a667531 100644 --- a/include/libtorrent/socks5_stream.hpp +++ b/include/libtorrent/socks5_stream.hpp @@ -119,6 +119,9 @@ public: // to avoid unnecessary copying of the handler, // store it in a shaed_ptr error_code e; +#if defined TORRENT_ASIO_DEBUGGING + add_outstanding_async("socks5_stream::connect1"); +#endif connect1(e, boost::make_shared(handler)); } diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 53c1dfb7b..f4477aac8 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -1653,6 +1653,11 @@ namespace libtorrent // progress parts per million (the number of // millionths of completeness) unsigned int m_progress_ppm:20; + +#if TORRENT_USE_ASSERTS + // set to true when torrent is start()ed. It may only be started once + bool m_was_started; +#endif }; struct torrent_ref_holder diff --git a/src/session.cpp b/src/session.cpp index aca0759c8..f8f40a1ca 100644 --- a/src/session.cpp +++ b/src/session.cpp @@ -368,7 +368,13 @@ namespace libtorrent int counter = 0; while (log_async()) { - sleep(1000); +#if defined TORRENT_WINDOWS || defined TORRENT_CYGWIN + Sleep(1000); +#elif defined TORRENT_BEOS + snooze_until(system_time() + 1000000, B_SYSTEM_TIMEBASE); +#else + usleep(1000000); +#endif ++counter; std::printf("\x1b[2J\x1b[0;0H\x1b[33m==== Waiting to shut down: %d ==== \x1b[0m\n\n" , counter); diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 1536f49ba..c927223d1 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -4634,7 +4634,9 @@ namespace aux { { // params is updated by add_torrent_impl() add_torrent_params params = p; - boost::shared_ptr const torrent_ptr = add_torrent_impl(params, ec); + boost::shared_ptr torrent_ptr; + bool added; + boost::tie(torrent_ptr, added) = add_torrent_impl(params, ec); torrent_handle const handle(torrent_ptr); m_alerts.emplace_alert(handle, params, ec); @@ -4644,9 +4646,25 @@ namespace aux { // params.info_hash should have been initialized by add_torrent_impl() TORRENT_ASSERT(params.info_hash != sha1_hash(0)); +#ifndef TORRENT_DISABLE_DHT + if (params.ti) + { + torrent_info::nodes_t const& nodes = params.ti->nodes(); + for (std::vector >::const_iterator i = nodes.begin() + , end(nodes.end()); i != end; ++i) + { + add_dht_node_name(*i); + } + } +#endif + if (m_alerts.should_post()) m_alerts.emplace_alert(handle); + // if this was an existing torrent, we can't start it again, or add + // another set of plugins etc. we're done + if (!added) return handle; + torrent_ptr->set_ip_filter(m_ip_filter); torrent_ptr->start(params); @@ -4664,18 +4682,6 @@ namespace aux { add_extensions_to_torrent(torrent_ptr, params.userdata); #endif -#ifndef TORRENT_DISABLE_DHT - if (params.ti) - { - torrent_info::nodes_t const& nodes = params.ti->nodes(); - for (std::vector >::const_iterator i = nodes.begin() - , end(nodes.end()); i != end; ++i) - { - add_dht_node_name(*i); - } - } -#endif - sha1_hash next_lsd(0); sha1_hash next_dht(0); if (m_next_lsd_torrent != m_torrents.end()) @@ -4756,18 +4762,19 @@ namespace aux { return handle; } - boost::shared_ptr session_impl::add_torrent_impl( + std::pair, bool> + session_impl::add_torrent_impl( add_torrent_params& params , error_code& ec) { TORRENT_ASSERT(!params.save_path.empty()); - typedef boost::shared_ptr ptr_t; + using ptr_t = boost::shared_ptr; if (string_begins_no_case("magnet:", params.url.c_str())) { parse_magnet_uri(params.url, params, ec); - if (ec) return ptr_t(); + if (ec) return std::make_pair(ptr_t(), false); params.url.clear(); } @@ -4775,7 +4782,7 @@ namespace aux { { std::string const filename = resolve_file_url(params.url); boost::shared_ptr t = boost::make_shared(filename, boost::ref(ec), 0); - if (ec) return ptr_t(); + if (ec) return std::make_pair(ptr_t(), false); params.url.clear(); params.ti = t; } @@ -4783,13 +4790,13 @@ namespace aux { if (params.ti && !params.ti->is_valid()) { ec = errors::no_metadata; - return ptr_t(); + return std::make_pair(ptr_t(), false); } if (params.ti && params.ti->is_valid() && params.ti->num_files() == 0) { ec = errors::no_files_in_torrent; - return ptr_t(); + return std::make_pair(ptr_t(), false); } #ifndef TORRENT_DISABLE_DHT @@ -4809,7 +4816,7 @@ namespace aux { if (is_aborted()) { ec = errors::session_is_closing; - return ptr_t(); + return std::make_pair(ptr_t(), false); } // figure out the info hash of the torrent and make sure params.info_hash @@ -4831,7 +4838,7 @@ namespace aux { if (params.info_hash == sha1_hash(0)) { ec = errors::missing_info_hash_in_uri; - return ptr_t(); + return std::make_pair(ptr_t(), false); } // is the torrent already active? @@ -4861,11 +4868,11 @@ namespace aux { if (!params.url.empty() && torrent_ptr->url().empty()) torrent_ptr->set_url(params.url); #endif - return torrent_ptr; + return std::make_pair(torrent_ptr, false); } ec = errors::duplicate_torrent; - return ptr_t(); + return std::make_pair(ptr_t(), false); } int queue_pos = ++m_max_queue_pos; @@ -4874,7 +4881,7 @@ namespace aux { , 16 * 1024, queue_pos, m_paused , boost::cref(params), boost::cref(params.info_hash)); - return torrent_ptr; + return std::make_pair(torrent_ptr, true); } void session_impl::update_outgoing_interfaces() diff --git a/src/torrent.cpp b/src/torrent.cpp index 64365f8ea..3a039adb3 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -276,6 +276,9 @@ namespace libtorrent , m_downloaded(0xffffff) , m_last_scrape((std::numeric_limits::min)()) , m_progress_ppm(0) +#if TORRENT_USE_ASSERTS + , m_was_started(false) +#endif { // we cannot log in the constructor, because it relies on shared_from_this // being initialized, which happens after the constructor returns. @@ -641,6 +644,10 @@ namespace libtorrent void torrent::start(add_torrent_params const& p) { TORRENT_ASSERT(is_single_thread()); + TORRENT_ASSERT(m_was_started == false); +#if TORRENT_USE_ASSERTS + m_was_started = true; +#endif #ifndef TORRENT_NO_DEPRECATE if (m_add_torrent_params diff --git a/test/test_torrent.cpp b/test/test_torrent.cpp index aa18ec169..07899ad33 100644 --- a/test/test_torrent.cpp +++ b/test/test_torrent.cpp @@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert_types.hpp" #include "libtorrent/torrent.hpp" #include "libtorrent/peer_info.hpp" +#include "libtorrent/extensions.hpp" #include #include @@ -306,6 +307,68 @@ TORRENT_TEST(torrent) } } +#ifndef TORRENT_DISABLE_EXTENSIONS +struct test_plugin : libtorrent::torrent_plugin {}; + +struct plugin_creator +{ + plugin_creator(int& c) : m_called(c) {} + + boost::shared_ptr + operator()(torrent_handle const&, void*) + { + ++m_called; + return boost::make_shared(); + } + + int& m_called; +}; + +TORRENT_TEST(duplicate_is_not_error) +{ + file_storage fs; + + fs.add_file("test_torrent_dir2/tmp1", 1024); + libtorrent::create_torrent t(fs, 128 * 1024, 6); + + std::vector piece(128 * 1024); + for (int i = 0; i < int(piece.size()); ++i) + piece[i] = (i % 26) + 'A'; + + // calculate the hash for all pieces + sha1_hash ph = hasher(&piece[0], piece.size()).final(); + int num = t.num_pieces(); + TEST_CHECK(t.num_pieces() > 0); + for (int i = 0; i < num; ++i) + t.set_hash(i, ph); + + std::vector tmp; + std::back_insert_iterator > out(tmp); + bencode(out, t.generate()); + error_code ec; + + int called = 0; + plugin_creator creator(called); + + add_torrent_params p; + p.ti = boost::make_shared(&tmp[0], tmp.size(), boost::ref(ec), 0); + p.flags &= ~add_torrent_params::flag_paused; + p.flags &= ~add_torrent_params::flag_auto_managed; + p.flags &= ~add_torrent_params::flag_duplicate_is_error; + p.save_path = "."; + p.extensions.push_back(creator); + + lt::session ses; + ses.async_add_torrent(p); + ses.async_add_torrent(p); + + wait_for_downloading(ses, "ses"); + + // we should only have added the plugin once + TEST_EQUAL(called, 1); +} +#endif + TORRENT_TEST(torrent_total_size_zero) { file_storage fs;