diff --git a/ChangeLog b/ChangeLog index b5be9102b..a9135970a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -101,6 +101,7 @@ * support disk I/O priority settings * added info_hash to torrent_deleted_alert * improved LSD performance and made the interval configurable + * improved UDP tracker support by caching connect tokens release 0.14.9 diff --git a/bindings/python/src/session_settings.cpp b/bindings/python/src/session_settings.cpp index b559425b2..15e1e782d 100644 --- a/bindings/python/src/session_settings.cpp +++ b/bindings/python/src/session_settings.cpp @@ -107,6 +107,7 @@ void bind_session_settings() .def_readwrite("drop_skipped_requests", &session_settings::drop_skipped_requests) .def_readwrite("low_prio_disk", &session_settings::low_prio_disk) .def_readwrite("local_service_announce_interval", &session_settings::local_service_announce_interval) + .def_readwrite("udp_tracker_token_expiry", &session_settings::udp_tracker_token_expiry) .def_readwrite("volatile_read_cache", &session_settings::volatile_read_cache) .def_readwrite("guided_read_cache", &guided_read_cache) ; diff --git a/docs/manual.rst b/docs/manual.rst index 971fa6350..f1f20ee49 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -3722,6 +3722,8 @@ session_settings bool low_prio_disk; int local_service_announce_interval; + + int udp_tracker_token_expiry; bool volatile_read_cache; bool guided_read_cache; bool default_min_cache_age; @@ -4219,6 +4221,13 @@ bound on the time a cache line stays in the cache is an attempt to avoid swapping the same pieces in and out of the cache in case there is a shortage of spare cache space. +``udp_tracker_token_expiry`` is the number of seconds libtorrent +will keep UDP tracker connection tokens around for. This is specified +to be 60 seconds, and defaults to that. The higher this value is, the +fewer packets have to be sent to the UDP tracker. In order for higher +values to work, the tracker needs to be configured to match the +expiration time for tokens. + pe_settings =========== diff --git a/include/libtorrent/session_settings.hpp b/include/libtorrent/session_settings.hpp index e061617fa..fc7d1584b 100644 --- a/include/libtorrent/session_settings.hpp +++ b/include/libtorrent/session_settings.hpp @@ -187,6 +187,7 @@ namespace libtorrent , drop_skipped_requests(false) , low_prio_disk(true) , local_service_announce_interval(5 * 60) + , udp_tracker_token_expiry(60) , volatile_read_cache(false) , guided_read_cache(true) , default_cache_min_age(1) @@ -694,6 +695,11 @@ namespace libtorrent // torrents. Defaults to 5 minutes int local_service_announce_interval; + // the number of seconds a connection ID received + // from a UDP tracker is valid for. This is specified + // as 60 seconds + int udp_tracker_token_expiry; + // if this is set to true, any block read from the // disk cache will be dropped from the cache immediately // following. This may be useful if the block is not diff --git a/include/libtorrent/udp_tracker_connection.hpp b/include/libtorrent/udp_tracker_connection.hpp index f0a777a1a..87cb888d0 100644 --- a/include/libtorrent/udp_tracker_connection.hpp +++ b/include/libtorrent/udp_tracker_connection.hpp @@ -114,10 +114,17 @@ namespace libtorrent std::list m_endpoints; int m_transaction_id; - boost::int64_t m_connection_id; aux::session_impl const& m_ses; int m_attempts; + struct connection_cache_entry + { + boost::int64_t connection_id; + ptime expires; + }; + + static std::map m_connection_cache; + action_t m_state; }; diff --git a/src/session_impl.cpp b/src/session_impl.cpp index fc3a047ca..b51285fc5 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -285,7 +285,13 @@ namespace aux { TORRENT_SETTING(integer, max_suggest_pieces) TORRENT_SETTING(boolean, drop_skipped_requests) TORRENT_SETTING(boolean, low_prio_disk) - TORRENT_SETTING(boolean, local_service_announce_interval) + TORRENT_SETTING(integer, local_service_announce_interval) + TORRENT_SETTING(integer, udp_tracker_token_expiry) + TORRENT_SETTING(boolean, volatile_read_cache) + TORRENT_SETTING(boolean, guided_read_cache) + TORRENT_SETTING(integer, default_cache_min_age) + TORRENT_SETTING(integer, num_optimistic_unchoke_slots) + TORRENT_SETTING(boolean, no_atime_storage) }; #undef TORRENT_SETTING diff --git a/src/udp_socket.cpp b/src/udp_socket.cpp index 337df3f1f..65e040a2d 100644 --- a/src/udp_socket.cpp +++ b/src/udp_socket.cpp @@ -94,6 +94,9 @@ udp_socket::~udp_socket() void udp_socket::send(udp::endpoint const& ep, char const* p, int len, error_code& ec) { CHECK_MAGIC; + + TORRENT_ASSERT(is_open()); + // if the sockets are closed, the udp_socket is closing too if (!is_open()) return; diff --git a/src/udp_tracker_connection.cpp b/src/udp_tracker_connection.cpp index 17ed09f35..6f1f43504 100644 --- a/src/udp_tracker_connection.cpp +++ b/src/udp_tracker_connection.cpp @@ -59,6 +59,9 @@ using boost::bind; namespace libtorrent { + std::map + udp_tracker_connection::m_connection_cache; + udp_tracker_connection::udp_tracker_connection( io_service& ios , connection_queue& cc @@ -72,7 +75,6 @@ namespace libtorrent , m_name_lookup(ios) , m_socket(ios, boost::bind(&udp_tracker_connection::on_receive, self(), _1, _2, _3, _4), cc) , m_transaction_id(0) - , m_connection_id(0) , m_ses(ses) , m_attempts(0) , m_state(action_error) @@ -185,16 +187,32 @@ namespace libtorrent if (cb) cb->m_tracker_address = tcp::endpoint(m_target.address(), m_target.port()); - if (bind_interface() != address_v4::any()) + error_code ec; + m_socket.bind(udp::endpoint(bind_interface(), 0), ec); + if (ec) { - error_code ec; - m_socket.bind(udp::endpoint(bind_interface(), 0), ec); - if (ec) + fail(-1, ec.message().c_str()); + return; + } + + std::map::iterator cc + = m_connection_cache.find(m_target.address()); + if (cc != m_connection_cache.end()) + { + // we found a cached entry! Now, we can only + // use if if it hasn't expired + if (time_now() < cc->second.expires) { - fail(-1, ec.message().c_str()); + if (tracker_req().kind == tracker_request::announce_request) + send_udp_announce(); + else if (tracker_req().kind == tracker_request::scrape_request) + send_udp_scrape(); return; } + // if it expired, remove it from the cache + m_connection_cache.erase(cc); } + send_udp_connect(); } @@ -277,8 +295,8 @@ namespace libtorrent if (cb) { char msg[200]; - snprintf(msg, 200, "*** UDP_TRACKER_RESPONSE [ cid: %x%x ]" - , int(m_connection_id >> 32), int(m_connection_id & 0xffffffff)); + snprintf(msg, 200, "*** UDP_TRACKER_RESPONSE [ tid: %x%x ]" + , int(transaction >> 32), int(transaction & 0xffffffff)); cb->debug_log(msg); } #endif @@ -309,7 +327,10 @@ namespace libtorrent // reset transaction m_transaction_id = 0; m_attempts = 0; - m_connection_id = detail::read_int64(buf); + boost::uint64_t connection_id = detail::read_int64(buf); + connection_cache_entry& cce = m_connection_cache[m_target.address()]; + cce.connection_id = connection_id; + cce.expires = time_now() + seconds(m_ses.m_settings.udp_tracker_token_expiry); if (tracker_req().kind == tracker_request::announce_request) send_udp_announce(); @@ -363,10 +384,16 @@ namespace libtorrent if (!m_socket.is_open()) return; // the operation was aborted + std::map::iterator i + = m_connection_cache.find(m_target.address()); + // this isn't really supposed to happen + TORRENT_ASSERT(i != m_connection_cache.end()); + if (i == m_connection_cache.end()) return; + char buf[8 + 4 + 4 + 20]; char* out = buf; - detail::write_int64(m_connection_id, out); // connection_id + detail::write_int64(i->second.connection_id, out); // connection_id detail::write_int32(action_scrape, out); // action (scrape) detail::write_int32(m_transaction_id, out); // transaction_id // info_hash @@ -390,8 +417,6 @@ namespace libtorrent { if (size < 20) return; - restart_read_timeout(); - buf += 8; // skip header restart_read_timeout(); int interval = detail::read_int32(buf); @@ -517,7 +542,13 @@ namespace libtorrent const bool stats = req.send_stats; session_settings const& settings = m_ses.settings(); - detail::write_int64(m_connection_id, out); // connection_id + std::map::iterator i + = m_connection_cache.find(m_target.address()); + // this isn't really supposed to happen + TORRENT_ASSERT(i != m_connection_cache.end()); + if (i == m_connection_cache.end()) return; + + detail::write_int64(i->second.connection_id, out); // connection_id detail::write_int32(action_announce, out); // action (announce) detail::write_int32(m_transaction_id, out); // transaction_id std::copy(req.info_hash.begin(), req.info_hash.end(), out); // info_hash