From 0b746d2ab14088c57c943cf1550ed4cc8cb59f4d Mon Sep 17 00:00:00 2001 From: Marcos Pinto Date: Fri, 21 Sep 2007 00:22:38 +0000 Subject: [PATCH] revert lt sync for later testing --- libtorrent/bindings/python/src/alert.cpp | 15 +- libtorrent/bindings/python/src/docstrings.cpp | 21 +- libtorrent/bindings/python/src/extensions.cpp | 1 + libtorrent/bindings/python/src/session.cpp | 9 +- .../bindings/python/src/session_settings.cpp | 4 +- .../bindings/python/src/torrent_info.cpp | 31 +- libtorrent/include/asio/basic_socket.hpp | 6 - libtorrent/include/asio/buffer.hpp | 7 +- .../include/asio/completion_condition.hpp | 44 -- .../include/asio/detail/epoll_reactor.hpp | 155 +++-- .../include/asio/detail/kqueue_reactor.hpp | 82 +-- libtorrent/include/asio/detail/null_event.hpp | 9 +- .../include/asio/detail/posix_event.hpp | 40 +- .../include/asio/detail/posix_mutex.hpp | 10 +- .../include/asio/detail/posix_thread.hpp | 3 +- .../include/asio/detail/posix_tss_ptr.hpp | 3 +- .../asio/detail/reactive_socket_service.hpp | 10 +- .../include/asio/detail/scoped_lock.hpp | 12 - .../include/asio/detail/select_reactor.hpp | 51 +- .../include/asio/detail/service_registry.hpp | 6 +- libtorrent/include/asio/detail/socket_ops.hpp | 38 +- .../include/asio/detail/socket_option.hpp | 13 +- .../include/asio/detail/socket_types.hpp | 7 - .../include/asio/detail/strand_service.hpp | 9 +- .../include/asio/detail/task_io_service.hpp | 99 +-- .../include/asio/detail/timer_queue.hpp | 52 +- .../include/asio/detail/timer_queue_base.hpp | 6 - libtorrent/include/asio/detail/win_event.hpp | 21 +- .../asio/detail/win_iocp_io_service.hpp | 14 +- .../asio/detail/win_iocp_io_service_fwd.hpp | 2 - .../asio/detail/win_iocp_socket_service.hpp | 166 ++--- libtorrent/include/asio/detail/win_mutex.hpp | 5 +- libtorrent/include/asio/detail/win_thread.hpp | 4 +- .../include/asio/detail/win_tss_ptr.hpp | 4 +- .../include/asio/detail/winsock_init.hpp | 3 +- .../include/asio/detail/wrapped_handler.hpp | 14 +- libtorrent/include/asio/error.hpp | 424 +++++++----- libtorrent/include/asio/error_code.hpp | 44 +- libtorrent/include/asio/impl/error_code.ipp | 6 +- libtorrent/include/asio/impl/io_service.ipp | 4 +- libtorrent/include/asio/impl/read_until.ipp | 18 +- libtorrent/include/asio/io_service.hpp | 2 +- libtorrent/include/asio/ip/basic_endpoint.hpp | 32 +- .../asio/ssl/detail/openssl_operation.hpp | 4 +- libtorrent/include/libtorrent/alert.hpp | 2 +- libtorrent/include/libtorrent/alert_types.hpp | 14 +- libtorrent/include/libtorrent/assert.hpp | 54 -- .../include/libtorrent/aux_/session_impl.hpp | 58 +- .../include/libtorrent/bandwidth_manager.hpp | 55 +- libtorrent/include/libtorrent/bencode.hpp | 2 - .../include/libtorrent/broadcast_socket.hpp | 84 --- .../include/libtorrent/bt_peer_connection.hpp | 30 +- libtorrent/include/libtorrent/buffer.hpp | 3 +- .../include/libtorrent/connection_queue.hpp | 5 - libtorrent/include/libtorrent/debug.hpp | 1 - .../include/libtorrent/disk_io_thread.hpp | 15 - libtorrent/include/libtorrent/entry.hpp | 2 +- libtorrent/include/libtorrent/enum_net.hpp | 44 -- libtorrent/include/libtorrent/extensions.hpp | 15 - .../extensions/metadata_transfer.hpp | 2 +- .../include/libtorrent/extensions/ut_pex.hpp | 2 +- libtorrent/include/libtorrent/fingerprint.hpp | 2 - libtorrent/include/libtorrent/hasher.hpp | 2 +- .../include/libtorrent/http_connection.hpp | 12 +- .../libtorrent/http_tracker_connection.hpp | 4 - .../include/libtorrent/intrusive_ptr_base.hpp | 5 +- .../include/libtorrent/invariant_check.hpp | 2 +- libtorrent/include/libtorrent/ip_filter.hpp | 6 +- .../include/libtorrent/kademlia/node.hpp | 2 +- .../include/libtorrent/kademlia/node_id.hpp | 2 +- .../libtorrent/kademlia/routing_table.hpp | 1 - libtorrent/include/libtorrent/lsd.hpp | 18 +- libtorrent/include/libtorrent/pe_crypto.hpp | 5 +- .../include/libtorrent/peer_connection.hpp | 72 +- libtorrent/include/libtorrent/peer_id.hpp | 2 +- libtorrent/include/libtorrent/peer_info.hpp | 15 +- .../include/libtorrent/piece_picker.hpp | 50 +- libtorrent/include/libtorrent/policy.hpp | 31 +- libtorrent/include/libtorrent/session.hpp | 33 +- .../include/libtorrent/session_impl.hpp | 594 ----------------- .../include/libtorrent/session_settings.hpp | 12 +- libtorrent/include/libtorrent/stat.hpp | 1 - libtorrent/include/libtorrent/storage.hpp | 30 +- libtorrent/include/libtorrent/time.hpp | 7 +- libtorrent/include/libtorrent/torrent.hpp | 57 +- .../include/libtorrent/torrent_handle.hpp | 6 +- .../include/libtorrent/torrent_info.hpp | 84 +-- .../include/libtorrent/tracker_manager.hpp | 3 +- libtorrent/include/libtorrent/upnp.hpp | 28 +- .../libtorrent/web_peer_connection.hpp | 3 +- libtorrent/src/assert.cpp | 73 --- libtorrent/src/broadcast_socket.cpp | 186 ------ libtorrent/src/bt_peer_connection.cpp | 245 +------ libtorrent/src/connection_queue.cpp | 26 +- libtorrent/src/disk_io_thread.cpp | 83 +-- libtorrent/src/enum_net.cpp | 142 ---- libtorrent/src/escape_string.cpp | 3 +- libtorrent/src/file.cpp | 19 +- libtorrent/src/http_connection.cpp | 7 +- libtorrent/src/http_tracker_connection.cpp | 101 ++- libtorrent/src/identify_client.cpp | 77 +-- libtorrent/src/kademlia/closest_nodes.cpp | 1 - libtorrent/src/kademlia/dht_tracker.cpp | 8 +- libtorrent/src/kademlia/node_id.cpp | 2 +- libtorrent/src/lsd.cpp | 88 ++- libtorrent/src/metadata_transfer.cpp | 4 +- libtorrent/src/natpmp.cpp | 6 +- libtorrent/src/pe_crypto.cpp | 263 ++++---- libtorrent/src/peer_connection.cpp | 617 +++++------------- libtorrent/src/piece_picker.cpp | 549 +++++----------- libtorrent/src/policy.cpp | 306 ++++----- libtorrent/src/session.cpp | 35 +- libtorrent/src/session_impl.cpp | 518 +++++---------- libtorrent/src/socks5_stream.cpp | 1 - libtorrent/src/storage.cpp | 254 +++---- libtorrent/src/torrent.cpp | 382 +++++------ libtorrent/src/torrent_handle.cpp | 460 ++++--------- libtorrent/src/torrent_info.cpp | 43 +- libtorrent/src/tracker_manager.cpp | 22 +- libtorrent/src/udp_tracker_connection.cpp | 38 +- libtorrent/src/upnp.cpp | 269 +++++--- libtorrent/src/ut_pex.cpp | 71 +- libtorrent/src/web_peer_connection.cpp | 31 +- 123 files changed, 2461 insertions(+), 5456 deletions(-) diff --git a/libtorrent/bindings/python/src/alert.cpp b/libtorrent/bindings/python/src/alert.cpp index 3e188a3ce..f34cf4b5d 100755 --- a/libtorrent/bindings/python/src/alert.cpp +++ b/libtorrent/bindings/python/src/alert.cpp @@ -25,8 +25,6 @@ extern char const* peer_error_alert_doc; extern char const* invalid_request_alert_doc; extern char const* peer_request_doc; extern char const* torrent_finished_alert_doc; -extern char const* torrent_paused_alert_doc; -extern char const* storage_moved_alert_doc; extern char const* metadata_failed_alert_doc; extern char const* metadata_received_alert_doc; extern char const* fastresume_rejected_alert_doc; @@ -142,18 +140,7 @@ void bind_alert() ) .def_readonly("handle", &torrent_finished_alert::handle) ; - - class_, noncopyable>( - "torrent_paused_alert", torrent_paused_alert_doc, no_init - ) - .def_readonly("handle", &torrent_paused_alert::handle) - ; - - class_, noncopyable>( - "storage_moved_alert", storage_moved_alert_doc, no_init - ) - .def_readonly("handle", &storage_moved_alert::handle) - ; + class_, noncopyable>( "metadata_failed_alert", metadata_failed_alert_doc, no_init ) diff --git a/libtorrent/bindings/python/src/docstrings.cpp b/libtorrent/bindings/python/src/docstrings.cpp index e4a99ba31..fbd0a157c 100755 --- a/libtorrent/bindings/python/src/docstrings.cpp +++ b/libtorrent/bindings/python/src/docstrings.cpp @@ -164,14 +164,14 @@ char const* session_set_severity_level_doc = ""; char const* session_pop_alert_doc = ""; -char const* session_start_upnp_doc = +char const* session_start_upnp_doc = ""; -char const* session_stop_upnp_doc = +char const* session_stop_upnp_doc = ""; -char const* session_start_natpmp_doc = - ""; -char const* session_stop_natpmp_doc = + char const* session_start_natpmp_doc = ""; +char const* session_stop_natpmp_doc = + ""; // -- alert ----------------------------------------------------------------- char const* alert_doc = @@ -257,17 +257,6 @@ char const* torrent_finished_alert_doc = "It contains a `torrent_handle` to the torrent in question. This alert\n" "is generated as severity level `alert.severity_levels.info`."; -char const* torrent_paused_alert_doc = - "This alert is generated when a torrent switches from being a\n" - "active to paused.\n" - "It contains a `torrent_handle` to the torrent in question. This alert\n" - "is generated as severity level `alert.severity_levels.warning`."; - -char const* storage_moved_alert_doc = - "This alert is generated when a torrent moves storage.\n" - "It contains a `torrent_handle` to the torrent in question. This alert\n" - "is generated as severity level `alert.severity_levels.warning`."; - char const* metadata_failed_alert_doc = "This alert is generated when the metadata has been completely\n" "received and the info-hash failed to match it. i.e. the\n" diff --git a/libtorrent/bindings/python/src/extensions.cpp b/libtorrent/bindings/python/src/extensions.cpp index f8fb30bdf..10d18ff94 100755 --- a/libtorrent/bindings/python/src/extensions.cpp +++ b/libtorrent/bindings/python/src/extensions.cpp @@ -142,6 +142,7 @@ void bind_extensions() // TODO move to it's own file class_("peer_connection", no_init); + class_ >("torrent_plugin", no_init); def("create_ut_pex_plugin", create_ut_pex_plugin); def("create_metadata_plugin", create_metadata_plugin); } diff --git a/libtorrent/bindings/python/src/session.cpp b/libtorrent/bindings/python/src/session.cpp index 480659537..4ea7a1711 100755 --- a/libtorrent/bindings/python/src/session.cpp +++ b/libtorrent/bindings/python/src/session.cpp @@ -46,7 +46,7 @@ extern char const* session_set_max_connections_doc; extern char const* session_set_max_half_open_connections_doc; extern char const* session_set_settings_doc; extern char const* session_set_pe_settings_doc; -extern char const* session_get_pe_settings_doc; +extern char const* session_get_pe_settings_doc; extern char const* session_set_severity_level_doc; extern char const* session_pop_alert_doc; extern char const* session_start_upnp_doc; @@ -86,10 +86,11 @@ namespace torrent_handle add_torrent(session& s, torrent_info const& ti , boost::filesystem::path const& save, entry const& resume - , bool compact, bool paused) + , bool compact, int block_size) { allow_threading_guard guard; - return s.add_torrent(ti, save, resume, compact, paused, default_storage_constructor); + return s.add_torrent(ti, save, resume, compact, block_size + , default_storage_constructor); } } // namespace unnamed @@ -174,7 +175,7 @@ void bind_session() "add_torrent", &add_torrent , ( arg("torrent_info"), "save_path", arg("resume_data") = entry() - , arg("compact_mode") = true, arg("paused") = false + , arg("compact_mode") = true, arg("block_size") = 16 * 1024 ) , session_add_torrent_doc ) diff --git a/libtorrent/bindings/python/src/session_settings.cpp b/libtorrent/bindings/python/src/session_settings.cpp index c19dfa4d4..f584956b2 100755 --- a/libtorrent/bindings/python/src/session_settings.cpp +++ b/libtorrent/bindings/python/src/session_settings.cpp @@ -47,7 +47,7 @@ void bind_session_settings() .value("http", proxy_settings::http) .value("http_pw", proxy_settings::http_pw) ; - class_("proxy_settings") + class_("proxy_settings") .def_readwrite("hostname", &proxy_settings::hostname) .def_readwrite("port", &proxy_settings::port) .def_readwrite("password", &proxy_settings::password) @@ -64,7 +64,7 @@ void bind_session_settings() enum_("enc_level") .value("rc4", pe_settings::rc4) .value("plaintext", pe_settings::plaintext) - .value("both", pe_settings::both) + .value("both", pe_settings::both) ; class_("pe_settings") diff --git a/libtorrent/bindings/python/src/torrent_info.cpp b/libtorrent/bindings/python/src/torrent_info.cpp index a17c449e3..301c4a5bf 100755 --- a/libtorrent/bindings/python/src/torrent_info.cpp +++ b/libtorrent/bindings/python/src/torrent_info.cpp @@ -16,6 +16,7 @@ namespace return i.trackers().begin(); } + std::vector::const_iterator end_trackers(torrent_info& i) { return i.trackers().end(); @@ -40,29 +41,6 @@ namespace return result; } - std::vector::const_iterator begin_files(torrent_info& i, bool storage) - { - return i.begin_files(storage); - } - - std::vector::const_iterator end_files(torrent_info& i, bool storage) - { - return i.end_files(storage); - } - - //list files(torrent_info const& ti, bool storage) { - list files(torrent_info const& ti, bool storage) { - list result; - - typedef std::vector list_type; - - for (list_type::const_iterator i = ti.begin_files(storage); i != ti.end_files(storage); ++i) - result.append(*i); - - return result; - } - - } // namespace unnamed void bind_torrent_info() @@ -93,9 +71,9 @@ void bind_torrent_info() .def("hash_for_piece", &torrent_info::hash_for_piece, copy) .def("piece_size", &torrent_info::piece_size) - .def("num_files", &torrent_info::num_files, (arg("storage")=false)) + .def("num_files", &torrent_info::num_files) .def("file_at", &torrent_info::file_at, return_internal_reference<>()) - .def("files", &files, (arg("storage")=false)) + .def("files", range(&torrent_info::begin_files, &torrent_info::end_files)) .def("priv", &torrent_info::priv) .def("set_priv", &torrent_info::set_priv) @@ -106,8 +84,9 @@ void bind_torrent_info() .def("add_node", &add_node) .def("nodes", &nodes) ; + class_("file_entry") - .add_property( + .add_property( "path" , make_getter( &file_entry::path, return_value_policy() diff --git a/libtorrent/include/asio/basic_socket.hpp b/libtorrent/include/asio/basic_socket.hpp index 2b2521b69..b0dc52e48 100644 --- a/libtorrent/include/asio/basic_socket.hpp +++ b/libtorrent/include/asio/basic_socket.hpp @@ -238,9 +238,6 @@ public: * with the asio::error::operation_aborted error. * * @throws asio::system_error Thrown on failure. - * - * @note For portable behaviour with respect to graceful closure of a - * connected socket, call shutdown() before closing the socket. */ void close() { @@ -268,9 +265,6 @@ public: * // An error occurred. * } * @endcode - * - * @note For portable behaviour with respect to graceful closure of a - * connected socket, call shutdown() before closing the socket. */ asio::error_code close(asio::error_code& ec) { diff --git a/libtorrent/include/asio/buffer.hpp b/libtorrent/include/asio/buffer.hpp index 9fe76178c..7e5dc76c8 100644 --- a/libtorrent/include/asio/buffer.hpp +++ b/libtorrent/include/asio/buffer.hpp @@ -542,10 +542,9 @@ inline const_buffers_1 buffer(const PodType (&data)[N], ? N * sizeof(PodType) : max_size_in_bytes)); } -#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) \ - || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) -// Borland C++ and Sun Studio think the overloads: +// Borland C++ thinks the overloads: // // unspecified buffer(boost::array& array ...); // @@ -611,7 +610,6 @@ buffer(boost::array& data, std::size_t max_size_in_bytes) } #else // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) - // || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) /// Create a new modifiable buffer that represents the given POD array. template @@ -652,7 +650,6 @@ inline const_buffers_1 buffer(boost::array& data, } #endif // BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) - // || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) /// Create a new non-modifiable buffer that represents the given POD array. template diff --git a/libtorrent/include/asio/completion_condition.hpp b/libtorrent/include/asio/completion_condition.hpp index 939a4a8f3..42696d599 100644 --- a/libtorrent/include/asio/completion_condition.hpp +++ b/libtorrent/include/asio/completion_condition.hpp @@ -71,28 +71,6 @@ private: /// Return a completion condition function object that indicates that a read or /// write operation should continue until all of the data has been transferred, /// or until an error occurs. -/** - * This function is used to create an object, of unspecified type, that meets - * CompletionCondition requirements. - * - * @par Example - * Reading until a buffer is full: - * @code - * boost::array buf; - * asio::error_code ec; - * std::size_t n = asio::read( - * sock, asio::buffer(buf), - * asio::transfer_all(), ec); - * if (ec) - * { - * // An error occurred. - * } - * else - * { - * // n == 128 - * } - * @endcode - */ #if defined(GENERATING_DOCUMENTATION) unspecified transfer_all(); #else @@ -105,28 +83,6 @@ inline detail::transfer_all_t transfer_all() /// Return a completion condition function object that indicates that a read or /// write operation should continue until a minimum number of bytes has been /// transferred, or until an error occurs. -/** - * This function is used to create an object, of unspecified type, that meets - * CompletionCondition requirements. - * - * @par Example - * Reading until a buffer is full or contains at least 64 bytes: - * @code - * boost::array buf; - * asio::error_code ec; - * std::size_t n = asio::read( - * sock, asio::buffer(buf), - * asio::transfer_at_least(64), ec); - * if (ec) - * { - * // An error occurred. - * } - * else - * { - * // n >= 64 && n <= 128 - * } - * @endcode - */ #if defined(GENERATING_DOCUMENTATION) unspecified transfer_at_least(std::size_t minimum); #else diff --git a/libtorrent/include/asio/detail/epoll_reactor.hpp b/libtorrent/include/asio/detail/epoll_reactor.hpp index e260c5194..d55e86454 100644 --- a/libtorrent/include/asio/detail/epoll_reactor.hpp +++ b/libtorrent/include/asio/detail/epoll_reactor.hpp @@ -157,8 +157,7 @@ public: int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); if (result != 0) { - asio::error_code ec(errno, - asio::error::system_category); + asio::error_code ec(errno, asio::native_ecat); read_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -191,8 +190,7 @@ public: int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); if (result != 0) { - asio::error_code ec(errno, - asio::error::system_category); + asio::error_code ec(errno, asio::native_ecat); write_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -221,8 +219,7 @@ public: int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); if (result != 0) { - asio::error_code ec(errno, - asio::error::system_category); + asio::error_code ec(errno, asio::native_ecat); except_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -253,8 +250,7 @@ public: int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); if (result != 0) { - asio::error_code ec(errno, - asio::error::system_category); + asio::error_code ec(errno, asio::native_ecat); write_op_queue_.dispatch_all_operations(descriptor, ec); except_op_queue_.dispatch_all_operations(descriptor, ec); } @@ -335,10 +331,7 @@ public: std::size_t cancel_timer(timer_queue& timer_queue, void* token) { asio::detail::mutex::scoped_lock lock(mutex_); - std::size_t n = timer_queue.cancel_timer(token); - if (n > 0) - interrupter_.interrupt(); - return n; + return timer_queue.cancel_timer(token); } private: @@ -354,13 +347,16 @@ private: read_op_queue_.dispatch_cancellations(); write_op_queue_.dispatch_cancellations(); except_op_queue_.dispatch_cancellations(); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - timer_queues_[i]->dispatch_cancellations(); // Check if the thread is supposed to stop. if (stop_thread_) { - cleanup_operations_and_timers(lock); + // Clean up operations. We must not hold the lock since the operations may + // make calls back into this reactor. + lock.unlock(); + read_op_queue_.cleanup_operations(); + write_op_queue_.cleanup_operations(); + except_op_queue_.cleanup_operations(); return; } @@ -369,7 +365,12 @@ private: if (!block && read_op_queue_.empty() && write_op_queue_.empty() && except_op_queue_.empty() && all_timer_queues_are_empty()) { - cleanup_operations_and_timers(lock); + // Clean up operations. We must not hold the lock since the operations may + // make calls back into this reactor. + lock.unlock(); + read_op_queue_.cleanup_operations(); + write_op_queue_.cleanup_operations(); + except_op_queue_.cleanup_operations(); return; } @@ -397,45 +398,59 @@ private: } else { - bool more_reads = false; - bool more_writes = false; - bool more_except = false; - asio::error_code ec; - - // Exception operations must be processed first to ensure that any - // out-of-band data is read before normal data. - if (events[i].events & (EPOLLPRI | EPOLLERR | EPOLLHUP)) - more_except = except_op_queue_.dispatch_operation(descriptor, ec); - else - more_except = except_op_queue_.has_operation(descriptor); - - if (events[i].events & (EPOLLIN | EPOLLERR | EPOLLHUP)) - more_reads = read_op_queue_.dispatch_operation(descriptor, ec); - else - more_reads = read_op_queue_.has_operation(descriptor); - - if (events[i].events & (EPOLLOUT | EPOLLERR | EPOLLHUP)) - more_writes = write_op_queue_.dispatch_operation(descriptor, ec); - else - more_writes = write_op_queue_.has_operation(descriptor); - - epoll_event ev = { 0, { 0 } }; - ev.events = EPOLLERR | EPOLLHUP; - if (more_reads) - ev.events |= EPOLLIN; - if (more_writes) - ev.events |= EPOLLOUT; - if (more_except) - ev.events |= EPOLLPRI; - ev.data.fd = descriptor; - int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); - if (result != 0) + if (events[i].events & (EPOLLERR | EPOLLHUP)) { - ec = asio::error_code(errno, - asio::error::system_category); + asio::error_code ec; + except_op_queue_.dispatch_all_operations(descriptor, ec); read_op_queue_.dispatch_all_operations(descriptor, ec); write_op_queue_.dispatch_all_operations(descriptor, ec); - except_op_queue_.dispatch_all_operations(descriptor, ec); + + epoll_event ev = { 0, { 0 } }; + ev.events = 0; + ev.data.fd = descriptor; + epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); + } + else + { + bool more_reads = false; + bool more_writes = false; + bool more_except = false; + asio::error_code ec; + + // Exception operations must be processed first to ensure that any + // out-of-band data is read before normal data. + if (events[i].events & EPOLLPRI) + more_except = except_op_queue_.dispatch_operation(descriptor, ec); + else + more_except = except_op_queue_.has_operation(descriptor); + + if (events[i].events & EPOLLIN) + more_reads = read_op_queue_.dispatch_operation(descriptor, ec); + else + more_reads = read_op_queue_.has_operation(descriptor); + + if (events[i].events & EPOLLOUT) + more_writes = write_op_queue_.dispatch_operation(descriptor, ec); + else + more_writes = write_op_queue_.has_operation(descriptor); + + epoll_event ev = { 0, { 0 } }; + ev.events = EPOLLERR | EPOLLHUP; + if (more_reads) + ev.events |= EPOLLIN; + if (more_writes) + ev.events |= EPOLLOUT; + if (more_except) + ev.events |= EPOLLPRI; + ev.data.fd = descriptor; + int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); + if (result != 0) + { + ec = asio::error_code(errno, asio::native_ecat); + read_op_queue_.dispatch_all_operations(descriptor, ec); + write_op_queue_.dispatch_all_operations(descriptor, ec); + except_op_queue_.dispatch_all_operations(descriptor, ec); + } } } } @@ -443,17 +458,19 @@ private: write_op_queue_.dispatch_cancellations(); except_op_queue_.dispatch_cancellations(); for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { timer_queues_[i]->dispatch_timers(); - timer_queues_[i]->dispatch_cancellations(); - } // Issue any pending cancellations. for (size_t i = 0; i < pending_cancellations_.size(); ++i) cancel_ops_unlocked(pending_cancellations_[i]); pending_cancellations_.clear(); - cleanup_operations_and_timers(lock); + // Clean up operations. We must not hold the lock since the operations may + // make calls back into this reactor. + lock.unlock(); + read_op_queue_.cleanup_operations(); + write_op_queue_.cleanup_operations(); + except_op_queue_.cleanup_operations(); } // Run the select loop in the thread. @@ -490,10 +507,8 @@ private: int fd = epoll_create(epoll_size); if (fd == -1) { - boost::throw_exception( - asio::system_error( - asio::error_code(errno, - asio::error::system_category), + boost::throw_exception(asio::system_error( + asio::error_code(errno, asio::native_ecat), "epoll")); } return fd; @@ -551,22 +566,6 @@ private: interrupter_.interrupt(); } - // Clean up operations and timers. We must not hold the lock since the - // destructors may make calls back into this reactor. We make a copy of the - // vector of timer queues since the original may be modified while the lock - // is not held. - void cleanup_operations_and_timers( - asio::detail::mutex::scoped_lock& lock) - { - timer_queues_for_cleanup_ = timer_queues_; - lock.unlock(); - read_op_queue_.cleanup_operations(); - write_op_queue_.cleanup_operations(); - except_op_queue_.cleanup_operations(); - for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i) - timer_queues_for_cleanup_[i]->cleanup_timers(); - } - // Mutex to protect access to internal data. asio::detail::mutex mutex_; @@ -591,10 +590,6 @@ private: // The timer queues. std::vector timer_queues_; - // A copy of the timer queues, used when cleaning up timers. The copy is - // stored as a class data member to avoid unnecessary memory allocation. - std::vector timer_queues_for_cleanup_; - // The descriptors that are pending cancellation. std::vector pending_cancellations_; diff --git a/libtorrent/include/asio/detail/kqueue_reactor.hpp b/libtorrent/include/asio/detail/kqueue_reactor.hpp index 5fffc6788..6628803af 100644 --- a/libtorrent/include/asio/detail/kqueue_reactor.hpp +++ b/libtorrent/include/asio/detail/kqueue_reactor.hpp @@ -150,8 +150,7 @@ public: EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, 0, 0, 0); if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { - asio::error_code ec(errno, - asio::error::system_category); + asio::error_code ec(errno, asio::native_ecat); read_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -177,8 +176,7 @@ public: EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0); if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { - asio::error_code ec(errno, - asio::error::system_category); + asio::error_code ec(errno, asio::native_ecat); write_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -203,8 +201,7 @@ public: EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0); if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { - asio::error_code ec(errno, - asio::error::system_category); + asio::error_code ec(errno, asio::native_ecat); except_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -227,8 +224,7 @@ public: EV_SET(&event, descriptor, EVFILT_WRITE, EV_ADD, 0, 0, 0); if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { - asio::error_code ec(errno, - asio::error::system_category); + asio::error_code ec(errno, asio::native_ecat); write_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -242,8 +238,7 @@ public: EV_SET(&event, descriptor, EVFILT_READ, EV_ADD, EV_OOBAND, 0, 0); if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { - asio::error_code ec(errno, - asio::error::system_category); + asio::error_code ec(errno, asio::native_ecat); except_op_queue_.dispatch_all_operations(descriptor, ec); write_op_queue_.dispatch_all_operations(descriptor, ec); } @@ -326,10 +321,7 @@ public: std::size_t cancel_timer(timer_queue& timer_queue, void* token) { asio::detail::mutex::scoped_lock lock(mutex_); - std::size_t n = timer_queue.cancel_timer(token); - if (n > 0) - interrupter_.interrupt(); - return n; + return timer_queue.cancel_timer(token); } private: @@ -345,13 +337,16 @@ private: read_op_queue_.dispatch_cancellations(); write_op_queue_.dispatch_cancellations(); except_op_queue_.dispatch_cancellations(); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - timer_queues_[i]->dispatch_cancellations(); // Check if the thread is supposed to stop. if (stop_thread_) { - cleanup_operations_and_timers(lock); + // Clean up operations. We must not hold the lock since the operations may + // make calls back into this reactor. + lock.unlock(); + read_op_queue_.cleanup_operations(); + write_op_queue_.cleanup_operations(); + except_op_queue_.cleanup_operations(); return; } @@ -360,7 +355,12 @@ private: if (!block && read_op_queue_.empty() && write_op_queue_.empty() && except_op_queue_.empty() && all_timer_queues_are_empty()) { - cleanup_operations_and_timers(lock); + // Clean up operations. We must not hold the lock since the operations may + // make calls back into this reactor. + lock.unlock(); + read_op_queue_.cleanup_operations(); + write_op_queue_.cleanup_operations(); + except_op_queue_.cleanup_operations(); return; } @@ -397,7 +397,7 @@ private: if (events[i].flags & EV_ERROR) { asio::error_code error( - events[i].data, asio::error::system_category); + events[i].data, asio::native_ecat); except_op_queue_.dispatch_all_operations(descriptor, error); read_op_queue_.dispatch_all_operations(descriptor, error); } @@ -427,8 +427,7 @@ private: EV_SET(&event, descriptor, EVFILT_READ, EV_DELETE, 0, 0, 0); if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { - asio::error_code error(errno, - asio::error::system_category); + asio::error_code error(errno, asio::native_ecat); except_op_queue_.dispatch_all_operations(descriptor, error); read_op_queue_.dispatch_all_operations(descriptor, error); } @@ -440,7 +439,7 @@ private: if (events[i].flags & EV_ERROR) { asio::error_code error( - events[i].data, asio::error::system_category); + events[i].data, asio::native_ecat); write_op_queue_.dispatch_all_operations(descriptor, error); } else @@ -457,8 +456,7 @@ private: EV_SET(&event, descriptor, EVFILT_WRITE, EV_DELETE, 0, 0, 0); if (::kevent(kqueue_fd_, &event, 1, 0, 0, 0) == -1) { - asio::error_code error(errno, - asio::error::system_category); + asio::error_code error(errno, asio::native_ecat); write_op_queue_.dispatch_all_operations(descriptor, error); } } @@ -468,17 +466,19 @@ private: write_op_queue_.dispatch_cancellations(); except_op_queue_.dispatch_cancellations(); for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { timer_queues_[i]->dispatch_timers(); - timer_queues_[i]->dispatch_cancellations(); - } // Issue any pending cancellations. for (std::size_t i = 0; i < pending_cancellations_.size(); ++i) cancel_ops_unlocked(pending_cancellations_[i]); pending_cancellations_.clear(); - cleanup_operations_and_timers(lock); + // Clean up operations. We must not hold the lock since the operations may + // make calls back into this reactor. + lock.unlock(); + read_op_queue_.cleanup_operations(); + write_op_queue_.cleanup_operations(); + except_op_queue_.cleanup_operations(); } // Run the select loop in the thread. @@ -512,10 +512,8 @@ private: int fd = kqueue(); if (fd == -1) { - boost::throw_exception( - asio::system_error( - asio::error_code(errno, - asio::error::system_category), + boost::throw_exception(asio::system_error( + asio::error_code(errno, asio::native_ecat), "kqueue")); } return fd; @@ -575,22 +573,6 @@ private: interrupter_.interrupt(); } - // Clean up operations and timers. We must not hold the lock since the - // destructors may make calls back into this reactor. We make a copy of the - // vector of timer queues since the original may be modified while the lock - // is not held. - void cleanup_operations_and_timers( - asio::detail::mutex::scoped_lock& lock) - { - timer_queues_for_cleanup_ = timer_queues_; - lock.unlock(); - read_op_queue_.cleanup_operations(); - write_op_queue_.cleanup_operations(); - except_op_queue_.cleanup_operations(); - for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i) - timer_queues_for_cleanup_[i]->cleanup_timers(); - } - // Mutex to protect access to internal data. asio::detail::mutex mutex_; @@ -615,10 +597,6 @@ private: // The timer queues. std::vector timer_queues_; - // A copy of the timer queues, used when cleaning up timers. The copy is - // stored as a class data member to avoid unnecessary memory allocation. - std::vector timer_queues_for_cleanup_; - // The descriptors that are pending cancellation. std::vector pending_cancellations_; diff --git a/libtorrent/include/asio/detail/null_event.hpp b/libtorrent/include/asio/detail/null_event.hpp index 99bcbc6a4..df522ce0f 100644 --- a/libtorrent/include/asio/detail/null_event.hpp +++ b/libtorrent/include/asio/detail/null_event.hpp @@ -43,20 +43,17 @@ public: } // Signal the event. - template - void signal(Lock&) + void signal() { } // Reset the event. - template - void clear(Lock&) + void clear() { } // Wait for the event to become signalled. - template - void wait(Lock&) + void wait() { } }; diff --git a/libtorrent/include/asio/detail/posix_event.hpp b/libtorrent/include/asio/detail/posix_event.hpp index b48586f15..408c23bb9 100644 --- a/libtorrent/include/asio/detail/posix_event.hpp +++ b/libtorrent/include/asio/detail/posix_event.hpp @@ -24,12 +24,10 @@ #if defined(BOOST_HAS_PTHREADS) #include "asio/detail/push_options.hpp" -#include #include #include #include "asio/detail/pop_options.hpp" -#include "asio/error.hpp" #include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" @@ -44,11 +42,21 @@ public: posix_event() : signalled_(false) { - int error = ::pthread_cond_init(&cond_, 0); + int error = ::pthread_mutex_init(&mutex_, 0); if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, asio::native_ecat), + "event"); + boost::throw_exception(e); + } + + error = ::pthread_cond_init(&cond_, 0); + if (error != 0) + { + ::pthread_mutex_destroy(&mutex_); + asio::system_error e( + asio::error_code(error, asio::native_ecat), "event"); boost::throw_exception(e); } @@ -58,37 +66,37 @@ public: ~posix_event() { ::pthread_cond_destroy(&cond_); + ::pthread_mutex_destroy(&mutex_); } // Signal the event. - template - void signal(Lock& lock) + void signal() { - BOOST_ASSERT(lock.locked()); - (void)lock; + ::pthread_mutex_lock(&mutex_); // Ignore EINVAL and EDEADLK. signalled_ = true; ::pthread_cond_signal(&cond_); // Ignore EINVAL. + ::pthread_mutex_unlock(&mutex_); // Ignore EINVAL and EPERM. } // Reset the event. - template - void clear(Lock& lock) + void clear() { - BOOST_ASSERT(lock.locked()); - (void)lock; + ::pthread_mutex_lock(&mutex_); // Ignore EINVAL and EDEADLK. signalled_ = false; + ::pthread_mutex_unlock(&mutex_); // Ignore EINVAL and EPERM. } // Wait for the event to become signalled. - template - void wait(Lock& lock) + void wait() { - BOOST_ASSERT(lock.locked()); + ::pthread_mutex_lock(&mutex_); // Ignore EINVAL and EDEADLK. while (!signalled_) - ::pthread_cond_wait(&cond_, &lock.mutex().mutex_); // Ignore EINVAL. + ::pthread_cond_wait(&cond_, &mutex_); // Ignore EINVAL. + ::pthread_mutex_unlock(&mutex_); // Ignore EINVAL and EPERM. } private: + ::pthread_mutex_t mutex_; ::pthread_cond_t cond_; bool signalled_; }; diff --git a/libtorrent/include/asio/detail/posix_mutex.hpp b/libtorrent/include/asio/detail/posix_mutex.hpp index 6067880fb..154089f3c 100644 --- a/libtorrent/include/asio/detail/posix_mutex.hpp +++ b/libtorrent/include/asio/detail/posix_mutex.hpp @@ -28,7 +28,6 @@ #include #include "asio/detail/pop_options.hpp" -#include "asio/error.hpp" #include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/scoped_lock.hpp" @@ -36,8 +35,6 @@ namespace asio { namespace detail { -class posix_event; - class posix_mutex : private noncopyable { @@ -51,7 +48,7 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, asio::native_ecat), "mutex"); boost::throw_exception(e); } @@ -70,7 +67,7 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, asio::native_ecat), "mutex"); boost::throw_exception(e); } @@ -83,14 +80,13 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, asio::native_ecat), "mutex"); boost::throw_exception(e); } } private: - friend class posix_event; ::pthread_mutex_t mutex_; }; diff --git a/libtorrent/include/asio/detail/posix_thread.hpp b/libtorrent/include/asio/detail/posix_thread.hpp index 6e5815426..f01b40428 100644 --- a/libtorrent/include/asio/detail/posix_thread.hpp +++ b/libtorrent/include/asio/detail/posix_thread.hpp @@ -29,7 +29,6 @@ #include #include "asio/detail/pop_options.hpp" -#include "asio/error.hpp" #include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" @@ -53,7 +52,7 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, asio::native_ecat), "thread"); boost::throw_exception(e); } diff --git a/libtorrent/include/asio/detail/posix_tss_ptr.hpp b/libtorrent/include/asio/detail/posix_tss_ptr.hpp index dda329c40..93fce3479 100644 --- a/libtorrent/include/asio/detail/posix_tss_ptr.hpp +++ b/libtorrent/include/asio/detail/posix_tss_ptr.hpp @@ -28,7 +28,6 @@ #include #include "asio/detail/pop_options.hpp" -#include "asio/error.hpp" #include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" @@ -47,7 +46,7 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, asio::native_ecat), "tss"); boost::throw_exception(e); } diff --git a/libtorrent/include/asio/detail/reactive_socket_service.hpp b/libtorrent/include/asio/detail/reactive_socket_service.hpp index 9c0075821..d5b8e4fc8 100644 --- a/libtorrent/include/asio/detail/reactive_socket_service.hpp +++ b/libtorrent/include/asio/detail/reactive_socket_service.hpp @@ -86,7 +86,7 @@ public: }; // The maximum number of buffers to support in a single operation. - enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; + enum { max_buffers = 16 }; // Constructor. reactive_socket_service(asio::io_service& io_service) @@ -157,7 +157,7 @@ public: if (int err = reactor_.register_descriptor(sock.get())) { - ec = asio::error_code(err, asio::error::system_category); + ec = asio::error_code(err, asio::native_ecat); return ec; } @@ -181,7 +181,7 @@ public: if (int err = reactor_.register_descriptor(native_socket)) { - ec = asio::error_code(err, asio::error::system_category); + ec = asio::error_code(err, asio::native_ecat); return ec; } @@ -1124,7 +1124,7 @@ public: bool operator()(const asio::error_code& result) { // Check whether the operation was successful. - if (result) + if (result != 0) { io_service_.post(bind_handler(handler_, result, 0)); return true; @@ -1489,7 +1489,7 @@ public: if (connect_error) { ec = asio::error_code(connect_error, - asio::error::system_category); + asio::native_ecat); io_service_.post(bind_handler(handler_, ec)); return true; } diff --git a/libtorrent/include/asio/detail/scoped_lock.hpp b/libtorrent/include/asio/detail/scoped_lock.hpp index 57f8cb8f6..64c77cbab 100644 --- a/libtorrent/include/asio/detail/scoped_lock.hpp +++ b/libtorrent/include/asio/detail/scoped_lock.hpp @@ -63,18 +63,6 @@ public: } } - // Test whether the lock is held. - bool locked() const - { - return locked_; - } - - // Get the underlying mutex. - Mutex& mutex() - { - return mutex_; - } - private: // The underlying mutex. Mutex& mutex_; diff --git a/libtorrent/include/asio/detail/select_reactor.hpp b/libtorrent/include/asio/detail/select_reactor.hpp index 079ec2de8..83f093ae6 100644 --- a/libtorrent/include/asio/detail/select_reactor.hpp +++ b/libtorrent/include/asio/detail/select_reactor.hpp @@ -229,10 +229,7 @@ public: std::size_t cancel_timer(timer_queue& timer_queue, void* token) { asio::detail::mutex::scoped_lock lock(mutex_); - std::size_t n = timer_queue.cancel_timer(token); - if (n > 0) - interrupter_.interrupt(); - return n; + return timer_queue.cancel_timer(token); } private: @@ -248,13 +245,16 @@ private: read_op_queue_.dispatch_cancellations(); write_op_queue_.dispatch_cancellations(); except_op_queue_.dispatch_cancellations(); - for (std::size_t i = 0; i < timer_queues_.size(); ++i) - timer_queues_[i]->dispatch_cancellations(); // Check if the thread is supposed to stop. if (stop_thread_) { - cleanup_operations_and_timers(lock); + // Clean up operations. We must not hold the lock since the operations may + // make calls back into this reactor. + lock.unlock(); + read_op_queue_.cleanup_operations(); + write_op_queue_.cleanup_operations(); + except_op_queue_.cleanup_operations(); return; } @@ -263,7 +263,12 @@ private: if (!block && read_op_queue_.empty() && write_op_queue_.empty() && except_op_queue_.empty() && all_timer_queues_are_empty()) { - cleanup_operations_and_timers(lock); + // Clean up operations. We must not hold the lock since the operations may + // make calls back into this reactor. + lock.unlock(); + read_op_queue_.cleanup_operations(); + write_op_queue_.cleanup_operations(); + except_op_queue_.cleanup_operations(); return; } @@ -316,17 +321,19 @@ private: write_op_queue_.dispatch_cancellations(); } for (std::size_t i = 0; i < timer_queues_.size(); ++i) - { timer_queues_[i]->dispatch_timers(); - timer_queues_[i]->dispatch_cancellations(); - } // Issue any pending cancellations. for (size_t i = 0; i < pending_cancellations_.size(); ++i) cancel_ops_unlocked(pending_cancellations_[i]); pending_cancellations_.clear(); - cleanup_operations_and_timers(lock); + // Clean up operations. We must not hold the lock since the operations may + // make calls back into this reactor. + lock.unlock(); + read_op_queue_.cleanup_operations(); + write_op_queue_.cleanup_operations(); + except_op_queue_.cleanup_operations(); } // Run the select loop in the thread. @@ -407,22 +414,6 @@ private: interrupter_.interrupt(); } - // Clean up operations and timers. We must not hold the lock since the - // destructors may make calls back into this reactor. We make a copy of the - // vector of timer queues since the original may be modified while the lock - // is not held. - void cleanup_operations_and_timers( - asio::detail::mutex::scoped_lock& lock) - { - timer_queues_for_cleanup_ = timer_queues_; - lock.unlock(); - read_op_queue_.cleanup_operations(); - write_op_queue_.cleanup_operations(); - except_op_queue_.cleanup_operations(); - for (std::size_t i = 0; i < timer_queues_for_cleanup_.size(); ++i) - timer_queues_for_cleanup_[i]->cleanup_timers(); - } - // Mutex to protect access to internal data. asio::detail::mutex mutex_; @@ -444,10 +435,6 @@ private: // The timer queues. std::vector timer_queues_; - // A copy of the timer queues, used when cleaning up timers. The copy is - // stored as a class data member to avoid unnecessary memory allocation. - std::vector timer_queues_for_cleanup_; - // The descriptors that are pending cancellation. std::vector pending_cancellations_; diff --git a/libtorrent/include/asio/detail/service_registry.hpp b/libtorrent/include/asio/detail/service_registry.hpp index 3a9e9f620..bd1c3ea5b 100644 --- a/libtorrent/include/asio/detail/service_registry.hpp +++ b/libtorrent/include/asio/detail/service_registry.hpp @@ -166,8 +166,7 @@ private: } // Check if a service matches the given id. - static bool service_id_matches( - const asio::io_service::service& service, + bool service_id_matches(const asio::io_service::service& service, const asio::io_service::id& id) { return service.id_ == &id; @@ -175,8 +174,7 @@ private: // Check if a service matches the given id. template - static bool service_id_matches( - const asio::io_service::service& service, + bool service_id_matches(const asio::io_service::service& service, const asio::detail::service_id& /*id*/) { return service.type_info_ != 0 && *service.type_info_ == typeid(Service); diff --git a/libtorrent/include/asio/detail/socket_ops.hpp b/libtorrent/include/asio/detail/socket_ops.hpp index 98f3b0f64..4b38c6ee8 100644 --- a/libtorrent/include/asio/detail/socket_ops.hpp +++ b/libtorrent/include/asio/detail/socket_ops.hpp @@ -52,10 +52,9 @@ inline ReturnType error_wrapper(ReturnType return_value, asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - ec = asio::error_code(WSAGetLastError(), - asio::error::system_category); + ec = asio::error_code(WSAGetLastError(), asio::native_ecat); #else - ec = asio::error_code(errno, asio::error::system_category); + ec = asio::error_code(errno, asio::native_ecat); #endif return return_value; } @@ -924,13 +923,6 @@ inline void gai_free(void* p) ::operator delete(p); } -inline void gai_strcpy(char* target, const char* source, std::size_t max_size) -{ - using namespace std; - *target = 0; - strncat(target, source, max_size); -} - enum { gai_clone_flag = 1 << 30 }; inline int gai_aistruct(addrinfo_type*** next, const addrinfo_type* hints, @@ -1300,15 +1292,14 @@ inline int getaddrinfo_emulation(const char* host, const char* service, if (host != 0 && host[0] != '\0' && hptr->h_name && hptr->h_name[0] && (hints.ai_flags & AI_CANONNAME) && canon == 0) { - std::size_t canon_len = strlen(hptr->h_name) + 1; - canon = gai_alloc(canon_len); + canon = gai_alloc(strlen(hptr->h_name) + 1); if (canon == 0) { freeaddrinfo_emulation(aihead); socket_ops::freehostent(hptr); return EAI_MEMORY; } - gai_strcpy(canon, hptr->h_name, canon_len); + strcpy(canon, hptr->h_name); } // Create an addrinfo structure for each returned address. @@ -1344,14 +1335,13 @@ inline int getaddrinfo_emulation(const char* host, const char* service, } else { - std::size_t canonname_len = strlen(search[0].host) + 1; - aihead->ai_canonname = gai_alloc(canonname_len); + aihead->ai_canonname = gai_alloc(strlen(search[0].host) + 1); if (aihead->ai_canonname == 0) { freeaddrinfo_emulation(aihead); return EAI_MEMORY; } - gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len); + strcpy(aihead->ai_canonname, search[0].host); } } gai_free(canon); @@ -1434,7 +1424,8 @@ inline asio::error_code getnameinfo_emulation( *dot = 0; } } - gai_strcpy(host, hptr->h_name, hostlen); + *host = '\0'; + strncat(host, hptr->h_name, hostlen); socket_ops::freehostent(hptr); } else @@ -1472,7 +1463,8 @@ inline asio::error_code getnameinfo_emulation( servent* sptr = ::getservbyport(port, (flags & NI_DGRAM) ? "udp" : 0); if (sptr && sptr->s_name && sptr->s_name[0] != '\0') { - gai_strcpy(serv, sptr->s_name, servlen); + *serv = '\0'; + strncat(serv, sptr->s_name, servlen); } else { @@ -1512,12 +1504,6 @@ inline asio::error_code translate_addrinfo_error(int error) case EAI_MEMORY: return asio::error::no_memory; case EAI_NONAME: -#if defined(EAI_ADDRFAMILY) - case EAI_ADDRFAMILY: -#endif -#if defined(EAI_NODATA) && (EAI_NODATA != EAI_NONAME) - case EAI_NODATA: -#endif return asio::error::host_not_found; case EAI_SERVICE: return asio::error::service_not_found; @@ -1526,10 +1512,10 @@ inline asio::error_code translate_addrinfo_error(int error) default: // Possibly the non-portable EAI_SYSTEM. #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) return asio::error_code( - WSAGetLastError(), asio::error::system_category); + WSAGetLastError(), asio::native_ecat); #else return asio::error_code( - errno, asio::error::system_category); + errno, asio::native_ecat); #endif } } diff --git a/libtorrent/include/asio/detail/socket_option.hpp b/libtorrent/include/asio/detail/socket_option.hpp index 1a03936ab..ee867e6b2 100644 --- a/libtorrent/include/asio/detail/socket_option.hpp +++ b/libtorrent/include/asio/detail/socket_option.hpp @@ -110,19 +110,8 @@ public: template void resize(const Protocol&, std::size_t s) { - // On some platforms (e.g. Windows Vista), the getsockopt function will - // return the size of a boolean socket option as one byte, even though a - // four byte integer was passed in. - switch (s) - { - case sizeof(char): - value_ = *reinterpret_cast(&value_) ? 1 : 0; - break; - case sizeof(value_): - break; - default: + if (s != sizeof(value_)) throw std::length_error("boolean socket option resize"); - } } private: diff --git a/libtorrent/include/asio/detail/socket_types.hpp b/libtorrent/include/asio/detail/socket_types.hpp index 02c3a78d5..49d1c7fc2 100644 --- a/libtorrent/include/asio/detail/socket_types.hpp +++ b/libtorrent/include/asio/detail/socket_types.hpp @@ -98,7 +98,6 @@ # include # include # include -# include # if defined(__sun) # include # include @@ -142,11 +141,6 @@ const int shutdown_both = SD_BOTH; const int message_peek = MSG_PEEK; const int message_out_of_band = MSG_OOB; const int message_do_not_route = MSG_DONTROUTE; -# if defined (_WIN32_WINNT) -const int max_iov_len = 64; -# else -const int max_iov_len = 16; -# endif #else typedef int socket_type; const int invalid_socket = -1; @@ -172,7 +166,6 @@ const int shutdown_both = SHUT_RDWR; const int message_peek = MSG_PEEK; const int message_out_of_band = MSG_OOB; const int message_do_not_route = MSG_DONTROUTE; -const int max_iov_len = IOV_MAX; #endif const int custom_socket_option_level = 0xA5100000; const int enable_connection_aborted_option = 1; diff --git a/libtorrent/include/asio/detail/strand_service.hpp b/libtorrent/include/asio/detail/strand_service.hpp index d987cb98d..f10289090 100644 --- a/libtorrent/include/asio/detail/strand_service.hpp +++ b/libtorrent/include/asio/detail/strand_service.hpp @@ -239,7 +239,6 @@ public: #else BOOST_ASSERT(size <= strand_impl::handler_storage_type::size); #endif - (void)size; return impl_->handler_storage_.address(); } @@ -416,14 +415,14 @@ public: } else { + asio::detail::mutex::scoped_lock lock(impl->mutex_); + // Allocate and construct an object to wrap the handler. typedef handler_wrapper value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); handler_ptr ptr(raw_ptr, handler); - asio::detail::mutex::scoped_lock lock(impl->mutex_); - if (impl->current_handler_ == 0) { // This handler now has the lock, so can be dispatched immediately. @@ -456,14 +455,14 @@ public: template void post(implementation_type& impl, Handler handler) { + asio::detail::mutex::scoped_lock lock(impl->mutex_); + // Allocate and construct an object to wrap the handler. typedef handler_wrapper value_type; typedef handler_alloc_traits alloc_traits; raw_handler_ptr raw_ptr(handler); handler_ptr ptr(raw_ptr, handler); - asio::detail::mutex::scoped_lock lock(impl->mutex_); - if (impl->current_handler_ == 0) { // This handler now has the lock, so can be dispatched immediately. diff --git a/libtorrent/include/asio/detail/task_io_service.hpp b/libtorrent/include/asio/detail/task_io_service.hpp index 802d7ea95..07df1c18a 100644 --- a/libtorrent/include/asio/detail/task_io_service.hpp +++ b/libtorrent/include/asio/detail/task_io_service.hpp @@ -40,7 +40,6 @@ public: : asio::detail::service_base >(io_service), mutex_(), task_(use_service(io_service)), - task_interrupted_(true), outstanding_work_(0), handler_queue_(&task_handler_), handler_queue_end_(&task_handler_), @@ -81,7 +80,8 @@ public: typename call_stack::context ctx(this); idle_thread_info this_idle_thread; - this_idle_thread.next = 0; + this_idle_thread.prev = &this_idle_thread; + this_idle_thread.next = &this_idle_thread; asio::detail::mutex::scoped_lock lock(mutex_); @@ -98,7 +98,8 @@ public: typename call_stack::context ctx(this); idle_thread_info this_idle_thread; - this_idle_thread.next = 0; + this_idle_thread.prev = &this_idle_thread; + this_idle_thread.next = &this_idle_thread; asio::detail::mutex::scoped_lock lock(mutex_); @@ -133,7 +134,7 @@ public: void stop() { asio::detail::mutex::scoped_lock lock(mutex_); - stop_all_threads(lock); + stop_all_threads(); } // Reset in preparation for a subsequent run invocation. @@ -155,7 +156,7 @@ public: { asio::detail::mutex::scoped_lock lock(mutex_); if (--outstanding_work_ == 0) - stop_all_threads(lock); + stop_all_threads(); } // Request invocation of the given handler. @@ -200,14 +201,9 @@ public: ++outstanding_work_; // Wake up a thread to execute the handler. - if (!interrupt_one_idle_thread(lock)) - { - if (!task_interrupted_) - { - task_interrupted_ = true; + if (!interrupt_one_idle_thread()) + if (task_handler_.next_ == 0 && handler_queue_end_ != &task_handler_) task_.interrupt(); - } - } } private: @@ -218,7 +214,7 @@ private: { if (outstanding_work_ == 0 && !stopped_) { - stop_all_threads(lock); + stop_all_threads(); ec = asio::error_code(); return 0; } @@ -234,14 +230,11 @@ private: handler_queue_ = h->next_; if (handler_queue_ == 0) handler_queue_end_ = 0; - h->next_ = 0; + bool more_handlers = (handler_queue_ != 0); + lock.unlock(); if (h == &task_handler_) { - bool more_handlers = (handler_queue_ != 0); - task_interrupted_ = more_handlers || polling; - lock.unlock(); - // If the task has already run and we're polling then we're done. if (task_has_run && polling) { @@ -259,7 +252,6 @@ private: } else { - lock.unlock(); handler_cleanup c(lock, *this); // Invoke the handler. May throw an exception. @@ -272,10 +264,31 @@ private: else if (this_idle_thread) { // Nothing to run right now, so just wait for work to do. - this_idle_thread->next = first_idle_thread_; + if (first_idle_thread_) + { + this_idle_thread->next = first_idle_thread_; + this_idle_thread->prev = first_idle_thread_->prev; + first_idle_thread_->prev->next = this_idle_thread; + first_idle_thread_->prev = this_idle_thread; + } first_idle_thread_ = this_idle_thread; - this_idle_thread->wakeup_event.clear(lock); - this_idle_thread->wakeup_event.wait(lock); + this_idle_thread->wakeup_event.clear(); + lock.unlock(); + this_idle_thread->wakeup_event.wait(); + lock.lock(); + if (this_idle_thread->next == this_idle_thread) + { + first_idle_thread_ = 0; + } + else + { + if (first_idle_thread_ == this_idle_thread) + first_idle_thread_ = this_idle_thread->next; + this_idle_thread->next->prev = this_idle_thread->prev; + this_idle_thread->prev->next = this_idle_thread->next; + this_idle_thread->next = this_idle_thread; + this_idle_thread->prev = this_idle_thread; + } } else { @@ -289,44 +302,39 @@ private: } // Stop the task and all idle threads. - void stop_all_threads( - asio::detail::mutex::scoped_lock& lock) + void stop_all_threads() { stopped_ = true; - interrupt_all_idle_threads(lock); - if (!task_interrupted_) - { - task_interrupted_ = true; + interrupt_all_idle_threads(); + if (task_handler_.next_ == 0 && handler_queue_end_ != &task_handler_) task_.interrupt(); - } } // Interrupt a single idle thread. Returns true if a thread was interrupted, // false if no running thread could be found to interrupt. - bool interrupt_one_idle_thread( - asio::detail::mutex::scoped_lock& lock) + bool interrupt_one_idle_thread() { if (first_idle_thread_) { - idle_thread_info* idle_thread = first_idle_thread_; - first_idle_thread_ = idle_thread->next; - idle_thread->next = 0; - idle_thread->wakeup_event.signal(lock); + first_idle_thread_->wakeup_event.signal(); + first_idle_thread_ = first_idle_thread_->next; return true; } return false; } // Interrupt all idle threads. - void interrupt_all_idle_threads( - asio::detail::mutex::scoped_lock& lock) + void interrupt_all_idle_threads() { - while (first_idle_thread_) + if (first_idle_thread_) { - idle_thread_info* idle_thread = first_idle_thread_; - first_idle_thread_ = idle_thread->next; - idle_thread->next = 0; - idle_thread->wakeup_event.signal(lock); + first_idle_thread_->wakeup_event.signal(); + idle_thread_info* current_idle_thread = first_idle_thread_->next; + while (current_idle_thread != first_idle_thread_) + { + current_idle_thread->wakeup_event.signal(); + current_idle_thread = current_idle_thread->next; + } } } @@ -432,7 +440,6 @@ private: { // Reinsert the task at the end of the handler queue. lock_.lock(); - task_io_service_.task_interrupted_ = true; task_io_service_.task_handler_.next_ = 0; if (task_io_service_.handler_queue_end_) { @@ -471,7 +478,7 @@ private: { lock_.lock(); if (--task_io_service_.outstanding_work_ == 0) - task_io_service_.stop_all_threads(lock_); + task_io_service_.stop_all_threads(); } private: @@ -496,9 +503,6 @@ private: } } task_handler_; - // Whether the task has been interrupted. - bool task_interrupted_; - // The count of unfinished work. int outstanding_work_; @@ -518,6 +522,7 @@ private: struct idle_thread_info { event wakeup_event; + idle_thread_info* prev; idle_thread_info* next; }; diff --git a/libtorrent/include/asio/detail/timer_queue.hpp b/libtorrent/include/asio/detail/timer_queue.hpp index 7735e87cf..af1e36bd5 100644 --- a/libtorrent/include/asio/detail/timer_queue.hpp +++ b/libtorrent/include/asio/detail/timer_queue.hpp @@ -48,9 +48,7 @@ public: // Constructor. timer_queue() : timers_(), - heap_(), - cancelled_timers_(0), - cleanup_timers_(0) + heap_() { } @@ -113,17 +111,12 @@ public: { timer_base* t = heap_[0]; remove_timer(t); - t->prev_ = 0; - t->next_ = cleanup_timers_; - cleanup_timers_ = t; t->invoke(asio::error_code()); } } - // Cancel the timers with the given token. Any timers pending for the token - // will be notified that they have been cancelled next time - // dispatch_cancellations is called. Returns the number of timers that were - // cancelled. + // Cancel the timer with the given token. The handler will be invoked + // immediately with the result operation_aborted. std::size_t cancel_timer(void* timer_token) { std::size_t num_cancelled = 0; @@ -136,9 +129,7 @@ public: { timer_base* next = t->next_; remove_timer(t); - t->prev_ = 0; - t->next_ = cancelled_timers_; - cancelled_timers_ = t; + t->invoke(asio::error::operation_aborted); t = next; ++num_cancelled; } @@ -146,31 +137,6 @@ public: return num_cancelled; } - // Dispatch any pending cancels for timers. - virtual void dispatch_cancellations() - { - while (cancelled_timers_) - { - timer_base* this_timer = cancelled_timers_; - cancelled_timers_ = this_timer->next_; - this_timer->next_ = cleanup_timers_; - cleanup_timers_ = this_timer; - this_timer->invoke(asio::error::operation_aborted); - } - } - - // Destroy timers that are waiting to be cleaned up. - virtual void cleanup_timers() - { - while (cleanup_timers_) - { - timer_base* next_timer = cleanup_timers_->next_; - cleanup_timers_->next_ = 0; - cleanup_timers_->destroy(); - cleanup_timers_ = next_timer; - } - } - // Destroy all timers. virtual void destroy_timers() { @@ -185,7 +151,6 @@ public: } heap_.clear(); timers_.clear(); - cleanup_timers(); } private: @@ -273,7 +238,8 @@ private: static void invoke_handler(timer_base* base, const asio::error_code& result) { - static_cast*>(base)->handler_(result); + std::auto_ptr > t(static_cast*>(base)); + t->handler_(result); } // Destroy the handler. @@ -372,12 +338,6 @@ private: // The heap of timers, with the earliest timer at the front. std::vector heap_; - - // The list of timers to be cancelled. - timer_base* cancelled_timers_; - - // The list of timers to be destroyed. - timer_base* cleanup_timers_; }; } // namespace detail diff --git a/libtorrent/include/asio/detail/timer_queue_base.hpp b/libtorrent/include/asio/detail/timer_queue_base.hpp index 6cf25747a..c8be49748 100644 --- a/libtorrent/include/asio/detail/timer_queue_base.hpp +++ b/libtorrent/include/asio/detail/timer_queue_base.hpp @@ -44,12 +44,6 @@ public: // Dispatch all ready timers. virtual void dispatch_timers() = 0; - // Dispatch any pending cancels for timers. - virtual void dispatch_cancellations() = 0; - - // Destroy timers that are waiting to be cleaned up. - virtual void cleanup_timers() = 0; - // Destroy all timers. virtual void destroy_timers() = 0; }; diff --git a/libtorrent/include/asio/detail/win_event.hpp b/libtorrent/include/asio/detail/win_event.hpp index c73ed56ea..8de9383da 100644 --- a/libtorrent/include/asio/detail/win_event.hpp +++ b/libtorrent/include/asio/detail/win_event.hpp @@ -23,13 +23,11 @@ #if defined(BOOST_WINDOWS) -#include "asio/error.hpp" #include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" #include "asio/detail/push_options.hpp" -#include #include #include "asio/detail/pop_options.hpp" @@ -48,8 +46,7 @@ public: { DWORD last_error = ::GetLastError(); asio::system_error e( - asio::error_code(last_error, - asio::error::system_category), + asio::error_code(last_error, asio::native_ecat), "event"); boost::throw_exception(e); } @@ -62,31 +59,21 @@ public: } // Signal the event. - template - void signal(Lock& lock) + void signal() { - BOOST_ASSERT(lock.locked()); - (void)lock; ::SetEvent(event_); } // Reset the event. - template - void clear(Lock& lock) + void clear() { - BOOST_ASSERT(lock.locked()); - (void)lock; ::ResetEvent(event_); } // Wait for the event to become signalled. - template - void wait(Lock& lock) + void wait() { - BOOST_ASSERT(lock.locked()); - lock.unlock(); ::WaitForSingleObject(event_, INFINITE); - lock.lock(); } private: diff --git a/libtorrent/include/asio/detail/win_iocp_io_service.hpp b/libtorrent/include/asio/detail/win_iocp_io_service.hpp index 61eeb1745..4957fb01a 100644 --- a/libtorrent/include/asio/detail/win_iocp_io_service.hpp +++ b/libtorrent/include/asio/detail/win_iocp_io_service.hpp @@ -63,8 +63,7 @@ public: { DWORD last_error = ::GetLastError(); asio::system_error e( - asio::error_code(last_error, - asio::error::system_category), + asio::error_code(last_error, asio::native_ecat), "iocp"); boost::throw_exception(e); } @@ -174,8 +173,7 @@ public: { DWORD last_error = ::GetLastError(); asio::system_error e( - asio::error_code(last_error, - asio::error::system_category), + asio::error_code(last_error, asio::native_ecat), "pqcs"); boost::throw_exception(e); } @@ -230,8 +228,7 @@ public: { DWORD last_error = ::GetLastError(); asio::system_error e( - asio::error_code(last_error, - asio::error::system_category), + asio::error_code(last_error, asio::native_ecat), "pqcs"); boost::throw_exception(e); } @@ -250,8 +247,7 @@ public: { DWORD last_error = ::GetLastError(); asio::system_error e( - asio::error_code(last_error, - asio::error::system_category), + asio::error_code(last_error, asio::native_ecat), "pqcs"); boost::throw_exception(e); } @@ -316,7 +312,7 @@ private: { DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, - asio::error::system_category); + asio::native_ecat); return 0; } diff --git a/libtorrent/include/asio/detail/win_iocp_io_service_fwd.hpp b/libtorrent/include/asio/detail/win_iocp_io_service_fwd.hpp index 26eacae2a..184fdfa18 100644 --- a/libtorrent/include/asio/detail/win_iocp_io_service_fwd.hpp +++ b/libtorrent/include/asio/detail/win_iocp_io_service_fwd.hpp @@ -21,8 +21,6 @@ #include #include "asio/detail/pop_options.hpp" -#include "asio/detail/socket_types.hpp" - // This service is only supported on Win32 (NT4 and later). #if !defined(ASIO_DISABLE_IOCP) #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) diff --git a/libtorrent/include/asio/detail/win_iocp_socket_service.hpp b/libtorrent/include/asio/detail/win_iocp_socket_service.hpp index 17d1d5887..007286e8d 100644 --- a/libtorrent/include/asio/detail/win_iocp_socket_service.hpp +++ b/libtorrent/include/asio/detail/win_iocp_socket_service.hpp @@ -137,7 +137,7 @@ public: enum { enable_connection_aborted = 1, // User wants connection_aborted errors. - close_might_block = 2, // User set linger option for blocking close. + user_set_linger = 2, // The user set the linger option. user_set_non_blocking = 4 // The user wants a non-blocking socket. }; @@ -170,7 +170,7 @@ public: typedef detail::select_reactor reactor_type; // The maximum number of buffers to support in a single operation. - enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; + enum { max_buffers = 16 }; // Constructor. win_iocp_socket_service(asio::io_service& io_service) @@ -192,7 +192,7 @@ public: while (impl) { asio::error_code ignored_ec; - close_for_destruction(*impl); + close(*impl, ignored_ec); impl = impl->next_; } } @@ -217,7 +217,34 @@ public: // Destroy a socket implementation. void destroy(implementation_type& impl) { - close_for_destruction(impl); + if (impl.socket_ != invalid_socket) + { + // Check if the reactor was created, in which case we need to close the + // socket on the reactor as well to cancel any operations that might be + // running there. + reactor_type* reactor = static_cast( + interlocked_compare_exchange_pointer( + reinterpret_cast(&reactor_), 0, 0)); + if (reactor) + reactor->close_descriptor(impl.socket_); + + if (impl.flags_ & implementation_type::user_set_linger) + { + ::linger opt; + opt.l_onoff = 0; + opt.l_linger = 0; + asio::error_code ignored_ec; + socket_ops::setsockopt(impl.socket_, + SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec); + } + + asio::error_code ignored_ec; + socket_ops::close(impl.socket_, ignored_ec); + impl.socket_ = invalid_socket; + impl.flags_ = 0; + impl.cancel_token_.reset(); + impl.safe_cancellation_thread_id_ = 0; + } // Remove implementation from linked list of all implementations. asio::detail::mutex::scoped_lock lock(mutex_); @@ -326,25 +353,6 @@ public: { ec = asio::error::bad_descriptor; } - else if (FARPROC cancel_io_ex_ptr = ::GetProcAddress( - ::GetModuleHandle("KERNEL32"), "CancelIoEx")) - { - // The version of Windows supports cancellation from any thread. - typedef BOOL (WINAPI* cancel_io_ex_t)(HANDLE, LPOVERLAPPED); - cancel_io_ex_t cancel_io_ex = (cancel_io_ex_t)cancel_io_ex_ptr; - socket_type sock = impl.socket_; - HANDLE sock_as_handle = reinterpret_cast(sock); - if (!cancel_io_ex(sock_as_handle, 0)) - { - DWORD last_error = ::GetLastError(); - ec = asio::error_code(last_error, - asio::error::system_category); - } - else - { - ec = asio::error_code(); - } - } else if (impl.safe_cancellation_thread_id_ == 0) { // No operations have been started, so there's nothing to cancel. @@ -359,8 +367,7 @@ public: if (!::CancelIo(sock_as_handle)) { DWORD last_error = ::GetLastError(); - ec = asio::error_code(last_error, - asio::error::system_category); + ec = asio::error_code(last_error, asio::native_ecat); } else { @@ -468,12 +475,7 @@ public: if (option.level(impl.protocol_) == SOL_SOCKET && option.name(impl.protocol_) == SO_LINGER) { - const ::linger* linger_option = - reinterpret_cast(option.data(impl.protocol_)); - if (linger_option->l_onoff != 0 && linger_option->l_linger != 0) - impl.flags_ |= implementation_type::close_might_block; - else - impl.flags_ &= ~implementation_type::close_might_block; + impl.flags_ |= implementation_type::user_set_linger; } socket_ops::setsockopt(impl.socket_, @@ -666,8 +668,7 @@ public: last_error = WSAECONNRESET; else if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; - ec = asio::error_code(last_error, - asio::error::system_category); + ec = asio::error_code(last_error, asio::native_ecat); return 0; } @@ -718,8 +719,7 @@ public: #endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) // Map non-portable errors to their portable counterparts. - asio::error_code ec(last_error, - asio::error::system_category); + asio::error_code ec(last_error, asio::native_ecat); if (ec.value() == ERROR_NETNAME_DELETED) { if (handler_op->cancel_token_.expired()) @@ -821,8 +821,7 @@ public: { asio::io_service::work work(this->io_service()); ptr.reset(); - asio::error_code ec(last_error, - asio::error::system_category); + asio::error_code ec(last_error, asio::native_ecat); iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else @@ -866,8 +865,7 @@ public: DWORD last_error = ::WSAGetLastError(); if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; - ec = asio::error_code(last_error, - asio::error::system_category); + ec = asio::error_code(last_error, asio::native_ecat); return 0; } @@ -916,8 +914,7 @@ public: #endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) // Map non-portable errors to their portable counterparts. - asio::error_code ec(last_error, - asio::error::system_category); + asio::error_code ec(last_error, asio::native_ecat); if (ec.value() == ERROR_PORT_UNREACHABLE) { ec = asio::error::connection_refused; @@ -1000,8 +997,7 @@ public: { asio::io_service::work work(this->io_service()); ptr.reset(); - asio::error_code ec(last_error, - asio::error::system_category); + asio::error_code ec(last_error, asio::native_ecat); iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else @@ -1055,8 +1051,7 @@ public: last_error = WSAECONNRESET; else if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; - ec = asio::error_code(last_error, - asio::error::system_category); + ec = asio::error_code(last_error, asio::native_ecat); return 0; } if (bytes_transferred == 0) @@ -1114,8 +1109,7 @@ public: #endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) // Map non-portable errors to their portable counterparts. - asio::error_code ec(last_error, - asio::error::system_category); + asio::error_code ec(last_error, asio::native_ecat); if (ec.value() == ERROR_NETNAME_DELETED) { if (handler_op->cancel_token_.expired()) @@ -1222,8 +1216,7 @@ public: { asio::io_service::work work(this->io_service()); ptr.reset(); - asio::error_code ec(last_error, - asio::error::system_category); + asio::error_code ec(last_error, asio::native_ecat); iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else @@ -1269,8 +1262,7 @@ public: DWORD last_error = ::WSAGetLastError(); if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; - ec = asio::error_code(last_error, - asio::error::system_category); + ec = asio::error_code(last_error, asio::native_ecat); return 0; } if (bytes_transferred == 0) @@ -1336,8 +1328,7 @@ public: #endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) // Map non-portable errors to their portable counterparts. - asio::error_code ec(last_error, - asio::error::system_category); + asio::error_code ec(last_error, asio::native_ecat); if (ec.value() == ERROR_PORT_UNREACHABLE) { ec = asio::error::connection_refused; @@ -1431,8 +1422,7 @@ public: { asio::io_service::work work(this->io_service()); ptr.reset(); - asio::error_code ec(last_error, - asio::error::system_category); + asio::error_code ec(last_error, asio::native_ecat); iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else @@ -1669,8 +1659,7 @@ public: ptr.reset(); // Call the handler. - asio::error_code ec(last_error, - asio::error::system_category); + asio::error_code ec(last_error, asio::native_ecat); asio_handler_invoke_helpers::invoke( detail::bind_handler(handler, ec), &handler); } @@ -1770,8 +1759,7 @@ public: { asio::io_service::work work(this->io_service()); ptr.reset(); - asio::error_code ec(last_error, - asio::error::system_category); + asio::error_code ec(last_error, asio::native_ecat); iocp_service_.post(bind_handler(handler, ec)); } } @@ -1847,8 +1835,8 @@ public: // If connection failed then post the handler with the error code. if (connect_error) { - ec = asio::error_code(connect_error, - asio::error::system_category); + ec = asio::error_code( + connect_error, asio::native_ecat); io_service_.post(bind_handler(handler_, ec)); return true; } @@ -1962,66 +1950,26 @@ public: } private: - // Helper function to close a socket when the associated object is being - // destroyed. - void close_for_destruction(implementation_type& impl) - { - if (is_open(impl)) - { - // Check if the reactor was created, in which case we need to close the - // socket on the reactor as well to cancel any operations that might be - // running there. - reactor_type* reactor = static_cast( - interlocked_compare_exchange_pointer( - reinterpret_cast(&reactor_), 0, 0)); - if (reactor) - reactor->close_descriptor(impl.socket_); - - // The socket destructor must not block. If the user has changed the - // linger option to block in the foreground, we will change it back to the - // default so that the closure is performed in the background. - if (impl.flags_ & implementation_type::close_might_block) - { - ::linger opt; - opt.l_onoff = 0; - opt.l_linger = 0; - asio::error_code ignored_ec; - socket_ops::setsockopt(impl.socket_, - SOL_SOCKET, SO_LINGER, &opt, sizeof(opt), ignored_ec); - } - - asio::error_code ignored_ec; - socket_ops::close(impl.socket_, ignored_ec); - impl.socket_ = invalid_socket; - impl.flags_ = 0; - impl.cancel_token_.reset(); - impl.safe_cancellation_thread_id_ = 0; - } - } - - // Helper function to emulate InterlockedCompareExchangePointer functionality - // for: - // - very old Platform SDKs; and - // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. + // Helper function to provide InterlockedCompareExchangePointer functionality + // on very old Platform SDKs. void* interlocked_compare_exchange_pointer(void** dest, void* exch, void* cmp) { -#if defined(_M_IX86) +#if defined(_WIN32_WINNT) && (_WIN32_WINNT <= 0x400) && (_M_IX86) return reinterpret_cast(InterlockedCompareExchange( - reinterpret_cast(dest), reinterpret_cast(exch), + reinterpret_cast(dest), reinterpret_cast(exch), reinterpret_cast(cmp))); #else return InterlockedCompareExchangePointer(dest, exch, cmp); #endif } - // Helper function to emulate InterlockedExchangePointer functionality for: - // - very old Platform SDKs; and - // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. + // Helper function to provide InterlockedExchangePointer functionality on very + // old Platform SDKs. void* interlocked_exchange_pointer(void** dest, void* val) { -#if defined(_M_IX86) +#if defined(_WIN32_WINNT) && (_WIN32_WINNT <= 0x400) && (_M_IX86) return reinterpret_cast(InterlockedExchange( - reinterpret_cast(dest), reinterpret_cast(val))); + reinterpret_cast(dest), reinterpret_cast(val))); #else return InterlockedExchangePointer(dest, val); #endif diff --git a/libtorrent/include/asio/detail/win_mutex.hpp b/libtorrent/include/asio/detail/win_mutex.hpp index 4d1bc20c2..82659831f 100644 --- a/libtorrent/include/asio/detail/win_mutex.hpp +++ b/libtorrent/include/asio/detail/win_mutex.hpp @@ -23,7 +23,6 @@ #if defined(BOOST_WINDOWS) -#include "asio/error.hpp" #include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" @@ -49,7 +48,7 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, asio::native_ecat), "mutex"); boost::throw_exception(e); } @@ -68,7 +67,7 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::error::system_category), + asio::error_code(error, asio::native_ecat), "mutex"); boost::throw_exception(e); } diff --git a/libtorrent/include/asio/detail/win_thread.hpp b/libtorrent/include/asio/detail/win_thread.hpp index c6bd61af5..a6c9b15d2 100644 --- a/libtorrent/include/asio/detail/win_thread.hpp +++ b/libtorrent/include/asio/detail/win_thread.hpp @@ -23,7 +23,6 @@ #if defined(BOOST_WINDOWS) -#include "asio/error.hpp" #include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" @@ -55,8 +54,7 @@ public: { DWORD last_error = ::GetLastError(); asio::system_error e( - asio::error_code(last_error, - asio::error::system_category), + asio::error_code(last_error, asio::native_ecat), "thread"); boost::throw_exception(e); } diff --git a/libtorrent/include/asio/detail/win_tss_ptr.hpp b/libtorrent/include/asio/detail/win_tss_ptr.hpp index d84810d41..d3e2f8161 100644 --- a/libtorrent/include/asio/detail/win_tss_ptr.hpp +++ b/libtorrent/include/asio/detail/win_tss_ptr.hpp @@ -23,7 +23,6 @@ #if defined(BOOST_WINDOWS) -#include "asio/error.hpp" #include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" @@ -48,8 +47,7 @@ public: { DWORD last_error = ::GetLastError(); asio::system_error e( - asio::error_code(last_error, - asio::error::system_category), + asio::error_code(last_error, asio::native_ecat), "tss"); boost::throw_exception(e); } diff --git a/libtorrent/include/asio/detail/winsock_init.hpp b/libtorrent/include/asio/detail/winsock_init.hpp index 874d2b77b..67c69e8ce 100644 --- a/libtorrent/include/asio/detail/winsock_init.hpp +++ b/libtorrent/include/asio/detail/winsock_init.hpp @@ -85,8 +85,7 @@ public: if (this != &instance_ && ref_->result() != 0) { asio::system_error e( - asio::error_code(ref_->result(), - asio::error::system_category), + asio::error_code(ref_->result(), asio::native_ecat), "winsock"); boost::throw_exception(e); } diff --git a/libtorrent/include/asio/detail/wrapped_handler.hpp b/libtorrent/include/asio/detail/wrapped_handler.hpp index 913a795dc..f757fd3dc 100644 --- a/libtorrent/include/asio/detail/wrapped_handler.hpp +++ b/libtorrent/include/asio/detail/wrapped_handler.hpp @@ -17,10 +17,6 @@ #include "asio/detail/push_options.hpp" -#include "asio/detail/push_options.hpp" -#include -#include "asio/detail/pop_options.hpp" - #include "asio/detail/bind_handler.hpp" #include "asio/detail/handler_alloc_helpers.hpp" #include "asio/detail/handler_invoke_helpers.hpp" @@ -34,9 +30,7 @@ class wrapped_handler public: typedef void result_type; - wrapped_handler( - typename boost::add_reference::type dispatcher, - Handler handler) + wrapped_handler(Dispatcher& dispatcher, Handler handler) : dispatcher_(dispatcher), handler_(handler) { @@ -123,7 +117,7 @@ public: } //private: - Dispatcher dispatcher_; + Dispatcher& dispatcher_; Handler handler_; }; @@ -177,9 +171,9 @@ inline void asio_handler_invoke(const Function& function, function, this_handler->handler_)); } -template +template inline void asio_handler_invoke(const Function& function, - rewrapped_handler* this_handler) + rewrapped_handler* this_handler) { asio_handler_invoke_helpers::invoke( function, &this_handler->context_); diff --git a/libtorrent/include/asio/error.hpp b/libtorrent/include/asio/error.hpp index a8316be2c..935cc6796 100644 --- a/libtorrent/include/asio/error.hpp +++ b/libtorrent/include/asio/error.hpp @@ -37,195 +37,327 @@ /// INTERNAL ONLY. # define ASIO_WIN_OR_POSIX(e_win, e_posix) implementation_defined #elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# define ASIO_NATIVE_ERROR(e) e -# define ASIO_SOCKET_ERROR(e) WSA ## e -# define ASIO_NETDB_ERROR(e) WSA ## e -# define ASIO_GETADDRINFO_ERROR(e) WSA ## e +# define ASIO_NATIVE_ERROR(e) \ + asio::error_code(e, \ + asio::native_ecat) +# define ASIO_SOCKET_ERROR(e) \ + asio::error_code(WSA ## e, \ + asio::native_ecat) +# define ASIO_NETDB_ERROR(e) \ + asio::error_code(WSA ## e, \ + asio::native_ecat) +# define ASIO_GETADDRINFO_ERROR(e) \ + asio::error_code(WSA ## e, \ + asio::native_ecat) +# define ASIO_MISC_ERROR(e) \ + asio::error_code(e, \ + asio::misc_ecat) # define ASIO_WIN_OR_POSIX(e_win, e_posix) e_win #else -# define ASIO_NATIVE_ERROR(e) e -# define ASIO_SOCKET_ERROR(e) e -# define ASIO_NETDB_ERROR(e) e -# define ASIO_GETADDRINFO_ERROR(e) e +# define ASIO_NATIVE_ERROR(e) \ + asio::error_code(e, \ + asio::native_ecat) +# define ASIO_SOCKET_ERROR(e) \ + asio::error_code(e, \ + asio::native_ecat) +# define ASIO_NETDB_ERROR(e) \ + asio::error_code(e, \ + asio::netdb_ecat) +# define ASIO_GETADDRINFO_ERROR(e) \ + asio::error_code(e, \ + asio::addrinfo_ecat) +# define ASIO_MISC_ERROR(e) \ + asio::error_code(e, \ + asio::misc_ecat) # define ASIO_WIN_OR_POSIX(e_win, e_posix) e_posix #endif namespace asio { -namespace error { -enum basic_errors +namespace detail { + +/// Hack to keep asio library header-file-only. +template +class error_base { +public: + // boostify: error category declarations go here. + /// Permission denied. - access_denied = ASIO_SOCKET_ERROR(EACCES), + static const asio::error_code access_denied; /// Address family not supported by protocol. - address_family_not_supported = ASIO_SOCKET_ERROR(EAFNOSUPPORT), + static const asio::error_code address_family_not_supported; /// Address already in use. - address_in_use = ASIO_SOCKET_ERROR(EADDRINUSE), + static const asio::error_code address_in_use; /// Transport endpoint is already connected. - already_connected = ASIO_SOCKET_ERROR(EISCONN), + static const asio::error_code already_connected; + + /// Already open. + static const asio::error_code already_open; /// Operation already in progress. - already_started = ASIO_SOCKET_ERROR(EALREADY), + static const asio::error_code already_started; /// A connection has been aborted. - connection_aborted = ASIO_SOCKET_ERROR(ECONNABORTED), + static const asio::error_code connection_aborted; /// Connection refused. - connection_refused = ASIO_SOCKET_ERROR(ECONNREFUSED), + static const asio::error_code connection_refused; /// Connection reset by peer. - connection_reset = ASIO_SOCKET_ERROR(ECONNRESET), + static const asio::error_code connection_reset; /// Bad file descriptor. - bad_descriptor = ASIO_SOCKET_ERROR(EBADF), - - /// Bad address. - fault = ASIO_SOCKET_ERROR(EFAULT), - - /// No route to host. - host_unreachable = ASIO_SOCKET_ERROR(EHOSTUNREACH), - - /// Operation now in progress. - in_progress = ASIO_SOCKET_ERROR(EINPROGRESS), - - /// Interrupted system call. - interrupted = ASIO_SOCKET_ERROR(EINTR), - - /// Invalid argument. - invalid_argument = ASIO_SOCKET_ERROR(EINVAL), - - /// Message too long. - message_size = ASIO_SOCKET_ERROR(EMSGSIZE), - - /// Network is down. - network_down = ASIO_SOCKET_ERROR(ENETDOWN), - - /// Network dropped connection on reset. - network_reset = ASIO_SOCKET_ERROR(ENETRESET), - - /// Network is unreachable. - network_unreachable = ASIO_SOCKET_ERROR(ENETUNREACH), - - /// Too many open files. - no_descriptors = ASIO_SOCKET_ERROR(EMFILE), - - /// No buffer space available. - no_buffer_space = ASIO_SOCKET_ERROR(ENOBUFS), - - /// Cannot allocate memory. - no_memory = ASIO_WIN_OR_POSIX( - ASIO_NATIVE_ERROR(ERROR_OUTOFMEMORY), - ASIO_NATIVE_ERROR(ENOMEM)), - - /// Operation not permitted. - no_permission = ASIO_WIN_OR_POSIX( - ASIO_NATIVE_ERROR(ERROR_ACCESS_DENIED), - ASIO_NATIVE_ERROR(EPERM)), - - /// Protocol not available. - no_protocol_option = ASIO_SOCKET_ERROR(ENOPROTOOPT), - - /// Transport endpoint is not connected. - not_connected = ASIO_SOCKET_ERROR(ENOTCONN), - - /// Socket operation on non-socket. - not_socket = ASIO_SOCKET_ERROR(ENOTSOCK), - - /// Operation cancelled. - operation_aborted = ASIO_WIN_OR_POSIX( - ASIO_NATIVE_ERROR(ERROR_OPERATION_ABORTED), - ASIO_NATIVE_ERROR(ECANCELED)), - - /// Operation not supported. - operation_not_supported = ASIO_SOCKET_ERROR(EOPNOTSUPP), - - /// Cannot send after transport endpoint shutdown. - shut_down = ASIO_SOCKET_ERROR(ESHUTDOWN), - - /// Connection timed out. - timed_out = ASIO_SOCKET_ERROR(ETIMEDOUT), - - /// Resource temporarily unavailable. - try_again = ASIO_WIN_OR_POSIX( - ASIO_NATIVE_ERROR(ERROR_RETRY), - ASIO_NATIVE_ERROR(EAGAIN)), - - /// The socket is marked non-blocking and the requested operation would block. - would_block = ASIO_SOCKET_ERROR(EWOULDBLOCK) -}; - -enum netdb_errors -{ - /// Host not found (authoritative). - host_not_found = ASIO_NETDB_ERROR(HOST_NOT_FOUND), - - /// Host not found (non-authoritative). - host_not_found_try_again = ASIO_NETDB_ERROR(TRY_AGAIN), - - /// The query is valid but does not have associated address data. - no_data = ASIO_NETDB_ERROR(NO_DATA), - - /// A non-recoverable error occurred. - no_recovery = ASIO_NETDB_ERROR(NO_RECOVERY) -}; - -enum addrinfo_errors -{ - /// The service is not supported for the given socket type. - service_not_found = ASIO_WIN_OR_POSIX( - ASIO_NATIVE_ERROR(WSATYPE_NOT_FOUND), - ASIO_GETADDRINFO_ERROR(EAI_SERVICE)), - - /// The socket type is not supported. - socket_type_not_supported = ASIO_WIN_OR_POSIX( - ASIO_NATIVE_ERROR(WSAESOCKTNOSUPPORT), - ASIO_GETADDRINFO_ERROR(EAI_SOCKTYPE)) -}; - -enum misc_errors -{ - /// Already open. - already_open = 1, + static const asio::error_code bad_descriptor; /// End of file or stream. - eof, + static const asio::error_code eof; + + /// Bad address. + static const asio::error_code fault; + + /// Host not found (authoritative). + static const asio::error_code host_not_found; + + /// Host not found (non-authoritative). + static const asio::error_code host_not_found_try_again; + + /// No route to host. + static const asio::error_code host_unreachable; + + /// Operation now in progress. + static const asio::error_code in_progress; + + /// Interrupted system call. + static const asio::error_code interrupted; + + /// Invalid argument. + static const asio::error_code invalid_argument; + + /// Message too long. + static const asio::error_code message_size; + + /// Network is down. + static const asio::error_code network_down; + + /// Network dropped connection on reset. + static const asio::error_code network_reset; + + /// Network is unreachable. + static const asio::error_code network_unreachable; + + /// Too many open files. + static const asio::error_code no_descriptors; + + /// No buffer space available. + static const asio::error_code no_buffer_space; + + /// The query is valid but does not have associated address data. + static const asio::error_code no_data; + + /// Cannot allocate memory. + static const asio::error_code no_memory; + + /// Operation not permitted. + static const asio::error_code no_permission; + + /// Protocol not available. + static const asio::error_code no_protocol_option; + + /// A non-recoverable error occurred. + static const asio::error_code no_recovery; + + /// Transport endpoint is not connected. + static const asio::error_code not_connected; /// Element not found. - not_found + static const asio::error_code not_found; + + /// Socket operation on non-socket. + static const asio::error_code not_socket; + + /// Operation cancelled. + static const asio::error_code operation_aborted; + + /// Operation not supported. + static const asio::error_code operation_not_supported; + + /// The service is not supported for the given socket type. + static const asio::error_code service_not_found; + + /// The socket type is not supported. + static const asio::error_code socket_type_not_supported; + + /// Cannot send after transport endpoint shutdown. + static const asio::error_code shut_down; + + /// Connection timed out. + static const asio::error_code timed_out; + + /// Resource temporarily unavailable. + static const asio::error_code try_again; + + /// The socket is marked non-blocking and the requested operation would block. + static const asio::error_code would_block; + +private: + error_base(); }; // boostify: error category definitions go here. -inline asio::error_code make_error_code(basic_errors e) -{ - return asio::error_code(static_cast(e), system_category); -} +template const asio::error_code +error_base::access_denied = ASIO_SOCKET_ERROR(EACCES); -inline asio::error_code make_error_code(netdb_errors e) -{ - return asio::error_code(static_cast(e), netdb_category); -} +template const asio::error_code +error_base::address_family_not_supported = ASIO_SOCKET_ERROR( + EAFNOSUPPORT); -inline asio::error_code make_error_code(addrinfo_errors e) -{ - return asio::error_code(static_cast(e), addrinfo_category); -} +template const asio::error_code +error_base::address_in_use = ASIO_SOCKET_ERROR(EADDRINUSE); -inline asio::error_code make_error_code(misc_errors e) -{ - return asio::error_code(static_cast(e), misc_category); -} +template const asio::error_code +error_base::already_connected = ASIO_SOCKET_ERROR(EISCONN); + +template const asio::error_code +error_base::already_open = ASIO_MISC_ERROR(1); + +template const asio::error_code +error_base::already_started = ASIO_SOCKET_ERROR(EALREADY); + +template const asio::error_code +error_base::connection_aborted = ASIO_SOCKET_ERROR(ECONNABORTED); + +template const asio::error_code +error_base::connection_refused = ASIO_SOCKET_ERROR(ECONNREFUSED); + +template const asio::error_code +error_base::connection_reset = ASIO_SOCKET_ERROR(ECONNRESET); + +template const asio::error_code +error_base::bad_descriptor = ASIO_SOCKET_ERROR(EBADF); + +template const asio::error_code +error_base::eof = ASIO_MISC_ERROR(2); + +template const asio::error_code +error_base::fault = ASIO_SOCKET_ERROR(EFAULT); + +template const asio::error_code +error_base::host_not_found = ASIO_NETDB_ERROR(HOST_NOT_FOUND); + +template const asio::error_code +error_base::host_not_found_try_again = ASIO_NETDB_ERROR(TRY_AGAIN); + +template const asio::error_code +error_base::host_unreachable = ASIO_SOCKET_ERROR(EHOSTUNREACH); + +template const asio::error_code +error_base::in_progress = ASIO_SOCKET_ERROR(EINPROGRESS); + +template const asio::error_code +error_base::interrupted = ASIO_SOCKET_ERROR(EINTR); + +template const asio::error_code +error_base::invalid_argument = ASIO_SOCKET_ERROR(EINVAL); + +template const asio::error_code +error_base::message_size = ASIO_SOCKET_ERROR(EMSGSIZE); + +template const asio::error_code +error_base::network_down = ASIO_SOCKET_ERROR(ENETDOWN); + +template const asio::error_code +error_base::network_reset = ASIO_SOCKET_ERROR(ENETRESET); + +template const asio::error_code +error_base::network_unreachable = ASIO_SOCKET_ERROR(ENETUNREACH); + +template const asio::error_code +error_base::no_descriptors = ASIO_SOCKET_ERROR(EMFILE); + +template const asio::error_code +error_base::no_buffer_space = ASIO_SOCKET_ERROR(ENOBUFS); + +template const asio::error_code +error_base::no_data = ASIO_NETDB_ERROR(NO_DATA); + +template const asio::error_code +error_base::no_memory = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(ERROR_OUTOFMEMORY), + ASIO_NATIVE_ERROR(ENOMEM)); + +template const asio::error_code +error_base::no_permission = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(ERROR_ACCESS_DENIED), + ASIO_NATIVE_ERROR(EPERM)); + +template const asio::error_code +error_base::no_protocol_option = ASIO_SOCKET_ERROR(ENOPROTOOPT); + +template const asio::error_code +error_base::no_recovery = ASIO_NETDB_ERROR(NO_RECOVERY); + +template const asio::error_code +error_base::not_connected = ASIO_SOCKET_ERROR(ENOTCONN); + +template const asio::error_code +error_base::not_found = ASIO_MISC_ERROR(3); + +template const asio::error_code +error_base::not_socket = ASIO_SOCKET_ERROR(ENOTSOCK); + +template const asio::error_code +error_base::operation_aborted = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(ERROR_OPERATION_ABORTED), + ASIO_NATIVE_ERROR(ECANCELED)); + +template const asio::error_code +error_base::operation_not_supported = ASIO_SOCKET_ERROR(EOPNOTSUPP); + +template const asio::error_code +error_base::service_not_found = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(WSATYPE_NOT_FOUND), + ASIO_GETADDRINFO_ERROR(EAI_SERVICE)); + +template const asio::error_code +error_base::socket_type_not_supported = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(WSAESOCKTNOSUPPORT), + ASIO_GETADDRINFO_ERROR(EAI_SOCKTYPE)); + +template const asio::error_code +error_base::shut_down = ASIO_SOCKET_ERROR(ESHUTDOWN); + +template const asio::error_code +error_base::timed_out = ASIO_SOCKET_ERROR(ETIMEDOUT); + +template const asio::error_code +error_base::try_again = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(ERROR_RETRY), + ASIO_NATIVE_ERROR(EAGAIN)); + +template const asio::error_code +error_base::would_block = ASIO_SOCKET_ERROR(EWOULDBLOCK); + +} // namespace detail + +/// Contains error constants. +class error : public asio::detail::error_base +{ +private: + error(); +}; -} // namespace error } // namespace asio #undef ASIO_NATIVE_ERROR #undef ASIO_SOCKET_ERROR #undef ASIO_NETDB_ERROR #undef ASIO_GETADDRINFO_ERROR +#undef ASIO_MISC_ERROR #undef ASIO_WIN_OR_POSIX #include "asio/impl/error_code.ipp" diff --git a/libtorrent/include/asio/error_code.hpp b/libtorrent/include/asio/error_code.hpp index 0941a8c00..0614490e2 100644 --- a/libtorrent/include/asio/error_code.hpp +++ b/libtorrent/include/asio/error_code.hpp @@ -32,27 +32,24 @@ namespace asio { -namespace error +/// Available error code categories. +enum error_category { - /// Available error code categories. - enum error_category - { - /// System error codes. - system_category = ASIO_WIN_OR_POSIX(0, 0), + /// Native error codes. + native_ecat = ASIO_WIN_OR_POSIX(0, 0), - /// Error codes from NetDB functions. - netdb_category = ASIO_WIN_OR_POSIX(system_category, 1), + /// Error codes from NetDB functions. + netdb_ecat = ASIO_WIN_OR_POSIX(native_ecat, 1), - /// Error codes from getaddrinfo. - addrinfo_category = ASIO_WIN_OR_POSIX(system_category, 2), + /// Error codes from getaddrinfo. + addrinfo_ecat = ASIO_WIN_OR_POSIX(native_ecat, 2), - /// Miscellaneous error codes. - misc_category = ASIO_WIN_OR_POSIX(3, 3), + /// Miscellaneous error codes. + misc_ecat = ASIO_WIN_OR_POSIX(3, 3), - /// SSL error codes. - ssl_category = ASIO_WIN_OR_POSIX(4, 4) - }; -} // namespace error + /// SSL error codes. + ssl_ecat = ASIO_WIN_OR_POSIX(4, 4) +}; /// Class to represent an error code value. class error_code @@ -64,24 +61,17 @@ public: /// Default constructor. error_code() : value_(0), - category_(error::system_category) + category_(native_ecat) { } /// Construct with specific error code and category. - error_code(value_type v, error::error_category c) + error_code(value_type v, error_category c) : value_(v), category_(c) { } - /// Construct from an error code enum. - template - error_code(ErrorEnum e) - { - *this = make_error_code(e); - } - /// Get the error value. value_type value() const { @@ -89,7 +79,7 @@ public: } /// Get the error category. - error::error_category category() const + error_category category() const { return category_; } @@ -135,7 +125,7 @@ private: value_type value_; // The category associated with the error code. - error::error_category category_; + error_category category_; }; } // namespace asio diff --git a/libtorrent/include/asio/impl/error_code.ipp b/libtorrent/include/asio/impl/error_code.ipp index f66b6fd94..da2f98833 100644 --- a/libtorrent/include/asio/impl/error_code.ipp +++ b/libtorrent/include/asio/impl/error_code.ipp @@ -35,12 +35,10 @@ inline std::string error_code::message() const return "Already open."; if (*this == error::not_found) return "Not found."; - if (category_ == error::ssl_category) + if (category_ == ssl_ecat) return "SSL error."; #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) value_type value = value_; - if (category() != error::system_category && *this != error::eof) - return "asio error"; if (*this == error::eof) value = ERROR_HANDLE_EOF; char* msg = 0; @@ -78,8 +76,6 @@ inline std::string error_code::message() const return "Service not found."; if (*this == error::socket_type_not_supported) return "Socket type not supported."; - if (category() != error::system_category) - return "asio error"; #if defined(__sun) || defined(__QNX__) return strerror(value_); #elif defined(__MACH__) && defined(__APPLE__) \ diff --git a/libtorrent/include/asio/impl/io_service.ipp b/libtorrent/include/asio/impl/io_service.ipp index f51d3697d..e973619d1 100644 --- a/libtorrent/include/asio/impl/io_service.ipp +++ b/libtorrent/include/asio/impl/io_service.ipp @@ -128,11 +128,11 @@ template #if defined(GENERATING_DOCUMENTATION) unspecified #else -inline detail::wrapped_handler +inline detail::wrapped_handler #endif io_service::wrap(Handler handler) { - return detail::wrapped_handler(*this, handler); + return detail::wrapped_handler(*this, handler); } inline io_service::work::work(asio::io_service& io_service) diff --git a/libtorrent/include/asio/impl/read_until.ipp b/libtorrent/include/asio/impl/read_until.ipp index 8b69a11c6..64c15ec7d 100644 --- a/libtorrent/include/asio/impl/read_until.ipp +++ b/libtorrent/include/asio/impl/read_until.ipp @@ -311,8 +311,7 @@ namespace detail if (streambuf_.size() == streambuf_.max_size()) { std::size_t bytes = 0; - asio::error_code ec(error::not_found); - handler_(ec, bytes); + handler_(error::not_found, bytes); return; } @@ -389,8 +388,7 @@ void async_read_until(AsyncReadStream& s, // No match. Check if buffer is full. if (b.size() == b.max_size()) { - asio::error_code ec(error::not_found); - s.io_service().post(detail::bind_handler(handler, ec, 0)); + s.io_service().post(detail::bind_handler(handler, error::not_found, 0)); return; } @@ -471,8 +469,7 @@ namespace detail if (streambuf_.size() == streambuf_.max_size()) { std::size_t bytes = 0; - asio::error_code ec(error::not_found); - handler_(ec, bytes); + handler_(error::not_found, bytes); return; } @@ -562,8 +559,7 @@ void async_read_until(AsyncReadStream& s, // Check if buffer is full. if (b.size() == b.max_size()) { - asio::error_code ec(error::not_found); - s.io_service().post(detail::bind_handler(handler, ec, 0)); + s.io_service().post(detail::bind_handler(handler, error::not_found, 0)); return; } @@ -645,8 +641,7 @@ namespace detail if (streambuf_.size() == streambuf_.max_size()) { std::size_t bytes = 0; - asio::error_code ec(error::not_found); - handler_(ec, bytes); + handler_(error::not_found, bytes); return; } @@ -736,8 +731,7 @@ void async_read_until(AsyncReadStream& s, // Check if buffer is full. if (b.size() == b.max_size()) { - asio::error_code ec(error::not_found); - s.io_service().post(detail::bind_handler(handler, ec, 0)); + s.io_service().post(detail::bind_handler(handler, error::not_found, 0)); return; } diff --git a/libtorrent/include/asio/io_service.hpp b/libtorrent/include/asio/io_service.hpp index 2101e56c4..b694545db 100644 --- a/libtorrent/include/asio/io_service.hpp +++ b/libtorrent/include/asio/io_service.hpp @@ -320,7 +320,7 @@ public: #if defined(GENERATING_DOCUMENTATION) unspecified #else - detail::wrapped_handler + detail::wrapped_handler #endif wrap(Handler handler); diff --git a/libtorrent/include/asio/ip/basic_endpoint.hpp b/libtorrent/include/asio/ip/basic_endpoint.hpp index 3d1316e22..3ca91dc03 100644 --- a/libtorrent/include/asio/ip/basic_endpoint.hpp +++ b/libtorrent/include/asio/ip/basic_endpoint.hpp @@ -172,7 +172,7 @@ public: /// The protocol associated with the endpoint. protocol_type protocol() const { - if (is_v4(data_)) + if (is_v4()) return InternetProtocol::v4(); return InternetProtocol::v6(); } @@ -192,7 +192,7 @@ public: /// Get the underlying size of the endpoint in the native type. size_type size() const { - if (is_v4(data_)) + if (is_v4()) return sizeof(asio::detail::sockaddr_in4_type); else return sizeof(asio::detail::sockaddr_in6_type); @@ -218,7 +218,7 @@ public: /// the host's byte order. unsigned short port() const { - if (is_v4(data_)) + if (is_v4()) { return asio::detail::socket_ops::network_to_host_short( reinterpret_cast( @@ -236,7 +236,7 @@ public: /// the host's byte order. void port(unsigned short port_num) { - if (is_v4(data_)) + if (is_v4()) { reinterpret_cast(data_).sin_port = asio::detail::socket_ops::host_to_network_short(port_num); @@ -252,7 +252,7 @@ public: asio::ip::address address() const { using namespace std; // For memcpy. - if (is_v4(data_)) + if (is_v4()) { const asio::detail::sockaddr_in4_type& data = reinterpret_cast( @@ -306,26 +306,14 @@ public: private: // Helper function to determine whether the endpoint is IPv4. + bool is_v4() const + { #if defined(_AIX) - template struct is_v4_helper {}; - - template - static bool is_v4(const T& ss, is_v4_helper* = 0) - { - return ss.ss_family == AF_INET; - } - - template - static bool is_v4(const T& ss, is_v4_helper* = 0) - { - return ss.__ss_family == AF_INET; - } + return data_.__ss_family == AF_INET; #else - static bool is_v4(const asio::detail::sockaddr_storage_type& ss) - { - return ss.ss_family == AF_INET; - } + return data_.ss_family == AF_INET; #endif + } // The underlying IP socket address. asio::detail::sockaddr_storage_type data_; diff --git a/libtorrent/include/asio/ssl/detail/openssl_operation.hpp b/libtorrent/include/asio/ssl/detail/openssl_operation.hpp index 5fd3ebba4..b7a564464 100755 --- a/libtorrent/include/asio/ssl/detail/openssl_operation.hpp +++ b/libtorrent/include/asio/ssl/detail/openssl_operation.hpp @@ -174,12 +174,12 @@ public: if (error_code == SSL_ERROR_SYSCALL) { return handler_(asio::error_code( - sys_error_code, asio::error::system_category), rc); + sys_error_code, asio::native_ecat), rc); } else { return handler_(asio::error_code( - error_code, asio::error::ssl_category), rc); + error_code, asio::ssl_ecat), rc); } } diff --git a/libtorrent/include/libtorrent/alert.hpp b/libtorrent/include/libtorrent/alert.hpp index 954e39ef5..b6b6711dc 100755 --- a/libtorrent/include/libtorrent/alert.hpp +++ b/libtorrent/include/libtorrent/alert.hpp @@ -36,6 +36,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #ifdef _MSC_VER @@ -55,7 +56,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/time.hpp" #include "libtorrent/config.hpp" -#include "libtorrent/assert.hpp" #ifndef TORRENT_MAX_ALERT_TYPES #define TORRENT_MAX_ALERT_TYPES 15 diff --git a/libtorrent/include/libtorrent/alert_types.hpp b/libtorrent/include/libtorrent/alert_types.hpp index 36c13c5ab..48491bca4 100755 --- a/libtorrent/include/libtorrent/alert_types.hpp +++ b/libtorrent/include/libtorrent/alert_types.hpp @@ -38,7 +38,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket.hpp" #include "libtorrent/peer_connection.hpp" #include "libtorrent/config.hpp" -#include "libtorrent/assert.hpp" namespace libtorrent { @@ -224,7 +223,7 @@ namespace libtorrent { block_downloading_alert( const torrent_handle& h - , char const* speedmsg + , std::string& speedmsg , int block_num , int piece_num , const std::string& msg) @@ -262,17 +261,6 @@ namespace libtorrent { return std::auto_ptr(new torrent_paused_alert(*this)); } }; - struct TORRENT_EXPORT torrent_checked_alert: torrent_alert - { - torrent_checked_alert(torrent_handle const& h, std::string const& msg) - : torrent_alert(h, alert::info, msg) - {} - - virtual std::auto_ptr clone() const - { return std::auto_ptr(new torrent_checked_alert(*this)); } - }; - - struct TORRENT_EXPORT url_seed_alert: torrent_alert { url_seed_alert( diff --git a/libtorrent/include/libtorrent/assert.hpp b/libtorrent/include/libtorrent/assert.hpp index 6577acc46..e69de29bb 100644 --- a/libtorrent/include/libtorrent/assert.hpp +++ b/libtorrent/include/libtorrent/assert.hpp @@ -1,54 +0,0 @@ -/* - -Copyright (c) 2007, 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 - -#ifndef NDEBUG -#if (defined __linux__ || defined __MACH__) && defined __GNUC__ -#ifdef assert -#undef assert -#endif - -#include "libtorrent/config.hpp" - -TORRENT_EXPORT void assert_fail(const char* expr, int line, char const* file, char const* function); - -#define assert(x) if (x) {} else assert_fail(#x, __LINE__, __FILE__, __PRETTY_FUNCTION__) - -#endif - -#else -#ifndef assert -#define assert(x) (void) -#endif -#endif - diff --git a/libtorrent/include/libtorrent/aux_/session_impl.hpp b/libtorrent/include/libtorrent/aux_/session_impl.hpp index 9300a1ce3..207016898 100644 --- a/libtorrent/include/libtorrent/aux_/session_impl.hpp +++ b/libtorrent/include/libtorrent/aux_/session_impl.hpp @@ -83,7 +83,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket_type.hpp" #include "libtorrent/connection_queue.hpp" #include "libtorrent/disk_io_thread.hpp" -#include "libtorrent/assert.hpp" namespace libtorrent { @@ -185,7 +184,7 @@ namespace libtorrent ~session_impl(); #ifndef TORRENT_DISABLE_EXTENSIONS - void add_extension(boost::function(torrent*, void*)> ext); + void add_extension(boost::function(torrent*)> ext); #endif void operator()(); @@ -241,13 +240,12 @@ namespace libtorrent bool is_listening() const; torrent_handle add_torrent( - boost::intrusive_ptr ti + torrent_info const& ti , fs::path const& save_path , entry const& resume_data , bool compact_mode - , storage_constructor_type sc - , bool paused - , void* userdata); + , int block_size + , storage_constructor_type sc); torrent_handle add_torrent( char const* tracker_url @@ -256,9 +254,8 @@ namespace libtorrent , fs::path const& save_path , entry const& resume_data , bool compact_mode - , storage_constructor_type sc - , bool paused - , void* userdata); + , int block_size + , storage_constructor_type sc); void remove_torrent(torrent_handle const& h); @@ -276,21 +273,8 @@ namespace libtorrent void set_max_connections(int limit); void set_max_uploads(int limit); - int max_connections() const { return m_max_connections; } - int max_uploads() const { return m_max_uploads; } - int max_half_open_connections() const { return m_half_open.limit(); } - - int num_uploads() const { return m_num_unchoked; } - int num_connections() const - { return m_connections.size(); } - - void unchoke_peer(peer_connection& c) - { - torrent* t = c.associated_torrent().lock().get(); - assert(t); - if (t->unchoke_peer(c)) - ++m_num_unchoked; - } + int num_uploads() const; + int num_connections() const; session_status status() const; void set_peer_id(peer_id const& id); @@ -433,28 +417,6 @@ namespace libtorrent int m_max_uploads; int m_max_connections; - // the number of unchoked peers - int m_num_unchoked; - - // this is initialized to the unchoke_interval - // session_setting and decreased every second. - // when it reaches zero, it is reset to the - // unchoke_interval and the unchoke set is - // recomputed. - int m_unchoke_time_scaler; - - // works like unchoke_time_scaler but it - // is only decresed when the unchoke set - // is recomputed, and when it reaches zero, - // the optimistic unchoke is moved to another peer. - int m_optimistic_unchoke_time_scaler; - - // works like unchoke_time_scaler. Each time - // it reaches 0, and all the connections are - // used, the worst connection will be disconnected - // from the torrent with the most peers - int m_disconnect_time_scaler; - // statistics gathered from all torrents. stat m_stat; @@ -497,7 +459,7 @@ namespace libtorrent // This implements a round robin. int m_next_connect_torrent; #ifndef NDEBUG - void check_invariant() const; + void check_invariant(const char *place = 0); #endif #ifdef TORRENT_STATS @@ -521,7 +483,7 @@ namespace libtorrent #ifndef TORRENT_DISABLE_EXTENSIONS typedef std::list(torrent*, void*)> > extension_list_t; + torrent_plugin>(torrent*)> > extension_list_t; extension_list_t m_extensions; #endif diff --git a/libtorrent/include/libtorrent/bandwidth_manager.hpp b/libtorrent/include/libtorrent/bandwidth_manager.hpp index 38aa67f43..75e1f1d4e 100644 --- a/libtorrent/include/libtorrent/bandwidth_manager.hpp +++ b/libtorrent/include/libtorrent/bandwidth_manager.hpp @@ -33,6 +33,9 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_BANDWIDTH_MANAGER_HPP_INCLUDED #define TORRENT_BANDWIDTH_MANAGER_HPP_INCLUDED +#include "libtorrent/socket.hpp" +#include "libtorrent/invariant_check.hpp" + #include #include #include @@ -41,17 +44,11 @@ POSSIBILITY OF SUCH DAMAGE. #include #include -#include "libtorrent/socket.hpp" -#include "libtorrent/invariant_check.hpp" -#include "libtorrent/assert.hpp" - using boost::weak_ptr; using boost::shared_ptr; using boost::intrusive_ptr; using boost::bind; -//#define TORRENT_VERBOSE_BANDWIDTH_LIMIT - namespace libtorrent { // the maximum block of bandwidth quota to @@ -180,7 +177,6 @@ struct bandwidth_manager , m_limit(bandwidth_limit::inf) , m_current_quota(0) , m_channel(channel) - , m_in_hand_out_bandwidth(false) {} void throttle(int limit) throw() @@ -241,10 +237,8 @@ struct bandwidth_manager i = j; } } -#ifdef TORRENT_VERBOSE_BANDWIDTH_LIMIT - std::cerr << " req_bandwidht. m_queue.size() = " << m_queue.size() << std::endl; -#endif - if (!m_queue.empty()) hand_out_bandwidth(); + + if (m_queue.size() == 1) hand_out_bandwidth(); } #ifndef NDEBUG @@ -329,10 +323,6 @@ private: void hand_out_bandwidth() throw() { - // if we're already handing out bandwidth, just return back - // to the loop further down on the callstack - if (m_in_hand_out_bandwidth) return; - m_in_hand_out_bandwidth = true; #ifndef NDEBUG try { #endif @@ -347,18 +337,10 @@ private: // available bandwidth to hand out int amount = limit - m_current_quota; -#ifdef TORRENT_VERBOSE_BANDWIDTH_LIMIT - std::cerr << " hand_out_bandwidht. m_queue.size() = " << m_queue.size() - << " amount = " << amount - << " limit = " << limit - << " m_current_quota = " << m_current_quota << std::endl; -#endif - while (!m_queue.empty() && amount > 0) { assert(amount == limit - m_current_quota); bw_queue_entry qe = m_queue.front(); - assert(qe.max_block_size > 0); m_queue.pop_front(); shared_ptr t = qe.peer->associated_torrent().lock(); @@ -366,7 +348,6 @@ private: if (qe.peer->is_disconnecting()) { t->expire_bandwidth(m_channel, qe.max_block_size); - assert(amount == limit - m_current_quota); continue; } @@ -380,7 +361,6 @@ private: if (max_assignable == 0) { t->expire_bandwidth(m_channel, qe.max_block_size); - assert(amount == limit - m_current_quota); continue; } @@ -394,16 +374,17 @@ private: // block size must be smaller for lower rates. This is because // the history window is one second, and the block will be forgotten // after one second. - int block_size = (std::min)(qe.peer->bandwidth_throttle(m_channel) - , limit / 10); + int block_size = (std::min)(qe.max_block_size + , (std::min)(qe.peer->bandwidth_throttle(m_channel) + , m_limit / 10)); if (block_size < min_bandwidth_block_size) { - block_size = (std::min)(int(min_bandwidth_block_size), limit); + block_size = min_bandwidth_block_size; } else if (block_size > max_bandwidth_block_size) { - if (limit == bandwidth_limit::inf) + if (m_limit == bandwidth_limit::inf) { block_size = max_bandwidth_block_size; } @@ -414,15 +395,11 @@ private: // as possible // TODO: move this calculcation to where the limit // is changed - block_size = limit - / (limit / max_bandwidth_block_size); + block_size = m_limit + / (m_limit / max_bandwidth_block_size); } } - if (block_size > qe.max_block_size) block_size = qe.max_block_size; -#ifdef TORRENT_VERBOSE_BANDWIDTH_LIMIT - std::cerr << " block_size = " << block_size << " amount = " << amount << std::endl; -#endif if (amount < block_size / 2) { m_queue.push_front(qe); @@ -435,21 +412,18 @@ private: int hand_out_amount = (std::min)((std::min)(block_size, max_assignable) , amount); assert(hand_out_amount > 0); - assert(amount == limit - m_current_quota); amount -= hand_out_amount; assert(hand_out_amount <= qe.max_block_size); t->assign_bandwidth(m_channel, hand_out_amount, qe.max_block_size); qe.peer->assign_bandwidth(m_channel, hand_out_amount); add_history_entry(history_entry( qe.peer, t, hand_out_amount, now + bw_window_size)); - assert(amount == limit - m_current_quota); } #ifndef NDEBUG } catch (std::exception& e) { assert(false); }; #endif - m_in_hand_out_bandwidth = false; } @@ -482,11 +456,6 @@ private: // this is the channel within the consumers // that bandwidth is assigned to (upload or download) int m_channel; - - // this is true while we're in the hand_out_bandwidth loop - // to prevent recursive invocations to interfere - bool m_in_hand_out_bandwidth; - }; } diff --git a/libtorrent/include/libtorrent/bencode.hpp b/libtorrent/include/libtorrent/bencode.hpp index 9e670c10b..a142b5864 100755 --- a/libtorrent/include/libtorrent/bencode.hpp +++ b/libtorrent/include/libtorrent/bencode.hpp @@ -79,8 +79,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/entry.hpp" #include "libtorrent/config.hpp" -#include "libtorrent/assert.hpp" - #if defined(_MSC_VER) namespace std { diff --git a/libtorrent/include/libtorrent/broadcast_socket.hpp b/libtorrent/include/libtorrent/broadcast_socket.hpp index 23be67b0d..e69de29bb 100644 --- a/libtorrent/include/libtorrent/broadcast_socket.hpp +++ b/libtorrent/include/libtorrent/broadcast_socket.hpp @@ -1,84 +0,0 @@ -/* - -Copyright (c) 2007, 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. - -*/ - -#ifndef TORRENT_BROADCAST_SOCKET_HPP_INCLUDED -#define TORRENT_BROADCAST_SOCKET_HPP_INCLUDED - -#include "libtorrent/socket.hpp" -#include -#include -#include - -namespace libtorrent -{ - - bool is_local(address const& a); - bool is_loopback(address const& addr); - bool is_multicast(address const& addr); - - address_v4 guess_local_address(asio::io_service&); - - typedef boost::function receive_handler_t; - - class broadcast_socket - { - public: - broadcast_socket(asio::io_service& ios, udp::endpoint const& multicast_endpoint - , receive_handler_t const& handler, bool loopback = true); - ~broadcast_socket() { close(); } - - void send(char const* buffer, int size, asio::error_code& ec); - void close(); - - private: - - struct socket_entry - { - socket_entry(boost::shared_ptr const& s): socket(s) {} - boost::shared_ptr socket; - char buffer[1024]; - udp::endpoint remote; - }; - - void on_receive(socket_entry* s, asio::error_code const& ec - , std::size_t bytes_transferred); - - std::list m_sockets; - udp::endpoint m_multicast_endpoint; - receive_handler_t m_on_receive; - - }; -} - -#endif - diff --git a/libtorrent/include/libtorrent/bt_peer_connection.hpp b/libtorrent/include/libtorrent/bt_peer_connection.hpp index 0fcba89a8..beec94979 100755 --- a/libtorrent/include/libtorrent/bt_peer_connection.hpp +++ b/libtorrent/include/libtorrent/bt_peer_connection.hpp @@ -65,6 +65,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert.hpp" #include "libtorrent/torrent_handle.hpp" #include "libtorrent/torrent.hpp" +#include "libtorrent/allocate_resources.hpp" #include "libtorrent/peer_request.hpp" #include "libtorrent/piece_block_progress.hpp" #include "libtorrent/config.hpp" @@ -121,16 +122,8 @@ namespace libtorrent msg_request, msg_piece, msg_cancel, - // DHT extension msg_dht_port, - // FAST extension - msg_suggest_piece = 0xd, - msg_have_all, - msg_have_none, - msg_reject_request, - msg_allowed_fast, - - // extension protocol message + // extension protocol message msg_extended = 20, num_supported_messages @@ -181,17 +174,8 @@ namespace libtorrent void on_request(int received); void on_piece(int received); void on_cancel(int received); - - // DHT extension void on_dht_port(int received); - // FAST extension - void on_suggest_piece(int received); - void on_have_all(int received); - void on_have_none(int received); - void on_reject_request(int received); - void on_allowed_fast(int received); - void on_extended(int received); void on_extended_handshake(); @@ -217,16 +201,7 @@ namespace libtorrent void write_metadata(std::pair req); void write_metadata_request(std::pair req); void write_keepalive(); - - // DHT extension void write_dht_port(int listen_port); - - // FAST extension - void write_have_all(); - void write_have_none(); - void write_reject_request(peer_request const&); - void write_allow_fast(int piece); - void on_connected(); void on_metadata(); @@ -350,7 +325,6 @@ namespace libtorrent bool m_supports_extensions; #endif bool m_supports_dht_port; - bool m_supports_fast; #ifndef TORRENT_DISABLE_ENCRYPTION // this is set to true after the encryption method has been diff --git a/libtorrent/include/libtorrent/buffer.hpp b/libtorrent/include/libtorrent/buffer.hpp index 0f37edcbd..0cb44225a 100644 --- a/libtorrent/include/libtorrent/buffer.hpp +++ b/libtorrent/include/libtorrent/buffer.hpp @@ -34,9 +34,8 @@ POSSIBILITY OF SUCH DAMAGE. //#define TORRENT_BUFFER_DEBUG -#include #include "libtorrent/invariant_check.hpp" -#include "libtorrent/assert.hpp" +#include namespace libtorrent { diff --git a/libtorrent/include/libtorrent/connection_queue.hpp b/libtorrent/include/libtorrent/connection_queue.hpp index b3b7cde86..17be248bf 100644 --- a/libtorrent/include/libtorrent/connection_queue.hpp +++ b/libtorrent/include/libtorrent/connection_queue.hpp @@ -36,7 +36,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include #include "libtorrent/socket.hpp" #include "libtorrent/time.hpp" @@ -89,10 +88,6 @@ private: int m_half_open_limit; deadline_timer m_timer; - - typedef boost::recursive_mutex mutex_t; - mutable mutex_t m_mutex; - #ifndef NDEBUG bool m_in_timeout_function; #endif diff --git a/libtorrent/include/libtorrent/debug.hpp b/libtorrent/include/libtorrent/debug.hpp index 1bb645a8e..436b695f6 100755 --- a/libtorrent/include/libtorrent/debug.hpp +++ b/libtorrent/include/libtorrent/debug.hpp @@ -80,4 +80,3 @@ namespace libtorrent } #endif // TORRENT_DEBUG_HPP_INCLUDED - diff --git a/libtorrent/include/libtorrent/disk_io_thread.hpp b/libtorrent/include/libtorrent/disk_io_thread.hpp index 61ca9bc53..16ee0bca4 100644 --- a/libtorrent/include/libtorrent/disk_io_thread.hpp +++ b/libtorrent/include/libtorrent/disk_io_thread.hpp @@ -30,10 +30,6 @@ POSSIBILITY OF SUCH DAMAGE. */ -#ifdef TORRENT_DISK_STATS -#include -#endif - #include "libtorrent/storage.hpp" #include #include @@ -54,7 +50,6 @@ namespace libtorrent , buffer_size(0) , piece(0) , offset(0) - , priority(0) {} enum action_t @@ -77,12 +72,6 @@ namespace libtorrent // to the error message std::string str; - // priority decides whether or not this - // job will skip entries in the queue or - // not. It always skips in front of entries - // with lower priority - int priority; - // this is called when operation completes boost::function callback; }; @@ -126,10 +115,6 @@ namespace libtorrent int m_block_size; #endif -#ifdef TORRENT_DISK_STATS - std::ofstream m_log; -#endif - // thread for performing blocking disk io operations boost::thread m_disk_io_thread; }; diff --git a/libtorrent/include/libtorrent/entry.hpp b/libtorrent/include/libtorrent/entry.hpp index 7fd6c8c53..59e29803d 100755 --- a/libtorrent/include/libtorrent/entry.hpp +++ b/libtorrent/include/libtorrent/entry.hpp @@ -64,10 +64,10 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include "libtorrent/size_type.hpp" #include "libtorrent/config.hpp" -#include "libtorrent/assert.hpp" namespace libtorrent { diff --git a/libtorrent/include/libtorrent/enum_net.hpp b/libtorrent/include/libtorrent/enum_net.hpp index 0c6063a2b..e69de29bb 100644 --- a/libtorrent/include/libtorrent/enum_net.hpp +++ b/libtorrent/include/libtorrent/enum_net.hpp @@ -1,44 +0,0 @@ -/* - -Copyright (c) 2007, 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. - -*/ - -#ifndef TORRENT_ENUM_NET_HPP_INCLUDED -#define TORRENT_ENUM_NET_HPP_INCLUDED - -#include "libtorrent/socket.hpp" - -namespace libtorrent -{ - std::vector
const& enum_net_interfaces(asio::io_service& ios, asio::error_code& ec); -} - -#endif - diff --git a/libtorrent/include/libtorrent/extensions.hpp b/libtorrent/include/libtorrent/extensions.hpp index fd48588e1..5f8172649 100644 --- a/libtorrent/include/libtorrent/extensions.hpp +++ b/libtorrent/include/libtorrent/extensions.hpp @@ -131,15 +131,6 @@ namespace libtorrent virtual bool on_bitfield(std::vector const& bitfield) { return false; } - virtual bool on_have_all() - { return false; } - - virtual bool on_have_none() - { return false; } - - virtual bool on_allowed_fast(int index) - { return false; } - virtual bool on_request(peer_request const& req) { return false; } @@ -149,12 +140,6 @@ namespace libtorrent virtual bool on_cancel(peer_request const& req) { return false; } - virtual bool on_reject(peer_request const& req) - { return false; } - - virtual bool on_suggest(int index) - { return false; } - // called when an extended message is received. If returning true, // the message is not processed by any other plugin and if false // is returned the next plugin in the chain will receive it to diff --git a/libtorrent/include/libtorrent/extensions/metadata_transfer.hpp b/libtorrent/include/libtorrent/extensions/metadata_transfer.hpp index c42136d70..210642161 100644 --- a/libtorrent/include/libtorrent/extensions/metadata_transfer.hpp +++ b/libtorrent/include/libtorrent/extensions/metadata_transfer.hpp @@ -48,7 +48,7 @@ namespace libtorrent { struct torrent_plugin; class torrent; - TORRENT_EXPORT boost::shared_ptr create_metadata_plugin(torrent*, void*); + TORRENT_EXPORT boost::shared_ptr create_metadata_plugin(torrent*); } #endif // TORRENT_METADATA_TRANSFER_HPP_INCLUDED diff --git a/libtorrent/include/libtorrent/extensions/ut_pex.hpp b/libtorrent/include/libtorrent/extensions/ut_pex.hpp index ebf6aa834..efd9ab4f6 100644 --- a/libtorrent/include/libtorrent/extensions/ut_pex.hpp +++ b/libtorrent/include/libtorrent/extensions/ut_pex.hpp @@ -48,7 +48,7 @@ namespace libtorrent { struct torrent_plugin; class torrent; - TORRENT_EXPORT boost::shared_ptr create_ut_pex_plugin(torrent*, void*); + TORRENT_EXPORT boost::shared_ptr create_ut_pex_plugin(torrent*); } #endif // TORRENT_UT_PEX_EXTENSION_HPP_INCLUDED diff --git a/libtorrent/include/libtorrent/fingerprint.hpp b/libtorrent/include/libtorrent/fingerprint.hpp index 712be6979..d7e5a5fc6 100755 --- a/libtorrent/include/libtorrent/fingerprint.hpp +++ b/libtorrent/include/libtorrent/fingerprint.hpp @@ -37,7 +37,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #include "libtorrent/peer_id.hpp" -#include "libtorrent/assert.hpp" namespace libtorrent { @@ -92,4 +91,3 @@ namespace libtorrent } #endif // TORRENT_FINGERPRINT_HPP_INCLUDED - diff --git a/libtorrent/include/libtorrent/hasher.hpp b/libtorrent/include/libtorrent/hasher.hpp index 71b7f9ede..932f2b100 100755 --- a/libtorrent/include/libtorrent/hasher.hpp +++ b/libtorrent/include/libtorrent/hasher.hpp @@ -33,11 +33,11 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_HASHER_HPP_INCLUDED #define TORRENT_HASHER_HPP_INCLUDED +#include #include #include "libtorrent/peer_id.hpp" #include "libtorrent/config.hpp" -#include "libtorrent/assert.hpp" #include "zlib.h" #ifdef TORRENT_USE_OPENSSL diff --git a/libtorrent/include/libtorrent/http_connection.hpp b/libtorrent/include/libtorrent/http_connection.hpp index ccc145413..409213857 100644 --- a/libtorrent/include/libtorrent/http_connection.hpp +++ b/libtorrent/include/libtorrent/http_connection.hpp @@ -44,18 +44,13 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket.hpp" #include "libtorrent/http_tracker_connection.hpp" #include "libtorrent/time.hpp" -#include "libtorrent/assert.hpp" namespace libtorrent { -struct http_connection; - typedef boost::function http_handler; -typedef boost::function http_connect_handler; - // TODO: add bind interface // when bottled, the last two arguments to the handler @@ -63,13 +58,11 @@ typedef boost::function http_connect_handler; struct http_connection : boost::enable_shared_from_this, boost::noncopyable { http_connection(asio::io_service& ios, connection_queue& cc - , http_handler const& handler, bool bottled = true - , http_connect_handler const& ch = http_connect_handler()) + , http_handler handler, bool bottled = true) : m_sock(ios) , m_read_pos(0) , m_resolver(ios) , m_handler(handler) - , m_connect_handler(ch) , m_timer(ios) , m_last_receive(time_now()) , m_bottled(bottled) @@ -99,8 +92,6 @@ struct http_connection : boost::enable_shared_from_this, boost: , time_duration timeout, bool handle_redirect = true); void close(); - tcp::socket const& socket() const { return m_sock; } - private: void on_resolve(asio::error_code const& e @@ -121,7 +112,6 @@ private: tcp::resolver m_resolver; http_parser m_parser; http_handler m_handler; - http_connect_handler m_connect_handler; deadline_timer m_timer; time_duration m_timeout; ptime m_last_receive; diff --git a/libtorrent/include/libtorrent/http_tracker_connection.hpp b/libtorrent/include/libtorrent/http_tracker_connection.hpp index 76c3aac98..35d529504 100755 --- a/libtorrent/include/libtorrent/http_tracker_connection.hpp +++ b/libtorrent/include/libtorrent/http_tracker_connection.hpp @@ -73,8 +73,6 @@ namespace libtorrent T header(char const* key) const; std::string const& protocol() const { return m_protocol; } int status_code() const { return m_status_code; } - std::string const& method() const { return m_method; } - std::string const& path() const { return m_path; } std::string message() const { return m_server_message; } buffer::const_interval get_body() const; bool header_finished() const { return m_state == read_body; } @@ -87,8 +85,6 @@ namespace libtorrent private: int m_recv_pos; int m_status_code; - std::string m_method; - std::string m_path; std::string m_protocol; std::string m_server_message; diff --git a/libtorrent/include/libtorrent/intrusive_ptr_base.hpp b/libtorrent/include/libtorrent/intrusive_ptr_base.hpp index d2c35ffe3..a432bc350 100644 --- a/libtorrent/include/libtorrent/intrusive_ptr_base.hpp +++ b/libtorrent/include/libtorrent/intrusive_ptr_base.hpp @@ -34,17 +34,14 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_INTRUSIVE_PTR_BASE #include +#include #include "libtorrent/config.hpp" -#include "libtorrent/assert.hpp" namespace libtorrent { template struct intrusive_ptr_base { - intrusive_ptr_base(intrusive_ptr_base const&) - : m_refs(0) {} - friend void intrusive_ptr_add_ref(intrusive_ptr_base const* s) { assert(s->m_refs >= 0); diff --git a/libtorrent/include/libtorrent/invariant_check.hpp b/libtorrent/include/libtorrent/invariant_check.hpp index 3eaacf34c..c6eacf338 100755 --- a/libtorrent/include/libtorrent/invariant_check.hpp +++ b/libtorrent/include/libtorrent/invariant_check.hpp @@ -5,7 +5,7 @@ #ifndef TORRENT_INVARIANT_ACCESS_HPP_INCLUDED #define TORRENT_INVARIANT_ACCESS_HPP_INCLUDED -#include "libtorrent/assert.hpp" +#include namespace libtorrent { diff --git a/libtorrent/include/libtorrent/ip_filter.hpp b/libtorrent/include/libtorrent/ip_filter.hpp index 7b8cc0e17..8b1793c3a 100644 --- a/libtorrent/include/libtorrent/ip_filter.hpp +++ b/libtorrent/include/libtorrent/ip_filter.hpp @@ -33,9 +33,6 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_IP_FILTER_HPP #define TORRENT_IP_FILTER_HPP -#include -#include - #ifdef _MSC_VER #pragma warning(push, 1) #endif @@ -51,7 +48,8 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/config.hpp" #include "libtorrent/socket.hpp" -#include "libtorrent/assert.hpp" +#include +#include namespace libtorrent { diff --git a/libtorrent/include/libtorrent/kademlia/node.hpp b/libtorrent/include/libtorrent/kademlia/node.hpp index ee75e7f0a..850333043 100644 --- a/libtorrent/include/libtorrent/kademlia/node.hpp +++ b/libtorrent/include/libtorrent/kademlia/node.hpp @@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #define NODE_HPP #include +#include #include #include @@ -44,7 +45,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #include -#include #include #include diff --git a/libtorrent/include/libtorrent/kademlia/node_id.hpp b/libtorrent/include/libtorrent/kademlia/node_id.hpp index 5e732acac..eb4d6c539 100644 --- a/libtorrent/include/libtorrent/kademlia/node_id.hpp +++ b/libtorrent/include/libtorrent/kademlia/node_id.hpp @@ -33,10 +33,10 @@ POSSIBILITY OF SUCH DAMAGE. #define NODE_ID_HPP #include +#include #include #include "libtorrent/peer_id.hpp" -#include "libtorrent/assert.hpp" namespace libtorrent { namespace dht { diff --git a/libtorrent/include/libtorrent/kademlia/routing_table.hpp b/libtorrent/include/libtorrent/kademlia/routing_table.hpp index 9e10a3483..45a7dd762 100644 --- a/libtorrent/include/libtorrent/kademlia/routing_table.hpp +++ b/libtorrent/include/libtorrent/kademlia/routing_table.hpp @@ -50,7 +50,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include namespace libtorrent { namespace dht { diff --git a/libtorrent/include/libtorrent/lsd.hpp b/libtorrent/include/libtorrent/lsd.hpp index e8eaf0df1..9ffbcdfc3 100644 --- a/libtorrent/include/libtorrent/lsd.hpp +++ b/libtorrent/include/libtorrent/lsd.hpp @@ -35,7 +35,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket.hpp" #include "libtorrent/peer_id.hpp" -#include "libtorrent/broadcast_socket.hpp" #include #include @@ -59,26 +58,35 @@ public: , peer_callback_t const& cb); ~lsd(); -// void rebind(address const& listen_interface); + void rebind(address const& listen_interface); void announce(sha1_hash const& ih, int listen_port); void close(); private: + static address_v4 lsd_multicast_address; + static udp::endpoint lsd_multicast_endpoint; + void resend_announce(asio::error_code const& e, std::string msg); - void on_announce(udp::endpoint const& from, char* buffer + void on_announce(asio::error_code const& e , std::size_t bytes_transferred); -// void setup_receive(); + void setup_receive(); peer_callback_t m_callback; // current retry count int m_retry_count; + // used to receive responses in + char m_receive_buffer[1024]; + + // the endpoint we received the message from + udp::endpoint m_remote; + // the udp socket used to send and receive // multicast messages on - broadcast_socket m_socket; + datagram_socket m_socket; // used to resend udp packets in case // they time out diff --git a/libtorrent/include/libtorrent/pe_crypto.hpp b/libtorrent/include/libtorrent/pe_crypto.hpp index e2276dee6..91616c42d 100644 --- a/libtorrent/include/libtorrent/pe_crypto.hpp +++ b/libtorrent/include/libtorrent/pe_crypto.hpp @@ -35,12 +35,13 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_PE_CRYPTO_HPP_INCLUDED #define TORRENT_PE_CRYPTO_HPP_INCLUDED +#include + #include #include #include -#include "libtorrent/peer_id.hpp" // For sha1_hash -#include "libtorrent/assert.hpp" +#include "peer_id.hpp" // For sha1_hash namespace libtorrent { diff --git a/libtorrent/include/libtorrent/peer_connection.hpp b/libtorrent/include/libtorrent/peer_connection.hpp index ea16a8d0a..31bcde94a 100755 --- a/libtorrent/include/libtorrent/peer_connection.hpp +++ b/libtorrent/include/libtorrent/peer_connection.hpp @@ -64,6 +64,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert.hpp" #include "libtorrent/torrent_handle.hpp" #include "libtorrent/torrent.hpp" +#include "libtorrent/allocate_resources.hpp" #include "libtorrent/peer_request.hpp" #include "libtorrent/piece_block_progress.hpp" #include "libtorrent/config.hpp" @@ -72,7 +73,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/policy.hpp" #include "libtorrent/socket_type.hpp" #include "libtorrent/intrusive_ptr_base.hpp" -#include "libtorrent/assert.hpp" namespace libtorrent { @@ -131,8 +131,6 @@ namespace libtorrent enum peer_speed_t { slow, medium, fast }; peer_speed_t peer_speed(); - void send_allowed_set(); - #ifndef TORRENT_DISABLE_EXTENSIONS void add_extension(boost::shared_ptr); #endif @@ -153,17 +151,11 @@ namespace libtorrent int upload_limit() const { return m_upload_limit; } int download_limit() const { return m_download_limit; } - int prefer_whole_pieces() const - { - if (on_parole()) return 1; - return m_prefer_whole_pieces; - } + bool prefer_whole_pieces() const + { return m_prefer_whole_pieces; } - bool on_parole() const - { return peer_info_struct() && peer_info_struct()->on_parole; } - - void prefer_whole_pieces(int num) - { m_prefer_whole_pieces = num; } + void prefer_whole_pieces(bool b) + { m_prefer_whole_pieces = b; } bool request_large_blocks() const { return m_request_large_blocks; } @@ -194,9 +186,9 @@ namespace libtorrent void set_pid(const peer_id& pid) { m_peer_id = pid; } bool has_piece(int i) const; - std::deque const& download_queue() const; - std::deque const& request_queue() const; - std::deque const& upload_queue() const; + const std::deque& download_queue() const; + const std::deque& request_queue() const; + const std::deque& upload_queue() const; bool is_interesting() const { return m_interesting; } bool is_choked() const { return m_choked; } @@ -219,14 +211,12 @@ namespace libtorrent void add_stat(size_type downloaded, size_type uploaded); // is called once every second by the main loop - void second_tick(float tick_interval) throw(); + void second_tick(float tick_interval); boost::shared_ptr get_socket() const { return m_socket; } tcp::endpoint const& remote() const { return m_remote; } std::vector const& get_bitfield() const; - std::vector const& allowed_fast(); - std::vector const& suggested_pieces() const { return m_suggested_pieces; } void timed_out(); // this will cause this peer_connection to be disconnected. @@ -304,14 +294,7 @@ namespace libtorrent void incoming_piece(peer_request const& p, char const* data); void incoming_piece_fragment(); void incoming_cancel(peer_request const& r); - void incoming_dht_port(int listen_port); - - void incoming_reject_request(peer_request const& r); - void incoming_have_all(); - void incoming_have_none(); - void incoming_allowed_fast(int index); - void incoming_suggest(int index); // the following functions appends messages // to the send buffer @@ -390,9 +373,6 @@ namespace libtorrent virtual void write_keepalive() = 0; virtual void write_piece(peer_request const& r, char const* buffer) = 0; - virtual void write_reject_request(peer_request const& r) = 0; - virtual void write_allow_fast(int piece) = 0; - virtual void on_connected() = 0; virtual void on_tick() {} @@ -502,11 +482,6 @@ namespace libtorrent // the time we sent a request to // this peer the last time ptime m_last_request; - // the time we received the last - // piece request from the peer - ptime m_last_incoming_request; - // the time when we unchoked this peer - ptime m_last_unchoke; int m_packet_size; int m_recv_pos; @@ -554,7 +529,7 @@ namespace libtorrent // set to the torrent it belongs to. boost::weak_ptr m_torrent; // is true if it was we that connected to the peer - // and false if we got an incoming connection + // and false if we got an incomming connection // could be considered: true = local, false = remote bool m_active; @@ -588,10 +563,6 @@ namespace libtorrent // the pieces the other end have std::vector m_have_piece; - // this is set to true when a have_all - // message is received. This information - // is used to fill the bitmask in init() - bool m_have_all; // the number of pieces this peer // has. Must be the same as @@ -604,7 +575,7 @@ namespace libtorrent std::deque m_requests; // the blocks we have reserved in the piece - // picker and will request from this peer. + // picker and will send to this peer. std::deque m_request_queue; // the queue of blocks we have requested @@ -672,13 +643,12 @@ namespace libtorrent bool m_writing; bool m_reading; - // if set to non-zero, this peer will always prefer - // to request entire n pieces, rather than blocks. - // where n is the value of this variable. - // if it is 0, the download rate limit setting + // if set to true, this peer will always prefer + // to request entire pieces, rather than blocks. + // if it is false, the download rate limit setting // will be used to determine if whole pieces // are preferred. - int m_prefer_whole_pieces; + bool m_prefer_whole_pieces; // if this is true, the blocks picked by the piece // picker will be merged before passed to the @@ -725,18 +695,6 @@ namespace libtorrent // was last updated ptime m_remote_dl_update; - // the pieces we will send to the peer - // if requested (regardless of choke state) - std::set m_accept_fast; - - // the pieces the peer will send us if - // requested (regardless of choke state) - std::vector m_allowed_fast; - - // pieces that has been suggested to be - // downloaded from this peer - std::vector m_suggested_pieces; - // the number of bytes send to the disk-io // thread that hasn't yet been completely written. int m_outstanding_writing_bytes; diff --git a/libtorrent/include/libtorrent/peer_id.hpp b/libtorrent/include/libtorrent/peer_id.hpp index 57303e2fd..b66c1d4bc 100755 --- a/libtorrent/include/libtorrent/peer_id.hpp +++ b/libtorrent/include/libtorrent/peer_id.hpp @@ -35,12 +35,12 @@ POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include #include #include #include "libtorrent/config.hpp" -#include "libtorrent/assert.hpp" namespace libtorrent { diff --git a/libtorrent/include/libtorrent/peer_info.hpp b/libtorrent/include/libtorrent/peer_info.hpp index b07acffd4..15ad34a7a 100755 --- a/libtorrent/include/libtorrent/peer_info.hpp +++ b/libtorrent/include/libtorrent/peer_info.hpp @@ -56,11 +56,10 @@ namespace libtorrent connecting = 0x80, queued = 0x100, on_parole = 0x200, - seed = 0x400, - optimistic_unchoke = 0x800 + seed = 0x400 #ifndef TORRENT_DISABLE_ENCRYPTION - , rc4_encrypted = 0x100000, - plaintext_encrypted = 0x200000 + , rc4_encrypted = 0x800, + plaintext_encrypted = 0x1000 #endif }; @@ -72,8 +71,7 @@ namespace libtorrent dht = 0x2, pex = 0x4, lsd = 0x8, - resume_data = 0x10, - incoming = 0x20 + resume_data = 0x10 }; int source; @@ -118,11 +116,6 @@ namespace libtorrent // for yet int download_queue_length; - // the number of requests that is - // tried to be maintained (this is - // typically a function of download speed) - int target_dl_queue_length; - // this is the number of requests // the peer has sent to us // that we haven't sent yet diff --git a/libtorrent/include/libtorrent/piece_picker.hpp b/libtorrent/include/libtorrent/piece_picker.hpp index 64f6203d5..54df003ef 100755 --- a/libtorrent/include/libtorrent/piece_picker.hpp +++ b/libtorrent/include/libtorrent/piece_picker.hpp @@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #ifdef _MSC_VER @@ -51,7 +52,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket.hpp" #include "libtorrent/session_settings.hpp" #include "libtorrent/config.hpp" -#include "libtorrent/assert.hpp" namespace libtorrent { @@ -191,33 +191,11 @@ namespace libtorrent // THIS IS DONE BY THE peer_connection::send_request() MEMBER FUNCTION! // The last argument is the policy::peer pointer for the peer that // we'll download from. - void pick_pieces(std::vector const& pieces + void pick_pieces(const std::vector& pieces , std::vector& interesting_blocks - , int num_pieces, int prefer_whole_pieces + , int num_pieces, bool prefer_whole_pieces , void* peer, piece_state_t speed - , bool rarest_first, bool on_parole - , std::vector const& suggested_pieces) const; - - // picks blocks from each of the pieces in the piece_list - // vector that is also in the piece bitmask. The blocks - // are added to interesting_blocks, and busy blocks are - // added to backup_blocks. num blocks is the number of - // blocks to be picked. Blocks are not picked from pieces - // that are being downloaded - int add_blocks(std::vector const& piece_list - , const std::vector& pieces - , std::vector& interesting_blocks - , int num_blocks, int prefer_whole_pieces - , void* peer, std::vector const& ignore) const; - - // picks blocks only from downloading pieces - int add_blocks_downloading( - std::vector const& pieces - , std::vector& interesting_blocks - , std::vector& backup_blocks - , int num_blocks, int prefer_whole_pieces - , void* peer, piece_state_t speed - , bool on_parole) const; + , bool rarest_first) const; // clears the peer pointer in all downloading pieces with this // peer pointer @@ -233,7 +211,7 @@ namespace libtorrent bool is_finished(piece_block block) const; // marks this piece-block as queued for downloading - bool mark_as_downloading(piece_block block, void* peer + void mark_as_downloading(piece_block block, void* peer , piece_state_t s); void mark_as_writing(piece_block block, void* peer); void mark_as_finished(piece_block block, void* peer); @@ -275,8 +253,6 @@ namespace libtorrent #ifndef NDEBUG // used in debug mode void check_invariant(const torrent* t = 0) const; - void verify_pick(std::vector const& picked - , std::vector const& bitfield) const; #endif // functor that compares indices on downloading_pieces @@ -295,10 +271,6 @@ namespace libtorrent private: - bool can_pick(int piece, std::vector const& bitmask) const; - std::pair expand_piece(int piece, int whole_pieces - , std::vector const& have) const; - struct piece_pos { piece_pos() {} @@ -348,9 +320,9 @@ namespace libtorrent int priority(int limit) const { - if (downloading || filtered() || have()) return 0; + if (filtered() || have()) return 0; // pieces we are currently downloading have high priority - int prio = peer_count * 2; + int prio = downloading ? (std::min)(1, int(peer_count)) : peer_count * 2; // if the peer_count is 0 or 1, the priority cannot be higher if (prio <= 1) return prio; if (prio >= limit * 2) prio = limit * 2; @@ -386,6 +358,14 @@ namespace libtorrent void move(int vec_index, int elem_index); void sort_piece(std::vector::iterator dp); + int add_interesting_blocks(const std::vector& piece_list + , const std::vector& pieces + , std::vector& interesting_blocks + , std::vector& backup_blocks + , int num_blocks, bool prefer_whole_pieces + , void* peer, piece_state_t speed + , bool ignore_downloading_pieces) const; + downloading_piece& add_download_piece(); void erase_download_piece(std::vector::iterator i); diff --git a/libtorrent/include/libtorrent/policy.hpp b/libtorrent/include/libtorrent/policy.hpp index 7a789ec8c..6c976d047 100755 --- a/libtorrent/include/libtorrent/policy.hpp +++ b/libtorrent/include/libtorrent/policy.hpp @@ -89,7 +89,7 @@ namespace libtorrent void new_connection(peer_connection& c); // the given connection was just closed - void connection_closed(const peer_connection& c) throw(); + void connection_closed(const peer_connection& c); // the peer has got at least one interesting piece void peer_is_interesting(peer_connection& c); @@ -155,13 +155,6 @@ namespace libtorrent // this is true if the peer is a seed bool seed; - // true if this peer currently is unchoked - // because of an optimistic unchoke. - // when the optimistic unchoke is moved to - // another peer, this peer will be choked - // if this is true - bool optimistically_unchoked; - // the time when this peer was optimistically unchoked // the last time. libtorrent::ptime last_optimistically_unchoked; @@ -210,18 +203,25 @@ namespace libtorrent peer_connection* connection; }; - int num_peers() const { return m_peers.size(); } + int num_peers() const + { + return m_peers.size(); + } + int num_uploads() const + { + return m_num_unchoked; + } + typedef std::list::iterator iterator; typedef std::list::const_iterator const_iterator; iterator begin_peer() { return m_peers.begin(); } iterator end_peer() { return m_peers.end(); } bool connect_one_peer(); - bool disconnect_one_peer(); private: -/* + bool unchoke_one_peer(); void choke_one_peer(); iterator find_choke_candidate(); @@ -233,7 +233,8 @@ namespace libtorrent void seed_choke_one_peer(); iterator find_seed_choke_candidate(); iterator find_seed_unchoke_candidate(); -*/ + + bool disconnect_one_peer(); iterator find_disconnect_candidate(); iterator find_connect_candidate(); @@ -241,6 +242,10 @@ namespace libtorrent torrent* m_torrent; + // the number of unchoked peers + // at any given time + int m_num_unchoked; + // free download we have got that hasn't // been distributed yet. size_type m_available_free_upload; @@ -248,7 +253,7 @@ namespace libtorrent // if there is a connection limit, // we disconnect one peer every minute in hope of // establishing a connection with a better peer -// ptime m_last_optimistic_disconnect; + ptime m_last_optimistic_disconnect; }; } diff --git a/libtorrent/include/libtorrent/session.hpp b/libtorrent/include/libtorrent/session.hpp index 3a9eb563b..38206f32c 100755 --- a/libtorrent/include/libtorrent/session.hpp +++ b/libtorrent/include/libtorrent/session.hpp @@ -53,7 +53,6 @@ POSSIBILITY OF SUCH DAMAGE. #pragma warning(pop) #endif -#include "libtorrent/config.hpp" #include "libtorrent/torrent_handle.hpp" #include "libtorrent/entry.hpp" #include "libtorrent/alert.hpp" @@ -61,6 +60,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/version.hpp" #include "libtorrent/fingerprint.hpp" +#include "libtorrent/resource_request.hpp" #include "libtorrent/storage.hpp" #ifdef _MSC_VER @@ -141,17 +141,22 @@ namespace libtorrent , fs::path const& save_path , entry const& resume_data = entry() , bool compact_mode = true - , bool paused = false - , storage_constructor_type sc = default_storage_constructor) TORRENT_DEPRECATED; + , int block_size = 16 * 1024 + , storage_constructor_type sc = default_storage_constructor); + // ==== deprecated, this is for backwards compatibility only + // instead, use one of the other add_torrent overloads torrent_handle add_torrent( - boost::intrusive_ptr ti + entry const& e , fs::path const& save_path , entry const& resume_data = entry() , bool compact_mode = true - , bool paused = false - , storage_constructor_type sc = default_storage_constructor - , void* userdata = 0); + , int block_size = 16 * 1024 + , storage_constructor_type sc = default_storage_constructor) TORRENT_DEPRECATED + { + return add_torrent(torrent_info(e), save_path, resume_data + , compact_mode, block_size, sc); + } torrent_handle add_torrent( char const* tracker_url @@ -160,9 +165,8 @@ namespace libtorrent , fs::path const& save_path , entry const& resume_data = entry() , bool compact_mode = true - , bool paused = false - , storage_constructor_type sc = default_storage_constructor - , void* userdata = 0); + , int block_size = 16 * 1024 + , storage_constructor_type sc = default_storage_constructor); session_proxy abort() { return session_proxy(m_impl); } @@ -183,7 +187,7 @@ namespace libtorrent #endif #ifndef TORRENT_DISABLE_EXTENSIONS - void add_extension(boost::function(torrent*, void*)> ext); + void add_extension(boost::function(torrent*)> ext); #endif void set_ip_filter(ip_filter const& f); @@ -239,7 +243,6 @@ namespace libtorrent int upload_rate_limit() const; int download_rate_limit() const; - int max_half_open_connections() const; void set_upload_rate_limit(int bytes_per_second); void set_download_rate_limit(int bytes_per_second); @@ -262,6 +265,12 @@ namespace libtorrent void stop_natpmp(); void stop_upnp(); + // Resource management used for global limits. + resource_request m_ul_bandwidth_quota; + resource_request m_dl_bandwidth_quota; + resource_request m_uploads_quota; + resource_request m_connections_quota; + private: // just a way to initialize boost.filesystem diff --git a/libtorrent/include/libtorrent/session_impl.hpp b/libtorrent/include/libtorrent/session_impl.hpp index 67c3fef1d..e69de29bb 100644 --- a/libtorrent/include/libtorrent/session_impl.hpp +++ b/libtorrent/include/libtorrent/session_impl.hpp @@ -1,594 +0,0 @@ -/* - -Copyright (c) 2006, 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. - -*/ - -#ifndef TORRENT_SESSION_IMPL_HPP_INCLUDED -#define TORRENT_SESSION_IMPL_HPP_INCLUDED - -#include -#include -#include -#include -#include -#include - -#ifdef _MSC_VER -#pragma warning(push, 1) -#endif - -#include -#include -#include -#include -#include - -#ifdef _MSC_VER -#pragma warning(pop) -#endif - -#include "libtorrent/torrent_handle.hpp" -#include "libtorrent/entry.hpp" -#include "libtorrent/torrent_info.hpp" -#include "libtorrent/socket.hpp" -#include "libtorrent/peer_connection.hpp" -#include "libtorrent/peer_id.hpp" -#include "libtorrent/policy.hpp" -#include "libtorrent/tracker_manager.hpp" -#include "libtorrent/peer_info.hpp" -#include "libtorrent/alert.hpp" -#include "libtorrent/fingerprint.hpp" -#include "libtorrent/debug.hpp" -#include "libtorrent/peer_request.hpp" -#include "libtorrent/piece_block_progress.hpp" -#include "libtorrent/ip_filter.hpp" -#include "libtorrent/config.hpp" -#include "libtorrent/session_settings.hpp" -#include "libtorrent/kademlia/dht_tracker.hpp" -#include "libtorrent/session_status.hpp" -#include "libtorrent/session.hpp" -#include "libtorrent/stat.hpp" -#include "libtorrent/file_pool.hpp" -#include "libtorrent/bandwidth_manager.hpp" -#include "libtorrent/natpmp.hpp" -#include "libtorrent/upnp.hpp" -#include "libtorrent/lsd.hpp" -#include "libtorrent/socket_type.hpp" -#include "libtorrent/connection_queue.hpp" -#include "libtorrent/disk_io_thread.hpp" - -namespace libtorrent -{ - - namespace fs = boost::filesystem; - - namespace aux - { - struct session_impl; - - // this data is shared between the main thread and the - // thread that initialize pieces - struct piece_checker_data - { - piece_checker_data() - : processing(false), progress(0.f), abort(false) {} - - boost::shared_ptr torrent_ptr; - fs::path save_path; - - sha1_hash info_hash; - - void parse_resume_data( - const entry& rd - , const torrent_info& info - , std::string& error); - - std::vector piece_map; - std::vector unfinished_pieces; - std::vector block_info; - std::vector peers; - entry resume_data; - - // this is true if this torrent is being processed (checked) - // if it is not being processed, then it can be removed from - // the queue without problems, otherwise the abort flag has - // to be set. - bool processing; - - // is filled in by storage::initialize_pieces() - // and represents the progress. It should be a - // value in the range [0, 1] - float progress; - - // abort defaults to false and is typically - // filled in by torrent_handle when the user - // aborts the torrent - bool abort; - }; - - struct checker_impl: boost::noncopyable - { - checker_impl(session_impl& s): m_ses(s), m_abort(false) {} - void operator()(); - piece_checker_data* find_torrent(const sha1_hash& info_hash); - void remove_torrent(sha1_hash const& info_hash); - -#ifndef NDEBUG - void check_invariant() const; -#endif - - // when the files has been checked - // the torrent is added to the session - session_impl& m_ses; - - mutable boost::mutex m_mutex; - boost::condition m_cond; - - // a list of all torrents that are currently in queue - // or checking their files - std::deque > m_torrents; - std::deque > m_processing; - - bool m_abort; - }; - -#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) - struct tracker_logger; -#endif - - // this is the link between the main thread and the - // thread started to run the main downloader loop - struct session_impl: boost::noncopyable - { -#ifndef NDEBUG - friend class ::libtorrent::peer_connection; -#endif - friend struct checker_impl; - friend class invariant_access; - typedef std::map - , boost::intrusive_ptr > - connection_map; - typedef std::map > torrent_map; - - session_impl( - std::pair listen_port_range - , fingerprint const& cl_fprint - , char const* listen_interface = "0.0.0.0"); - ~session_impl(); - -#ifndef TORRENT_DISABLE_EXTENSIONS - void add_extension(boost::function(torrent*)> ext); -#endif - void operator()(); - - void open_listen_port(); - - void async_accept(); - void on_incoming_connection(boost::shared_ptr const& s - , boost::weak_ptr const& as, asio::error_code const& e); - - // must be locked to access the data - // in this struct - typedef boost::recursive_mutex mutex_t; - mutable mutex_t m_mutex; - - boost::weak_ptr find_torrent(const sha1_hash& info_hash); - peer_id const& get_peer_id() const { return m_peer_id; } - - void close_connection(boost::intrusive_ptr const& p); - void connection_failed(boost::shared_ptr const& s - , tcp::endpoint const& a, char const* message); - - void set_settings(session_settings const& s); - session_settings const& settings() const { return m_settings; } - -#ifndef TORRENT_DISABLE_DHT - void add_dht_node(std::pair const& node); - void add_dht_node(udp::endpoint n); - void add_dht_router(std::pair const& node); - void set_dht_settings(dht_settings const& s); - dht_settings const& get_dht_settings() const { return m_dht_settings; } - void start_dht(entry const& startup_state); - void stop_dht(); - entry dht_state() const; -#endif - -#ifndef TORRENT_DISABLE_ENCRYPTION - void set_pe_settings(pe_settings const& settings); - pe_settings const& get_pe_settings() const { return m_pe_settings; } -#endif - - // called when a port mapping is successful, or a router returns - // a failure to map a port - void on_port_mapping(int tcp_port, int udp_port, std::string const& errmsg); - - bool is_aborted() const { return m_abort; } - - void set_ip_filter(ip_filter const& f); - void set_port_filter(port_filter const& f); - - bool listen_on( - std::pair const& port_range - , const char* net_interface = 0); - bool is_listening() const; - - torrent_handle add_torrent( - torrent_info const& ti - , fs::path const& save_path - , entry const& resume_data - , bool compact_mode - , int block_size - , storage_constructor_type sc); - - torrent_handle add_torrent( - char const* tracker_url - , sha1_hash const& info_hash - , char const* name - , fs::path const& save_path - , entry const& resume_data - , bool compact_mode - , int block_size - , storage_constructor_type sc); - - void remove_torrent(torrent_handle const& h); - - std::vector get_torrents(); - - void set_severity_level(alert::severity_t s); - std::auto_ptr pop_alert(); - - int upload_rate_limit() const; - int download_rate_limit() const; - - void set_download_rate_limit(int bytes_per_second); - void set_upload_rate_limit(int bytes_per_second); - void set_max_half_open_connections(int limit); - void set_max_connections(int limit); - void set_max_uploads(int limit); - - int max_connections() const { return m_max_connections; } - int max_uploads() const { return m_max_uploads; } - - int num_uploads() const { return m_num_unchoked; } - int num_connections() const - { return m_connections.size(); } - - void unchoke_peer(peer_connection& c) - { - c.send_unchoke(); - ++m_num_unchoked; - } - - session_status status() const; - void set_peer_id(peer_id const& id); - void set_key(int key); - unsigned short listen_port() const; - - void abort(); - - torrent_handle find_torrent_handle(sha1_hash const& info_hash); - - void announce_lsd(sha1_hash const& ih); - - void set_peer_proxy(proxy_settings const& s) - { m_peer_proxy = s; } - void set_web_seed_proxy(proxy_settings const& s) - { m_web_seed_proxy = s; } - void set_tracker_proxy(proxy_settings const& s) - { m_tracker_proxy = s; } - - proxy_settings const& peer_proxy() const - { return m_peer_proxy; } - proxy_settings const& web_seed_proxy() const - { return m_web_seed_proxy; } - proxy_settings const& tracker_proxy() const - { return m_tracker_proxy; } - -#ifndef TORRENT_DISABLE_DHT - void set_dht_proxy(proxy_settings const& s) - { m_dht_proxy = s; } - proxy_settings const& dht_proxy() const - { return m_dht_proxy; } -#endif - - void start_lsd(); - void start_natpmp(); - void start_upnp(); - - void stop_lsd(); - void stop_natpmp(); - void stop_upnp(); - - // handles delayed alerts - alert_manager m_alerts; - -// private: - - void on_lsd_peer(tcp::endpoint peer, sha1_hash const& ih); - - // this is where all active sockets are stored. - // the selector can sleep while there's no activity on - // them - io_service m_io_service; - asio::strand m_strand; - - // the file pool that all storages in this session's - // torrents uses. It sets a limit on the number of - // open files by this session. - // file pool must be destructed after the torrents - // since they will still have references to it - // when they are destructed. - file_pool m_files; - - // handles disk io requests asynchronously - disk_io_thread m_disk_thread; - - // this is a list of half-open tcp connections - // (only outgoing connections) - // this has to be one of the last - // members to be destructed - connection_queue m_half_open; - - // the bandwidth manager is responsible for - // handing out bandwidth to connections that - // asks for it, it can also throttle the - // rate. - bandwidth_manager m_download_channel; - bandwidth_manager m_upload_channel; - - bandwidth_manager* m_bandwidth_manager[2]; - - tracker_manager m_tracker_manager; - torrent_map m_torrents; - - // this maps sockets to their peer_connection - // object. It is the complete list of all connected - // peers. - connection_map m_connections; - - // filters incoming connections - ip_filter m_ip_filter; - - // filters outgoing connections - port_filter m_port_filter; - - // the peer id that is generated at the start of the session - peer_id m_peer_id; - - // the key is an id that is used to identify the - // client with the tracker only. It is randomized - // at startup - int m_key; - - // the range of ports we try to listen on - std::pair m_listen_port_range; - - // the ip-address of the interface - // we are supposed to listen on. - // if the ip is set to zero, it means - // that we should let the os decide which - // interface to listen on - tcp::endpoint m_listen_interface; - - // this is typically set to the same as the local - // listen port. In case a NAT port forward was - // successfully opened, this will be set to the - // port that is open on the external (NAT) interface - // on the NAT box itself. This is the port that has - // to be published to peers, since this is the port - // the client is reachable through. - int m_external_listen_port; - - boost::shared_ptr m_listen_socket; - - // the settings for the client - session_settings m_settings; - // the proxy settings for different - // kinds of connections - proxy_settings m_peer_proxy; - proxy_settings m_web_seed_proxy; - proxy_settings m_tracker_proxy; -#ifndef TORRENT_DISABLE_DHT - proxy_settings m_dht_proxy; -#endif - - // set to true when the session object - // is being destructed and the thread - // should exit - volatile bool m_abort; - - int m_max_uploads; - int m_max_connections; - - // the number of unchoked peers - int m_num_unchoked; - - // this is initialized to the unchoke_interval - // session_setting and decreased every second. - // when it reaches zero, it is reset to the - // unchoke_interval and the unchoke set is - // recomputed. - int m_unchoke_time_scaler; - - // works like unchoke_time_scaler but it - // is only decresed when the unchoke set - // is recomputed, and when it reaches zero, - // the optimistic unchoke is moved to another peer. - int m_optimistic_unchoke_time_scaler; - - // works like unchoke_time_scaler. Each time - // it reaches 0, and all the connections are - // used, the worst connection will be disconnected - // from the torrent with the most peers - int m_disconnect_time_scaler; - - // statistics gathered from all torrents. - stat m_stat; - - // is false by default and set to true when - // the first incoming connection is established - // this is used to know if the client is behind - // NAT or not. - bool m_incoming_connection; - - void second_tick(asio::error_code const& e); - ptime m_last_tick; - -#ifndef TORRENT_DISABLE_DHT - boost::intrusive_ptr m_dht; - dht_settings m_dht_settings; - // if this is set to true, the dht listen port - // will be set to the same as the tcp listen port - // and will be synchronlized with it as it changes - // it defaults to true - bool m_dht_same_port; - - // see m_external_listen_port. This is the same - // but for the udp port used by the DHT. - int m_external_udp_port; -#endif - -#ifndef TORRENT_DISABLE_ENCRYPTION - pe_settings m_pe_settings; -#endif - - boost::shared_ptr m_natpmp; - boost::shared_ptr m_upnp; - boost::shared_ptr m_lsd; - - // the timer used to fire the second_tick - deadline_timer m_timer; - - // the index of the torrent that will be offered to - // connect to a peer next time second_tick is called. - // This implements a round robin. - int m_next_connect_torrent; -#ifndef NDEBUG - void check_invariant(const char *place = 0); -#endif - -#ifdef TORRENT_STATS - // logger used to write bandwidth usage statistics - std::ofstream m_stats_logger; - int m_second_counter; -#endif -#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - boost::shared_ptr create_log(std::string const& name - , int instance, bool append = true); - - // this list of tracker loggers serves as tracker_callbacks when - // shutting down. This list is just here to keep them alive during - // whe shutting down process - std::list > m_tracker_loggers; - - public: - boost::shared_ptr m_logger; - private: -#endif - -#ifndef TORRENT_DISABLE_EXTENSIONS - typedef std::list(torrent*)> > extension_list_t; - - extension_list_t m_extensions; -#endif - - // data shared between the main thread - // and the checker thread - checker_impl m_checker_impl; - - // the main working thread - boost::scoped_ptr m_thread; - - // the thread that calls initialize_pieces() - // on all torrents before they start downloading - boost::scoped_ptr m_checker_thread; - }; - -#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) - struct tracker_logger : request_callback - { - tracker_logger(session_impl& ses): m_ses(ses) {} - void tracker_warning(std::string const& str) - { - debug_log("*** tracker warning: " + str); - } - - void tracker_response(tracker_request const& - , std::vector& peers - , int interval - , int complete - , int incomplete) - { - std::stringstream s; - s << "TRACKER RESPONSE:\n" - "interval: " << interval << "\n" - "peers:\n"; - for (std::vector::const_iterator i = peers.begin(); - i != peers.end(); ++i) - { - s << " " << std::setfill(' ') << std::setw(16) << i->ip - << " " << std::setw(5) << std::dec << i->port << " "; - if (!i->pid.is_all_zeros()) s << " " << i->pid; - s << "\n"; - } - debug_log(s.str()); - } - - void tracker_request_timed_out( - tracker_request const&) - { - debug_log("*** tracker timed out"); - } - - void tracker_request_error( - tracker_request const& - , int response_code - , const std::string& str) - { - debug_log(std::string("*** tracker error: ") - + boost::lexical_cast(response_code) + ": " - + str); - } - - void debug_log(const std::string& line) - { - (*m_ses.m_logger) << line << "\n"; - } - session_impl& m_ses; - }; -#endif - - } -} - - -#endif - diff --git a/libtorrent/include/libtorrent/session_settings.hpp b/libtorrent/include/libtorrent/session_settings.hpp index 3a145c687..ebc30eae3 100644 --- a/libtorrent/include/libtorrent/session_settings.hpp +++ b/libtorrent/include/libtorrent/session_settings.hpp @@ -105,11 +105,9 @@ namespace libtorrent , send_redundant_have(false) , lazy_bitfields(true) , inactivity_timeout(600) - , unchoke_interval(15) - , optimistic_unchoke_multiplier(4) + , unchoke_interval(20) , num_want(200) , initial_picker_threshold(4) - , allowed_fast_set_size(10) , max_outstanding_disk_bytes_per_connection(64 * 1024) #ifndef TORRENT_DISABLE_DHT , use_dht_as_fallback(true) @@ -243,10 +241,6 @@ namespace libtorrent // the number of seconds between chokes/unchokes int unchoke_interval; - // the number of unchoke intervals between - // optimistic unchokes - int optimistic_unchoke_multiplier; - // if this is set, this IP will be reported do the // tracker in the ip= parameter. address announce_ip; @@ -258,10 +252,6 @@ namespace libtorrent // random pieces instead of rarest first. int initial_picker_threshold; - // the number of allowed pieces to send to peers - // that supports the fast extensions - int allowed_fast_set_size; - // the maximum number of bytes a connection may have // pending in the disk write queue before its download // rate is being throttled. This prevents fast downloads diff --git a/libtorrent/include/libtorrent/stat.hpp b/libtorrent/include/libtorrent/stat.hpp index 24e477a37..2424d5d6c 100755 --- a/libtorrent/include/libtorrent/stat.hpp +++ b/libtorrent/include/libtorrent/stat.hpp @@ -40,7 +40,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/size_type.hpp" #include "libtorrent/invariant_check.hpp" #include "libtorrent/config.hpp" -#include "libtorrent/assert.hpp" namespace libtorrent { diff --git a/libtorrent/include/libtorrent/storage.hpp b/libtorrent/include/libtorrent/storage.hpp index 9db79ea3d..8a10c7148 100755 --- a/libtorrent/include/libtorrent/storage.hpp +++ b/libtorrent/include/libtorrent/storage.hpp @@ -43,7 +43,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include #include #ifdef _MSC_VER @@ -148,11 +147,10 @@ namespace libtorrent }; typedef storage_interface* (&storage_constructor_type)( - boost::intrusive_ptr, fs::path const& + torrent_info const&, fs::path const& , file_pool&); - TORRENT_EXPORT storage_interface* default_storage_constructor( - boost::intrusive_ptr ti + TORRENT_EXPORT storage_interface* default_storage_constructor(torrent_info const& ti , fs::path const& path, file_pool& fp); // returns true if the filesystem the path relies on supports @@ -171,7 +169,7 @@ namespace libtorrent piece_manager( boost::shared_ptr const& torrent - , boost::intrusive_ptr ti + , torrent_info const& ti , fs::path const& path , file_pool& fp , disk_io_thread& io @@ -201,9 +199,7 @@ namespace libtorrent void async_read( peer_request const& r - , boost::function const& handler - , char* buffer = 0 - , int priority = 0); + , boost::function const& handler); void async_write( peer_request const& r @@ -231,7 +227,7 @@ namespace libtorrent { return m_compact_mode; } #ifndef NDEBUG - std::string name() const { return m_info->name(); } + std::string name() const { return m_info.name(); } #endif private: @@ -287,7 +283,7 @@ namespace libtorrent // a bitmask representing the pieces we have std::vector m_have_piece; - boost::intrusive_ptr m_info; + torrent_info const& m_info; // slots that haven't had any file storage allocated std::vector m_unallocated_slots; @@ -317,6 +313,12 @@ namespace libtorrent mutable boost::recursive_mutex m_mutex; + bool m_allocating; + boost::mutex m_allocating_monitor; + boost::condition m_allocating_condition; + + // these states are used while checking/allocating the torrent + enum { // the default initial state state_none, @@ -331,11 +333,6 @@ namespace libtorrent } m_state; int m_current_slot; - // this is saved in case we need to instantiate a new - // storage (osed when remapping files) - storage_constructor_type m_storage_constructor; - - // temporary buffer used while checking std::vector m_piece_data; // this maps a piece hash to piece index. It will be @@ -343,9 +340,6 @@ namespace libtorrent // isn't needed) std::multimap m_hash_to_piece; - // this map contains partial hashes for downloading - // pieces. This is only accessed from within the - // disk-io thread. std::map m_piece_hasher; disk_io_thread& m_io_thread; diff --git a/libtorrent/include/libtorrent/time.hpp b/libtorrent/include/libtorrent/time.hpp index 27d61af9d..2227fc932 100644 --- a/libtorrent/include/libtorrent/time.hpp +++ b/libtorrent/include/libtorrent/time.hpp @@ -55,7 +55,6 @@ namespace libtorrent || _POSIX_MONOTONIC_CLOCK < 0)) || defined (TORRENT_USE_BOOST_DATE_TIME) #include -#include "libtorrent/assert.hpp" namespace libtorrent { @@ -86,7 +85,6 @@ namespace libtorrent #include #include -#include "libtorrent/assert.hpp" namespace libtorrent { @@ -172,7 +170,6 @@ namespace asio #include #include -#include "libtorrent/assert.hpp" // high precision timer for darwin intel and ppc @@ -252,7 +249,6 @@ namespace libtorrent #define WIN32_LEAN_AND_MEAN #endif #include -#include "libtorrent/assert.hpp" namespace libtorrent { @@ -339,7 +335,6 @@ namespace libtorrent #elif defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0 #include -#include "libtorrent/assert.hpp" namespace libtorrent { @@ -390,4 +385,4 @@ namespace libtorrent #endif #endif - + diff --git a/libtorrent/include/libtorrent/torrent.hpp b/libtorrent/include/libtorrent/torrent.hpp index bcc54899f..2eef2656b 100755 --- a/libtorrent/include/libtorrent/torrent.hpp +++ b/libtorrent/include/libtorrent/torrent.hpp @@ -62,13 +62,13 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/tracker_manager.hpp" #include "libtorrent/stat.hpp" #include "libtorrent/alert.hpp" +#include "libtorrent/resource_request.hpp" #include "libtorrent/piece_picker.hpp" #include "libtorrent/config.hpp" #include "libtorrent/escape_string.hpp" #include "libtorrent/bandwidth_manager.hpp" #include "libtorrent/storage.hpp" #include "libtorrent/hasher.hpp" -#include "libtorrent/assert.hpp" namespace libtorrent { @@ -98,13 +98,13 @@ namespace libtorrent torrent( aux::session_impl& ses , aux::checker_impl& checker - , boost::intrusive_ptr tf + , torrent_info const& tf , fs::path const& save_path , tcp::endpoint const& net_interface , bool compact_mode , int block_size - , storage_constructor_type sc - , bool paused); + , session_settings const& s + , storage_constructor_type sc); // used with metadata-less torrents // (the metadata is downloaded from the peers) @@ -118,8 +118,8 @@ namespace libtorrent , tcp::endpoint const& net_interface , bool compact_mode , int block_size - , storage_constructor_type sc - , bool paused); + , session_settings const& s + , storage_constructor_type sc); ~torrent(); @@ -154,6 +154,10 @@ namespace libtorrent bool verify_resume_data(entry& rd, std::string& error) { assert(m_storage); return m_storage->verify_resume_data(rd, error); } + // is called every second by session. This will + // caclulate the upload/download and number + // of connections this torrent needs. And prepare + // it for being used by allocate_resources. void second_tick(stat& accumulator, float tick_interval); // debug purpose only @@ -250,15 +254,6 @@ namespace libtorrent void remove_url_seed(std::string const& url) { m_web_seeds.erase(url); } - std::set url_seeds() const - { return m_web_seeds; } - - bool free_upload_slots() const - { return m_num_uploads < m_max_uploads; } - - void choke_peer(peer_connection& c); - bool unchoke_peer(peer_connection& c); - // used by peer_connection to attach itself to a torrent // since incoming connections don't know what torrent // they're a part of until they have received an info_hash. @@ -470,14 +465,14 @@ namespace libtorrent bool is_seed() const { return valid_metadata() - && m_num_pieces == m_torrent_file->num_pieces(); + && m_num_pieces == m_torrent_file.num_pieces(); } // this is true if we have all the pieces that we want bool is_finished() const { if (is_seed()) return true; - return valid_metadata() && m_torrent_file->num_pieces() + return valid_metadata() && m_torrent_file.num_pieces() - m_num_pieces - m_picker->num_filtered() == 0; } @@ -499,7 +494,7 @@ namespace libtorrent } piece_manager& filesystem(); torrent_info const& torrent_file() const - { return *m_torrent_file; } + { return m_torrent_file; } std::vector const& trackers() const { return m_trackers; } @@ -521,6 +516,11 @@ namespace libtorrent // -------------------------------------------- // RESOURCE MANAGEMENT + void distribute_resources(float tick_interval); + + resource_request m_uploads_quota; + resource_request m_connections_quota; + void set_peer_upload_limit(tcp::endpoint ip, int limit); void set_peer_download_limit(tcp::endpoint ip, int limit); @@ -530,9 +530,7 @@ namespace libtorrent int download_limit() const; void set_max_uploads(int limit); - int max_uploads() const { return m_max_uploads; } void set_max_connections(int limit); - int max_connections() const { return m_max_connections; } void move_storage(fs::path const& save_path); // unless this returns true, new connections must wait @@ -540,7 +538,7 @@ namespace libtorrent bool ready_for_connections() const { return m_connections_initialized; } bool valid_metadata() const - { return m_torrent_file->is_valid(); } + { return m_torrent_file.is_valid(); } // parses the info section from the given // bencoded tree and moves the torrent @@ -564,7 +562,7 @@ namespace libtorrent void update_peer_interest(); - boost::intrusive_ptr m_torrent_file; + torrent_info m_torrent_file; // is set to true when the torrent has // been aborted. @@ -707,9 +705,9 @@ namespace libtorrent // determine the timeout until next try. int m_failed_trackers; - // this is a counter that is decreased every - // second, and when it reaches 0, the policy::pulse() - // is called and the time scaler is reset to 10. + // this is a counter that is increased every + // second, and when it reaches 10, the policy::pulse() + // is called and the time scaler is reset to 0. int m_time_scaler; // the bitmask that says which pieces we have @@ -776,15 +774,6 @@ namespace libtorrent session_settings const& m_settings; storage_constructor_type m_storage_constructor; - - // the maximum number of uploads for this torrent - int m_max_uploads; - - // the number of unchoked peers in this torrent - int m_num_uploads; - - // the maximum number of connections for this torrent - int m_max_connections; #ifndef TORRENT_DISABLE_EXTENSIONS typedef std::list > extension_list_t; diff --git a/libtorrent/include/libtorrent/torrent_handle.hpp b/libtorrent/include/libtorrent/torrent_handle.hpp index 287c57305..3f7ae5bcc 100755 --- a/libtorrent/include/libtorrent/torrent_handle.hpp +++ b/libtorrent/include/libtorrent/torrent_handle.hpp @@ -34,7 +34,6 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_TORRENT_HANDLE_HPP_INCLUDED #include -#include #ifdef _MSC_VER #pragma warning(push, 1) @@ -274,9 +273,7 @@ namespace libtorrent std::vector const& trackers() const; void replace_trackers(std::vector const&) const; - void add_url_seed(std::string const& url) const; - void remove_url_seed(std::string const& url) const; - std::set url_seeds() const; + void add_url_seed(std::string const& url); bool has_metadata() const; const torrent_info& get_torrent_info() const; @@ -399,7 +396,6 @@ namespace libtorrent , m_info_hash(h) { assert(m_ses != 0); - assert(m_chk != 0); } #ifndef NDEBUG diff --git a/libtorrent/include/libtorrent/torrent_info.hpp b/libtorrent/include/libtorrent/torrent_info.hpp index 492fda48d..a2d6c4ef9 100755 --- a/libtorrent/include/libtorrent/torrent_info.hpp +++ b/libtorrent/include/libtorrent/torrent_info.hpp @@ -57,8 +57,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/peer_request.hpp" #include "libtorrent/config.hpp" #include "libtorrent/time.hpp" -#include "libtorrent/intrusive_ptr_base.hpp" -#include "libtorrent/assert.hpp" namespace libtorrent { @@ -73,7 +71,7 @@ namespace libtorrent size_type offset; // the offset of this file inside the torrent size_type size; // the size of this file // if the path was incorrectly encoded, this is - // the original corrupt encoded string. It is + // the origianal corrupt encoded string. It is // preserved in order to be able to reproduce // the correct info-hash boost::shared_ptr orig_path; @@ -98,7 +96,7 @@ namespace libtorrent virtual const char* what() const throw() { return "invalid torrent file"; } }; - class TORRENT_EXPORT torrent_info : public intrusive_ptr_base + class TORRENT_EXPORT torrent_info { public: @@ -117,12 +115,8 @@ namespace libtorrent void add_file(fs::path file, size_type size); void add_url_seed(std::string const& url); - bool remap_files(std::vector > const& map); - - std::vector map_block(int piece, size_type offset - , int size, bool storage = false) const; - peer_request map_file(int file, size_type offset, int size - , bool storage = false) const; + std::vector map_block(int piece, size_type offset, int size) const; + peer_request map_file(int file, size_type offset, int size) const; std::vector const& url_seeds() const { @@ -134,60 +128,15 @@ namespace libtorrent typedef std::vector::const_reverse_iterator reverse_file_iterator; // list the files in the torrent file - file_iterator begin_files(bool storage = false) const - { - if (!storage || m_remapped_files.empty()) - return m_files.begin(); - else - return m_remapped_files.begin(); - } + file_iterator begin_files() const { return m_files.begin(); } + file_iterator end_files() const { return m_files.end(); } + reverse_file_iterator rbegin_files() const { return m_files.rbegin(); } + reverse_file_iterator rend_files() const { return m_files.rend(); } - file_iterator end_files(bool storage = false) const - { - if (!storage || m_remapped_files.empty()) - return m_files.end(); - else - return m_remapped_files.end(); - } - - reverse_file_iterator rbegin_files(bool storage = false) const - { - if (!storage || m_remapped_files.empty()) - return m_files.rbegin(); - else - return m_remapped_files.rbegin(); - } - - reverse_file_iterator rend_files(bool storage = false) const - { - if (!storage || m_remapped_files.empty()) - return m_files.rend(); - else - return m_remapped_files.rend(); - } - - int num_files(bool storage = false) const - { - assert(m_piece_length > 0); - if (!storage || m_remapped_files.empty()) - return (int)m_files.size(); - else - return (int)m_remapped_files.size(); - } - - const file_entry& file_at(int index, bool storage = false) const - { - if (!storage || m_remapped_files.empty()) - { - assert(index >= 0 && index < (int)m_files.size()); - return m_files[index]; - } - else - { - assert(index >= 0 && index < (int)m_remapped_files.size()); - return m_remapped_files[index]; - } - } + int num_files() const + { assert(m_piece_length > 0); return (int)m_files.size(); } + const file_entry& file_at(int index) const + { assert(index >= 0 && index < (int)m_files.size()); return m_files[index]; } const std::vector& trackers() const { return m_urls; } @@ -269,13 +218,6 @@ namespace libtorrent // the list of files that this torrent consists of std::vector m_files; - // this vector is typically empty. If it is not - // empty, it means the user has re-mapped the - // files in this torrent to diffefrent names - // on disk. This is only used when reading and - // writing the disk. - std::vector m_remapped_files; - nodes_t m_nodes; // the sum of all filesizes @@ -322,10 +264,8 @@ namespace libtorrent entry m_extra_info; #ifndef NDEBUG - public: // this is set to true when seed_free() is called bool m_half_metadata; - private: #endif }; diff --git a/libtorrent/include/libtorrent/tracker_manager.hpp b/libtorrent/include/libtorrent/tracker_manager.hpp index 57f7bd851..1435ceda6 100755 --- a/libtorrent/include/libtorrent/tracker_manager.hpp +++ b/libtorrent/include/libtorrent/tracker_manager.hpp @@ -194,10 +194,11 @@ namespace libtorrent , address bind_interface , boost::weak_ptr r); - boost::shared_ptr requester(); + request_callback& requester(); virtual ~tracker_connection() {} tracker_request const& tracker_req() const { return m_req; } + bool has_requester() const { return !m_requester.expired(); } void fail(int code, char const* msg); void fail_timeout(); diff --git a/libtorrent/include/libtorrent/upnp.hpp b/libtorrent/include/libtorrent/upnp.hpp index fc0650631..d4b701aad 100644 --- a/libtorrent/include/libtorrent/upnp.hpp +++ b/libtorrent/include/libtorrent/upnp.hpp @@ -34,7 +34,6 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_UPNP_HPP #include "libtorrent/socket.hpp" -#include "libtorrent/broadcast_socket.hpp" #include "libtorrent/http_connection.hpp" #include "libtorrent/connection_queue.hpp" @@ -57,6 +56,9 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { +bool is_local(address const& a); +address_v4 guess_local_address(asio::io_service&); + // int: external tcp port // int: external udp port // std::string: error message @@ -70,6 +72,8 @@ public: , portmap_callback_t const& cb); ~upnp(); + void rebind(address const& listen_interface); + // maps the ports, if a port is set to 0 // it will not be mapped void set_mappings(int tcp, int udp); @@ -86,7 +90,7 @@ private: void update_mapping(int i, int port); void resend_request(asio::error_code const& e); - void on_reply(udp::endpoint const& from, char* buffer + void on_reply(asio::error_code const& e , std::size_t bytes_transferred); void discover_device(); @@ -102,15 +106,12 @@ private: , int mapping); void on_expire(asio::error_code const& e); + void post(rootdevice& d, std::stringstream const& s + , std::string const& soap_action); void map_port(rootdevice& d, int i); void unmap_port(rootdevice& d, int i); void disable(); - void delete_port_mapping(rootdevice& d, int i); - void create_port_mapping(http_connection& c, rootdevice& d, int i); - void post(upnp::rootdevice const& d, std::string const& soap - , std::string const& soap_action); - struct mapping_t { mapping_t() @@ -197,13 +198,18 @@ private: // current retry count int m_retry_count; - asio::io_service& m_io_service; + // used to receive responses in + char m_receive_buffer[1024]; - asio::strand m_strand; + // the endpoint we received the message from + udp::endpoint m_remote; + // the local address we're listening on + address_v4 m_local_ip; + // the udp socket used to send and receive // multicast messages on the network - broadcast_socket m_socket; + datagram_socket m_socket; // used to resend udp packets in case // they time out @@ -211,6 +217,8 @@ private: // timer used to refresh mappings deadline_timer m_refresh_timer; + + asio::strand m_strand; bool m_disabled; bool m_closing; diff --git a/libtorrent/include/libtorrent/web_peer_connection.hpp b/libtorrent/include/libtorrent/web_peer_connection.hpp index 1290f14a1..ba7450c0a 100755 --- a/libtorrent/include/libtorrent/web_peer_connection.hpp +++ b/libtorrent/include/libtorrent/web_peer_connection.hpp @@ -65,6 +65,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert.hpp" #include "libtorrent/torrent_handle.hpp" #include "libtorrent/torrent.hpp" +#include "libtorrent/allocate_resources.hpp" #include "libtorrent/peer_request.hpp" #include "libtorrent/piece_block_progress.hpp" #include "libtorrent/config.hpp" @@ -125,8 +126,6 @@ namespace libtorrent void write_piece(peer_request const& r, char const* buffer) { assert(false); } void write_keepalive() {} void on_connected(); - void write_reject_request(peer_request const&) {} - void write_allow_fast(int) {} #ifndef NDEBUG void check_invariant() const; diff --git a/libtorrent/src/assert.cpp b/libtorrent/src/assert.cpp index b4f011978..e69de29bb 100644 --- a/libtorrent/src/assert.cpp +++ b/libtorrent/src/assert.cpp @@ -1,73 +0,0 @@ -/* - -Copyright (c) 2007, 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. - -*/ - -#ifndef NDEBUG - -#include -#include -#include -#if defined __linux__ && defined __GNUC__ -#include -#endif - -void assert_fail(char const* expr, int line, char const* file, char const* function) -{ - - fprintf(stderr, "assertion failed. Please file a bugreport at " - "http://code.rasterbar.com/libtorrent/newticket\n" - "Please include the following information:\n\n" - "file: '%s'\n" - "line: %d\n" - "function: %s\n" - "expression: %s\n" - "stack:\n", file, line, function, expr); - -#if defined __linux__ && defined __GNUC__ - void* stack[50]; - int size = backtrace(stack, 50); - char** symbols = backtrace_symbols(stack, size); - - for (int i = 0; i < size; ++i) - { - fprintf(stderr, "%d: %s\n", i, symbols[i]); - } - - free(symbols); -#endif - // send SIGINT to the current process - // to break into the debugger - raise(SIGINT); - abort(); -} - -#endif - diff --git a/libtorrent/src/broadcast_socket.cpp b/libtorrent/src/broadcast_socket.cpp index 3aaadcc81..e69de29bb 100644 --- a/libtorrent/src/broadcast_socket.cpp +++ b/libtorrent/src/broadcast_socket.cpp @@ -1,186 +0,0 @@ -/* - -Copyright (c) 2007, 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 -#include -#include - -#include "libtorrent/socket.hpp" -#include "libtorrent/enum_net.hpp" -#include "libtorrent/broadcast_socket.hpp" -#include "libtorrent/assert.hpp" - -namespace libtorrent -{ - bool is_local(address const& a) - { - if (a.is_v6()) return a.to_v6().is_link_local(); - address_v4 a4 = a.to_v4(); - unsigned long ip = a4.to_ulong(); - return ((ip & 0xff000000) == 0x0a000000 - || (ip & 0xfff00000) == 0xac100000 - || (ip & 0xffff0000) == 0xc0a80000); - } - - address_v4 guess_local_address(asio::io_service& ios) - { - // make a best guess of the interface we're using and its IP - udp::resolver r(ios); - udp::resolver::iterator i = r.resolve(udp::resolver::query(asio::ip::host_name(), "0")); - for (;i != udp::resolver_iterator(); ++i) - { - address const& a = i->endpoint().address(); - // ignore non-IPv4 addresses - if (!a.is_v4()) break; - // ignore the loopback - if (a.to_v4() == address_v4::loopback()) continue; - } - if (i == udp::resolver_iterator()) return address_v4::any(); - return i->endpoint().address().to_v4(); - } - - bool is_loopback(address const& addr) - { - if (addr.is_v4()) - return addr.to_v4() == address_v4::loopback(); - else - return addr.to_v6() == address_v6::loopback(); - } - - bool is_multicast(address const& addr) - { - if (addr.is_v4()) - return addr.to_v4().is_multicast(); - else - return addr.to_v6().is_multicast(); - } - - broadcast_socket::broadcast_socket(asio::io_service& ios - , udp::endpoint const& multicast_endpoint - , receive_handler_t const& handler - , bool loopback) - : m_multicast_endpoint(multicast_endpoint) - , m_on_receive(handler) - { - assert(is_multicast(m_multicast_endpoint.address())); - - using namespace asio::ip::multicast; - - asio::error_code ec; - std::vector
interfaces = enum_net_interfaces(ios, ec); - - for (std::vector
::const_iterator i = interfaces.begin() - , end(interfaces.end()); i != end; ++i) - { - // only broadcast to IPv4 addresses that are not local - if (!is_local(*i)) continue; - // only multicast on compatible networks - if (i->is_v4() != multicast_endpoint.address().is_v4()) continue; - // ignore any loopback interface - if (is_loopback(*i)) continue; - - boost::shared_ptr s(new datagram_socket(ios)); - if (i->is_v4()) - { - s->open(udp::v4(), ec); - if (ec) continue; - s->set_option(datagram_socket::reuse_address(true), ec); - if (ec) continue; - s->bind(udp::endpoint(address_v4::any(), multicast_endpoint.port()), ec); - if (ec) continue; - s->set_option(join_group(multicast_endpoint.address()), ec); - if (ec) continue; - s->set_option(outbound_interface(i->to_v4()), ec); - if (ec) continue; - } - else - { - s->open(udp::v6(), ec); - if (ec) continue; - s->set_option(datagram_socket::reuse_address(true), ec); - if (ec) continue; - s->bind(udp::endpoint(address_v6::any(), multicast_endpoint.port()), ec); - if (ec) continue; - s->set_option(join_group(multicast_endpoint.address()), ec); - if (ec) continue; -// s->set_option(outbound_interface(i->to_v6()), ec); -// if (ec) continue; - } - s->set_option(hops(255), ec); - if (ec) continue; - s->set_option(enable_loopback(loopback), ec); - if (ec) continue; - m_sockets.push_back(socket_entry(s)); - socket_entry& se = m_sockets.back(); - s->async_receive_from(asio::buffer(se.buffer, sizeof(se.buffer)) - , se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2)); -#ifndef NDEBUG -// std::cerr << "broadcast socket [ if: " << i->to_v4().to_string() -// << " group: " << multicast_endpoint.address() << " ]" << std::endl; -#endif - } - } - - void broadcast_socket::send(char const* buffer, int size, asio::error_code& ec) - { - for (std::list::iterator i = m_sockets.begin() - , end(m_sockets.end()); i != end; ++i) - { - asio::error_code e; - i->socket->send_to(asio::buffer(buffer, size), m_multicast_endpoint, 0, e); -#ifndef NDEBUG -// std::cerr << " sending on " << i->socket->local_endpoint().address().to_string() << std::endl; -#endif - if (e) ec = e; - } - } - - void broadcast_socket::on_receive(socket_entry* s, asio::error_code const& ec - , std::size_t bytes_transferred) - { - if (ec || bytes_transferred == 0) return; - m_on_receive(s->remote, s->buffer, bytes_transferred); - s->socket->async_receive_from(asio::buffer(s->buffer, sizeof(s->buffer)) - , s->remote, bind(&broadcast_socket::on_receive, this, s, _1, _2)); - } - - void broadcast_socket::close() - { - for (std::list::iterator i = m_sockets.begin() - , end(m_sockets.end()); i != end; ++i) - { - i->socket->close(); - } - } -} - - diff --git a/libtorrent/src/bt_peer_connection.cpp b/libtorrent/src/bt_peer_connection.cpp index ab61d98f9..5b63f26cd 100755 --- a/libtorrent/src/bt_peer_connection.cpp +++ b/libtorrent/src/bt_peer_connection.cpp @@ -50,7 +50,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/version.hpp" #include "libtorrent/extensions.hpp" #include "libtorrent/aux_/session_impl.hpp" -#include "libtorrent/enum_net.hpp" #ifndef TORRENT_DISABLE_ENCRYPTION #include "libtorrent/pe_crypto.hpp" @@ -76,14 +75,7 @@ namespace libtorrent &bt_peer_connection::on_piece, &bt_peer_connection::on_cancel, &bt_peer_connection::on_dht_port, - 0, 0, 0, - // FAST extension messages - &bt_peer_connection::on_suggest_piece, - &bt_peer_connection::on_have_all, - &bt_peer_connection::on_have_none, - &bt_peer_connection::on_reject_request, - &bt_peer_connection::on_allowed_fast, - 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, &bt_peer_connection::on_extended }; @@ -101,7 +93,6 @@ namespace libtorrent , m_supports_extensions(false) #endif , m_supports_dht_port(false) - , m_supports_fast(false) #ifndef TORRENT_DISABLE_ENCRYPTION , m_encrypted(false) , m_rc4_encrypted(false) @@ -133,7 +124,6 @@ namespace libtorrent , m_supports_extensions(false) #endif , m_supports_dht_port(false) - , m_supports_fast(false) #ifndef TORRENT_DISABLE_ENCRYPTION , m_encrypted(false) , m_rc4_encrypted(false) @@ -236,10 +226,6 @@ namespace libtorrent boost::shared_ptr t = associated_torrent().lock(); assert(t); write_bitfield(t->pieces()); -#ifndef TORRENT_DISABLE_DHT - if (m_supports_dht_port && m_ses.m_dht) - write_dht_port(m_ses.get_dht_settings().service_port); -#endif } void bt_peer_connection::write_dht_port(int listen_port) @@ -260,75 +246,6 @@ namespace libtorrent setup_send(); } - void bt_peer_connection::write_have_all() - { - INVARIANT_CHECK; - assert(m_sent_handshake && !m_sent_bitfield); -#ifndef NDEBUG - m_sent_bitfield = true; -#endif -#ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << time_now_string() - << " ==> HAVE_ALL\n"; -#endif - char buf[] = {0,0,0,1, msg_have_all}; - send_buffer(buf, buf + sizeof(buf)); - } - - void bt_peer_connection::write_have_none() - { - INVARIANT_CHECK; - assert(m_sent_handshake && !m_sent_bitfield); -#ifndef NDEBUG - m_sent_bitfield = true; -#endif -#ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << time_now_string() - << " ==> HAVE_NONE\n"; -#endif - char buf[] = {0,0,0,1, msg_have_none}; - send_buffer(buf, buf + sizeof(buf)); - } - - void bt_peer_connection::write_reject_request(peer_request const& r) - { - INVARIANT_CHECK; - - assert(m_sent_handshake && m_sent_bitfield); - assert(associated_torrent().lock()->valid_metadata()); - - char buf[] = {0,0,0,13, msg_reject_request}; - - buffer::interval i = allocate_send_buffer(17); - - std::copy(buf, buf + 5, i.begin); - i.begin += 5; - - // index - detail::write_int32(r.piece, i.begin); - // begin - detail::write_int32(r.start, i.begin); - // length - detail::write_int32(r.length, i.begin); - assert(i.begin == i.end); - - setup_send(); - } - - void bt_peer_connection::write_allow_fast(int piece) - { - INVARIANT_CHECK; - - assert(m_sent_handshake && m_sent_bitfield); - assert(associated_torrent().lock()->valid_metadata()); - - char buf[] = {0,0,0,5, msg_allowed_fast, 0, 0, 0, 0}; - - char* ptr = buf + 5; - detail::write_int32(piece, ptr); - send_buffer(buf, buf + sizeof(buf)); - } - void bt_peer_connection::get_specific_peer_info(peer_info& p) const { assert(!associated_torrent().expired()); @@ -711,17 +628,14 @@ namespace libtorrent #ifndef TORRENT_DISABLE_DHT // indicate that we support the DHT messages - *(i.begin + 7) |= 0x01; + *(i.begin + 7) = 0x01; #endif #ifndef TORRENT_DISABLE_EXTENSIONS // we support extensions - *(i.begin + 5) |= 0x10; + *(i.begin + 5) = 0x10; #endif - // we support FAST extension - *(i.begin + 7) |= 0x04; - i.begin += 8; // info hash @@ -807,20 +721,6 @@ namespace libtorrent if (!packet_finished()) return; incoming_choke(); - if (!m_supports_fast) - { - boost::shared_ptr t = associated_torrent().lock(); - assert(t); - while (!request_queue().empty()) - { - piece_block const& b = request_queue().front(); - peer_request r; - r.piece = b.piece_index; - r.start = b.block_index * t->block_size(); - r.length = t->block_size(); - incoming_reject_request(r); - } - } } // ----------------------------- @@ -1039,9 +939,6 @@ namespace libtorrent { INVARIANT_CHECK; - if (!m_supports_dht_port) - throw protocol_error("got 'dht_port' message from peer that doesn't support it"); - assert(received > 0); if (packet_size() != 3) throw protocol_error("'dht_port' message size != 3"); @@ -1056,80 +953,6 @@ namespace libtorrent incoming_dht_port(listen_port); } - void bt_peer_connection::on_suggest_piece(int received) - { - INVARIANT_CHECK; - - if (!m_supports_fast) - throw protocol_error("got 'suggest_piece' without FAST extension support"); - - m_statistics.received_bytes(0, received); - if (!packet_finished()) return; - - buffer::const_interval recv_buffer = receive_buffer(); - - const char* ptr = recv_buffer.begin + 1; - int piece = detail::read_uint32(ptr); - incoming_suggest(piece); - } - - void bt_peer_connection::on_have_all(int received) - { - INVARIANT_CHECK; - - if (!m_supports_fast) - throw protocol_error("got 'have_all' without FAST extension support"); - m_statistics.received_bytes(0, received); - incoming_have_all(); - } - - void bt_peer_connection::on_have_none(int received) - { - INVARIANT_CHECK; - - if (!m_supports_fast) - throw protocol_error("got 'have_none' without FAST extension support"); - m_statistics.received_bytes(0, received); - incoming_have_none(); - } - - void bt_peer_connection::on_reject_request(int received) - { - INVARIANT_CHECK; - - if (!m_supports_fast) - throw protocol_error("got 'reject_request' without FAST extension support"); - - m_statistics.received_bytes(0, received); - if (!packet_finished()) return; - - buffer::const_interval recv_buffer = receive_buffer(); - - peer_request r; - const char* ptr = recv_buffer.begin + 1; - r.piece = detail::read_int32(ptr); - r.start = detail::read_int32(ptr); - r.length = detail::read_int32(ptr); - - incoming_reject_request(r); - } - - void bt_peer_connection::on_allowed_fast(int received) - { - INVARIANT_CHECK; - - if (!m_supports_fast) - throw protocol_error("got 'allowed_fast' without FAST extension support"); - - m_statistics.received_bytes(0, received); - if (!packet_finished()) return; - buffer::const_interval recv_buffer = receive_buffer(); - const char* ptr = recv_buffer.begin + 1; - int index = detail::read_int32(ptr); - - incoming_allowed_fast(index); - } - // ----------------------------- // --------- EXTENDED ---------- // ----------------------------- @@ -1222,7 +1045,7 @@ namespace libtorrent { tcp::endpoint adr(remote().address() , (unsigned short)listen_port->integer()); - t->get_policy().peer_from_tracker(adr, pid(), peer_info::incoming, 0); + t->get_policy().peer_from_tracker(adr, pid(), 0, 0); } } // there should be a version too @@ -1352,22 +1175,6 @@ namespace libtorrent assert(m_sent_handshake && !m_sent_bitfield); assert(t->valid_metadata()); - // in this case, have_all or have_none should be sent instead - assert(!m_supports_fast || !t->is_seed() || t->num_pieces() != 0); - - if (m_supports_fast && t->is_seed()) - { - write_have_all(); - send_allowed_set(); - return; - } - else if (m_supports_fast && t->num_pieces() == 0) - { - write_have_none(); - send_allowed_set(); - return; - } - int num_pieces = bitfield.size(); int lazy_pieces[50]; int num_lazy_pieces = 0; @@ -1376,7 +1183,7 @@ namespace libtorrent assert(t->is_seed() == (std::count(bitfield.begin(), bitfield.end(), true) == num_pieces)); if (t->is_seed() && m_ses.settings().lazy_bitfields) { - num_lazy_pieces = (std::min)(50, num_pieces / 10); + num_lazy_pieces = std::min(50, num_pieces / 10); if (num_lazy_pieces < 1) num_lazy_pieces = 1; for (int i = 0; i < num_pieces; ++i) { @@ -1444,9 +1251,6 @@ namespace libtorrent #endif } } - - if (m_supports_fast) - send_allowed_set(); } #ifndef TORRENT_DISABLE_EXTENSIONS @@ -1475,19 +1279,6 @@ namespace libtorrent detail::write_address(remote().address(), out); handshake["yourip"] = remote_address; handshake["reqq"] = m_ses.settings().max_allowed_in_request_queue; - asio::error_code ec; - std::vector
const& interfaces = enum_net_interfaces(get_socket()->io_service(), ec); - for (std::vector
::const_iterator i = interfaces.begin() - , end(interfaces.end()); i != end; ++i) - { - // TODO: only use global IPv6 addresses - if (!i->is_v6() || i->to_v6().is_link_local()) continue; - std::string ipv6_address; - std::back_insert_iterator out(ipv6_address); - detail::write_address(*i, out); - handshake["ipv6"] = ipv6_address; - break; - } // loop backwards, to make the first extension be the last // to fill in the handshake (i.e. give the first extensions priority) @@ -1755,7 +1546,7 @@ namespace libtorrent if (m_sync_bytes_read >= 512) throw protocol_error("sync hash not found within 532 bytes"); - cut_receive_buffer(bytes_processed, (std::min)(packet_size(), (512+20) - m_sync_bytes_read)); + cut_receive_buffer(bytes_processed, std::min(packet_size(), (512+20) - m_sync_bytes_read)); assert(!packet_finished()); return; @@ -1893,7 +1684,7 @@ namespace libtorrent if (m_sync_bytes_read >= 512) throw protocol_error("sync verification constant not found within 520 bytes"); - cut_receive_buffer(bytes_processed, (std::min)(packet_size(), (512+8) - m_sync_bytes_read)); + cut_receive_buffer(bytes_processed, std::min(packet_size(), (512+8) - m_sync_bytes_read)); assert(!packet_finished()); return; @@ -2225,9 +2016,6 @@ namespace libtorrent if (recv_buffer[7] & 0x01) m_supports_dht_port = true; - if (recv_buffer[7] & 0x04) - m_supports_fast = true; - // ok, now we have got enough of the handshake. Is this connection // attached to a torrent? if (!t) @@ -2261,10 +2049,10 @@ namespace libtorrent assert(t); // if this is a local connection, we have already - // sent the handshake + // send the handshake if (!is_local()) write_handshake(); -// if (t->valid_metadata()) -// write_bitfield(t->pieces()); + if (t->valid_metadata()) + write_bitfield(t->pieces()); assert(t->get_policy().has_connection(this)); @@ -2337,6 +2125,11 @@ namespace libtorrent throw protocol_error("closing connection to ourself"); } +#ifndef TORRENT_DISABLE_DHT + if (m_supports_dht_port && m_ses.m_dht) + write_dht_port(m_ses.get_dht_settings().service_port); +#endif + m_client_version = identify_client(pid); boost::optional f = client_fingerprint(pid); if (f && std::equal(f->name, f->name + 2, "BC")) @@ -2388,14 +2181,6 @@ namespace libtorrent m_state = read_packet_size; reset_recv_buffer(4); - if (t->valid_metadata()) - { - write_bitfield(t->pieces()); -#ifndef TORRENT_DISABLE_DHT - if (m_supports_dht_port && m_ses.m_dht) - write_dht_port(m_ses.get_dht_settings().service_port); -#endif - } assert(!packet_finished()); return; diff --git a/libtorrent/src/connection_queue.cpp b/libtorrent/src/connection_queue.cpp index 0b3f5ff54..859205ed0 100644 --- a/libtorrent/src/connection_queue.cpp +++ b/libtorrent/src/connection_queue.cpp @@ -54,8 +54,6 @@ namespace libtorrent , boost::function const& on_timeout , time_duration timeout) { - mutex_t::scoped_lock l(m_mutex); - INVARIANT_CHECK; m_queue.push_back(entry()); @@ -70,8 +68,6 @@ namespace libtorrent void connection_queue::done(int ticket) { - mutex_t::scoped_lock l(m_mutex); - INVARIANT_CHECK; std::list::iterator i = std::find_if(m_queue.begin() @@ -152,8 +148,6 @@ namespace libtorrent void connection_queue::on_timeout(asio::error_code const& e) { - mutex_t::scoped_lock l(m_mutex); - INVARIANT_CHECK; #ifndef NDEBUG function_guard guard_(m_in_timeout_function); @@ -164,35 +158,21 @@ namespace libtorrent ptime next_expire = max_time(); ptime now = time_now(); - std::list timed_out; for (std::list::iterator i = m_queue.begin(); !m_queue.empty() && i != m_queue.end();) { if (i->connecting && i->expires < now) { - std::list::iterator j = i; - ++i; - timed_out.splice(timed_out.end(), m_queue, j, i); + boost::function on_timeout = i->on_timeout; + m_queue.erase(i++); --m_num_connecting; + try { on_timeout(); } catch (std::exception&) {} continue; } if (i->expires < next_expire) next_expire = i->expires; ++i; } - - // we don't want to call the timeout callback while we're locked - // since that is a recepie for dead-locks - l.unlock(); - - for (std::list::iterator i = timed_out.begin() - , end(timed_out.end()); i != end; ++i) - { - try { i->on_timeout(); } catch (std::exception&) {} - } - - l.lock(); - if (next_expire < max_time()) { m_timer.expires_at(next_expire); diff --git a/libtorrent/src/disk_io_thread.cpp b/libtorrent/src/disk_io_thread.cpp index 4fb2cfb3a..6bc357506 100644 --- a/libtorrent/src/disk_io_thread.cpp +++ b/libtorrent/src/disk_io_thread.cpp @@ -34,24 +34,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #include "libtorrent/disk_io_thread.hpp" -#ifdef TORRENT_DISK_STATS - -#include "libtorrent/time.hpp" -#include - -namespace -{ - std::string log_time() - { - using namespace libtorrent; - static ptime start = time_now(); - return boost::lexical_cast( - total_milliseconds(time_now() - start)); - } -} - -#endif - namespace libtorrent { @@ -63,12 +45,7 @@ namespace libtorrent , m_block_size(block_size) #endif , m_disk_io_thread(boost::ref(*this)) - { - -#ifdef TORRENT_DISK_STATS - m_log.open("disk_io_thread.log", std::ios::trunc); -#endif - } + {} disk_io_thread::~disk_io_thread() { @@ -112,15 +89,8 @@ namespace libtorrent namespace { - // The semantic of this operator is: - // shouls lhs come before rhs in the job queue bool operator<(disk_io_job const& lhs, disk_io_job const& rhs) { - // NOTE: comparison inverted to make higher priority - // skip _in_front_of_ lower priority - if (lhs.priority > rhs.priority) return true; - if (lhs.priority < rhs.priority) return false; - if (lhs.storage.get() < rhs.storage.get()) return true; if (lhs.storage.get() > rhs.storage.get()) return false; if (lhs.piece < rhs.piece) return true; @@ -195,9 +165,6 @@ namespace libtorrent { for (;;) { -#ifdef TORRENT_DISK_STATS - m_log << log_time() << " idle" << std::endl; -#endif boost::mutex::scoped_lock l(m_mutex); while (m_jobs.empty() && !m_abort) m_signal.wait(l); @@ -212,46 +179,31 @@ namespace libtorrent int ret = 0; - bool free_buffer = true; try { -#ifdef TORRENT_DISK_STATS - ptime start = time_now(); -#endif // std::cerr << "DISK THREAD: executing job: " << j.action << std::endl; switch (j.action) { case disk_io_job::read: -#ifdef TORRENT_DISK_STATS - m_log << log_time() << " read " << j.buffer_size << std::endl; -#endif + l.lock(); + j.buffer = (char*)m_pool.ordered_malloc(); + l.unlock(); if (j.buffer == 0) { - l.lock(); - j.buffer = (char*)m_pool.ordered_malloc(); - l.unlock(); - assert(j.buffer_size <= m_block_size); - if (j.buffer == 0) - { - ret = -1; - j.str = "out of memory"; - break; - } + ret = -1; + j.str = "out of memory"; } else { - free_buffer = false; - } - ret = j.storage->read_impl(j.buffer, j.piece, j.offset - , j.buffer_size); + assert(j.buffer_size <= m_block_size); + ret = j.storage->read_impl(j.buffer, j.piece, j.offset + , j.buffer_size); - // simulates slow drives - // usleep(300); + // simulates slow drives + // usleep(300); + } break; case disk_io_job::write: -#ifdef TORRENT_DISK_STATS - m_log << log_time() << " write " << j.buffer_size << std::endl; -#endif assert(j.buffer); assert(j.buffer_size <= m_block_size); j.storage->write_impl(j.buffer, j.piece, j.offset @@ -262,25 +214,16 @@ namespace libtorrent break; case disk_io_job::hash: { -#ifdef TORRENT_DISK_STATS - m_log << log_time() << " hash" << std::endl; -#endif sha1_hash h = j.storage->hash_for_piece_impl(j.piece); j.str.resize(20); std::memcpy(&j.str[0], &h[0], 20); } break; case disk_io_job::move_storage: -#ifdef TORRENT_DISK_STATS - m_log << log_time() << " move" << std::endl; -#endif ret = j.storage->move_storage_impl(j.str) ? 1 : 0; j.str = j.storage->save_path().string(); break; case disk_io_job::release_files: -#ifdef TORRENT_DISK_STATS - m_log << log_time() << " release" << std::endl; -#endif j.storage->release_files_impl(); break; } @@ -297,7 +240,7 @@ namespace libtorrent try { if (handler) handler(ret, j); } catch (std::exception&) {} - if (j.buffer && free_buffer) + if (j.buffer) { l.lock(); m_pool.ordered_free(j.buffer); diff --git a/libtorrent/src/enum_net.cpp b/libtorrent/src/enum_net.cpp index 172719793..e69de29bb 100644 --- a/libtorrent/src/enum_net.cpp +++ b/libtorrent/src/enum_net.cpp @@ -1,142 +0,0 @@ -/* - -Copyright (c) 2007, 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. - -*/ - -#if defined __linux__ || defined __MACH__ -#include -#include -#include -#endif - -#include "libtorrent/enum_net.hpp" - -namespace libtorrent -{ - std::vector
const& enum_net_interfaces(asio::io_service& ios, asio::error_code& ec) - { - static std::vector
ret; - if (!ret.empty()) return ret; - -#if defined __linux__ || defined __MACH__ || defined(__FreeBSD__) - int s = socket(AF_INET, SOCK_DGRAM, 0); - if (s < 0) - { - ec = asio::error::fault; - return ret; - } - ifconf ifc; - char buf[1024]; - ifc.ifc_len = sizeof(buf); - ifc.ifc_buf = buf; - if (ioctl(s, SIOCGIFCONF, &ifc) < 0) - { - close(s); - ec = asio::error::fault; - return ret; - } - close(s); - - char *ifr = (char*)ifc.ifc_req; - int remaining = ifc.ifc_len; - - while (remaining) - { - ifreq const& item = *reinterpret_cast(ifr); - if (item.ifr_addr.sa_family == AF_INET) - { - typedef asio::ip::address_v4::bytes_type bytes_t; - bytes_t b; - memcpy(&b[0], &((sockaddr_in const*)&item.ifr_addr)->sin_addr, b.size()); - ret.push_back(address_v4(b)); - } - else if (item.ifr_addr.sa_family == AF_INET6) - { - typedef asio::ip::address_v6::bytes_type bytes_t; - bytes_t b; - memcpy(&b[0], &((sockaddr_in6 const*)&item.ifr_addr)->sin6_addr, b.size()); - ret.push_back(address_v6(b)); - } - -#if defined __MACH__ || defined(__FreeBSD__) - int current_size = item.ifr_addr.sa_len + IFNAMSIZ; -#elif defined __linux__ - int current_size = sizeof(ifreq); -#endif - ifr += current_size; - remaining -= current_size; - } - -#elif defined WIN32 - - SOCKET s = socket(AF_INET, SOCK_DGRAM, 0); - if (s == SOCKET_ERROR) - { - ec = asio::error::fault; - return ret; - } - - INTERFACE_INFO buffer[30]; - DWORD size; - - if (WSAIoctl(s, SIO_GET_INTERFACE_LIST, 0, 0, buffer, - sizeof(buffer), &size, 0, 0) != 0) - { - closesocket(s); - ec = asio::error::fault; - return ret; - } - closesocket(s); - - int n = size / sizeof(INTERFACE_INFO); - - for (int i = 0; i < n; ++i) - { - sockaddr_in *sockaddr = (sockaddr_in*)&buffer[i].iiAddress; - address a(address::from_string(inet_ntoa(sockaddr->sin_addr))); - if (a == address_v4::any()) continue; - ret.push_back(a); - } - -#else - // make a best guess of the interface we're using and its IP - udp::resolver r(ios); - udp::resolver::iterator i = r.resolve(udp::resolver::query(asio::ip::host_name(), "0")); - for (;i != udp::resolver_iterator(); ++i) - { - ret.push_back(i->endpoint().address()); - } -#endif - return ret; - } - -} - - diff --git a/libtorrent/src/escape_string.cpp b/libtorrent/src/escape_string.cpp index faff3de95..02a4fa085 100755 --- a/libtorrent/src/escape_string.cpp +++ b/libtorrent/src/escape_string.cpp @@ -33,14 +33,13 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/pch.hpp" #include +#include #include #include #include #include #include -#include "libtorrent/assert.hpp" - namespace libtorrent { std::string unescape_string(std::string const& s) diff --git a/libtorrent/src/file.cpp b/libtorrent/src/file.cpp index 72876d528..3d568d1f7 100755 --- a/libtorrent/src/file.cpp +++ b/libtorrent/src/file.cpp @@ -247,16 +247,19 @@ namespace libtorrent void set_size(size_type s) { -#ifdef _WIN32 -#error file.cpp is for posix systems only. use file_win.cpp on windows -#else - if (ftruncate(m_fd, s) < 0) + size_type pos = tell(); + // Only set size if current file size not equals s. + // 2 as "m" argument is to be sure seek() sets SEEK_END on + // all compilers. + if(s != seek(0, 2)) { - std::stringstream msg; - msg << "ftruncate failed: '" << strerror(errno); - throw file_error(msg.str()); + seek(s - 1); + char dummy = 0; + read(&dummy, 1); + seek(s - 1); + write(&dummy, 1); } -#endif + seek(pos); } size_type seek(size_type offset, int m = 1) diff --git a/libtorrent/src/http_connection.cpp b/libtorrent/src/http_connection.cpp index 2b306ca6d..53798cae1 100644 --- a/libtorrent/src/http_connection.cpp +++ b/libtorrent/src/http_connection.cpp @@ -42,8 +42,6 @@ using boost::bind; namespace libtorrent { - enum { max_bottled_buffer = 1024 * 1024 }; - void http_connection::get(std::string const& url, time_duration timeout , bool handle_redirect) { @@ -167,7 +165,6 @@ void http_connection::on_connect(asio::error_code const& e if (!e) { m_last_receive = time_now(); - if (m_connect_handler) m_connect_handler(*this); asio::async_write(m_sock, asio::buffer(sendbuffer) , bind(&http_connection::on_write, shared_from_this(), _1)); } @@ -313,8 +310,8 @@ void http_connection::on_read(asio::error_code const& e } if (int(m_recvbuffer.size()) == m_read_pos) - m_recvbuffer.resize((std::min)(m_read_pos + 2048, int(max_bottled_buffer))); - if (m_read_pos == max_bottled_buffer) + m_recvbuffer.resize((std::min)(m_read_pos + 2048, 1024*500)); + if (m_read_pos == 1024 * 500) { close(); if (m_bottled && m_called) return; diff --git a/libtorrent/src/http_tracker_connection.cpp b/libtorrent/src/http_tracker_connection.cpp index 0a0e59c48..936f8292a 100755 --- a/libtorrent/src/http_tracker_connection.cpp +++ b/libtorrent/src/http_tracker_connection.cpp @@ -148,19 +148,13 @@ namespace libtorrent pos = newline; line >> m_protocol; - if (m_protocol.substr(0, 5) == "HTTP/") + if (m_protocol.substr(0, 5) != "HTTP/") { - line >> m_status_code; - std::getline(line, m_server_message); - } - else - { - m_method = m_protocol; - std::transform(m_method.begin(), m_method.end(), m_method.begin(), &to_lower); - m_protocol.clear(); - line >> m_path >> m_protocol; - m_status_code = 0; + throw std::runtime_error("unknown protocol in HTTP response: " + + m_protocol + " line: " + std::string(pos, newline)); } + line >> m_status_code; + std::getline(line, m_server_message); m_state = read_header; } @@ -256,7 +250,7 @@ namespace libtorrent assert(m_state == read_body); if (m_content_length >= 0) return buffer::const_interval(m_recv_buffer.begin + m_body_start_pos - , m_recv_buffer.begin + (std::min)(m_recv_pos + , m_recv_buffer.begin + std::min(m_recv_pos , m_body_start_pos + m_content_length)); else return buffer::const_interval(m_recv_buffer.begin + m_body_start_pos @@ -414,7 +408,7 @@ namespace libtorrent { m_send_buffer += "numwant="; m_send_buffer += boost::lexical_cast( - (std::min)(req.num_want, 999)); + std::min(req.num_want, 999)); m_send_buffer += '&'; } if (m_settings.announce_ip != address() && !url_has_argument(request, "ip")) @@ -465,16 +459,14 @@ namespace libtorrent m_send_buffer += "\r\n\r\n"; #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - - boost::shared_ptr cb = requester(); - if (cb) + if (has_requester()) { - cb->debug_log("==> TRACKER_REQUEST [ str: " + m_send_buffer + " ]"); + requester().debug_log("==> TRACKER_REQUEST [ str: " + m_send_buffer + " ]"); std::stringstream info_hash_str; info_hash_str << req.info_hash; - cb->debug_log("info_hash: " + requester().debug_log("info_hash: " + boost::lexical_cast(req.info_hash)); - cb->debug_log("name lookup: " + hostname); + requester().debug_log("name lookup: " + hostname); } #endif @@ -499,9 +491,8 @@ namespace libtorrent void http_tracker_connection::name_lookup(asio::error_code const& error , tcp::resolver::iterator i) try { - boost::shared_ptr cb = requester(); #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (cb) cb->debug_log("tracker name lookup handler called"); + if (has_requester()) requester().debug_log("tracker name lookup handler called"); #endif if (error == asio::error::operation_aborted) return; if (m_timed_out) return; @@ -513,7 +504,7 @@ namespace libtorrent } #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (cb) cb->debug_log("tracker name lookup successful"); + if (has_requester()) requester().debug_log("tracker name lookup successful"); #endif restart_read_timeout(); @@ -528,11 +519,11 @@ namespace libtorrent if (target == end) { assert(target_address.address().is_v4() != bind_interface().is_v4()); - if (cb) + if (has_requester()) { std::string tracker_address_type = target_address.address().is_v4() ? "IPv4" : "IPv6"; std::string bind_address_type = bind_interface().is_v4() ? "IPv4" : "IPv6"; - cb->tracker_warning("the tracker only resolves to an " + requester().tracker_warning("the tracker only resolves to an " + tracker_address_type + " address, and you're listening on an " + bind_address_type + " socket. This may prevent you from receiving incoming connections."); } @@ -542,7 +533,7 @@ namespace libtorrent target_address = *target; } - if (cb) cb->m_tracker_address = target_address; + if (has_requester()) requester().m_tracker_address = target_address; m_socket = instantiate_connection(m_name_lookup.io_service(), m_proxy); if (m_proxy.type == proxy_settings::http @@ -583,8 +574,7 @@ namespace libtorrent } #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - boost::shared_ptr cb = requester(); - if (cb) cb->debug_log("tracker connection successful"); + if (has_requester()) requester().debug_log("tracker connection successful"); #endif restart_read_timeout(); @@ -608,8 +598,7 @@ namespace libtorrent } #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - boost::shared_ptr cb = requester(); - if (cb) cb->debug_log("tracker send data completed"); + if (has_requester()) requester().debug_log("tracker send data completed"); #endif restart_read_timeout(); assert(m_buffer.size() - m_recv_pos > 0); @@ -645,8 +634,7 @@ namespace libtorrent restart_read_timeout(); assert(bytes_transferred > 0); #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - boost::shared_ptr cb = requester(); - if (cb) cb->debug_log("tracker connection reading " + if (has_requester()) requester().debug_log("tracker connection reading " + boost::lexical_cast(bytes_transferred)); #endif @@ -712,8 +700,6 @@ namespace libtorrent } std::string location = m_parser.header("location"); - - boost::shared_ptr cb = requester(); if (m_parser.status_code() >= 300 && m_parser.status_code() < 400) { @@ -734,9 +720,9 @@ namespace libtorrent } #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (cb) cb->debug_log("Redirecting to \"" + location + "\""); + if (has_requester()) requester().debug_log("Redirecting to \"" + location + "\""); #endif - if (cb) cb->tracker_warning("Redirecting to \"" + location + "\""); + if (has_requester()) requester().tracker_warning("Redirecting to \"" + location + "\""); tracker_request req = tracker_req(); req.url = location; @@ -759,18 +745,20 @@ namespace libtorrent std::string content_encoding = m_parser.header("content-encoding"); #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (cb) cb->debug_log("content-encoding: \"" + content_encoding + "\""); + if (has_requester()) requester().debug_log("content-encoding: \"" + content_encoding + "\""); #endif if (content_encoding == "gzip" || content_encoding == "x-gzip") { - if (!cb) + boost::shared_ptr r = m_requester.lock(); + + if (!r) { close(); return; } m_buffer.erase(m_buffer.begin(), m_buffer.begin() + m_parser.body_start()); - if (inflate_gzip(m_buffer, tracker_request(), cb.get(), + if (inflate_gzip(m_buffer, tracker_request(), r.get(), m_settings.tracker_maximum_response_length)) { close(); @@ -847,8 +835,7 @@ namespace libtorrent void http_tracker_connection::parse(entry const& e) { - boost::shared_ptr cb = requester(); - if (!cb) return; + if (!has_requester()) return; try { @@ -865,7 +852,8 @@ namespace libtorrent try { entry const& warning = e["warning message"]; - cb->tracker_warning(warning.string()); + if (has_requester()) + requester().tracker_warning(warning.string()); } catch(type_error const&) {} @@ -879,7 +867,7 @@ namespace libtorrent entry scrape_data = e["files"][ih]; int complete = scrape_data["complete"].integer(); int incomplete = scrape_data["incomplete"].integer(); - cb->tracker_response(tracker_request(), peer_list, 0, complete + requester().tracker_response(tracker_request(), peer_list, 0, complete , incomplete); return; } @@ -896,7 +884,12 @@ namespace libtorrent peer_entry p; p.pid.clear(); - p.ip = detail::read_v4_address(i).to_string(); + std::stringstream ip_str; + ip_str << (int)detail::read_uint8(i) << "."; + ip_str << (int)detail::read_uint8(i) << "."; + ip_str << (int)detail::read_uint8(i) << "."; + ip_str << (int)detail::read_uint8(i); + p.ip = ip_str.str(); p.port = detail::read_uint16(i); peer_list.push_back(p); } @@ -911,22 +904,6 @@ namespace libtorrent } } - if (entry const* ipv6_peers = e.find_key("peers6")) - { - std::string const& peers = ipv6_peers->string(); - for (std::string::const_iterator i = peers.begin(); - i != peers.end();) - { - if (std::distance(i, peers.end()) < 18) break; - - peer_entry p; - p.pid.clear(); - p.ip = detail::read_v6_address(i).to_string(); - p.port = detail::read_uint16(i); - peer_list.push_back(p); - } - } - // look for optional scrape info int complete = -1; int incomplete = -1; @@ -937,16 +914,16 @@ namespace libtorrent try { incomplete = e["incomplete"].integer(); } catch(type_error&) {} - cb->tracker_response(tracker_request(), peer_list, interval, complete + requester().tracker_response(tracker_request(), peer_list, interval, complete , incomplete); } catch(type_error& e) { - cb->tracker_request_error(tracker_request(), m_parser.status_code(), e.what()); + requester().tracker_request_error(tracker_request(), m_parser.status_code(), e.what()); } catch(std::runtime_error& e) { - cb->tracker_request_error(tracker_request(), m_parser.status_code(), e.what()); + requester().tracker_request_error(tracker_request(), m_parser.status_code(), e.what()); } } diff --git a/libtorrent/src/identify_client.cpp b/libtorrent/src/identify_client.cpp index 7fa808f20..26ddb51dc 100755 --- a/libtorrent/src/identify_client.cpp +++ b/libtorrent/src/identify_client.cpp @@ -184,7 +184,6 @@ namespace , {"SB", "Swiftbit"} , {"SN", "ShareNet"} , {"SS", "SwarmScope"} - , {"ST", "SymTorrent"} , {"SZ", "Shareaza"} , {"S~", "Shareaza (beta)"} , {"T", "BitTornado"} @@ -195,57 +194,12 @@ namespace , {"U", "UPnP"} , {"UL", "uLeecher"} , {"UT", "uTorrent"} - , {"XL", "Xunlei"} , {"XT", "XanTorrent"} , {"XX", "Xtorrent"} , {"ZT", "ZipTorrent"} , {"lt", "rTorrent"} , {"pX", "pHoeniX"} , {"qB", "qBittorrent"} - , {"st", "SharkTorrent"} - }; - - struct generic_map_entry - { - int offset; - char const* id; - char const* name; - }; - // non-standard names - generic_map_entry generic_mappings[] = - { - {0, "Deadman Walking-", "Deadman"} - , {5, "Azureus", "Azureus 2.0.3.2"} - , {0, "DansClient", "XanTorrent"} - , {4, "btfans", "SimpleBT"} - , {0, "PRC.P---", "Bittorrent Plus! II"} - , {0, "P87.P---", "Bittorrent Plus!"} - , {0, "S587Plus", "Bittorrent Plus!"} - , {0, "martini", "Martini Man"} - , {0, "Plus---", "Bittorrent Plus"} - , {0, "turbobt", "TurboBT"} - , {0, "a00---0", "Swarmy"} - , {0, "a02---0", "Swarmy"} - , {0, "T00---0", "Teeweety"} - , {0, "BTDWV-", "Deadman Walking"} - , {2, "BS", "BitSpirit"} - , {0, "Pando-", "Pando"} - , {0, "LIME", "LimeWire"} - , {0, "btuga", "BTugaXP"} - , {0, "oernu", "BTugaXP"} - , {0, "Mbrst", "Burst!"} - , {0, "PEERAPP", "PeerApp"} - , {0, "Plus", "Plus!"} - , {0, "-Qt-", "Qt"} - , {0, "exbc", "BitComet"} - , {0, "DNA", "BitTorrent DNA"} - , {0, "-G3", "G3 Torrent"} - , {0, "-FG", "FlashGet"} - , {0, "-ML", "MLdonkey"} - , {0, "XBT", "XBT"} - , {0, "OP", "Opera"} - , {2, "RS", "Rufus"} - , {0, "AZ2500BT", "BitTyrant"} }; bool compare_id(map_entry const& lhs, map_entry const& rhs) @@ -327,13 +281,30 @@ namespace libtorrent // non standard encodings // ---------------------- - int num_generic_mappings = sizeof(generic_mappings) / sizeof(generic_mappings[0]); - - for (int i = 0; i < num_generic_mappings; ++i) - { - generic_map_entry const& e = generic_mappings[i]; - if (find_string(PID + e.offset, e.id)) return e.name; - } + if (find_string(PID, "Deadman Walking-")) return "Deadman"; + if (find_string(PID + 5, "Azureus")) return "Azureus 2.0.3.2"; + if (find_string(PID, "DansClient")) return "XanTorrent"; + if (find_string(PID + 4, "btfans")) return "SimpleBT"; + if (find_string(PID, "PRC.P---")) return "Bittorrent Plus! II"; + if (find_string(PID, "P87.P---")) return "Bittorrent Plus!"; + if (find_string(PID, "S587Plus")) return "Bittorrent Plus!"; + if (find_string(PID, "martini")) return "Martini Man"; + if (find_string(PID, "Plus---")) return "Bittorrent Plus"; + if (find_string(PID, "turbobt")) return "TurboBT"; + if (find_string(PID, "a00---0")) return "Swarmy"; + if (find_string(PID, "a02---0")) return "Swarmy"; + if (find_string(PID, "T00---0")) return "Teeweety"; + if (find_string(PID, "BTDWV-")) return "Deadman Walking"; + if (find_string(PID + 2, "BS")) return "BitSpirit"; + if (find_string(PID, "btuga")) return "BTugaXP"; + if (find_string(PID, "oernu")) return "BTugaXP"; + if (find_string(PID, "Mbrst")) return "Burst!"; + if (find_string(PID, "Plus")) return "Plus!"; + if (find_string(PID, "-Qt-")) return "Qt"; + if (find_string(PID, "exbc")) return "BitComet"; + if (find_string(PID, "-G3")) return "G3 Torrent"; + if (find_string(PID, "XBT")) return "XBT"; + if (find_string(PID, "OP")) return "Opera"; if (find_string(PID, "-BOW") && PID[7] == '-') return "Bits on Wheels " + std::string(PID + 4, PID + 7); diff --git a/libtorrent/src/kademlia/closest_nodes.cpp b/libtorrent/src/kademlia/closest_nodes.cpp index a3849ed69..0c7d9d276 100644 --- a/libtorrent/src/kademlia/closest_nodes.cpp +++ b/libtorrent/src/kademlia/closest_nodes.cpp @@ -35,7 +35,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include "libtorrent/assert.hpp" namespace libtorrent { namespace dht { diff --git a/libtorrent/src/kademlia/dht_tracker.cpp b/libtorrent/src/kademlia/dht_tracker.cpp index c9908a163..eda6cd864 100644 --- a/libtorrent/src/kademlia/dht_tracker.cpp +++ b/libtorrent/src/kademlia/dht_tracker.cpp @@ -237,7 +237,6 @@ namespace libtorrent { namespace dht try { if (e) return; - if (!m_socket.is_open()) return; time_duration d = m_dht.connection_timeout(); m_connection_timer.expires_from_now(d); m_connection_timer.async_wait(m_strand.wrap(bind(&dht_tracker::connection_timeout, self(), _1))); @@ -255,7 +254,6 @@ namespace libtorrent { namespace dht try { if (e) return; - if (!m_socket.is_open()) return; time_duration d = m_dht.refresh_timeout(); m_refresh_timer.expires_from_now(d); m_refresh_timer.async_wait(m_strand.wrap( @@ -278,9 +276,8 @@ namespace libtorrent { namespace dht try { if (e) return; - if (!m_socket.is_open()) return; m_timer.expires_from_now(minutes(tick_period)); - m_timer.async_wait(m_strand.wrap(bind(&dht_tracker::tick, self(), _1))); + m_timer.async_wait(m_strand.wrap(bind(&dht_tracker::tick, this, _1))); ptime now = time_now(); if (now - m_last_new_key > minutes(key_refresh)) @@ -391,7 +388,6 @@ namespace libtorrent { namespace dht try { if (error == asio::error::operation_aborted) return; - if (!m_socket.is_open()) return; int current_buffer = m_buffer; m_buffer = (m_buffer + 1) & 1; @@ -720,7 +716,6 @@ namespace libtorrent { namespace dht , udp::resolver::iterator host) try { if (e || host == udp::resolver::iterator()) return; - if (!m_socket.is_open()) return; add_node(host->endpoint()); } catch (std::exception&) @@ -739,7 +734,6 @@ namespace libtorrent { namespace dht , udp::resolver::iterator host) try { if (e || host == udp::resolver::iterator()) return; - if (!m_socket.is_open()) return; m_dht.add_router_node(host->endpoint()); } catch (std::exception&) diff --git a/libtorrent/src/kademlia/node_id.cpp b/libtorrent/src/kademlia/node_id.cpp index ad06c515d..4ed413714 100644 --- a/libtorrent/src/kademlia/node_id.cpp +++ b/libtorrent/src/kademlia/node_id.cpp @@ -34,10 +34,10 @@ POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include #include "libtorrent/kademlia/node_id.hpp" -#include "libtorrent/assert.hpp" using boost::bind; diff --git a/libtorrent/src/lsd.cpp b/libtorrent/src/lsd.cpp index d7590ec47..76f25548d 100644 --- a/libtorrent/src/lsd.cpp +++ b/libtorrent/src/lsd.cpp @@ -35,7 +35,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/lsd.hpp" #include "libtorrent/io.hpp" #include "libtorrent/http_tracker_connection.hpp" - #include #include #include @@ -53,22 +52,76 @@ namespace libtorrent address_v4 guess_local_address(asio::io_service&); } +address_v4 lsd::lsd_multicast_address; +udp::endpoint lsd::lsd_multicast_endpoint; + lsd::lsd(io_service& ios, address const& listen_interface , peer_callback_t const& cb) : m_callback(cb) , m_retry_count(0) - , m_socket(ios, udp::endpoint(address_v4::from_string("239.192.152.143"), 6771) - , bind(&lsd::on_announce, this, _1, _2, _3)) + , m_socket(ios) , m_broadcast_timer(ios) , m_disabled(false) { + // Bittorrent Local discovery multicast address and port + lsd_multicast_address = address_v4::from_string("239.192.152.143"); + lsd_multicast_endpoint = udp::endpoint(lsd_multicast_address, 6771); + #if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) m_log.open("lsd.log", std::ios::in | std::ios::out | std::ios::trunc); #endif + assert(lsd_multicast_address.is_multicast()); + rebind(listen_interface); } lsd::~lsd() {} +void lsd::rebind(address const& listen_interface) +{ + address_v4 local_ip = address_v4::any(); + if (listen_interface.is_v4() && listen_interface != address_v4::any()) + { + local_ip = listen_interface.to_v4(); + } + + try + { + // the local interface hasn't changed + if (m_socket.is_open() + && m_socket.local_endpoint().address() == local_ip) + return; + + m_socket.close(); + + using namespace asio::ip::multicast; + + m_socket.open(udp::v4()); + m_socket.set_option(datagram_socket::reuse_address(true)); + m_socket.bind(udp::endpoint(local_ip, 6771)); + +#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) + m_log << "local ip: " << local_ip << std::endl; +#endif + + m_socket.set_option(join_group(lsd_multicast_address)); + m_socket.set_option(outbound_interface(local_ip)); + m_socket.set_option(enable_loopback(true)); + m_socket.set_option(hops(255)); + } + catch (std::exception& e) + { +#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) + m_log << "socket multicast error " << e.what() + << ". disabling local service discovery" << std::endl; +#endif + m_disabled = true; + return; + } + m_disabled = false; + + setup_receive(); +} + void lsd::announce(sha1_hash const& ih, int listen_port) { if (m_disabled) return; @@ -83,7 +136,8 @@ void lsd::announce(sha1_hash const& ih, int listen_port) m_retry_count = 0; asio::error_code ec; - m_socket.send(msg.c_str(), int(msg.size()), ec); + m_socket.send_to(asio::buffer(msg.c_str(), msg.size() - 1) + , lsd_multicast_endpoint, 0, ec); if (ec) { m_disabled = true; @@ -103,8 +157,8 @@ void lsd::resend_announce(asio::error_code const& e, std::string msg) try { if (e) return; - asio::error_code ec; - m_socket.send(msg.c_str(), int(msg.size()), ec); + m_socket.send_to(asio::buffer(msg, msg.size() - 1) + , lsd_multicast_endpoint); ++m_retry_count; if (m_retry_count >= 5) @@ -116,13 +170,14 @@ void lsd::resend_announce(asio::error_code const& e, std::string msg) try catch (std::exception&) {} -void lsd::on_announce(udp::endpoint const& from, char* buffer +void lsd::on_announce(asio::error_code const& e , std::size_t bytes_transferred) { using namespace libtorrent::detail; + if (e) return; - char* p = buffer; - char* end = buffer + bytes_transferred; + char* p = m_receive_buffer; + char* end = m_receive_buffer + bytes_transferred; char* line = std::find(p, end, '\n'); for (char* i = p; i < line; ++i) *i = std::tolower(*i); #if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) @@ -135,6 +190,7 @@ void lsd::on_announce(udp::endpoint const& from, char* buffer m_log << time_now_string() << " *** assumed 'bt-search', ignoring" << std::endl; #endif + setup_receive(); return; } p = line + 1; @@ -167,15 +223,25 @@ void lsd::on_announce(udp::endpoint const& from, char* buffer { #if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) m_log << time_now_string() - << " *** incoming local announce " << from.address() + << " *** incoming local announce " << m_remote.address() << ":" << port << " ih: " << ih << std::endl; #endif // we got an announce, pass it on through the callback - try { m_callback(tcp::endpoint(from.address(), port), ih); } + try { m_callback(tcp::endpoint(m_remote.address(), port), ih); } catch (std::exception&) {} } + setup_receive(); } +void lsd::setup_receive() try +{ + assert(m_socket.is_open()); + m_socket.async_receive_from(asio::buffer(m_receive_buffer + , sizeof(m_receive_buffer)), m_remote, bind(&lsd::on_announce, this, _1, _2)); +} +catch (std::exception&) +{} + void lsd::close() { m_socket.close(); diff --git a/libtorrent/src/metadata_transfer.cpp b/libtorrent/src/metadata_transfer.cpp index 0623b156f..97635cdb9 100644 --- a/libtorrent/src/metadata_transfer.cpp +++ b/libtorrent/src/metadata_transfer.cpp @@ -523,7 +523,7 @@ namespace libtorrent { namespace if (num_blocks < 1) num_blocks = 1; assert(num_blocks <= 128); - int min_element = (std::numeric_limits::max)(); + int min_element = std::numeric_limits::max(); int best_index = 0; for (int i = 0; i < 256 - num_blocks + 1; ++i) { @@ -556,7 +556,7 @@ namespace libtorrent { namespace namespace libtorrent { - boost::shared_ptr create_metadata_plugin(torrent* t, void*) + boost::shared_ptr create_metadata_plugin(torrent* t) { return boost::shared_ptr(new metadata_plugin(*t)); } diff --git a/libtorrent/src/natpmp.cpp b/libtorrent/src/natpmp.cpp index bdcabce9a..0a5932a56 100644 --- a/libtorrent/src/natpmp.cpp +++ b/libtorrent/src/natpmp.cpp @@ -32,13 +32,11 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/pch.hpp" +#include +#include #include #include -#include "libtorrent/natpmp.hpp" -#include "libtorrent/io.hpp" -#include "libtorrent/assert.hpp" - using boost::bind; using namespace libtorrent; diff --git a/libtorrent/src/pe_crypto.cpp b/libtorrent/src/pe_crypto.cpp index 981eca63d..e999473da 100644 --- a/libtorrent/src/pe_crypto.cpp +++ b/libtorrent/src/pe_crypto.cpp @@ -1,131 +1,132 @@ -/* - -Copyright (c) 2007, Un Shyam -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. - -*/ - -#ifndef TORRENT_DISABLE_ENCRYPTION - -#include - -#include -#include - -#include "libtorrent/pe_crypto.hpp" -#include "libtorrent/assert.hpp" - -namespace libtorrent { - - - // Set the prime P and the generator, generate local public key - DH_key_exchange::DH_key_exchange () - { - m_DH = DH_new (); - - m_DH->p = BN_bin2bn (m_dh_prime, sizeof(m_dh_prime), NULL); - m_DH->g = BN_bin2bn (m_dh_generator, sizeof(m_dh_generator), NULL); - m_DH->length = 160l; - - assert (sizeof(m_dh_prime) == DH_size(m_DH)); - - DH_generate_key (m_DH); // TODO Check != 0 - - assert (m_DH->pub_key); - - // DH can generate key sizes that are smaller than the size of - // P with exponentially decreasing probability, in which case - // the msb's of m_dh_local_key need to be zeroed - // appropriately. - int key_size = get_local_key_size(); - int len_dh = sizeof(m_dh_prime); // must equal DH_size(m_DH) - if (key_size != len_dh) - { - assert(key_size > 0 && key_size < len_dh); - - int pad_zero_size = len_dh - key_size; - std::fill(m_dh_local_key, m_dh_local_key + pad_zero_size, 0); - BN_bn2bin(m_DH->pub_key, (unsigned char*)m_dh_local_key + pad_zero_size); - } - else - BN_bn2bin(m_DH->pub_key, (unsigned char*)m_dh_local_key); // TODO Check return value - } - - DH_key_exchange::~DH_key_exchange () - { - assert (m_DH); - DH_free (m_DH); - } - - char const* DH_key_exchange::get_local_key () const - { - return m_dh_local_key; - } - - - // compute shared secret given remote public key - void DH_key_exchange::compute_secret (char const* remote_pubkey) - { - assert (remote_pubkey); - BIGNUM* bn_remote_pubkey = BN_bin2bn ((unsigned char*)remote_pubkey, 96, NULL); - char dh_secret[96]; - - int secret_size = DH_compute_key ( (unsigned char*)dh_secret, - bn_remote_pubkey, m_DH); // TODO Check for errors - - if (secret_size != 96) - { - assert(secret_size < 96 && secret_size > 0); - std::fill(m_dh_secret, m_dh_secret + 96 - secret_size, 0); - } - std::copy(dh_secret, dh_secret + secret_size, m_dh_secret + 96 - secret_size); - - BN_free (bn_remote_pubkey); - } - - char const* DH_key_exchange::get_secret () const - { - return m_dh_secret; - } - - const unsigned char DH_key_exchange::m_dh_prime[96] = { - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, - 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, - 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, - 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, - 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, - 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, - 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, - 0xA6, 0x3A, 0x36, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, 0x63 - }; - - const unsigned char DH_key_exchange::m_dh_generator[1] = { 2 }; - -} // namespace libtorrent - -#endif // #ifndef TORRENT_DISABLE_ENCRYPTION +/* + +Copyright (c) 2007, Un Shyam +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. + +*/ + +#ifndef TORRENT_DISABLE_ENCRYPTION + +#include +#include + +#include +#include + +#include "libtorrent/pe_crypto.hpp" + +namespace libtorrent { + + + // Set the prime P and the generator, generate local public key + DH_key_exchange::DH_key_exchange () + { + m_DH = DH_new (); + + m_DH->p = BN_bin2bn (m_dh_prime, sizeof(m_dh_prime), NULL); + m_DH->g = BN_bin2bn (m_dh_generator, sizeof(m_dh_generator), NULL); + m_DH->length = 160l; + + assert (sizeof(m_dh_prime) == DH_size(m_DH)); + + DH_generate_key (m_DH); // TODO Check != 0 + + assert (m_DH->pub_key); + + // DH can generate key sizes that are smaller than the size of + // P with exponentially decreasing probability, in which case + // the msb's of m_dh_local_key need to be zeroed + // appropriately. + int key_size = get_local_key_size(); + int len_dh = sizeof(m_dh_prime); // must equal DH_size(m_DH) + if (key_size != len_dh) + { + assert(key_size > 0 && key_size < len_dh); + + int pad_zero_size = len_dh - key_size; + std::fill(m_dh_local_key, m_dh_local_key + pad_zero_size, 0); + BN_bn2bin(m_DH->pub_key, (unsigned char*)m_dh_local_key + pad_zero_size); + } + else + BN_bn2bin(m_DH->pub_key, (unsigned char*)m_dh_local_key); // TODO Check return value + } + + DH_key_exchange::~DH_key_exchange () + { + assert (m_DH); + DH_free (m_DH); + } + + char const* DH_key_exchange::get_local_key () const + { + return m_dh_local_key; + } + + + // compute shared secret given remote public key + void DH_key_exchange::compute_secret (char const* remote_pubkey) + { + assert (remote_pubkey); + BIGNUM* bn_remote_pubkey = BN_bin2bn ((unsigned char*)remote_pubkey, 96, NULL); + char dh_secret[96]; + + int secret_size = DH_compute_key ( (unsigned char*)dh_secret, + bn_remote_pubkey, m_DH); // TODO Check for errors + + if (secret_size != 96) + { + assert(secret_size < 96 && secret_size > 0); + std::fill(m_dh_secret, m_dh_secret + 96 - secret_size, 0); + } + std::copy(dh_secret, dh_secret + secret_size, m_dh_secret + 96 - secret_size); + + BN_free (bn_remote_pubkey); + } + + char const* DH_key_exchange::get_secret () const + { + return m_dh_secret; + } + + const unsigned char DH_key_exchange::m_dh_prime[96] = { + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC9, 0x0F, 0xDA, 0xA2, + 0x21, 0x68, 0xC2, 0x34, 0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1, + 0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74, 0x02, 0x0B, 0xBE, 0xA6, + 0x3B, 0x13, 0x9B, 0x22, 0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD, + 0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B, 0x30, 0x2B, 0x0A, 0x6D, + 0xF2, 0x5F, 0x14, 0x37, 0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45, + 0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6, 0xF4, 0x4C, 0x42, 0xE9, + 0xA6, 0x3A, 0x36, 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x05, 0x63 + }; + + const unsigned char DH_key_exchange::m_dh_generator[1] = { 2 }; + +} // namespace libtorrent + +#endif // #ifndef TORRENT_DISABLE_ENCRYPTION + diff --git a/libtorrent/src/peer_connection.cpp b/libtorrent/src/peer_connection.cpp index 25bc0ba63..b73e32896 100755 --- a/libtorrent/src/peer_connection.cpp +++ b/libtorrent/src/peer_connection.cpp @@ -51,7 +51,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/aux_/session_impl.hpp" #include "libtorrent/policy.hpp" #include "libtorrent/socket_type.hpp" -#include "libtorrent/assert.hpp" using boost::bind; using boost::shared_ptr; @@ -77,8 +76,6 @@ namespace libtorrent , m_timeout(m_ses.settings().peer_timeout) , m_last_piece(time_now()) , m_last_request(time_now()) - , m_last_incoming_request(min_time()) - , m_last_unchoke(min_time()) , m_packet_size(0) , m_recv_pos(0) , m_current_send_buffer(0) @@ -96,7 +93,6 @@ namespace libtorrent , m_choked(true) , m_failed(false) , m_ignore_bandwidth_limits(false) - , m_have_all(false) , m_num_pieces(0) , m_desired_queue_size(2) , m_free_upload(0) @@ -112,8 +108,8 @@ namespace libtorrent , m_prefer_whole_pieces(false) , m_request_large_blocks(false) , m_non_prioritized(false) - , m_upload_limit(bandwidth_limit::inf) - , m_download_limit(bandwidth_limit::inf) + , m_upload_limit(resource_request::inf) + , m_download_limit(resource_request::inf) , m_peer_info(peerinfo) , m_speed(slow) , m_connection_ticket(-1) @@ -157,8 +153,6 @@ namespace libtorrent , m_timeout(m_ses.settings().peer_timeout) , m_last_piece(time_now()) , m_last_request(time_now()) - , m_last_incoming_request(min_time()) - , m_last_unchoke(min_time()) , m_packet_size(0) , m_recv_pos(0) , m_current_send_buffer(0) @@ -174,7 +168,6 @@ namespace libtorrent , m_choked(true) , m_failed(false) , m_ignore_bandwidth_limits(false) - , m_have_all(false) , m_num_pieces(0) , m_desired_queue_size(2) , m_free_upload(0) @@ -190,11 +183,10 @@ namespace libtorrent , m_prefer_whole_pieces(false) , m_request_large_blocks(false) , m_non_prioritized(false) - , m_upload_limit(bandwidth_limit::inf) - , m_download_limit(bandwidth_limit::inf) + , m_upload_limit(resource_request::inf) + , m_download_limit(resource_request::inf) , m_peer_info(peerinfo) , m_speed(slow) - , m_connection_ticket(-1) , m_remote_bytes_dled(0) , m_remote_dl_rate(0) , m_remote_dl_update(time_now()) @@ -259,67 +251,6 @@ namespace libtorrent } #endif - void peer_connection::send_allowed_set() - { - INVARIANT_CHECK; - - boost::shared_ptr t = m_torrent.lock(); - assert(t); - - int num_allowed_pieces = m_ses.settings().allowed_fast_set_size; - int num_pieces = t->torrent_file().num_pieces(); - - if (num_allowed_pieces >= num_pieces) - { - for (int i = 0; i < num_pieces; ++i) - { -#ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << time_now_string() - << " ==> ALLOWED_FAST [ " << i << " ]\n"; -#endif - write_allow_fast(i); - m_accept_fast.insert(i); - } - return; - } - - std::string x; - address const& addr = m_remote.address(); - if (addr.is_v4()) - { - address_v4::bytes_type bytes = addr.to_v4().to_bytes(); - x.assign((char*)&bytes[0], bytes.size()); - } - else - { - address_v6::bytes_type bytes = addr.to_v6().to_bytes(); - x.assign((char*)&bytes[0], bytes.size()); - } - x.append((char*)&t->torrent_file().info_hash()[0], 20); - - sha1_hash hash = hasher(&x[0], x.size()).final(); - for (;;) - { - char* p = (char*)&hash[0]; - for (int i = 0; i < 5; ++i) - { - int piece = detail::read_uint32(p) % num_pieces; - if (m_accept_fast.find(piece) == m_accept_fast.end()) - { -#ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << time_now_string() - << " ==> ALLOWED_FAST [ " << piece << " ]\n"; -#endif - write_allow_fast(piece); - m_accept_fast.insert(piece); - if (int(m_accept_fast.size()) >= num_allowed_pieces - || int(m_accept_fast.size()) == num_pieces) return; - } - } - hash = hasher((char*)&hash[0], 20).final(); - } - } - void peer_connection::init() { INVARIANT_CHECK; @@ -329,7 +260,7 @@ namespace libtorrent assert(t->valid_metadata()); assert(t->ready_for_connections()); - m_have_piece.resize(t->torrent_file().num_pieces(), m_have_all); + m_have_piece.resize(t->torrent_file().num_pieces(), false); // now that we have a piece_picker, // update it with this peers pieces @@ -343,7 +274,7 @@ namespace libtorrent // if this is a web seed. we don't have a peer_info struct if (m_peer_info) m_peer_info->seed = true; // if we're a seed too, disconnect - if (t->is_finished()) + if (t->is_seed()) { throw std::runtime_error("seed to seed connection redundant, disconnecting"); } @@ -400,12 +331,7 @@ namespace libtorrent { // dont announce during handshake if (in_handshake()) return; - - // remove suggested pieces that we have - std::vector::iterator i = std::find( - m_suggested_pieces.begin(), m_suggested_pieces.end(), index); - if (i != m_suggested_pieces.end()) m_suggested_pieces.erase(i); - + // optimization, don't send have messages // to peers that already have the piece if (!m_ses.settings().send_redundant_have @@ -452,6 +378,8 @@ namespace libtorrent void peer_connection::add_stat(size_type downloaded, size_type uploaded) { + INVARIANT_CHECK; + m_statistics.add_stat(downloaded, uploaded); } @@ -521,7 +449,6 @@ namespace libtorrent assert(t); assert(t->valid_metadata()); - torrent_info const& ti = t->torrent_file(); return p.piece >= 0 && p.piece < t->torrent_file().num_pieces() @@ -529,30 +456,35 @@ namespace libtorrent && p.start >= 0 && (p.length == t->block_size() || (p.length < t->block_size() - && p.piece == ti.num_pieces()-1 - && p.start + p.length == ti.piece_size(p.piece)) + && p.piece == t->torrent_file().num_pieces()-1 + && p.start + p.length == t->torrent_file().piece_size(p.piece)) || (m_request_large_blocks - && p.length <= ti.piece_length() * m_prefer_whole_pieces == 0 ? - 1 : m_prefer_whole_pieces)) - && p.piece * size_type(ti.piece_length()) + p.start + p.length - <= ti.total_size() + && p.length <= t->torrent_file().piece_size(p.piece))) + && p.start + p.length <= t->torrent_file().piece_size(p.piece) && (p.start % t->block_size() == 0); } - + + struct disconnect_torrent + { + disconnect_torrent(boost::weak_ptr& t): m_t(&t) {} + ~disconnect_torrent() { if (m_t) m_t->reset(); } + void cancel() { m_t = 0; } + private: + boost::weak_ptr* m_t; + }; + void peer_connection::attach_to_torrent(sha1_hash const& ih) { INVARIANT_CHECK; assert(!m_disconnecting); - assert(m_torrent.expired()); - boost::weak_ptr wpt = m_ses.find_torrent(ih); - boost::shared_ptr t = wpt.lock(); + m_torrent = m_ses.find_torrent(ih); + + boost::shared_ptr t = m_torrent.lock(); if (t && t->is_aborted()) { -#ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << " *** the torrent has been aborted\n"; -#endif + m_torrent.reset(); t.reset(); } @@ -560,18 +492,12 @@ namespace libtorrent { // we couldn't find the torrent! #ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << " *** couldn't find a torrent with the given info_hash: " << ih << "\n"; - (*m_logger) << " torrents:\n"; - session_impl::torrent_map const& torrents = m_ses.m_torrents; - for (session_impl::torrent_map::const_iterator i = torrents.begin() - , end(torrents.end()); i != end; ++i) - { - (*m_logger) << " " << i->second->torrent_file().info_hash() << "\n"; - } + (*m_logger) << " couldn't find a torrent with the given info_hash: " << ih << "\n"; #endif throw std::runtime_error("got info-hash that is not in our session"); } + disconnect_torrent disconnect(m_torrent); if (t->is_paused()) { // paused torrents will not accept @@ -582,27 +508,21 @@ namespace libtorrent throw std::runtime_error("connection rejected by paused torrent"); } - assert(m_torrent.expired()); // check to make sure we don't have another connection with the same // info_hash and peer_id. If we do. close this connection. t->attach_peer(this); - m_torrent = wpt; - - assert(!m_torrent.expired()); // if the torrent isn't ready to accept // connections yet, we'll have to wait with // our initialization if (t->ready_for_connections()) init(); - assert(!m_torrent.expired()); - // assume the other end has no pieces // if we don't have valid metadata yet, // leave the vector unallocated assert(m_num_pieces == 0); std::fill(m_have_piece.begin(), m_have_piece.end(), false); - assert(!m_torrent.expired()); + disconnect.cancel(); } // message handlers @@ -668,117 +588,6 @@ namespace libtorrent m_request_queue.clear(); } - bool match_request(peer_request const& r, piece_block const& b, int block_size) - { - if (b.piece_index != r.piece) return false; - if (b.block_index != r.start / block_size) return false; - if (r.start % block_size != 0) return false; - return true; - } - - // ----------------------------- - // -------- REJECT PIECE ------- - // ----------------------------- - - void peer_connection::incoming_reject_request(peer_request const& r) - { - INVARIANT_CHECK; - - boost::shared_ptr t = m_torrent.lock(); - assert(t); - -#ifndef TORRENT_DISABLE_EXTENSIONS - for (extension_list_t::iterator i = m_extensions.begin() - , end(m_extensions.end()); i != end; ++i) - { - if ((*i)->on_reject(r)) return; - } -#endif - - std::deque::iterator i = std::find_if( - m_download_queue.begin(), m_download_queue.end() - , bind(match_request, boost::cref(r), _1, t->block_size())); - -#ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << time_now_string() - << " <== REJECT_PIECE [ piece: " << r.piece << " | s: " << r.start << " | l: " << r.length << " ]\n"; -#endif - - piece_block b(-1, 0); - if (i != m_download_queue.end()) - { - b = *i; - m_download_queue.erase(i); - } - else - { - i = std::find_if(m_request_queue.begin(), m_request_queue.end() - , bind(match_request, boost::cref(r), _1, t->block_size())); - - if (i != m_request_queue.end()) - { - b = *i; - m_request_queue.erase(i); - } - } - - if (b.piece_index != -1 && !t->is_seed()) - { - piece_picker& p = t->picker(); - p.abort_download(b); - } -#ifdef TORRENT_VERBOSE_LOGGING - else - { - (*m_logger) << time_now_string() - << " *** PIECE NOT IN REQUEST QUEUE\n"; - } -#endif - if (m_request_queue.empty()) - { - if (m_download_queue.size() < 2) - { - request_a_block(*t, *this); - } - send_block_requests(); - } - } - - // ----------------------------- - // -------- REJECT PIECE ------- - // ----------------------------- - - void peer_connection::incoming_suggest(int index) - { - INVARIANT_CHECK; - -#ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << time_now_string() - << " <== SUGGEST_PIECE [ piece: " << index << " ]\n"; -#endif - boost::shared_ptr t = m_torrent.lock(); - if (!t) return; - -#ifndef TORRENT_DISABLE_EXTENSIONS - for (extension_list_t::iterator i = m_extensions.begin() - , end(m_extensions.end()); i != end; ++i) - { - if ((*i)->on_suggest(index)) return; - } -#endif - - if (t->have_piece(index)) return; - - if (m_suggested_pieces.size() > 9) - m_suggested_pieces.erase(m_suggested_pieces.begin()); - m_suggested_pieces.push_back(index); - -#ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << time_now_string() - << " ** SUGGEST_PIECE [ piece: " << index << " added to set: " << m_suggested_pieces.size() << " ]\n"; -#endif - } - // ----------------------------- // ---------- UNCHOKE ---------- // ----------------------------- @@ -933,7 +742,7 @@ namespace libtorrent { assert(m_peer_info); m_peer_info->seed = true; - if (t->is_finished()) + if (t->is_seed()) { throw protocol_error("seed to seed connection redundant, disconnecting"); } @@ -989,12 +798,11 @@ namespace libtorrent { m_have_piece = bitfield; m_num_pieces = std::count(bitfield.begin(), bitfield.end(), true); - if (m_peer_info) m_peer_info->seed = (m_num_pieces == int(bitfield.size())); + + if (m_peer_info) m_peer_info->seed = true; return; } - assert(t->valid_metadata()); - int num_pieces = std::count(bitfield.begin(), bitfield.end(), true); if (num_pieces == int(m_have_piece.size())) { @@ -1004,7 +812,7 @@ namespace libtorrent // if this is a web seed. we don't have a peer_info struct if (m_peer_info) m_peer_info->seed = true; // if we're a seed too, disconnect - if (t->is_finished()) + if (t->is_seed()) { throw protocol_error("seed to seed connection redundant, disconnecting"); } @@ -1098,7 +906,6 @@ namespace libtorrent "t: " << (int)t->torrent_file().piece_size(r.piece) << " | " "n: " << t->torrent_file().num_pieces() << " ]\n"; #endif - write_reject_request(r); return; } @@ -1118,7 +925,6 @@ namespace libtorrent "t: " << (int)t->torrent_file().piece_size(r.piece) << " | " "n: " << t->torrent_file().num_pieces() << " ]\n"; #endif - write_reject_request(r); return; } @@ -1141,20 +947,11 @@ namespace libtorrent #endif // if we have choked the client // ignore the request - if (m_choked && m_accept_fast.find(r.piece) == m_accept_fast.end()) - { - write_reject_request(r); -#ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << time_now_string() - << " *** REJECTING REQUEST [ peer choked and piece not in allowed fast set ]\n"; -#endif - } - else - { - m_requests.push_back(r); - m_last_incoming_request = time_now(); - fill_send_buffer(); - } + if (m_choked) + return; + + m_requests.push_back(r); + fill_send_buffer(); } else { @@ -1171,7 +968,6 @@ namespace libtorrent "block_limit: " << t->block_size() << " ]\n"; #endif - write_reject_request(r); ++m_num_invalid_requests; if (t->alerts().should_post(alert::debug)) @@ -1181,7 +977,7 @@ namespace libtorrent , t->get_handle() , m_remote , m_peer_id - , "peer sent an illegal piece request")); + , "peer sent an illegal piece request, ignoring")); } } } @@ -1335,8 +1131,11 @@ namespace libtorrent "request queue ***\n"; #endif t->received_redundant_data(p.length); - request_a_block(*t, *this); - send_block_requests(); + if (!has_peer_choked()) + { + request_a_block(*t, *this); + send_block_requests(); + } return; } @@ -1345,8 +1144,11 @@ namespace libtorrent { t->received_redundant_data(p.length); - request_a_block(*t, *this); - send_block_requests(); + if (!has_peer_choked()) + { + request_a_block(*t, *this); + send_block_requests(); + } return; } @@ -1403,11 +1205,15 @@ namespace libtorrent block_finished.block_index, block_finished.piece_index, "block finished")); } - if (!t->is_seed() && !m_torrent.expired()) + if (!has_peer_choked() && !t->is_seed() && !m_torrent.expired()) { // this is a free function defined in policy.cpp request_a_block(*t, *this); - send_block_requests(); + try + { + send_block_requests(); + } + catch (std::exception const&) {} } #ifndef NDEBUG @@ -1489,146 +1295,6 @@ namespace libtorrent #endif } - // ----------------------------- - // --------- HAVE ALL ---------- - // ----------------------------- - - void peer_connection::incoming_have_all() - { - INVARIANT_CHECK; - - boost::shared_ptr t = m_torrent.lock(); - assert(t); - -#ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << time_now_string() << " <== HAVE_ALL\n"; -#endif - -#ifndef TORRENT_DISABLE_EXTENSIONS - for (extension_list_t::iterator i = m_extensions.begin() - , end(m_extensions.end()); i != end; ++i) - { - if ((*i)->on_have_all()) return; - } -#endif - - m_have_all = true; - - if (m_peer_info) m_peer_info->seed = true; - - // if we don't have metadata yet - // just remember the bitmask - // don't update the piecepicker - // (since it doesn't exist yet) - if (!t->ready_for_connections()) - { - // TODO: this might need something more - // so that once we have the metadata - // we can construct a full bitfield - return; - } - -#ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << " *** THIS IS A SEED ***\n"; -#endif - - // if we're a seed too, disconnect - if (t->is_finished()) - throw protocol_error("seed to seed connection redundant, disconnecting"); - - assert(!m_have_piece.empty()); - std::fill(m_have_piece.begin(), m_have_piece.end(), true); - m_num_pieces = m_have_piece.size(); - - t->peer_has_all(); - if (!t->is_finished()) - t->get_policy().peer_is_interesting(*this); - } - - // ----------------------------- - // --------- HAVE NONE --------- - // ----------------------------- - - void peer_connection::incoming_have_none() - { - INVARIANT_CHECK; - - boost::shared_ptr t = m_torrent.lock(); - assert(t); - -#ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << time_now_string() << " <== HAVE_NONE\n"; -#endif - -#ifndef TORRENT_DISABLE_EXTENSIONS - for (extension_list_t::iterator i = m_extensions.begin() - , end(m_extensions.end()); i != end; ++i) - { - if ((*i)->on_have_none()) return; - } -#endif - - if (m_peer_info) m_peer_info->seed = false; - assert(!m_have_piece.empty() || !t->ready_for_connections()); - } - - // ----------------------------- - // ------- ALLOWED FAST -------- - // ----------------------------- - - void peer_connection::incoming_allowed_fast(int index) - { - INVARIANT_CHECK; - - boost::shared_ptr t = m_torrent.lock(); - assert(t); - -#ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << time_now_string() << " <== ALLOWED_FAST [ " << index << " ]\n"; -#endif - -#ifndef TORRENT_DISABLE_EXTENSIONS - for (extension_list_t::iterator i = m_extensions.begin() - , end(m_extensions.end()); i != end; ++i) - { - if ((*i)->on_allowed_fast(index)) return; - } -#endif - - // if we already have the piece, we can - // ignore this message - if (t->valid_metadata() - && t->have_piece(index)) - return; - - m_allowed_fast.push_back(index); - - // if the peer has the piece and we want - // to download it, request it - if (int(m_have_piece.size()) > index - && m_have_piece[index] - && t->has_picker() - && t->picker().piece_priority(index) > 0) - { - t->get_policy().peer_is_interesting(*this); - } - } - - std::vector const& peer_connection::allowed_fast() - { - INVARIANT_CHECK; - - boost::shared_ptr t = m_torrent.lock(); - assert(t); - - m_allowed_fast.erase(std::remove_if(m_allowed_fast.begin() - , m_allowed_fast.end(), bind(&torrent::have_piece, t, _1)) - , m_allowed_fast.end()); - - // TODO: sort the allowed fast set in priority order - return m_allowed_fast; - } - void peer_connection::add_request(piece_block const& block) { INVARIANT_CHECK; @@ -1642,11 +1308,10 @@ namespace libtorrent assert(block.block_index >= 0); assert(block.block_index < t->torrent_file().piece_size(block.piece_index)); assert(!t->picker().is_requested(block) || (t->picker().num_peers(block) > 0)); - assert(!t->have_piece(block.piece_index)); piece_picker::piece_state_t state; peer_speed_t speed = peer_speed(); - char const* speedmsg = 0; + std::string speedmsg; if (speed == fast) { speedmsg = "fast"; @@ -1663,10 +1328,8 @@ namespace libtorrent state = piece_picker::slow; } - if (!t->picker().mark_as_downloading(block, peer_info_struct(), state)) - return; - - if (t->alerts().should_post(alert::info)) + t->picker().mark_as_downloading(block, peer_info_struct(), state); + if (t->alerts().should_post(alert::info)) { t->alerts().post_alert(block_downloading_alert(t->get_handle(), speedmsg, block.block_index, block.piece_index, "block downloading")); @@ -1717,7 +1380,7 @@ namespace libtorrent int block_offset = block.block_index * t->block_size(); int block_size - = (std::min)((int)t->torrent_file().piece_size(block.piece_index)-block_offset, + = std::min((int)t->torrent_file().piece_size(block.piece_index)-block_offset, t->block_size()); assert(block_size > 0); assert(block_size <= t->block_size()); @@ -1740,8 +1403,6 @@ namespace libtorrent { INVARIANT_CHECK; - assert(!m_peer_info || !m_peer_info->optimistically_unchoked); - if (m_choked) return; write_choke(); m_choked = true; @@ -1760,8 +1421,15 @@ namespace libtorrent { INVARIANT_CHECK; +#ifndef NDEBUG + // TODO: once the policy lowers the interval for optimistic + // unchoke, increase this value that interval + // this condition cannot be guaranteed since if peers disconnect + // a new one will be unchoked ignoring when it was last choked + //assert(time_now() - m_last_choke > seconds(9)); +#endif + if (!m_choked) return; - m_last_unchoke = time_now(); write_unchoke(); m_choked = false; @@ -1802,9 +1470,13 @@ namespace libtorrent { INVARIANT_CHECK; + if (has_peer_choked()) return; + boost::shared_ptr t = m_torrent.lock(); assert(t); + assert(!has_peer_choked()); + if ((int)m_download_queue.size() >= m_desired_queue_size) return; while (!m_request_queue.empty() @@ -1813,7 +1485,7 @@ namespace libtorrent piece_block block = m_request_queue.front(); int block_offset = block.block_index * t->block_size(); - int block_size = (std::min)((int)t->torrent_file().piece_size( + int block_size = std::min((int)t->torrent_file().piece_size( block.piece_index) - block_offset, t->block_size()); assert(block_size > 0); assert(block_size <= t->block_size()); @@ -1837,29 +1509,23 @@ namespace libtorrent // blocks that are in the same piece into larger requests if (m_request_large_blocks) { - int blocks_per_piece = t->torrent_file().piece_length() / t->block_size(); - - while (!m_request_queue.empty()) + while (!m_request_queue.empty() + && m_request_queue.front().piece_index == r.piece + && m_request_queue.front().block_index == block.block_index + 1) { - // check to see if this block is connected to the previous one - // if it is, merge them, otherwise, break this merge loop - piece_block const& front = m_request_queue.front(); - if (front.piece_index * blocks_per_piece + front.block_index - != block.piece_index * blocks_per_piece + block.block_index + 1) - break; block = m_request_queue.front(); m_request_queue.pop_front(); m_download_queue.push_back(block); - +/* #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << time_now_string() - << " *** MERGING REQUEST ** [ " + << " *** REQUEST-QUEUE** [ " "piece: " << block.piece_index << " | " "block: " << block.block_index << " ]\n"; #endif - +*/ block_offset = block.block_index * t->block_size(); - block_size = (std::min)((int)t->torrent_file().piece_size( + block_size = std::min((int)t->torrent_file().piece_size( block.piece_index) - block_offset, t->block_size()); assert(block_size > 0); assert(block_size <= t->block_size()); @@ -1952,6 +1618,7 @@ namespace libtorrent } t->remove_peer(this); + m_torrent.reset(); } @@ -1961,7 +1628,7 @@ namespace libtorrent void peer_connection::set_upload_limit(int limit) { assert(limit >= -1); - if (limit == -1) limit = (std::numeric_limits::max)(); + if (limit == -1) limit = resource_request::inf; if (limit < 10) limit = 10; m_upload_limit = limit; m_bandwidth_limit[upload_channel].throttle(m_upload_limit); @@ -1970,7 +1637,7 @@ namespace libtorrent void peer_connection::set_download_limit(int limit) { assert(limit >= -1); - if (limit == -1) limit = (std::numeric_limits::max)(); + if (limit == -1) limit = resource_request::inf; if (limit < 10) limit = 10; m_download_limit = limit; m_bandwidth_limit[download_channel].throttle(m_download_limit); @@ -1988,7 +1655,7 @@ namespace libtorrent // if we have an infinite ratio, just say we have downloaded // much more than we have uploaded. And we'll keep uploading. if (ratio == 0.f) - return (std::numeric_limits::max)(); + return std::numeric_limits::max(); return m_free_upload + static_cast(m_statistics.total_payload_download() * ratio) @@ -2036,9 +1703,8 @@ namespace libtorrent p.load_balancing = total_free_upload(); - p.download_queue_length = int(download_queue().size() + m_request_queue.size()); - p.target_dl_queue_length = int(desired_queue_size()); - p.upload_queue_length = int(upload_queue().size()); + p.download_queue_length = (int)download_queue().size(); + p.upload_queue_length = (int)upload_queue().size(); if (boost::optional ret = downloading_piece_progress()) { @@ -2058,7 +1724,7 @@ namespace libtorrent p.pieces = get_bitfield(); ptime now = time_now(); p.last_request = now - m_last_request; - p.last_active = now - (std::max)(m_last_sent, m_last_receive); + p.last_active = now - std::max(m_last_sent, m_last_receive); // this will set the flags so that we can update them later p.flags = 0; @@ -2071,7 +1737,6 @@ namespace libtorrent p.failcount = peer_info_struct()->failcount; p.num_hashfails = peer_info_struct()->hashfails; p.flags |= peer_info_struct()->on_parole ? peer_info::on_parole : 0; - p.flags |= peer_info_struct()->optimistically_unchoked ? peer_info::optimistic_unchoke : 0; p.remote_dl_rate = m_remote_dl_rate; } else @@ -2107,13 +1772,10 @@ namespace libtorrent if (m_packet_size >= m_recv_pos) m_recv_buffer.resize(m_packet_size); } - void peer_connection::second_tick(float tick_interval) throw() + void peer_connection::second_tick(float tick_interval) { INVARIANT_CHECK; - try - { - ptime now(time_now()); boost::shared_ptr t = m_torrent.lock(); @@ -2192,8 +1854,11 @@ namespace libtorrent m_assume_fifo = true; - request_a_block(*t, *this); - send_block_requests(); + if (!has_peer_choked()) + { + request_a_block(*t, *this); + send_block_requests(); + } } } @@ -2204,7 +1869,7 @@ namespace libtorrent // maintain the share ratio given by m_ratio // with all peers. - if (t->is_finished() || is_choked() || t->ratio() == 0.0f) + if (t->is_seed() || is_choked() || t->ratio() == 0.0f) { // if we have downloaded more than one piece more // than we have uploaded OR if we are a seed @@ -2226,14 +1891,14 @@ namespace libtorrent if (t->ratio() != 1.f) soon_downloaded = (size_type)(soon_downloaded*(double)t->ratio()); - double upload_speed_limit = (std::min)((soon_downloaded - have_uploaded + double upload_speed_limit = std::min((soon_downloaded - have_uploaded + bias) / break_even_time, double(m_upload_limit)); - upload_speed_limit = (std::min)(upload_speed_limit, - (double)(std::numeric_limits::max)()); + upload_speed_limit = std::min(upload_speed_limit, + (double)std::numeric_limits::max()); m_bandwidth_limit[upload_channel].throttle( - (std::min)((std::max)((int)upload_speed_limit, 20) + std::min(std::max((int)upload_speed_limit, 20) , m_upload_limit)); } @@ -2252,14 +1917,43 @@ namespace libtorrent } fill_send_buffer(); - } - catch (std::exception& e) +/* + size_type diff = share_diff(); + + enum { block_limit = 2 }; // how many blocks difference is considered unfair + + // if the peer has been choked, send the current piece + // as fast as possible + if (diff > block_limit*m_torrent->block_size() || m_torrent->is_seed() || is_choked()) { -#ifdef TORRENT_VERBOSE_LOGGING - (*m_logger) << "**ERROR**: " << e.what() << "\n"; -#endif - m_ses.connection_failed(m_socket, remote(), e.what()); + // if we have downloaded more than one piece more + // than we have uploaded OR if we are a seed + // have an unlimited upload rate + m_ul_bandwidth_quota.wanted = std::numeric_limits::max(); } + else + { + float ratio = m_torrent->ratio(); + // if we have downloaded too much, response with an + // upload rate of 10 kB/s more than we dowlload + // if we have uploaded too much, send with a rate of + // 10 kB/s less than we receive + int bias = 0; + if (diff > -block_limit*m_torrent->block_size()) + { + bias = static_cast(m_statistics.download_rate() * ratio) / 2; + if (bias < 10*1024) bias = 10*1024; + } + else + { + bias = -static_cast(m_statistics.download_rate() * ratio) / 2; + } + m_ul_bandwidth_quota.wanted = static_cast(m_statistics.download_rate()) + bias; + + // the maximum send_quota given our download rate from this peer + if (m_ul_bandwidth_quota.wanted < 256) m_ul_bandwidth_quota.wanted = 256; + } +*/ } void peer_connection::fill_send_buffer() @@ -2294,6 +1988,20 @@ namespace libtorrent m_reading_bytes += r.length; m_requests.erase(m_requests.begin()); +/* + if (m_requests.empty() + && m_num_invalid_requests > 0 + && is_peer_interested() + && !is_seed()) + { + // this will make the peer clear + // its download queue and re-request + // pieces. Hopefully it will not + // send invalid requests then + send_choke(); + send_unchoke(); + } +*/ } } @@ -2834,14 +2542,9 @@ namespace libtorrent void peer_connection::check_invariant() const { if (m_peer_info) - { assert(m_peer_info->connection == this || m_peer_info->connection == 0); - - if (m_peer_info->optimistically_unchoked) - assert(!is_choked()); - } - + boost::shared_ptr t = m_torrent.lock(); if (!t) { @@ -2855,8 +2558,6 @@ namespace libtorrent return; } - assert(t->connection_for(remote()) != 0 || m_in_constructor); - if (!m_in_constructor && t->connection_for(remote()) != this && !m_ses.settings().allow_multiple_connections_per_ip) { @@ -2916,6 +2617,11 @@ namespace libtorrent // TODO: the timeout should be called by an event INVARIANT_CHECK; +#ifndef NDEBUG + // allow step debugging without timing out + return false; +#endif + ptime now(time_now()); // if the socket is still connecting, don't @@ -2926,24 +2632,9 @@ namespace libtorrent // if the peer hasn't said a thing for a certain // time, it is considered to have timed out time_duration d; - d = now - m_last_receive; + d = time_now() - m_last_receive; if (d > seconds(m_timeout)) return true; - // if it takes more than 5 seconds to receive - // handshake, disconnect - if (in_handshake() && d > seconds(5)) return true; - - // disconnect peers that we unchoked, but - // they didn't send a request within 20 seconds. - // but only if we're a seed - boost::shared_ptr t = m_torrent.lock(); - d = now - (std::max)(m_last_unchoke, m_last_incoming_request); - if (m_requests.empty() - && !m_choked - && m_peer_interested - && t && t->is_finished() - && d > seconds(20)) return true; - // TODO: as long as we have less than 95% of the // global (or local) connection limit, connections should // never time out for another reason diff --git a/libtorrent/src/piece_picker.cpp b/libtorrent/src/piece_picker.cpp index 398573d33..ddc2c2f5a 100755 --- a/libtorrent/src/piece_picker.cpp +++ b/libtorrent/src/piece_picker.cpp @@ -167,7 +167,6 @@ namespace libtorrent return; assert(sequenced_download_threshold > 0); - if (sequenced_download_threshold <= 0) return; int old_limit = m_sequenced_download_threshold; m_sequenced_download_threshold = sequenced_download_threshold; @@ -192,22 +191,22 @@ namespace libtorrent // the previous max availability was reached // we need to shuffle that bucket, if not, we // don't have to do anything - if (int(m_piece_info.size()) > old_limit * 2) + if (int(m_piece_info.size()) > old_limit) { - info_t& in = m_piece_info[old_limit * 2]; + info_t& in = m_piece_info[old_limit]; std::random_shuffle(in.begin(), in.end()); int c = 0; for (info_t::iterator i = in.begin() , end(in.end()); i != end; ++i) { m_piece_map[*i].index = c++; - assert(m_piece_map[*i].priority(old_limit) == old_limit * 2); + assert(m_piece_map[*i].priority(old_limit) == old_limit); } } } - else if (int(m_piece_info.size()) > sequenced_download_threshold * 2) + else if (int(m_piece_info.size()) > sequenced_download_threshold) { - info_t& in = m_piece_info[sequenced_download_threshold * 2]; + info_t& in = m_piece_info[sequenced_download_threshold]; std::sort(in.begin(), in.end()); int c = 0; for (info_t::iterator i = in.begin() @@ -215,7 +214,7 @@ namespace libtorrent { m_piece_map[*i].index = c++; assert(m_piece_map[*i].priority( - sequenced_download_threshold) == sequenced_download_threshold * 2); + sequenced_download_threshold) == sequenced_download_threshold); } } } @@ -263,23 +262,8 @@ namespace libtorrent } m_downloads.erase(i); } - #ifndef NDEBUG - void piece_picker::verify_pick(std::vector const& picked - , std::vector const& bitfield) const - { - assert(bitfield.size() == m_piece_map.size()); - for (std::vector::const_iterator i = picked.begin() - , end(picked.end()); i != end; ++i) - { - assert(i->piece_index >= 0); - assert(i->piece_index < int(bitfield.size())); - assert(bitfield[i->piece_index]); - assert(!m_piece_map[i->piece_index].have()); - } - } - void piece_picker::check_invariant(const torrent* t) const { assert(sizeof(piece_pos) == 4); @@ -410,7 +394,6 @@ namespace libtorrent assert(!t->have_piece(index)); int prio = i->priority(m_sequenced_download_threshold); - assert(prio < int(m_piece_info.size())); if (prio > 0) { const std::vector& vec = m_piece_info[prio]; @@ -464,7 +447,7 @@ namespace libtorrent if (i->have()) ++peer_count; if (min_availability > peer_count) { - min_availability = peer_count; + min_availability = i->peer_count; fraction_part += integer_part; integer_part = 1; } @@ -655,13 +638,12 @@ namespace libtorrent if (dp == m_downloads.begin()) return; int complete = dp->writing + dp->finished; for (std::vector::iterator i = dp, j(dp-1); - i != m_downloads.begin(); --i, --j) + i != m_downloads.begin() && j != m_downloads.begin(); --i, --j) { assert(j >= m_downloads.begin()); if (j->finished + j->writing >= complete) return; using std::swap; swap(*j, *i); - if (j == m_downloads.begin()) break; } } @@ -757,7 +739,6 @@ namespace libtorrent , end(m_piece_map.end()); i != end; ++i) { int prev_prio = i->priority(m_sequenced_download_threshold); - assert(prev_prio < int(m_piece_info.size())); ++i->peer_count; // if the assumption that the priority would // increase by 2 when increasing the availability @@ -847,8 +828,6 @@ namespace libtorrent , end(m_piece_map.end()); i != end; ++i) { int prev_prio = i->priority(m_sequenced_download_threshold); - assert(prev_prio < int(m_piece_info.size())); - assert(pushed_out_index < int(m_piece_info.size())); assert(i->peer_count > 0); --i->peer_count; // if the assumption that the priority would @@ -900,7 +879,6 @@ namespace libtorrent piece_pos& p = m_piece_map[i]; int index = p.index; int prev_priority = p.priority(m_sequenced_download_threshold); - assert(prev_priority < int(m_piece_info.size())); assert(p.peer_count < piece_pos::max_peer_count); p.peer_count++; @@ -935,7 +913,6 @@ namespace libtorrent piece_pos& p = m_piece_map[i]; int prev_priority = p.priority(m_sequenced_download_threshold); - assert(prev_priority < int(m_piece_info.size())); int index = p.index; assert(p.peer_count > 0); @@ -960,7 +937,6 @@ namespace libtorrent piece_pos& p = m_piece_map[index]; int info_index = p.index; int priority = p.priority(m_sequenced_download_threshold); - assert(priority < int(m_piece_info.size())); assert(p.downloading == 1); assert(!p.have()); @@ -1004,7 +980,6 @@ namespace libtorrent if (new_piece_priority == int(p.piece_priority)) return false; int prev_priority = p.priority(m_sequenced_download_threshold); - assert(prev_priority < int(m_piece_info.size())); bool ret = false; if (new_piece_priority == piece_pos::filter_priority @@ -1028,7 +1003,6 @@ namespace libtorrent p.piece_priority = new_piece_priority; int new_priority = p.priority(m_sequenced_download_threshold); - assert(prev_priority < int(m_piece_info.size())); if (new_priority == prev_priority) return false; @@ -1094,9 +1068,8 @@ namespace libtorrent // or slow once they're started. void piece_picker::pick_pieces(const std::vector& pieces , std::vector& interesting_blocks - , int num_blocks, int prefer_whole_pieces - , void* peer, piece_state_t speed, bool rarest_first - , bool on_parole, std::vector const& suggested_pieces) const + , int num_blocks, bool prefer_whole_pieces + , void* peer, piece_state_t speed, bool rarest_first) const { TORRENT_PIECE_PICKER_INVARIANT_CHECK; assert(num_blocks > 0); @@ -1112,84 +1085,59 @@ namespace libtorrent // blocks belonging to a piece that others have // downloaded to std::vector backup_blocks; - // suggested pieces for each vector is put in this vector - std::vector suggested_bucket; - const std::vector empty_vector; // When prefer_whole_pieces is set (usually set when downloading from // fast peers) the partial pieces will not be prioritized, but actually // ignored as long as possible. All blocks found in downloading // pieces are regarded as backup blocks - - num_blocks = add_blocks_downloading(pieces - , interesting_blocks, backup_blocks, num_blocks - , prefer_whole_pieces, peer, speed, on_parole); - - if (num_blocks <= 0) return; - - if (rarest_first) + bool ignore_downloading_pieces = false; + if (prefer_whole_pieces) { - // this loop will loop from pieces with priority 1 and up - // until we either reach the end of the piece list or - // has filled the interesting_blocks with num_blocks - // blocks. - - // +1 is to ignore pieces that no peer has. The bucket with index 0 contains - // pieces that 0 other peers have. bucket will point to a bucket with - // pieces with the same priority. It will be iterated in priority - // order (high priority/rare pices first). The content of each - // bucket is randomized - for (std::vector >::const_iterator bucket - = m_piece_info.begin() + 1; num_blocks > 0 && bucket != m_piece_info.end(); - ++bucket) + std::vector downloading_pieces; + downloading_pieces.reserve(m_downloads.size()); + for (std::vector::const_iterator i = m_downloads.begin() + , end(m_downloads.end()); i != end; ++i) { - if (bucket->empty()) continue; - if (!suggested_pieces.empty()) - { - int bucket_index = bucket - m_piece_info.begin(); - suggested_bucket.clear(); - for (std::vector::const_iterator i = suggested_pieces.begin() - , end(suggested_pieces.end()); i != end; ++i) - { - assert(*i >= 0); - assert(*i < int(m_piece_map.size())); - if (!can_pick(*i, pieces)) continue; - if (m_piece_map[*i].priority(m_sequenced_download_threshold) == bucket_index) - suggested_bucket.push_back(*i); - } - if (!suggested_bucket.empty()) - { - num_blocks = add_blocks(suggested_bucket, pieces - , interesting_blocks, num_blocks - , prefer_whole_pieces, peer, empty_vector); - if (num_blocks == 0) break; - } - } - num_blocks = add_blocks(*bucket, pieces - , interesting_blocks, num_blocks - , prefer_whole_pieces, peer, suggested_bucket); - assert(num_blocks >= 0); + downloading_pieces.push_back(i->index); } + add_interesting_blocks(downloading_pieces, pieces + , backup_blocks, backup_blocks, num_blocks + , prefer_whole_pieces, peer, speed, ignore_downloading_pieces); + ignore_downloading_pieces = true; } - else + + // this loop will loop from pieces with priority 1 and up + // until we either reach the end of the piece list or + // has filled the interesting_blocks with num_blocks + // blocks. + + // +1 is to ignore pieces that no peer has. The bucket with index 0 contains + // pieces that 0 other peers have. bucket will point to a bucket with + // pieces with the same priority. It will be iterated in priority + // order (high priority/rare pices first). The content of each + // bucket is randomized + for (std::vector >::const_iterator bucket + = m_piece_info.begin() + 1; bucket != m_piece_info.end(); + ++bucket) { + if (bucket->empty()) continue; + num_blocks = add_interesting_blocks(*bucket, pieces + , interesting_blocks, backup_blocks, num_blocks + , prefer_whole_pieces, peer, speed, ignore_downloading_pieces); + assert(num_blocks >= 0); + if (num_blocks == 0) return; + if (rarest_first) continue; + // we're not using rarest first (only for the first // bucket, since that's where the currently downloading // pieces are) - int start_piece = rand() % m_piece_map.size(); - - // if we have suggested pieces, try to find one of those instead - for (std::vector::const_iterator i = suggested_pieces.begin() - , end(suggested_pieces.end()); i != end; ++i) - { - if (!can_pick(*i, pieces)) continue; - start_piece = *i; - break; - } - int piece = start_piece; while (num_blocks > 0) { - while (!can_pick(piece, pieces)) + int start_piece = rand() % m_piece_map.size(); + int piece = start_piece; + while (!pieces[piece] + || m_piece_map[piece].index == piece_pos::we_have_index + || m_piece_map[piece].priority(m_sequenced_download_threshold) < 2) { ++piece; if (piece == int(m_piece_map.size())) piece = 0; @@ -1197,45 +1145,27 @@ namespace libtorrent if (piece == start_piece) return; } - int start, end; - boost::tie(start, end) = expand_piece(piece, prefer_whole_pieces, pieces); - for (int k = start; k < end; ++k) - { - assert(m_piece_map[piece].downloading == false); - assert(m_piece_map[k].priority(m_sequenced_download_threshold) > 0); - int num_blocks_in_piece = blocks_in_piece(k); - if (prefer_whole_pieces == 0 && num_blocks_in_piece > num_blocks) - num_blocks_in_piece = num_blocks; - for (int j = 0; j < num_blocks_in_piece; ++j) - { - interesting_blocks.push_back(piece_block(k, j)); - --num_blocks; - } - } - piece = end; - if (piece == int(m_piece_map.size())) piece = 0; - // could not find any more pieces - if (piece == start_piece) return; + assert(m_piece_map[piece].downloading == false); + + int num_blocks_in_piece = blocks_in_piece(piece); + + if (!prefer_whole_pieces && num_blocks_in_piece > num_blocks) + num_blocks_in_piece = num_blocks; + for (int j = 0; j < num_blocks_in_piece; ++j) + interesting_blocks.push_back(piece_block(piece, j)); + num_blocks -= (std::min)(num_blocks_in_piece, num_blocks); } - + if (num_blocks == 0) return; + break; } - if (num_blocks <= 0) return; + assert(num_blocks > 0); if (!backup_blocks.empty()) interesting_blocks.insert(interesting_blocks.end() , backup_blocks.begin(), backup_blocks.end()); } - bool piece_picker::can_pick(int piece, std::vector const& bitmask) const - { - assert(piece >= 0 && piece < int(m_piece_map.size())); - return bitmask[piece] - && !m_piece_map[piece].have() - && !m_piece_map[piece].downloading - && !m_piece_map[piece].filtered(); - } - void piece_picker::clear_peer(void* peer) { for (std::vector::iterator i = m_block_info.begin() @@ -1273,12 +1203,17 @@ namespace libtorrent } } - int piece_picker::add_blocks(std::vector const& piece_list + int piece_picker::add_interesting_blocks(std::vector const& piece_list , std::vector const& pieces , std::vector& interesting_blocks - , int num_blocks, int prefer_whole_pieces - , void* peer, std::vector const& ignore) const + , std::vector& backup_blocks + , int num_blocks, bool prefer_whole_pieces + , void* peer, piece_state_t speed + , bool ignore_downloading_pieces) const { + // if we have less than 1% of the pieces, ignore speed priorities and just try + // to finish any downloading piece + bool ignore_speed_categories = (m_num_have * 100 / m_piece_map.size()) < 1; for (std::vector::const_iterator i = piece_list.begin(); i != piece_list.end(); ++i) { @@ -1289,267 +1224,110 @@ namespace libtorrent // skip it if (!pieces[*i]) continue; - // ignore pieces found in the ignore list - if (std::find(ignore.begin(), ignore.end(), *i) != ignore.end()) continue; - - // skip the piece is the priority is 0 - assert(m_piece_map[*i].priority(m_sequenced_download_threshold) > 0); - int num_blocks_in_piece = blocks_in_piece(*i); - assert(m_piece_map[*i].downloading == 0); - assert(m_piece_map[*i].priority(m_sequenced_download_threshold) > 0); - - // pick a new piece - if (prefer_whole_pieces == 0) + if (m_piece_map[*i].downloading == 1) { - if (num_blocks_in_piece > num_blocks) - num_blocks_in_piece = num_blocks; - for (int j = 0; j < num_blocks_in_piece; ++j) - interesting_blocks.push_back(piece_block(*i, j)); - num_blocks -= num_blocks_in_piece; - } - else - { - int start, end; - boost::tie(start, end) = expand_piece(*i, prefer_whole_pieces, pieces); - for (int k = start; k < end; ++k) - { - assert(m_piece_map[k].priority(m_sequenced_download_threshold) > 0); - num_blocks_in_piece = blocks_in_piece(k); - for (int j = 0; j < num_blocks_in_piece; ++j) - { - interesting_blocks.push_back(piece_block(k, j)); - --num_blocks; - } - } - } - if (num_blocks <= 0) - { -#ifndef NDEBUG - verify_pick(interesting_blocks, pieces); -#endif - return 0; - } - } -#ifndef NDEBUG - verify_pick(interesting_blocks, pieces); -#endif - return num_blocks; - } + if (ignore_downloading_pieces) continue; + std::vector::const_iterator p + = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(*i)); + assert(p != m_downloads.end()); - int piece_picker::add_blocks_downloading(std::vector const& pieces - , std::vector& interesting_blocks - , std::vector& backup_blocks - , int num_blocks, int prefer_whole_pieces - , void* peer, piece_state_t speed, bool on_parole) const - { - for (std::vector::const_iterator i = m_downloads.begin() - , end(m_downloads.end()); i != end; ++i) - { - if (!pieces[i->index]) continue; - - int num_blocks_in_piece = blocks_in_piece(i->index); - - // is true if all the other pieces that are currently - // requested from this piece are from the same - // peer as 'peer'. - bool exclusive; - bool exclusive_active; - boost::tie(exclusive, exclusive_active) - = requested_from(*i, num_blocks_in_piece, peer); - - // peers on parole are only allowed to pick blocks from - // pieces that only they have downloaded/requested from - if (on_parole && !exclusive) continue; - - if (prefer_whole_pieces > 0 && !exclusive_active) continue; - - // don't pick too many back-up blocks - if (i->state != none - && i->state != speed - && !exclusive_active - && int(backup_blocks.size()) >= num_blocks) - continue; - - for (int j = 0; j < num_blocks_in_piece; ++j) - { - // ignore completed blocks and already requested blocks - block_info const& info = i->info[j]; - if (info.state != block_info::state_none) - continue; - - assert(i->info[j].state == block_info::state_none); - - // if the piece is fast and the peer is slow, or vice versa, - // add the block as a backup. - // override this behavior if all the other blocks - // have been requested from the same peer or - // if the state of the piece is none (the - // piece will in that case change state). - if (i->state != none && i->state != speed - && !exclusive_active) - { - backup_blocks.push_back(piece_block(i->index, j)); - continue; - } - - // this block is interesting (we don't have it - // yet). - interesting_blocks.push_back(piece_block(i->index, j)); - // we have found a block that's free to download - num_blocks--; - // if we prefer whole pieces, continue picking from this - // piece even though we have num_blocks - if (prefer_whole_pieces > 0) continue; - assert(num_blocks >= 0); - if (num_blocks <= 0) break; - } - if (num_blocks <= 0) break; - } - - assert(num_blocks >= 0 || prefer_whole_pieces > 0); - -#ifndef NDEBUG - verify_pick(interesting_blocks, pieces); - verify_pick(backup_blocks, pieces); -#endif - - if (num_blocks <= 0) return 0; - if (on_parole) return num_blocks; - - int to_copy; - if (prefer_whole_pieces == 0) - to_copy = (std::min)(int(backup_blocks.size()), num_blocks); - else - to_copy = int(backup_blocks.size()); - - interesting_blocks.insert(interesting_blocks.end() - , backup_blocks.begin(), backup_blocks.begin() + to_copy); - num_blocks -= to_copy; - backup_blocks.clear(); - - if (num_blocks <= 0) return 0; - - if (prefer_whole_pieces > 0) - { - for (std::vector::const_iterator i = m_downloads.begin() - , end(m_downloads.end()); i != end; ++i) - { - if (!pieces[i->index]) continue; - int num_blocks_in_piece = blocks_in_piece(i->index); + // is true if all the other pieces that are currently + // requested from this piece are from the same + // peer as 'peer'. bool exclusive; bool exclusive_active; boost::tie(exclusive, exclusive_active) - = requested_from(*i, num_blocks_in_piece, peer); + = requested_from(*p, num_blocks_in_piece, peer); + + // this means that this partial piece has + // been downloaded/requested partially from + // another peer that isn't us. And since + // we prefer whole pieces, add this piece's + // blocks to the backup list. If the prioritized + // blocks aren't enough, blocks from this list + // will be picked. + if (prefer_whole_pieces && !exclusive) + { + for (int j = 0; j < num_blocks_in_piece; ++j) + { + block_info const& info = p->info[j]; + if (info.state == block_info::state_finished + || info.state == block_info::state_writing) + continue; + if (info.state == block_info::state_requested + && info.peer == peer) continue; + backup_blocks.push_back(piece_block(*i, j)); + } + continue; + } - if (exclusive_active) continue; - for (int j = 0; j < num_blocks_in_piece; ++j) { - block_info const& info = i->info[j]; - if (info.state != block_info::state_none) continue; - backup_blocks.push_back(piece_block(i->index, j)); + // ignore completed blocks + block_info const& info = p->info[j]; + if (info.state == block_info::state_finished + || info.state == block_info::state_writing) + continue; + // ignore blocks requested from this peer already + if (info.state == block_info::state_requested + && info.peer == peer) + continue; + // if the piece is fast and the peer is slow, or vice versa, + // add the block as a backup. + // override this behavior if all the other blocks + // have been requested from the same peer or + // if the state of the piece is none (the + // piece will in that case change state). + if (p->state != none && p->state != speed + && !exclusive_active + && !ignore_speed_categories) + { + backup_blocks.push_back(piece_block(*i, j)); + continue; + } + // this block is interesting (we don't have it + // yet). But it may already have been requested + // from another peer. We have to add it anyway + // to allow the requester to determine if the + // block should be requested from more than one + // peer. If it is being downloaded, we continue + // to look for blocks until we have num_blocks + // blocks that have not been requested from any + // other peer. + if (p->info[j].state == block_info::state_none) + { + interesting_blocks.push_back(piece_block(*i, j)); + // we have found a block that's free to download + num_blocks--; + // if we prefer whole pieces, continue picking from this + // piece even though we have num_blocks + if (prefer_whole_pieces) continue; + assert(num_blocks >= 0); + if (num_blocks == 0) return num_blocks; + } + else + { + backup_blocks.push_back(piece_block(*i, j)); + } } + assert(num_blocks >= 0 || prefer_whole_pieces); + if (num_blocks < 0) num_blocks = 0; } - } - - if (int(backup_blocks.size()) >= num_blocks) return num_blocks; - - -#ifndef NDEBUG -// make sure that we at this point has added requests to all unrequested blocks -// in all downloading pieces - - for (std::vector::const_iterator i = m_downloads.begin() - , end(m_downloads.end()); i != end; ++i) - { - if (!pieces[i->index]) continue; - - int num_blocks_in_piece = blocks_in_piece(i->index); - for (int j = 0; j < num_blocks_in_piece; ++j) + else { - block_info const& info = i->info[j]; - if (info.state != block_info::state_none) continue; - std::vector::iterator k = std::find( - interesting_blocks.begin(), interesting_blocks.end() - , piece_block(i->index, j)); - if (k != interesting_blocks.end()) continue; - - k = std::find(backup_blocks.begin() - , backup_blocks.end(), piece_block(i->index, j)); - if (k != backup_blocks.end()) continue; - - std::cerr << "interesting blocks:" << std::endl; - for (k = interesting_blocks.begin(); k != interesting_blocks.end(); ++k) - std::cerr << "(" << k->piece_index << ", " << k->block_index << ") "; - std::cerr << std::endl; - std::cerr << "backup blocks:" << std::endl; - for (k = backup_blocks.begin(); k != backup_blocks.end(); ++k) - std::cerr << "(" << k->piece_index << ", " << k->block_index << ") "; - std::cerr << std::endl; - std::cerr << "num_blocks: " << num_blocks << std::endl; - - for (std::vector::const_iterator l = m_downloads.begin() - , end(m_downloads.end()); l != end; ++l) - { - std::cerr << l->index << " : "; - int num_blocks_in_piece = blocks_in_piece(l->index); - for (int m = 0; m < num_blocks_in_piece; ++m) - std::cerr << l->info[m].state; - std::cerr << std::endl; - } - - assert(false); + if (!prefer_whole_pieces && num_blocks_in_piece > num_blocks) + num_blocks_in_piece = num_blocks; + for (int j = 0; j < num_blocks_in_piece; ++j) + interesting_blocks.push_back(piece_block(*i, j)); + num_blocks -= (std::min)(num_blocks_in_piece, num_blocks); } + assert(num_blocks >= 0); + if (num_blocks == 0) return num_blocks; } -#endif - - for (std::vector::const_iterator i = m_downloads.begin() - , end(m_downloads.end()); i != end; ++i) - { - if (!pieces[i->index]) continue; - - int num_blocks_in_piece = blocks_in_piece(i->index); - - // fill in with blocks requested from other peers - // as backups - for (int j = 0; j < num_blocks_in_piece; ++j) - { - block_info const& info = i->info[j]; - if (info.state != block_info::state_requested - || info.peer == peer) - continue; - backup_blocks.push_back(piece_block(i->index, j)); - } - } -#ifndef NDEBUG - verify_pick(backup_blocks, pieces); -#endif return num_blocks; } - - std::pair piece_picker::expand_piece(int piece, int whole_pieces - , std::vector const& have) const - { - if (whole_pieces == 0) return std::make_pair(piece, piece + 1); - - int start = piece - 1; - int lower_limit = piece - whole_pieces; - if (lower_limit < -1) lower_limit = -1; - while (start > lower_limit - && can_pick(start, have)) - --start; - ++start; - assert(start >= 0); - int end = piece + 1; - int upper_limit = start + whole_pieces; - if (upper_limit > int(m_piece_map.size())) upper_limit = int(m_piece_map.size()); - while (end < upper_limit - && can_pick(end, have)) - ++end; - return std::make_pair(start, end); - } bool piece_picker::is_piece_finished(int index) const { @@ -1627,7 +1405,7 @@ namespace libtorrent } - bool piece_picker::mark_as_downloading(piece_block block + void piece_picker::mark_as_downloading(piece_block block , void* peer, piece_state_t state) { TORRENT_PIECE_PICKER_INVARIANT_CHECK; @@ -1636,14 +1414,11 @@ namespace libtorrent assert(block.block_index >= 0); assert(block.piece_index < (int)m_piece_map.size()); assert(block.block_index < blocks_in_piece(block.piece_index)); - assert(!m_piece_map[block.piece_index].have()); piece_pos& p = m_piece_map[block.piece_index]; if (p.downloading == 0) { int prio = p.priority(m_sequenced_download_threshold); - assert(prio < int(m_piece_info.size())); - assert(prio > 0); p.downloading = 1; move(prio, p.index); @@ -1662,9 +1437,6 @@ namespace libtorrent = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index)); assert(i != m_downloads.end()); block_info& info = i->info[block.block_index]; - if (info.state == block_info::state_writing - || info.state == block_info::state_finished) - return false; assert(info.state == block_info::state_none || (info.state == block_info::state_requested && (info.num_peers > 0))); @@ -1677,7 +1449,6 @@ namespace libtorrent ++info.num_peers; if (i->state == none) i->state = state; } - return true; } int piece_picker::num_peers(piece_block block) const @@ -1758,7 +1529,6 @@ namespace libtorrent assert(peer == 0); int prio = p.priority(m_sequenced_download_threshold); - assert(prio < int(m_piece_info.size())); p.downloading = 1; if (prio > 0) move(prio, p.index); else assert(p.priority(m_sequenced_download_threshold) == 0); @@ -1880,12 +1650,9 @@ namespace libtorrent { erase_download_piece(i); piece_pos& p = m_piece_map[block.piece_index]; - int prev_prio = p.priority(m_sequenced_download_threshold); - assert(prev_prio < int(m_piece_info.size())); - p.downloading = 0; int prio = p.priority(m_sequenced_download_threshold); - if (prev_prio == 0 && prio > 0) add(block.piece_index); - else if (prio > 0) move(prio, p.index); + p.downloading = 0; + if (prio > 0) move(prio, p.index); assert(std::find_if(m_downloads.begin(), m_downloads.end() , has_index(block.piece_index)) == m_downloads.end()); diff --git a/libtorrent/src/policy.cpp b/libtorrent/src/policy.cpp index 4faed837e..572f48d35 100755 --- a/libtorrent/src/policy.cpp +++ b/libtorrent/src/policy.cpp @@ -83,7 +83,7 @@ namespace // (and we should not consider it free). If the share diff is // negative, there's no free download to get from this peer. size_type diff = i->second->share_diff(); - assert(diff < (std::numeric_limits::max)()); + assert(diff < std::numeric_limits::max()); if (i->second->is_peer_interested() || diff <= 0) continue; @@ -110,7 +110,7 @@ namespace for (torrent::peer_iterator i = start; i != end; ++i) { size_type d = i->second->share_diff(); - assert(d < (std::numeric_limits::max)()); + assert(d < std::numeric_limits::max()); total_diff += d; if (!i->second->is_peer_interested() || i->second->share_diff() >= 0) continue; ++num_peers; @@ -120,7 +120,7 @@ namespace size_type upload_share; if (total_diff >= 0) { - upload_share = (std::min)(free_upload, total_diff) / num_peers; + upload_share = std::min(free_upload, total_diff) / num_peers; } else { @@ -138,28 +138,28 @@ namespace return free_upload; } - struct match_peer_address + struct match_peer_ip { - match_peer_address(address const& addr) - : m_addr(addr) + match_peer_ip(address const& ip) + : m_ip(ip) {} bool operator()(policy::peer const& p) const - { return p.ip.address() == m_addr; } + { return p.ip.address() == m_ip; } - address const& m_addr; + address const& m_ip; }; - struct match_peer_endpoint + struct match_peer_id { - match_peer_endpoint(tcp::endpoint const& ep) - : m_ep(ep) + match_peer_id(peer_id const& id_) + : m_id(id_) {} bool operator()(policy::peer const& p) const - { return p.ip == m_ep; } + { return p.connection && p.connection->pid() == m_id; } - tcp::endpoint const& m_ep; + peer_id const& m_id; }; struct match_peer_connection @@ -187,19 +187,17 @@ namespace libtorrent // have only one piece that we don't have, and it's the // same piece for both peers. Then they might get into an // infinite loop, fighting to request the same blocks. - void request_a_block(torrent& t, peer_connection& c) + void request_a_block( + torrent& t + , peer_connection& c) { - if (t.is_seed()) return; - - assert(t.valid_metadata()); + assert(!t.is_seed()); + assert(!c.has_peer_choked()); assert(c.peer_info_struct() != 0 || !dynamic_cast(&c)); int num_requests = c.desired_queue_size() - (int)c.download_queue().size() - (int)c.request_queue().size(); -#ifdef TORRENT_VERBOSE_LOGGING - (*c.m_logger) << time_now_string() << " PIECE_PICKER [ req: " << num_requests << " ]\n"; -#endif assert(c.desired_queue_size() > 0); // if our request queue is already full, we // don't have to make any new requests yet @@ -209,15 +207,16 @@ namespace libtorrent std::vector interesting_pieces; interesting_pieces.reserve(100); - int prefer_whole_pieces = c.prefer_whole_pieces(); + bool prefer_whole_pieces = c.prefer_whole_pieces() + || (c.peer_info_struct() && c.peer_info_struct()->on_parole); bool rarest_first = t.num_pieces() >= t.settings().initial_picker_threshold; - if (prefer_whole_pieces == 0) + if (!prefer_whole_pieces) { prefer_whole_pieces = c.statistics().download_payload_rate() * t.settings().whole_pieces_threshold - > t.torrent_file().piece_length() ? 1 : 0; + > t.torrent_file().piece_length(); } // if we prefer whole pieces, the piece picker will pick at least @@ -232,6 +231,18 @@ namespace libtorrent else if (speed == peer_connection::medium) state = piece_picker::medium; else state = piece_picker::slow; + // picks the interesting pieces from this peer + // the integer is the number of pieces that + // should be guaranteed to be available for download + // (if num_requests is too big, too many pieces are + // picked and cpu-time is wasted) + // the last argument is if we should prefer whole pieces + // for this peer. If we're downloading one piece in 20 seconds + // then use this mode. + p.pick_pieces(c.get_bitfield(), interesting_pieces + , num_requests, prefer_whole_pieces, c.peer_info_struct() + , state, rarest_first); + // this vector is filled with the interesting pieces // that some other peer is currently downloading // we should then compare this peer's download speed @@ -240,56 +251,14 @@ namespace libtorrent std::vector busy_pieces; busy_pieces.reserve(num_requests); - std::vector const& suggested = c.suggested_pieces(); - std::vector const& bitfield = c.get_bitfield(); - - if (c.has_peer_choked()) - { - // if we are choked we can only pick pieces from the - // allowed fast set. The allowed fast set is sorted - // in ascending priority order - std::vector const& allowed_fast = c.allowed_fast(); - - // build a bitmask with only the allowed pieces in it - std::vector mask(c.get_bitfield().size(), false); - for (std::vector::const_iterator i = allowed_fast.begin() - , end(allowed_fast.end()); i != end; ++i) - if (bitfield[*i]) mask[*i] = true; - - p.pick_pieces(mask, interesting_pieces - , num_requests, prefer_whole_pieces, c.peer_info_struct() - , state, rarest_first, c.on_parole(), suggested); - } - else - { - // picks the interesting pieces from this peer - // the integer is the number of pieces that - // should be guaranteed to be available for download - // (if num_requests is too big, too many pieces are - // picked and cpu-time is wasted) - // the last argument is if we should prefer whole pieces - // for this peer. If we're downloading one piece in 20 seconds - // then use this mode. - p.pick_pieces(bitfield, interesting_pieces - , num_requests, prefer_whole_pieces, c.peer_info_struct() - , state, rarest_first, c.on_parole(), suggested); - } - -#ifdef TORRENT_VERBOSE_LOGGING - (*c.m_logger) << time_now_string() << " PIECE_PICKER [ php: " << prefer_whole_pieces - << " picked: " << interesting_pieces.size() << " ]\n"; -#endif - std::deque const& dq = c.download_queue(); - std::deque const& rq = c.request_queue(); for (std::vector::iterator i = interesting_pieces.begin(); i != interesting_pieces.end(); ++i) { - if (prefer_whole_pieces == 0 && num_requests <= 0) break; - if (p.is_requested(*i)) { - if (num_requests <= 0) break; // don't request pieces we already have in our request queue + const std::deque& dq = c.download_queue(); + const std::deque& rq = c.request_queue(); if (std::find(dq.begin(), dq.end(), *i) != dq.end() || std::find(rq.begin(), rq.end(), *i) != rq.end()) continue; @@ -308,13 +277,13 @@ namespace libtorrent num_requests--; } - if (busy_pieces.empty() || num_requests <= 0) - { - // in this case, we could not find any blocks - // that was free. If we couldn't find any busy - // blocks as well, we cannot download anything - // more from this peer. + // in this case, we could not find any blocks + // that was free. If we couldn't find any busy + // blocks as well, we cannot download anything + // more from this peer. + if (busy_pieces.empty() || num_requests == 0) + { c.send_block_requests(); return; } @@ -339,8 +308,9 @@ namespace libtorrent policy::policy(torrent* t) : m_torrent(t) + , m_num_unchoked(0) , m_available_free_upload(0) -// , m_last_optimistic_disconnect(min_time()) + , m_last_optimistic_disconnect(min_time()) { assert(t); } // disconnects and removes all peers that are now filtered @@ -382,7 +352,7 @@ namespace libtorrent m_peers.erase(i++); } } -/* + // finds the peer that has the worst download rate // and returns it. May return 0 if all peers are // choked. @@ -391,7 +361,7 @@ namespace libtorrent INVARIANT_CHECK; iterator worst_peer = m_peers.end(); - size_type min_weight = (std::numeric_limits::min)(); + size_type min_weight = std::numeric_limits::min(); #ifndef NDEBUG int unchoked_counter = m_num_unchoked; @@ -464,13 +434,13 @@ namespace libtorrent } return unchoke_peer; } -*/ + policy::iterator policy::find_disconnect_candidate() { INVARIANT_CHECK; iterator disconnect_peer = m_peers.end(); - double slowest_transfer_rate = (std::numeric_limits::max)(); + double slowest_transfer_rate = std::numeric_limits::max(); ptime now = time_now(); @@ -513,8 +483,7 @@ namespace libtorrent policy::iterator policy::find_connect_candidate() { -// too expensive -// INVARIANT_CHECK; + INVARIANT_CHECK; ptime now = time_now(); ptime min_connect_time(now); @@ -522,7 +491,6 @@ namespace libtorrent int max_failcount = m_torrent->settings().max_failcount; int min_reconnect_time = m_torrent->settings().min_reconnect_time; - bool finished = m_torrent->is_finished(); aux::session_impl& ses = m_torrent->session(); @@ -531,7 +499,7 @@ namespace libtorrent if (i->connection) continue; if (i->banned) continue; if (i->type == peer::not_connectable) continue; - if (i->seed && finished) continue; + if (i->seed && m_torrent->is_seed()) continue; if (i->failcount >= max_failcount) continue; if (now - i->connected < seconds(i->failcount * min_reconnect_time)) continue; @@ -551,7 +519,7 @@ namespace libtorrent return candidate; } -/* + policy::iterator policy::find_seed_choke_candidate() { INVARIANT_CHECK; @@ -657,7 +625,7 @@ namespace libtorrent --m_num_unchoked; } } -*/ + void policy::pulse() { INVARIANT_CHECK; @@ -689,7 +657,7 @@ namespace libtorrent // ------------------------------------- // maintain the number of connections // ------------------------------------- -/* + // count the number of connected peers except for peers // that are currently in the process of disconnecting int num_connected_peers = 0; @@ -701,9 +669,10 @@ namespace libtorrent ++num_connected_peers; } - if (m_torrent->max_connections() != (std::numeric_limits::max)()) + if (m_torrent->m_connections_quota.given != std::numeric_limits::max()) { - int max_connections = m_torrent->max_connections(); + + int max_connections = m_torrent->m_connections_quota.given; if (num_connected_peers >= max_connections) { @@ -731,7 +700,7 @@ namespace libtorrent --num_connected_peers; } } -*/ + // ------------------------ // upload shift // ------------------------ @@ -762,7 +731,7 @@ namespace libtorrent , m_torrent->end() , m_available_free_upload); } -/* + // ------------------------ // seed choking policy // ------------------------ @@ -878,7 +847,6 @@ namespace libtorrent while (m_num_unchoked < m_torrent->m_uploads_quota.given && unchoke_one_peer()); } -*/ } int policy::count_choked() const @@ -911,8 +879,7 @@ namespace libtorrent // override at a time assert(c.remote() == c.get_socket()->remote_endpoint()); - if (m_torrent->num_peers() >= m_torrent->max_connections() - && m_torrent->session().num_connections() >= m_torrent->session().max_connections() + if (m_torrent->num_peers() >= m_torrent->m_connections_quota.given && c.remote().address() != m_torrent->current_tracker().address()) { throw protocol_error("too many connections, refusing incoming connection"); // cause a disconnect @@ -939,7 +906,7 @@ namespace libtorrent i = std::find_if( m_peers.begin() , m_peers.end() - , match_peer_address(c.remote().address())); + , match_peer_ip(c.remote().address())); } if (i != m_peers.end()) @@ -994,17 +961,16 @@ namespace libtorrent i->connection = &c; assert(i->connection); i->connected = time_now(); -// m_last_optimistic_disconnect = time_now(); + m_last_optimistic_disconnect = time_now(); } void policy::peer_from_tracker(const tcp::endpoint& remote, const peer_id& pid , int src, char flags) { -// too expensive -// INVARIANT_CHECK; + INVARIANT_CHECK; // just ignore the obviously invalid entries - if (remote.address() == address() || remote.port() == 0) + if(remote.address() == address() || remote.port() == 0) return; aux::session_impl& ses = m_torrent->session(); @@ -1029,14 +995,14 @@ namespace libtorrent i = std::find_if( m_peers.begin() , m_peers.end() - , match_peer_endpoint(remote)); + , match_peer_id(pid)); } else { i = std::find_if( m_peers.begin() , m_peers.end() - , match_peer_address(remote.address())); + , match_peer_ip(remote.address())); } if (i == m_peers.end()) @@ -1090,10 +1056,7 @@ namespace libtorrent if (i->failcount > 0 && src != peer_info::dht) --i->failcount; - // if we're connected to this peer - // we already know if it's a seed or not - // so we don't have to trust this source - if ((flags & 0x02) && !i->connection) i->seed = true; + if (flags & 0x02) i->seed = true; if (i->connection) { @@ -1183,38 +1146,14 @@ namespace libtorrent // In that case we don't care if people are leeching, they // can't pay for their downloads anyway. if (c.is_choked() - && m_torrent->session().num_uploads() < m_torrent->session().max_uploads() + && m_num_unchoked < m_torrent->m_uploads_quota.given && (m_torrent->ratio() == 0 || c.share_diff() >= -free_upload_amount - || m_torrent->is_finished())) + || m_torrent->is_seed())) { - m_torrent->session().unchoke_peer(c); + c.send_unchoke(); + ++m_num_unchoked; } -#if defined(TORRENT_VERBOSE_LOGGING) - else if (c.is_choked()) - { - std::string reason; - if (m_torrent->session().num_uploads() >= m_torrent->session().max_uploads()) - { - reason = "the number of uploads (" - + boost::lexical_cast(m_torrent->session().num_uploads()) - + ") is more than or equal to the limit (" - + boost::lexical_cast(m_torrent->session().max_uploads()) - + ")"; - } - else - { - reason = "the share ratio (" - + boost::lexical_cast(c.share_diff()) - + ") is <= free_upload_amount (" - + boost::lexical_cast(int(free_upload_amount)) - + ") and we are not seeding and the ratio (" - + boost::lexical_cast(m_torrent->ratio()) - + ")is non-zero"; - } - (*c.m_logger) << time_now_string() << " DID NOT UNCHOKE [ " << reason << " ]\n"; - } -#endif } // called when a peer is no longer interested in us @@ -1224,7 +1163,7 @@ namespace libtorrent if (m_torrent->ratio() != 0.f) { - assert(c.share_diff() < (std::numeric_limits::max)()); + assert(c.share_diff() < std::numeric_limits::max()); size_type diff = c.share_diff(); if (diff > 0 && c.is_seed()) { @@ -1246,7 +1185,7 @@ namespace libtorrent } */ } -/* + bool policy::unchoke_one_peer() { INVARIANT_CHECK; @@ -1275,7 +1214,7 @@ namespace libtorrent p->connection->send_choke(); --m_num_unchoked; } -*/ + bool policy::connect_one_peer() { INVARIANT_CHECK; @@ -1291,15 +1230,9 @@ namespace libtorrent try { - INVARIANT_CHECK; - p->connected = time_now(); + p->connected = m_last_optimistic_disconnect = time_now(); p->connection = m_torrent->connect_to_peer(&*p); - assert(p->connection == m_torrent->connection_for(p->ip)); - if (p->connection == 0) - { - ++p->failcount; - return false; - } + if (p->connection == 0) return false; p->connection->add_stat(p->prev_amount_download, p->prev_amount_upload); p->prev_amount_download = 0; p->prev_amount_upload = 0; @@ -1311,7 +1244,6 @@ namespace libtorrent (*m_torrent->session().m_logger) << "*** CONNECTION FAILED '" << e.what() << "'\n"; #endif - std::cerr << e.what() << std::endl; ++p->failcount; return false; } @@ -1331,33 +1263,33 @@ namespace libtorrent } // this is called whenever a peer connection is closed - void policy::connection_closed(const peer_connection& c) throw() + void policy::connection_closed(const peer_connection& c) try { -// too expensive -// INVARIANT_CHECK; + INVARIANT_CHECK; - peer* p = c.peer_info_struct(); +// assert(c.is_disconnecting()); + bool unchoked = false; - assert((std::find_if( + iterator i = std::find_if( m_peers.begin() , m_peers.end() - , match_peer_connection(c)) - != m_peers.end()) == (p != 0)); - + , match_peer_connection(c)); + // if we couldn't find the connection in our list, just ignore it. - if (p == 0) return; + if (i == m_peers.end()) return; + assert(i->connection == &c); + i->connection = 0; - assert(p->connection == &c); - - p->connection = 0; - p->optimistically_unchoked = false; - - p->connected = time_now(); + i->connected = time_now(); + if (!c.is_choked() && !m_torrent->is_aborted()) + { + unchoked = true; + } if (c.failed()) { - ++p->failcount; -// p->connected = time_now(); + ++i->failcount; +// i->connected = time_now(); } // if the share ratio is 0 (infinite), the @@ -1366,11 +1298,28 @@ namespace libtorrent if (m_torrent->ratio() != 0.f) { assert(c.associated_torrent().lock().get() == m_torrent); - assert(c.share_diff() < (std::numeric_limits::max)()); + assert(c.share_diff() < std::numeric_limits::max()); m_available_free_upload += c.share_diff(); } - p->prev_amount_download += c.statistics().total_payload_download(); - p->prev_amount_upload += c.statistics().total_payload_upload(); + i->prev_amount_download += c.statistics().total_payload_download(); + i->prev_amount_upload += c.statistics().total_payload_upload(); + + if (unchoked) + { + // if the peer that is diconnecting is unchoked + // then unchoke another peer in order to maintain + // the total number of unchoked peers + --m_num_unchoked; + if (m_torrent->is_seed()) seed_unchoke_one_peer(); + else unchoke_one_peer(); + } + } + catch (std::exception& e) + { +#ifndef NDEBUG + std::string err = e.what(); +#endif + assert(false); } void policy::peer_is_interesting(peer_connection& c) @@ -1378,21 +1327,17 @@ namespace libtorrent INVARIANT_CHECK; c.send_interested(); - if (c.has_peer_choked() - && c.allowed_fast().empty()) - return; + if (c.has_peer_choked()) return; request_a_block(*m_torrent, c); } #ifndef NDEBUG bool policy::has_connection(const peer_connection* c) { -// too expensive -// INVARIANT_CHECK; + INVARIANT_CHECK; assert(c); - try { assert(c->remote() == c->get_socket()->remote_endpoint()); } - catch (std::exception&) {} + assert(c->remote() == c->get_socket()->remote_endpoint()); return std::find_if( m_peers.begin() @@ -1403,28 +1348,22 @@ namespace libtorrent void policy::check_invariant() const { if (m_torrent->is_aborted()) return; + int actual_unchoked = 0; int connected_peers = 0; int total_connections = 0; int nonempty_connections = 0; - + std::set
unique_test; - std::set unique_test2; for (const_iterator i = m_peers.begin(); i != m_peers.end(); ++i) { peer const& p = *i; if (!m_torrent->settings().allow_multiple_connections_per_ip) assert(unique_test.find(p.ip.address()) == unique_test.end()); - assert(unique_test2.find(p.ip) == unique_test2.end()); unique_test.insert(p.ip.address()); - unique_test2.insert(p.ip); ++total_connections; - if (!p.connection) - { -// assert(m_torrent->connection_for(p.ip) == 0); - continue; - } + if (!p.connection) continue; if (!m_torrent->settings().allow_multiple_connections_per_ip) { std::vector conns; @@ -1433,17 +1372,15 @@ namespace libtorrent , boost::bind(std::equal_to(), _1, p.connection)) != conns.end()); } - if (p.optimistically_unchoked) - { - assert(p.connection); - assert(!p.connection->is_choked()); - } assert(p.connection->peer_info_struct() == 0 || p.connection->peer_info_struct() == &p); ++nonempty_connections; if (!p.connection->is_disconnecting()) ++connected_peers; + if (!p.connection->is_choked()) ++actual_unchoked; } +// assert(actual_unchoked <= m_torrent->m_uploads_quota.given); + assert(actual_unchoked == m_num_unchoked); int num_torrent_peers = 0; for (torrent::const_peer_iterator i = m_torrent->begin(); @@ -1510,7 +1447,6 @@ namespace libtorrent , failcount(0) , hashfails(0) , seed(false) - , optimistically_unchoked(false) , last_optimistically_unchoked(min_time()) , connected(min_time()) , trust_points(0) diff --git a/libtorrent/src/session.cpp b/libtorrent/src/session.cpp index 6298b3c2c..485c90d62 100755 --- a/libtorrent/src/session.cpp +++ b/libtorrent/src/session.cpp @@ -68,6 +68,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert_types.hpp" #include "libtorrent/invariant_check.hpp" #include "libtorrent/file.hpp" +#include "libtorrent/allocate_resources.hpp" #include "libtorrent/bt_peer_connection.hpp" #include "libtorrent/ip_filter.hpp" #include "libtorrent/socket.hpp" @@ -132,7 +133,7 @@ namespace libtorrent m_impl->abort(); } - void session::add_extension(boost::function(torrent*, void*)> ext) + void session::add_extension(boost::function(torrent*)> ext) { m_impl->add_extension(ext); } @@ -179,27 +180,11 @@ namespace libtorrent , fs::path const& save_path , entry const& resume_data , bool compact_mode - , bool paused + , int block_size , storage_constructor_type sc) { - assert(!ti.m_half_metadata); - boost::intrusive_ptr tip(new torrent_info(ti)); - return m_impl->add_torrent(tip, save_path, resume_data - , compact_mode, sc, paused, 0); - } - - torrent_handle session::add_torrent( - boost::intrusive_ptr ti - , fs::path const& save_path - , entry const& resume_data - , bool compact_mode - , bool paused - , storage_constructor_type sc - , void* userdata) - { - assert(!ti->m_half_metadata); return m_impl->add_torrent(ti, save_path, resume_data - , compact_mode, sc, paused, userdata); + , compact_mode, block_size, sc); } torrent_handle session::add_torrent( @@ -209,12 +194,11 @@ namespace libtorrent , fs::path const& save_path , entry const& e , bool compact_mode - , bool paused - , storage_constructor_type sc - , void* userdata) + , int block_size + , storage_constructor_type sc) { return m_impl->add_torrent(tracker_url, info_hash, name, save_path, e - , compact_mode, sc, paused, userdata); + , compact_mode, block_size, sc); } void session::remove_torrent(const torrent_handle& h) @@ -353,11 +337,6 @@ namespace libtorrent m_impl->set_max_connections(limit); } - int session::max_half_open_connections() const - { - return m_impl->max_half_open_connections(); - } - void session::set_max_half_open_connections(int limit) { m_impl->set_max_half_open_connections(limit); diff --git a/libtorrent/src/session_impl.cpp b/libtorrent/src/session_impl.cpp index 6e1129b99..81f48a3ce 100755 --- a/libtorrent/src/session_impl.cpp +++ b/libtorrent/src/session_impl.cpp @@ -68,6 +68,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/alert_types.hpp" #include "libtorrent/invariant_check.hpp" #include "libtorrent/file.hpp" +#include "libtorrent/allocate_resources.hpp" #include "libtorrent/bt_peer_connection.hpp" #include "libtorrent/ip_filter.hpp" #include "libtorrent/socket.hpp" @@ -222,12 +223,6 @@ namespace detail if (!m_ses.is_aborted()) { m_ses.m_torrents.insert(std::make_pair(t->info_hash, t->torrent_ptr)); - if (m_ses.m_alerts.should_post(alert::info)) - { - m_ses.m_alerts.post_alert(torrent_checked_alert( - processing->torrent_ptr->get_handle() - , "torrent finished checking")); - } if (t->torrent_ptr->is_seed() && m_ses.m_alerts.should_post(alert::info)) { m_ses.m_alerts.post_alert(torrent_finished_alert( @@ -350,12 +345,6 @@ namespace detail processing->torrent_ptr->files_checked(processing->unfinished_pieces); m_ses.m_torrents.insert(std::make_pair( processing->info_hash, processing->torrent_ptr)); - if (m_ses.m_alerts.should_post(alert::info)) - { - m_ses.m_alerts.post_alert(torrent_checked_alert( - processing->torrent_ptr->get_handle() - , "torrent finished checking")); - } if (processing->torrent_ptr->is_seed() && m_ses.m_alerts.should_post(alert::info)) { @@ -516,12 +505,8 @@ namespace detail , m_listen_interface(address::from_string(listen_interface), listen_port_range.first) , m_external_listen_port(0) , m_abort(false) - , m_max_uploads(8) - , m_max_connections(200) - , m_num_unchoked(0) - , m_unchoke_time_scaler(0) - , m_optimistic_unchoke_time_scaler(0) - , m_disconnect_time_scaler(0) + , m_max_uploads(-1) + , m_max_connections(-1) , m_incoming_connection(false) , m_last_tick(time_now()) #ifndef TORRENT_DISABLE_DHT @@ -532,11 +517,6 @@ namespace detail , m_next_connect_torrent(0) , m_checker_impl(*this) { -#ifdef WIN32 - // windows XP has a limit of 10 simultaneous connections - m_half_open.limit(8); -#endif - m_bandwidth_manager[peer_connection::download_channel] = &m_download_channel; m_bandwidth_manager[peer_connection::upload_channel] = &m_upload_channel; @@ -593,7 +573,7 @@ namespace detail #ifndef TORRENT_DISABLE_EXTENSIONS void session_impl::add_extension( - boost::function(torrent*, void*)> ext) + boost::function(torrent*)> ext) { m_extensions.push_back(ext); } @@ -629,9 +609,6 @@ namespace detail void session_impl::set_ip_filter(ip_filter const& f) { mutex_t::scoped_lock l(m_mutex); - - INVARIANT_CHECK; - m_ip_filter = f; // Close connections whose endpoint is filtered @@ -644,9 +621,6 @@ namespace detail void session_impl::set_settings(session_settings const& s) { mutex_t::scoped_lock l(m_mutex); - - INVARIANT_CHECK; - assert(s.connection_speed > 0); assert(s.file_pool_size > 0); @@ -666,25 +640,22 @@ namespace detail try { // create listener socket - m_listen_socket.reset(new socket_acceptor(m_io_service)); + m_listen_socket = boost::shared_ptr(new socket_acceptor(m_io_service)); for(;;) { try { m_listen_socket->open(m_listen_interface.protocol()); - m_listen_socket->set_option(socket_acceptor::reuse_address(true)); m_listen_socket->bind(m_listen_interface); m_listen_socket->listen(); - m_listen_interface = m_listen_socket->local_endpoint(); m_external_listen_port = m_listen_interface.port(); break; } catch (asio::system_error& e) { // TODO: make sure this is correct - if (e.code() == asio::error::host_not_found - || m_listen_interface.port() == 0) + if (e.code() == asio::error::host_not_found) { if (m_alerts.should_post(alert::fatal)) { @@ -729,18 +700,14 @@ namespace detail } } +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) if (m_listen_socket) { -#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) (*m_logger) << "listening on port: " << m_listen_interface.port() << " external port: " << m_external_listen_port << "\n"; -#endif - async_accept(); - if (m_natpmp.get()) - m_natpmp->set_mappings(m_listen_interface.port(), 0); - if (m_upnp.get()) - m_upnp->set_mappings(m_listen_interface.port(), 0); } +#endif + if (m_listen_socket) async_accept(); } void session_impl::async_accept() @@ -766,6 +733,7 @@ namespace detail if (m_abort) return; + async_accept(); if (e) { #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) @@ -774,12 +742,8 @@ namespace detail (*m_logger) << msg << "\n"; #endif assert(m_listen_socket.unique()); - // try any random port - m_listen_interface.port(0); - open_listen_port(); return; } - async_accept(); // we got a connection request! m_incoming_connection = true; @@ -801,30 +765,8 @@ namespace detail return; } - // check if we have any active torrents - // if we don't reject the connection - if (m_torrents.empty()) - { - return; - } - else - { - bool has_active_torrent = false; - for (torrent_map::iterator i = m_torrents.begin() - , end(m_torrents.end()); i != end; ++i) - { - if (!i->second->is_paused()) - { - has_active_torrent = true; - break; - } - } - if (!has_active_torrent) - return; - } - boost::intrusive_ptr c( - new bt_peer_connection(*this, s, 0)); + new bt_peer_connection(*this, s, 0)); #ifndef NDEBUG c->m_in_constructor = false; #endif @@ -845,9 +787,6 @@ namespace detail #endif { mutex_t::scoped_lock l(m_mutex); - -// too expensive -// INVARIANT_CHECK; connection_map::iterator p = m_connections.find(s); @@ -879,16 +818,10 @@ namespace detail { mutex_t::scoped_lock l(m_mutex); -// too expensive -// INVARIANT_CHECK; - assert(p->is_disconnecting()); connection_map::iterator i = m_connections.find(p->get_socket()); if (i != m_connections.end()) - { - if (!i->second->is_choked()) --m_num_unchoked; m_connections.erase(i); - } } void session_impl::set_peer_id(peer_id const& id) @@ -907,8 +840,6 @@ namespace detail { session_impl::mutex_t::scoped_lock l(m_mutex); - INVARIANT_CHECK; - if (e) { #if defined(TORRENT_LOGGING) @@ -970,9 +901,7 @@ namespace detail // round robin fashion, so that every torrent is // equallt likely to connect to a peer - if (!m_torrents.empty() - && m_half_open.free_slots() - && num_connections() < m_max_connections) + if (!m_torrents.empty() && m_half_open.free_slots()) { // this is the maximum number of connections we will // attempt this tick @@ -989,13 +918,11 @@ namespace detail { torrent& t = *i->second; if (t.want_more_peers()) - { if (t.try_connect_peer()) { --max_connections; steps_since_last_connect = 0; } - } ++m_next_connect_torrent; ++steps_since_last_connect; ++i; @@ -1013,8 +940,6 @@ namespace detail // if we should not make any more connections // attempts this tick, abort if (max_connections == 0) break; - // maintain the global limit on number of connections - if (num_connections() >= m_max_connections) break; } } @@ -1051,7 +976,18 @@ namespace detail continue; } - c.keep_alive(); + try + { + c.keep_alive(); + } + catch (std::exception& exc) + { +#ifdef TORRENT_VERBOSE_LOGGING + (*c.m_logger) << "**ERROR**: " << exc.what() << "\n"; +#endif + c.set_failed(); + c.disconnect(); + } } // check each torrent for tracker updates @@ -1083,183 +1019,30 @@ namespace detail } m_stat.second_tick(tick_interval); + // distribute the maximum upload rate among the torrents - // -------------------------------------------------------------- - // unchoke set and optimistic unchoke calculations - // -------------------------------------------------------------- - m_unchoke_time_scaler--; - if (m_unchoke_time_scaler <= 0 && !m_connections.empty()) + assert(m_max_uploads >= -1); + assert(m_max_connections >= -1); + + allocate_resources(m_max_uploads == -1 + ? std::numeric_limits::max() + : m_max_uploads + , m_torrents + , &torrent::m_uploads_quota); + + allocate_resources(m_max_connections == -1 + ? std::numeric_limits::max() + : m_max_connections + , m_torrents + , &torrent::m_connections_quota); + + for (std::map >::iterator i + = m_torrents.begin(); i != m_torrents.end(); ++i) { - m_unchoke_time_scaler = settings().unchoke_interval; - - std::vector peers; - for (connection_map::iterator i = m_connections.begin() - , end(m_connections.end()); i != end; ++i) - { - peer_connection* p = i->second.get(); - torrent* t = p->associated_torrent().lock().get(); - if (!p->peer_info_struct() - || t == 0 - || !p->is_peer_interested() - || p->is_disconnecting() - || p->is_connecting() - || (p->share_diff() < -free_upload_amount - && !t->is_seed())) - { - if (!i->second->is_choked() && t) - { - policy::peer* pi = p->peer_info_struct(); - if (pi && pi->optimistically_unchoked) - { - pi->optimistically_unchoked = false; - // force a new optimistic unchoke - m_optimistic_unchoke_time_scaler = 0; - } - t->choke_peer(*i->second); - } - continue; - } - peers.push_back(i->second.get()); - } - - // sort the peers that are eligible for unchoke by download rate and secondary - // by total upload. The reason for this is, if all torrents are being seeded, - // the download rate will be 0, and the peers we have sent the least to should - // be unchoked - std::sort(peers.begin(), peers.end() - , bind(&stat::total_payload_upload, bind(&peer_connection::statistics, _1)) - < bind(&stat::total_payload_upload, bind(&peer_connection::statistics, _2))); - - std::stable_sort(peers.begin(), peers.end() - , bind(&stat::download_payload_rate, bind(&peer_connection::statistics, _1)) - > bind(&stat::download_payload_rate, bind(&peer_connection::statistics, _2))); - - // reserve one upload slot for optimistic unchokes - int unchoke_set_size = m_max_uploads - 1; - - m_num_unchoked = 0; - // go through all the peers and unchoke the first ones and choke - // all the other ones. - for (std::vector::iterator i = peers.begin() - , end(peers.end()); i != end; ++i) - { - peer_connection* p = *i; - assert(p); - torrent* t = p->associated_torrent().lock().get(); - assert(t); - if (unchoke_set_size > 0) - { - if (p->is_choked()) - { - if (!t->unchoke_peer(*p)) - continue; - } - - --unchoke_set_size; - ++m_num_unchoked; - - assert(p->peer_info_struct()); - if (p->peer_info_struct()->optimistically_unchoked) - { - // force a new optimistic unchoke - m_optimistic_unchoke_time_scaler = 0; - p->peer_info_struct()->optimistically_unchoked = false; - } - } - else - { - assert(p->peer_info_struct()); - if (!p->is_choked() && !p->peer_info_struct()->optimistically_unchoked) - t->choke_peer(*p); - if (!p->is_choked()) - ++m_num_unchoked; - } - } - - m_optimistic_unchoke_time_scaler--; - if (m_optimistic_unchoke_time_scaler <= 0) - { - m_optimistic_unchoke_time_scaler - = settings().optimistic_unchoke_multiplier; - - // find the peer that has been waiting the longest to be optimistically - // unchoked - connection_map::iterator current_optimistic_unchoke = m_connections.end(); - connection_map::iterator optimistic_unchoke_candidate = m_connections.end(); - ptime last_unchoke = max_time(); - - for (connection_map::iterator i = m_connections.begin() - , end(m_connections.end()); i != end; ++i) - { - peer_connection* p = i->second.get(); - assert(p); - policy::peer* pi = p->peer_info_struct(); - if (!pi) continue; - torrent* t = p->associated_torrent().lock().get(); - if (!t) continue; - - if (pi->optimistically_unchoked) - { - assert(!p->is_choked()); - assert(current_optimistic_unchoke == m_connections.end()); - current_optimistic_unchoke = i; - } - - if (pi->last_optimistically_unchoked < last_unchoke - && !p->is_connecting() - && !p->is_disconnecting() - && p->is_peer_interested() - && t->free_upload_slots() - && p->is_choked()) - { - last_unchoke = pi->last_optimistically_unchoked; - optimistic_unchoke_candidate = i; - } - } - - if (optimistic_unchoke_candidate != m_connections.end() - && optimistic_unchoke_candidate != current_optimistic_unchoke) - { - if (current_optimistic_unchoke != m_connections.end()) - { - torrent* t = current_optimistic_unchoke->second->associated_torrent().lock().get(); - assert(t); - current_optimistic_unchoke->second->peer_info_struct()->optimistically_unchoked = false; - t->choke_peer(*current_optimistic_unchoke->second); - } - else - { - ++m_num_unchoked; - } - - torrent* t = optimistic_unchoke_candidate->second->associated_torrent().lock().get(); - assert(t); - bool ret = t->unchoke_peer(*optimistic_unchoke_candidate->second); - assert(ret); - optimistic_unchoke_candidate->second->peer_info_struct()->optimistically_unchoked = true; - } - } - } - - // -------------------------------------------------------------- - // disconnect peers when we have too many - // -------------------------------------------------------------- - --m_disconnect_time_scaler; - if (m_disconnect_time_scaler <= 0) - { - m_disconnect_time_scaler = 60; - - // every 60 seconds, disconnect the worst peer - // if we have reached the connection limit - if (num_connections() >= max_connections() && !m_torrents.empty()) - { - torrent_map::iterator i = std::max_element(m_torrents.begin(), m_torrents.end() - , bind(&torrent::num_peers, bind(&torrent_map::value_type::second, _1)) - < bind(&torrent::num_peers, bind(&torrent_map::value_type::second, _2))); - - assert(i != m_torrents.end()); - i->second->get_policy().disconnect_one_peer(); - } +#ifndef NDEBUG + i->second->check_invariant(); +#endif + i->second->distribute_resources(tick_interval); } } catch (std::exception& exc) @@ -1269,7 +1052,29 @@ namespace detail assert(false); #endif }; // msvc 7.1 seems to require this +/* + void session_impl::connection_completed( + boost::intrusive_ptr const& p) try + { + mutex_t::scoped_lock l(m_mutex); + connection_map::iterator i = m_half_open.find(p->get_socket()); + m_connections.insert(std::make_pair(p->get_socket(), p)); + assert(i != m_half_open.end()); + if (i != m_half_open.end()) m_half_open.erase(i); + + if (m_abort) return; + + process_connection_queue(); + } + catch (std::exception& e) + { +#ifndef NDEBUG + std::cerr << e.what() << std::endl; + assert(false); +#endif + }; +*/ void session_impl::operator()() { eh_initializer(); @@ -1278,6 +1083,10 @@ namespace detail { session_impl::mutex_t::scoped_lock l(m_mutex); open_listen_port(); + if (m_natpmp.get()) + m_natpmp->set_mappings(m_listen_interface.port(), 0); + if (m_upnp.get()) + m_upnp->set_mappings(m_listen_interface.port(), 0); } ptime timer = time_now(); @@ -1347,9 +1156,6 @@ namespace detail } } - // close listen socket - m_listen_socket.reset(); - ptime start(time_now()); l.unlock(); @@ -1469,37 +1275,47 @@ namespace detail } torrent_handle session_impl::add_torrent( - boost::intrusive_ptr ti + torrent_info const& ti , fs::path const& save_path , entry const& resume_data , bool compact_mode - , storage_constructor_type sc - , bool paused - , void* userdata) + , int block_size + , storage_constructor_type sc) { // if you get this assert, you haven't managed to // open a listen port. call listen_on() first. assert(m_external_listen_port > 0); + + // make sure the block_size is an even power of 2 +#ifndef NDEBUG + for (int i = 0; i < 32; ++i) + { + if (block_size & (1 << i)) + { + assert((block_size & ~(1 << i)) == 0); + break; + } + } +#endif + assert(!save_path.empty()); - if (ti->begin_files() == ti->end_files()) + if (ti.begin_files() == ti.end_files()) throw std::runtime_error("no files in torrent"); // lock the session and the checker thread (the order is important!) mutex_t::scoped_lock l(m_mutex); mutex::scoped_lock l2(m_checker_impl.m_mutex); - INVARIANT_CHECK; - if (is_aborted()) throw std::runtime_error("session is closing"); // is the torrent already active? - if (!find_torrent(ti->info_hash()).expired()) + if (!find_torrent(ti.info_hash()).expired()) throw duplicate_torrent(); // is the torrent currently being checked? - if (m_checker_impl.find_torrent(ti->info_hash())) + if (m_checker_impl.find_torrent(ti.info_hash())) throw duplicate_torrent(); // create the torrent and the data associated with @@ -1507,15 +1323,15 @@ namespace detail // the thread boost::shared_ptr torrent_ptr( new torrent(*this, m_checker_impl, ti, save_path - , m_listen_interface, compact_mode, 16 * 1024 - , sc, paused)); + , m_listen_interface, compact_mode, block_size + , settings(), sc)); torrent_ptr->start(); #ifndef TORRENT_DISABLE_EXTENSIONS for (extension_list_t::iterator i = m_extensions.begin() , end(m_extensions.end()); i != end; ++i) { - boost::shared_ptr tp((*i)(torrent_ptr.get(), userdata)); + boost::shared_ptr tp((*i)(torrent_ptr.get())); if (tp) torrent_ptr->add_extension(tp); } #endif @@ -1524,13 +1340,13 @@ namespace detail new aux::piece_checker_data); d->torrent_ptr = torrent_ptr; d->save_path = save_path; - d->info_hash = ti->info_hash(); + d->info_hash = ti.info_hash(); d->resume_data = resume_data; #ifndef TORRENT_DISABLE_DHT if (m_dht) { - torrent_info::nodes_t const& nodes = ti->nodes(); + torrent_info::nodes_t const& nodes = ti.nodes(); std::for_each(nodes.begin(), nodes.end(), bind( (void(dht::dht_tracker::*)(std::pair const&)) &dht::dht_tracker::add_node @@ -1544,7 +1360,7 @@ namespace detail // job in its queue m_checker_impl.m_cond.notify_one(); - return torrent_handle(this, &m_checker_impl, ti->info_hash()); + return torrent_handle(this, &m_checker_impl, ti.info_hash()); } torrent_handle session_impl::add_torrent( @@ -1554,10 +1370,20 @@ namespace detail , fs::path const& save_path , entry const& , bool compact_mode - , storage_constructor_type sc - , bool paused - , void* userdata) + , int block_size + , storage_constructor_type sc) { + // make sure the block_size is an even power of 2 +#ifndef NDEBUG + for (int i = 0; i < 32; ++i) + { + if (block_size & (1 << i)) + { + assert((block_size & ~(1 << i)) == 0); + break; + } + } +#endif // TODO: support resume data in this case assert(!save_path.empty()); @@ -1573,8 +1399,6 @@ namespace detail // lock the session session_impl::mutex_t::scoped_lock l(m_mutex); - INVARIANT_CHECK; - // is the torrent already active? if (!find_torrent(info_hash).expired()) throw duplicate_torrent(); @@ -1587,15 +1411,15 @@ namespace detail // the thread boost::shared_ptr torrent_ptr( new torrent(*this, m_checker_impl, tracker_url, info_hash, name - , save_path, m_listen_interface, compact_mode, 16 * 1024 - , sc, paused)); + , save_path, m_listen_interface, compact_mode, block_size + , settings(), sc)); torrent_ptr->start(); #ifndef TORRENT_DISABLE_EXTENSIONS for (extension_list_t::iterator i = m_extensions.begin() , end(m_extensions.end()); i != end; ++i) { - boost::shared_ptr tp((*i)(torrent_ptr.get(), userdata)); + boost::shared_ptr tp((*i)(torrent_ptr.get())); if (tp) torrent_ptr->add_extension(tp); } #endif @@ -1613,9 +1437,6 @@ namespace detail assert(h.m_ses != 0); mutex_t::scoped_lock l(m_mutex); - - INVARIANT_CHECK; - session_impl::torrent_map::iterator i = m_torrents.find(h.m_info_hash); if (i != m_torrents.end()) @@ -1678,8 +1499,6 @@ namespace detail { session_impl::mutex_t::scoped_lock l(m_mutex); - INVARIANT_CHECK; - tcp::endpoint new_interface; if (net_interface && std::strlen(net_interface) > 0) new_interface = tcp::endpoint(address::from_string(net_interface), port_range.first); @@ -1703,6 +1522,21 @@ namespace detail bool new_listen_address = m_listen_interface.address() != new_interface.address(); + if (new_listen_address) + { + if (m_natpmp.get()) + m_natpmp->rebind(new_interface.address()); + if (m_upnp.get()) + m_upnp->rebind(new_interface.address()); + if (m_lsd.get()) + m_lsd->rebind(new_interface.address()); + } + + if (m_natpmp.get()) + m_natpmp->set_mappings(m_listen_interface.port(), 0); + if (m_upnp.get()) + m_upnp->set_mappings(m_listen_interface.port(), 0); + #ifndef TORRENT_DISABLE_DHT if ((new_listen_address || m_dht_same_port) && m_dht) { @@ -1744,8 +1578,6 @@ namespace detail { mutex_t::scoped_lock l(m_mutex); - INVARIANT_CHECK; - boost::shared_ptr t = find_torrent(ih).lock(); if (!t) return; // don't add peers from lsd to private torrents @@ -1800,9 +1632,6 @@ namespace detail session_status session_impl::status() const { mutex_t::scoped_lock l(m_mutex); - - INVARIANT_CHECK; - session_status s; s.has_incoming_connections = m_incoming_connection; s.num_peers = (int)m_connections.size(); @@ -1844,9 +1673,6 @@ namespace detail void session_impl::start_dht(entry const& startup_state) { mutex_t::scoped_lock l(m_mutex); - - INVARIANT_CHECK; - if (m_dht) { m_dht->stop(); @@ -2006,10 +1832,6 @@ namespace detail { assert(limit > 0 || limit == -1); mutex_t::scoped_lock l(m_mutex); - - INVARIANT_CHECK; - - if (limit <= 0) limit = (std::numeric_limits::max)(); m_max_uploads = limit; } @@ -2017,10 +1839,6 @@ namespace detail { assert(limit > 0 || limit == -1); mutex_t::scoped_lock l(m_mutex); - - INVARIANT_CHECK; - - if (limit <= 0) limit = (std::numeric_limits::max)(); m_max_connections = limit; } @@ -2028,10 +1846,7 @@ namespace detail { assert(limit > 0 || limit == -1); mutex_t::scoped_lock l(m_mutex); - - INVARIANT_CHECK; - - if (limit <= 0) limit = (std::numeric_limits::max)(); + m_half_open.limit(limit); } @@ -2039,10 +1854,7 @@ namespace detail { assert(bytes_per_second > 0 || bytes_per_second == -1); mutex_t::scoped_lock l(m_mutex); - - INVARIANT_CHECK; - - if (bytes_per_second <= 0) bytes_per_second = bandwidth_limit::inf; + if (bytes_per_second == -1) bytes_per_second = bandwidth_limit::inf; m_bandwidth_manager[peer_connection::download_channel]->throttle(bytes_per_second); } @@ -2050,20 +1862,31 @@ namespace detail { assert(bytes_per_second > 0 || bytes_per_second == -1); mutex_t::scoped_lock l(m_mutex); - - INVARIANT_CHECK; - - if (bytes_per_second <= 0) bytes_per_second = bandwidth_limit::inf; + if (bytes_per_second == -1) bytes_per_second = bandwidth_limit::inf; m_bandwidth_manager[peer_connection::upload_channel]->throttle(bytes_per_second); } + int session_impl::num_uploads() const + { + int uploads = 0; + mutex_t::scoped_lock l(m_mutex); + for (torrent_map::const_iterator i = m_torrents.begin() + , end(m_torrents.end()); i != end; i++) + { + uploads += i->second->get_policy().num_uploads(); + } + return uploads; + } + + int session_impl::num_connections() const + { + mutex_t::scoped_lock l(m_mutex); + return m_connections.size(); + } + std::auto_ptr session_impl::pop_alert() { mutex_t::scoped_lock l(m_mutex); - -// too expensive -// INVARIANT_CHECK; - if (m_alerts.pending()) return m_alerts.get(); return std::auto_ptr(0); @@ -2078,26 +1901,20 @@ namespace detail int session_impl::upload_rate_limit() const { mutex_t::scoped_lock l(m_mutex); - - INVARIANT_CHECK; - int ret = m_bandwidth_manager[peer_connection::upload_channel]->throttle(); - return ret == (std::numeric_limits::max)() ? -1 : ret; + return ret == std::numeric_limits::max() ? -1 : ret; } int session_impl::download_rate_limit() const { mutex_t::scoped_lock l(m_mutex); int ret = m_bandwidth_manager[peer_connection::download_channel]->throttle(); - return ret == (std::numeric_limits::max)() ? -1 : ret; + return ret == std::numeric_limits::max() ? -1 : ret; } void session_impl::start_lsd() { mutex_t::scoped_lock l(m_mutex); - - INVARIANT_CHECK; - m_lsd.reset(new lsd(m_io_service , m_listen_interface.address() , bind(&session_impl::on_lsd_peer, this, _1, _2))); @@ -2106,9 +1923,6 @@ namespace detail void session_impl::start_natpmp() { mutex_t::scoped_lock l(m_mutex); - - INVARIANT_CHECK; - m_natpmp.reset(new natpmp(m_io_service , m_listen_interface.address() , bind(&session_impl::on_port_mapping @@ -2124,9 +1938,6 @@ namespace detail void session_impl::start_upnp() { mutex_t::scoped_lock l(m_mutex); - - INVARIANT_CHECK; - m_upnp.reset(new upnp(m_io_service, m_half_open , m_listen_interface.address() , m_settings.user_agent @@ -2164,35 +1975,20 @@ namespace detail #ifndef NDEBUG - void session_impl::check_invariant() const + void session_impl::check_invariant(const char *place) { - assert(m_max_connections > 0); - assert(m_max_uploads > 0); - int unchokes = 0; - int num_optimistic = 0; - for (connection_map::const_iterator i = m_connections.begin(); + assert(place); + for (connection_map::iterator i = m_connections.begin(); i != m_connections.end(); ++i) { assert(i->second); boost::shared_ptr t = i->second->associated_torrent().lock(); - if (!i->second->is_choked()) ++unchokes; - if (i->second->peer_info_struct() - && i->second->peer_info_struct()->optimistically_unchoked) - { - ++num_optimistic; - assert(!i->second->is_choked()); - } - if (t && i->second->peer_info_struct()) + if (t) { assert(t->get_policy().has_connection(boost::get_pointer(i->second))); } } - assert(num_optimistic == 0 || num_optimistic == 1); - if (m_num_unchoked != unchokes) - { - assert(false); - } } #endif @@ -2305,7 +2101,7 @@ namespace detail const std::string& bitmask = (*i)["bitmask"].string(); - const int num_bitmask_bytes = (std::max)(num_blocks_per_piece / 8, 1); + const int num_bitmask_bytes = std::max(num_blocks_per_piece / 8, 1); if ((int)bitmask.size() != num_bitmask_bytes) { error = "invalid size of bitmask (" + boost::lexical_cast(bitmask.size()) + ")"; @@ -2314,7 +2110,7 @@ namespace detail for (int j = 0; j < num_bitmask_bytes; ++j) { unsigned char bits = bitmask[j]; - int num_bits = (std::min)(num_blocks_per_piece - j*8, 8); + int num_bits = std::min(num_blocks_per_piece - j*8, 8); for (int k = 0; k < num_bits; ++k) { const int bit = j * 8 + k; diff --git a/libtorrent/src/socks5_stream.cpp b/libtorrent/src/socks5_stream.cpp index a6b5544e4..b1679c4ac 100644 --- a/libtorrent/src/socks5_stream.cpp +++ b/libtorrent/src/socks5_stream.cpp @@ -33,7 +33,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/pch.hpp" #include "libtorrent/socks5_stream.hpp" -#include "libtorrent/assert.hpp" namespace libtorrent { diff --git a/libtorrent/src/storage.cpp b/libtorrent/src/storage.cpp index dbf6a9382..b23a2e858 100755 --- a/libtorrent/src/storage.cpp +++ b/libtorrent/src/storage.cpp @@ -88,12 +88,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #endif -#if defined(__FreeBSD__) -// for statfs() -#include -#include -#endif - #if defined(_WIN32) && defined(UNICODE) #include @@ -253,8 +247,8 @@ namespace libtorrent { p = complete(p); std::vector > sizes; - for (torrent_info::file_iterator i = t.begin_files(true); - i != t.end_files(true); ++i) + for (torrent_info::file_iterator i = t.begin_files(); + i != t.end_files(); ++i) { size_type size = 0; std::time_t time = 0; @@ -293,7 +287,7 @@ namespace libtorrent , bool compact_mode , std::string* error) { - if ((int)sizes.size() != t.num_files(true)) + if ((int)sizes.size() != t.num_files()) { if (error) *error = "mismatching number of files"; return false; @@ -302,8 +296,8 @@ namespace libtorrent std::vector >::const_iterator s = sizes.begin(); - for (torrent_info::file_iterator i = t.begin_files(true); - i != t.end_files(true); ++i, ++s) + for (torrent_info::file_iterator i = t.begin_files(); + i != t.end_files(); ++i, ++s) { size_type size = 0; std::time_t time = 0; @@ -348,14 +342,50 @@ namespace libtorrent return true; } - class storage : public storage_interface, boost::noncopyable + struct thread_safe_storage + { + thread_safe_storage(std::size_t n) + : slots(n, false) + {} + + boost::mutex mutex; + boost::condition condition; + std::vector slots; + }; + + struct slot_lock + { + slot_lock(thread_safe_storage& s, int slot_) + : storage_(s) + , slot(slot_) + { + assert(slot_>=0 && slot_ < (int)s.slots.size()); + boost::mutex::scoped_lock lock(storage_.mutex); + + while (storage_.slots[slot]) + storage_.condition.wait(lock); + storage_.slots[slot] = true; + } + + ~slot_lock() + { + storage_.slots[slot] = false; + storage_.condition.notify_all(); + } + + thread_safe_storage& storage_; + int slot; + }; + + class storage : public storage_interface, thread_safe_storage, boost::noncopyable { public: - storage(boost::intrusive_ptr info, fs::path const& path, file_pool& fp) - : m_info(info) + storage(torrent_info const& info, fs::path const& path, file_pool& fp) + : thread_safe_storage(info.num_pieces()) + , m_info(info) , m_files(fp) { - assert(info->begin_files(true) != info->end_files(true)); + assert(info.begin_files() != info.end_files()); m_save_path = fs::complete(path); assert(m_save_path.is_complete()); } @@ -375,9 +405,11 @@ namespace libtorrent size_type read_impl(char* buf, int slot, int offset, int size, bool fill_zero); ~storage() - { m_files.release(this); } + { + m_files.release(this); + } - boost::intrusive_ptr m_info; + torrent_info const& m_info; fs::path m_save_path; // the file pool is typically stored in // the session, to make all storage @@ -403,27 +435,21 @@ namespace libtorrent assert(ph.offset == 0 || partial_copy.final() == partial.final()); #endif int slot_size = piece_size - ph.offset; - if (slot_size > 0) - { - m_scratch_buffer.resize(slot_size); - read_impl(&m_scratch_buffer[0], slot, ph.offset, slot_size, true); - ph.h.update(&m_scratch_buffer[0], slot_size); - } -#ifndef NDEBUG + if (slot_size == 0) return ph.h.final(); + m_scratch_buffer.resize(slot_size); + read_impl(&m_scratch_buffer[0], slot, ph.offset, slot_size, true); + ph.h.update(&m_scratch_buffer[0], slot_size); sha1_hash ret = ph.h.final(); - assert(ret == whole.final()); + assert(whole.final() == ret); return ret; -#else - return ph.h.final(); -#endif } void storage::initialize(bool allocate_files) { // first, create all missing directories fs::path last_path; - for (torrent_info::file_iterator file_iter = m_info->begin_files(true), - end_iter = m_info->end_files(true); file_iter != end_iter; ++file_iter) + for (torrent_info::file_iterator file_iter = m_info.begin_files(), + end_iter = m_info.end_files(); file_iter != end_iter; ++file_iter) { fs::path dir = (m_save_path / file_iter->path).branch_path(); @@ -471,7 +497,7 @@ namespace libtorrent void storage::write_resume_data(entry& rd) const { std::vector > file_sizes - = get_filesizes(*m_info, m_save_path); + = get_filesizes(m_info, m_save_path); rd["file sizes"] = entry::list_type(); entry::list_type& fl = rd["file sizes"].list(); @@ -505,7 +531,7 @@ namespace libtorrent } entry::list_type& slots = rd["slots"].list(); - bool seed = int(slots.size()) == m_info->num_pieces() + bool seed = int(slots.size()) == m_info.num_pieces() && std::find_if(slots.begin(), slots.end() , boost::bind(std::less() , boost::bind((size_type const& (entry::*)() const) @@ -520,11 +546,11 @@ namespace libtorrent if (seed) { - if (m_info->num_files(true) != (int)file_sizes.size()) + if (m_info.num_files() != (int)file_sizes.size()) { error = "the number of files does not match the torrent (num: " + boost::lexical_cast(file_sizes.size()) + " actual: " - + boost::lexical_cast(m_info->num_files(true)) + ")"; + + boost::lexical_cast(m_info.num_files()) + ")"; return false; } @@ -532,8 +558,8 @@ namespace libtorrent fs = file_sizes.begin(); // the resume data says we have the entire torrent // make sure the file sizes are the right ones - for (torrent_info::file_iterator i = m_info->begin_files(true) - , end(m_info->end_files(true)); i != end; ++i, ++fs) + for (torrent_info::file_iterator i = m_info.begin_files() + , end(m_info.end_files()); i != end; ++i, ++fs) { if (i->size != fs->first) { @@ -546,7 +572,7 @@ namespace libtorrent return true; } - return match_filesizes(*m_info, m_save_path, file_sizes + return match_filesizes(m_info, m_save_path, file_sizes , !full_allocation_mode, &error); } @@ -585,11 +611,11 @@ namespace libtorrent m_files.release(this); #if defined(_WIN32) && defined(UNICODE) && BOOST_VERSION >= 103400 - old_path = safe_convert((m_save_path / m_info->name()).string()); - new_path = safe_convert((save_path / m_info->name()).string()); + old_path = safe_convert((m_save_path / m_info.name()).string()); + new_path = safe_convert((save_path / m_info.name()).string()); #else - old_path = m_save_path / m_info->name(); - new_path = save_path / m_info->name(); + old_path = m_save_path / m_info.name(); + new_path = save_path / m_info.name(); #endif try @@ -611,7 +637,7 @@ namespace libtorrent /* void storage::shuffle() { - int num_pieces = m_info->num_pieces(); + int num_pieces = m_info.num_pieces(); std::vector pieces(num_pieces); for (std::vector::iterator i = pieces.begin(); @@ -628,7 +654,7 @@ namespace libtorrent { const int slot_index = targets[i]; const int piece_index = pieces[i]; - const int slot_size =static_cast(m_info->piece_size(slot_index)); + const int slot_size =static_cast(m_info.piece_size(slot_index)); std::vector buf(slot_size); read(&buf[0], piece_index, 0, slot_size); write(&buf[0], slot_index, 0, slot_size); @@ -639,7 +665,7 @@ namespace libtorrent void storage::move_slot(int src_slot, int dst_slot) { - int piece_size = m_info->piece_size(dst_slot); + int piece_size = m_info.piece_size(dst_slot); m_scratch_buffer.resize(piece_size); read_impl(&m_scratch_buffer[0], src_slot, 0, piece_size, true); write(&m_scratch_buffer[0], dst_slot, 0, piece_size); @@ -648,9 +674,9 @@ namespace libtorrent void storage::swap_slots(int slot1, int slot2) { // the size of the target slot is the size of the piece - int piece_size = m_info->piece_length(); - int piece1_size = m_info->piece_size(slot2); - int piece2_size = m_info->piece_size(slot1); + int piece_size = m_info.piece_length(); + int piece1_size = m_info.piece_size(slot2); + int piece2_size = m_info.piece_size(slot1); m_scratch_buffer.resize(piece_size * 2); read_impl(&m_scratch_buffer[0], slot1, 0, piece1_size, true); read_impl(&m_scratch_buffer[piece_size], slot2, 0, piece2_size, true); @@ -661,10 +687,10 @@ namespace libtorrent void storage::swap_slots3(int slot1, int slot2, int slot3) { // the size of the target slot is the size of the piece - int piece_size = m_info->piece_length(); - int piece1_size = m_info->piece_size(slot2); - int piece2_size = m_info->piece_size(slot3); - int piece3_size = m_info->piece_size(slot1); + int piece_size = m_info.piece_length(); + int piece1_size = m_info.piece_size(slot2); + int piece2_size = m_info.piece_size(slot3); + int piece3_size = m_info.piece_size(slot1); m_scratch_buffer.resize(piece_size * 2); read_impl(&m_scratch_buffer[0], slot1, 0, piece1_size, true); read_impl(&m_scratch_buffer[piece_size], slot2, 0, piece2_size, true); @@ -691,25 +717,27 @@ namespace libtorrent , bool fill_zero) { assert(buf != 0); - assert(slot >= 0 && slot < m_info->num_pieces()); + assert(slot >= 0 && slot < m_info.num_pieces()); assert(offset >= 0); - assert(offset < m_info->piece_size(slot)); + assert(offset < m_info.piece_size(slot)); assert(size > 0); + slot_lock lock(*this, slot); + #ifndef NDEBUG std::vector slices - = m_info->map_block(slot, offset, size, true); + = m_info.map_block(slot, offset, size); assert(!slices.empty()); #endif - size_type start = slot * (size_type)m_info->piece_length() + offset; - assert(start + size <= m_info->total_size()); + size_type start = slot * (size_type)m_info.piece_length() + offset; + assert(start + size <= m_info.total_size()); // find the file iterator and file offset size_type file_offset = start; std::vector::const_iterator file_iter; - for (file_iter = m_info->begin_files(true);;) + for (file_iter = m_info.begin_files();;) { if (file_offset < file_iter->size) break; @@ -742,7 +770,7 @@ namespace libtorrent #endif int left_to_read = size; - int slot_size = static_cast(m_info->piece_size(slot)); + int slot_size = static_cast(m_info.piece_size(slot)); if (offset + left_to_read > slot_size) left_to_read = slot_size - offset; @@ -767,7 +795,7 @@ namespace libtorrent assert(int(slices.size()) > counter); size_type slice_size = slices[counter].size; assert(slice_size == read_bytes); - assert(m_info->file_at(slices[counter].file_index, true).path + assert(m_info.file_at(slices[counter].file_index).path == file_iter->path); #endif @@ -817,30 +845,32 @@ namespace libtorrent { assert(buf != 0); assert(slot >= 0); - assert(slot < m_info->num_pieces()); + assert(slot < m_info.num_pieces()); assert(offset >= 0); assert(size > 0); + slot_lock lock(*this, slot); + #ifndef NDEBUG std::vector slices - = m_info->map_block(slot, offset, size, true); + = m_info.map_block(slot, offset, size); assert(!slices.empty()); #endif - size_type start = slot * (size_type)m_info->piece_length() + offset; + size_type start = slot * (size_type)m_info.piece_length() + offset; // find the file iterator and file offset size_type file_offset = start; std::vector::const_iterator file_iter; - for (file_iter = m_info->begin_files(true);;) + for (file_iter = m_info.begin_files();;) { if (file_offset < file_iter->size) break; file_offset -= file_iter->size; ++file_iter; - assert(file_iter != m_info->end_files(true)); + assert(file_iter != m_info.end_files()); } fs::path p(m_save_path / file_iter->path); @@ -860,7 +890,7 @@ namespace libtorrent } int left_to_write = size; - int slot_size = static_cast(m_info->piece_size(slot)); + int slot_size = static_cast(m_info.piece_size(slot)); if (offset + left_to_write > slot_size) left_to_write = slot_size - offset; @@ -884,7 +914,7 @@ namespace libtorrent { assert(int(slices.size()) > counter); assert(slices[counter].size == write_bytes); - assert(m_info->file_at(slices[counter].file_index, true).path + assert(m_info.file_at(slices[counter].file_index).path == file_iter->path); assert(buf_pos >= 0); @@ -912,7 +942,7 @@ namespace libtorrent #endif ++file_iter; - assert(file_iter != m_info->end_files(true)); + assert(file_iter != m_info.end_files()); fs::path p = m_save_path / file_iter->path; file_offset = 0; out = m_files.open_file( @@ -923,7 +953,7 @@ namespace libtorrent } } - storage_interface* default_storage_constructor(boost::intrusive_ptr ti + storage_interface* default_storage_constructor(torrent_info const& ti , fs::path const& path, file_pool& fp) { return new storage(ti, path, fp); @@ -1002,6 +1032,9 @@ namespace libtorrent int err = statfs(query_path.native_directory_string().c_str(), &buf); if (err == 0) { +#ifndef NDEBUG + std::cerr << "buf.f_type " << std::hex << buf.f_type << std::endl; +#endif switch (buf.f_type) { case 0x5346544e: // NTFS @@ -1034,7 +1067,7 @@ namespace libtorrent piece_manager::piece_manager( boost::shared_ptr const& torrent - , boost::intrusive_ptr ti + , torrent_info const& ti , fs::path const& save_path , file_pool& fp , disk_io_thread& io @@ -1044,7 +1077,7 @@ namespace libtorrent , m_fill_mode(true) , m_info(ti) , m_save_path(complete(save_path)) - , m_storage_constructor(sc) + , m_allocating(false) , m_io_thread(io) , m_torrent(torrent) { @@ -1086,9 +1119,7 @@ namespace libtorrent void piece_manager::async_read( peer_request const& r - , boost::function const& handler - , char* buffer - , int priority) + , boost::function const& handler) { disk_io_job j; j.storage = this; @@ -1096,11 +1127,7 @@ namespace libtorrent j.piece = r.piece; j.offset = r.start; j.buffer_size = r.length; - j.buffer = buffer; - j.priority = priority; - // if a buffer is not specified, only one block can be read - // since that is the size of the pool allocator's buffers - assert(r.length <= 16 * 1024 || buffer != 0); + assert(r.length <= 16 * 1024); m_io_thread.add_job(j, handler); } @@ -1153,7 +1180,7 @@ namespace libtorrent int slot = m_piece_to_slot[piece]; assert(slot != has_no_slot); - return m_storage->hash_for_slot(slot, ph, m_info->piece_size(piece)); + return m_storage->hash_for_slot(slot, ph, m_info.piece_size(piece)); } void piece_manager::release_files_impl() @@ -1213,7 +1240,7 @@ namespace libtorrent int piece_manager::slot_for_piece(int piece_index) const { - assert(piece_index >= 0 && piece_index < m_info->num_pieces()); + assert(piece_index >= 0 && piece_index < m_info.num_pieces()); return m_piece_to_slot[piece_index]; } @@ -1224,13 +1251,13 @@ namespace libtorrent try { assert(slot_index >= 0); - assert(slot_index < m_info->num_pieces()); + assert(slot_index < m_info.num_pieces()); assert(block_size > 0); adler32_crc crc; std::vector buf(block_size); - int num_blocks = static_cast(m_info->piece_size(slot_index)) / block_size; - int last_block_size = static_cast(m_info->piece_size(slot_index)) % block_size; + int num_blocks = static_cast(m_info.piece_size(slot_index)) / block_size; + int last_block_size = static_cast(m_info.piece_size(slot_index)) % block_size; if (last_block_size == 0) last_block_size = block_size; for (int i = 0; i < num_blocks-1; ++i) @@ -1300,7 +1327,6 @@ namespace libtorrent if (i != m_piece_hasher.end()) { assert(i->second.offset > 0); - assert(offset >= i->second.offset); if (offset == i->second.offset) { i->second.offset += size; @@ -1324,11 +1350,11 @@ namespace libtorrent { // INVARIANT_CHECK; - assert((int)have_pieces.size() == m_info->num_pieces()); + assert((int)have_pieces.size() == m_info.num_pieces()); - const int piece_size = static_cast(m_info->piece_length()); - const int last_piece_size = static_cast(m_info->piece_size( - m_info->num_pieces() - 1)); + const int piece_size = static_cast(m_info.piece_length()); + const int last_piece_size = static_cast(m_info.piece_size( + m_info.num_pieces() - 1)); assert((int)piece_data.size() >= last_piece_size); @@ -1484,7 +1510,7 @@ namespace libtorrent INVARIANT_CHECK; - assert(m_info->piece_length() > 0); + assert(m_info.piece_length() > 0); m_compact_mode = compact_mode; @@ -1494,13 +1520,13 @@ namespace libtorrent // by check_pieces. // m_storage->shuffle(); - m_piece_to_slot.resize(m_info->num_pieces(), has_no_slot); - m_slot_to_piece.resize(m_info->num_pieces(), unallocated); + m_piece_to_slot.resize(m_info.num_pieces(), has_no_slot); + m_slot_to_piece.resize(m_info.num_pieces(), unallocated); m_free_slots.clear(); m_unallocated_slots.clear(); pieces.clear(); - pieces.resize(m_info->num_pieces(), false); + pieces.resize(m_info.num_pieces(), false); num_pieces = 0; // if we have fast-resume info @@ -1605,7 +1631,7 @@ namespace libtorrent return std::make_pair(false, 1.f); } - if (int(m_unallocated_slots.size()) == m_info->num_pieces() + if (int(m_unallocated_slots.size()) == m_info.num_pieces() && !m_fill_mode) { // if there is not a single file on disk, just @@ -1647,8 +1673,8 @@ namespace libtorrent assert(!m_fill_mode); std::vector().swap(m_unallocated_slots); std::fill(m_slot_to_piece.begin(), m_slot_to_piece.end(), int(unassigned)); - m_free_slots.resize(m_info->num_pieces()); - for (int i = 0; i < m_info->num_pieces(); ++i) + m_free_slots.resize(m_info.num_pieces()); + for (int i = 0; i < m_info.num_pieces(); ++i) m_free_slots[i] = i; } @@ -1668,15 +1694,15 @@ namespace libtorrent if (m_hash_to_piece.empty()) { m_current_slot = 0; - for (int i = 0; i < m_info->num_pieces(); ++i) + for (int i = 0; i < m_info.num_pieces(); ++i) { - m_hash_to_piece.insert(std::make_pair(m_info->hash_for_piece(i), i)); + m_hash_to_piece.insert(std::make_pair(m_info.hash_for_piece(i), i)); } std::fill(pieces.begin(), pieces.end(), false); } - m_piece_data.resize(int(m_info->piece_length())); - int piece_size = int(m_info->piece_size(m_current_slot)); + m_piece_data.resize(int(m_info.piece_length())); + int piece_size = int(m_info.piece_size(m_current_slot)); int num_read = m_storage->read(&m_piece_data[0] , m_current_slot, 0, piece_size); @@ -1879,9 +1905,9 @@ namespace libtorrent { // find the file that failed, and skip all the blocks in that file size_type file_offset = 0; - size_type current_offset = m_current_slot * m_info->piece_length(); - for (torrent_info::file_iterator i = m_info->begin_files(true); - i != m_info->end_files(true); ++i) + size_type current_offset = m_current_slot * m_info.piece_length(); + for (torrent_info::file_iterator i = m_info.begin_files(); + i != m_info.end_files(); ++i) { file_offset += i->size; if (file_offset > current_offset) break; @@ -1889,8 +1915,8 @@ namespace libtorrent assert(file_offset > current_offset); int skip_blocks = static_cast( - (file_offset - current_offset + m_info->piece_length() - 1) - / m_info->piece_length()); + (file_offset - current_offset + m_info.piece_length() - 1) + / m_info.piece_length()); for (int i = m_current_slot; i < m_current_slot + skip_blocks; ++i) { @@ -1903,9 +1929,9 @@ namespace libtorrent } ++m_current_slot; - if (m_current_slot >= m_info->num_pieces()) + if (m_current_slot >= m_info.num_pieces()) { - assert(m_current_slot == m_info->num_pieces()); + assert(m_current_slot == m_info.num_pieces()); // clear the memory we've been using std::vector().swap(m_piece_data); @@ -1917,7 +1943,7 @@ namespace libtorrent assert(num_pieces == std::count(pieces.begin(), pieces.end(), true)); - return std::make_pair(false, (float)m_current_slot / m_info->num_pieces()); + return std::make_pair(false, (float)m_current_slot / m_info.num_pieces()); } int piece_manager::allocate_slot_for_piece(int piece_index) @@ -1959,7 +1985,7 @@ namespace libtorrent // special case to make sure we don't use the last slot // when we shouldn't, since it's smaller than ordinary slots - if (*iter == m_info->num_pieces() - 1 && piece_index != *iter) + if (*iter == m_info.num_pieces() - 1 && piece_index != *iter) { if (m_free_slots.size() == 1) allocate_slots(1); @@ -2064,13 +2090,13 @@ namespace libtorrent } else if (m_fill_mode) { - int piece_size = int(m_info->piece_size(pos)); + int piece_size = int(m_info.piece_size(pos)); int offset = 0; for (; piece_size > 0; piece_size -= stack_buffer_size , offset += stack_buffer_size) { m_storage->write(zeroes, pos, offset - , (std::min)(piece_size, stack_buffer_size)); + , std::min(piece_size, stack_buffer_size)); } written = true; } @@ -2090,8 +2116,8 @@ namespace libtorrent boost::recursive_mutex::scoped_lock lock(m_mutex); if (m_piece_to_slot.empty()) return; - assert((int)m_piece_to_slot.size() == m_info->num_pieces()); - assert((int)m_slot_to_piece.size() == m_info->num_pieces()); + assert((int)m_piece_to_slot.size() == m_info.num_pieces()); + assert((int)m_slot_to_piece.size() == m_info.num_pieces()); for (std::vector::const_iterator i = m_free_slots.begin(); i != m_free_slots.end(); ++i) @@ -2113,7 +2139,7 @@ namespace libtorrent == m_unallocated_slots.end()); } - for (int i = 0; i < m_info->num_pieces(); ++i) + for (int i = 0; i < m_info.num_pieces(); ++i) { // Check domain of piece_to_slot's elements if (m_piece_to_slot[i] != has_no_slot) @@ -2201,7 +2227,7 @@ namespace libtorrent s << "index\tslot\tpiece\n"; - for (int i = 0; i < m_info->num_pieces(); ++i) + for (int i = 0; i < m_info.num_pieces(); ++i) { s << i << "\t" << m_slot_to_piece[i] << "\t"; s << m_piece_to_slot[i] << "\n"; diff --git a/libtorrent/src/torrent.cpp b/libtorrent/src/torrent.cpp index 252461bc6..13309c1e7 100755 --- a/libtorrent/src/torrent.cpp +++ b/libtorrent/src/torrent.cpp @@ -72,7 +72,6 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/extensions.hpp" #include "libtorrent/aux_/session_impl.hpp" #include "libtorrent/instantiate_connection.hpp" -#include "libtorrent/assert.hpp" using namespace libtorrent; using boost::tuples::tuple; @@ -151,16 +150,16 @@ namespace libtorrent torrent::torrent( session_impl& ses , aux::checker_impl& checker - , boost::intrusive_ptr tf + , torrent_info const& tf , fs::path const& save_path , tcp::endpoint const& net_interface , bool compact_mode , int block_size - , storage_constructor_type sc - , bool paused) + , session_settings const& s + , storage_constructor_type sc) : m_torrent_file(tf) , m_abort(false) - , m_paused(paused) + , m_paused(false) , m_just_paused(false) , m_event(tracker_request::started) , m_block_size(0) @@ -182,7 +181,7 @@ namespace libtorrent , m_ses(ses) , m_checker(checker) , m_picker(0) - , m_trackers(m_torrent_file->trackers()) + , m_trackers(m_torrent_file.trackers()) , m_last_working_tracker(-1) , m_currently_trying_tracker(0) , m_failed_trackers(0) @@ -198,15 +197,24 @@ namespace libtorrent , m_compact_mode(compact_mode) , m_default_block_size(block_size) , m_connections_initialized(true) - , m_settings(ses.settings()) + , m_settings(s) , m_storage_constructor(sc) - , m_max_uploads((std::numeric_limits::max)()) - , m_num_uploads(0) - , m_max_connections((std::numeric_limits::max)()) { +#ifndef NDEBUG + m_initial_done = 0; +#endif + + m_uploads_quota.min = 0; + m_connections_quota.min = 2; + // this will be corrected the next time the main session + // distributes resources, i.e. on average in 0.5 seconds + m_connections_quota.given = 100; + m_uploads_quota.max = std::numeric_limits::max(); + m_connections_quota.max = std::numeric_limits::max(); m_policy.reset(new policy(this)); } + torrent::torrent( session_impl& ses , aux::checker_impl& checker @@ -217,11 +225,11 @@ namespace libtorrent , tcp::endpoint const& net_interface , bool compact_mode , int block_size - , storage_constructor_type sc - , bool paused) - : m_torrent_file(new torrent_info(info_hash)) + , session_settings const& s + , storage_constructor_type sc) + : m_torrent_file(info_hash) , m_abort(false) - , m_paused(paused) + , m_paused(false) , m_just_paused(false) , m_event(tracker_request::started) , m_block_size(0) @@ -258,20 +266,28 @@ namespace libtorrent , m_compact_mode(compact_mode) , m_default_block_size(block_size) , m_connections_initialized(false) - , m_settings(ses.settings()) + , m_settings(s) , m_storage_constructor(sc) - , m_max_uploads((std::numeric_limits::max)()) - , m_num_uploads(0) - , m_max_connections((std::numeric_limits::max)()) { +#ifndef NDEBUG + m_initial_done = 0; +#endif + INVARIANT_CHECK; if (name) m_name.reset(new std::string(name)); + m_uploads_quota.min = 0; + m_connections_quota.min = 2; + // this will be corrected the next time the main session + // distributes resources, i.e. on average in 0.5 seconds + m_connections_quota.given = 100; + m_uploads_quota.max = std::numeric_limits::max(); + m_connections_quota.max = std::numeric_limits::max(); if (tracker_url) { m_trackers.push_back(announce_entry(tracker_url)); - m_torrent_file->add_tracker(tracker_url); + m_torrent_file.add_tracker(tracker_url); } m_policy.reset(new policy(this)); @@ -280,7 +296,7 @@ namespace libtorrent void torrent::start() { boost::weak_ptr self(shared_from_this()); - if (m_torrent_file->is_valid()) init(); + if (m_torrent_file.is_valid()) init(); m_announce_timer.expires_from_now(seconds(1)); m_announce_timer.async_wait(m_ses.m_strand.wrap( bind(&torrent::on_announce_disp, self, _1))); @@ -290,7 +306,7 @@ namespace libtorrent bool torrent::should_announce_dht() const { // don't announce private torrents - if (m_torrent_file->is_valid() && m_torrent_file->priv()) return false; + if (m_torrent_file.is_valid() && m_torrent_file.priv()) return false; if (m_trackers.empty()) return true; @@ -313,14 +329,6 @@ namespace libtorrent INVARIANT_CHECK; -#if defined(TORRENT_VERBOSE_LOGGING) - for (peer_iterator i = m_connections.begin(); - i != m_connections.end(); ++i) - { - (*i->second->m_logger) << "*** DESTRUCTING TORRENT\n"; - } -#endif - assert(m_abort); if (!m_connections.empty()) disconnect_all(); @@ -328,7 +336,7 @@ namespace libtorrent std::string torrent::name() const { - if (valid_metadata()) return m_torrent_file->name(); + if (valid_metadata()) return m_torrent_file.name(); if (m_name) return *m_name; return ""; } @@ -344,22 +352,22 @@ namespace libtorrent // shared_from_this() void torrent::init() { - assert(m_torrent_file->is_valid()); - assert(m_torrent_file->num_files() > 0); - assert(m_torrent_file->total_size() >= 0); + assert(m_torrent_file.is_valid()); + assert(m_torrent_file.num_files() > 0); + assert(m_torrent_file.total_size() >= 0); - m_have_pieces.resize(m_torrent_file->num_pieces(), false); + m_have_pieces.resize(m_torrent_file.num_pieces(), false); // the shared_from_this() will create an intentional // cycle of ownership, se the hpp file for description. m_owning_storage = new piece_manager(shared_from_this(), m_torrent_file , m_save_path, m_ses.m_files, m_ses.m_disk_thread, m_storage_constructor); m_storage = m_owning_storage.get(); - m_block_size = calculate_block_size(*m_torrent_file, m_default_block_size); + m_block_size = calculate_block_size(m_torrent_file, m_default_block_size); m_picker.reset(new piece_picker( - static_cast(m_torrent_file->piece_length() / m_block_size) - , static_cast((m_torrent_file->total_size()+m_block_size-1)/m_block_size))); + static_cast(m_torrent_file.piece_length() / m_block_size) + , static_cast((m_torrent_file.total_size()+m_block_size-1)/m_block_size))); - std::vector const& url_seeds = m_torrent_file->url_seeds(); + std::vector const& url_seeds = m_torrent_file.url_seeds(); std::copy(url_seeds.begin(), url_seeds.end(), std::inserter(m_web_seeds , m_web_seeds.begin())); } @@ -387,7 +395,7 @@ namespace libtorrent { boost::weak_ptr self(shared_from_this()); - if (!m_torrent_file->priv()) + if (!m_torrent_file.priv()) { // announce on local network every 5 minutes m_announce_timer.expires_from_now(minutes(5)); @@ -395,7 +403,7 @@ namespace libtorrent bind(&torrent::on_announce_disp, self, _1))); // announce with the local discovery service - m_ses.announce_lsd(m_torrent_file->info_hash()); + m_ses.announce_lsd(m_torrent_file.info_hash()); } else { @@ -413,7 +421,7 @@ namespace libtorrent // TODO: There should be a way to abort an announce operation on the dht. // when the torrent is destructed assert(m_ses.m_external_listen_port > 0); - m_ses.m_dht->announce(m_torrent_file->info_hash() + m_ses.m_dht->announce(m_torrent_file.info_hash() , m_ses.m_external_listen_port , m_ses.m_strand.wrap(bind(&torrent::on_dht_announce_response_disp, self, _1))); } @@ -459,7 +467,7 @@ namespace libtorrent { INVARIANT_CHECK; - if (m_torrent_file->trackers().empty()) return false; + if (m_torrent_file.trackers().empty()) return false; if (m_just_paused) { @@ -609,7 +617,7 @@ namespace libtorrent // if we don't have the metadata yet, we // cannot tell how big the torrent is. if (!valid_metadata()) return -1; - return m_torrent_file->total_size() + return m_torrent_file.total_size() - quantized_bytes_done(); } @@ -619,23 +627,23 @@ namespace libtorrent if (!valid_metadata()) return 0; - if (m_torrent_file->num_pieces() == 0) + if (m_torrent_file.num_pieces() == 0) return 0; - if (is_seed()) return m_torrent_file->total_size(); + if (is_seed()) return m_torrent_file.total_size(); - const int last_piece = m_torrent_file->num_pieces() - 1; + const int last_piece = m_torrent_file.num_pieces() - 1; size_type total_done - = m_num_pieces * m_torrent_file->piece_length(); + = m_num_pieces * m_torrent_file.piece_length(); // if we have the last piece, we have to correct // the amount we have, since the first calculation // assumed all pieces were of equal size if (m_have_pieces[last_piece]) { - int corr = m_torrent_file->piece_size(last_piece) - - m_torrent_file->piece_length(); + int corr = m_torrent_file.piece_size(last_piece) + - m_torrent_file.piece_length(); total_done += corr; } return total_done; @@ -648,42 +656,42 @@ namespace libtorrent { INVARIANT_CHECK; - if (!valid_metadata() || m_torrent_file->num_pieces() == 0) + if (!valid_metadata() || m_torrent_file.num_pieces() == 0) return tuple(0,0); - const int last_piece = m_torrent_file->num_pieces() - 1; + const int last_piece = m_torrent_file.num_pieces() - 1; if (is_seed()) - return make_tuple(m_torrent_file->total_size() - , m_torrent_file->total_size()); + return make_tuple(m_torrent_file.total_size() + , m_torrent_file.total_size()); size_type wanted_done = (m_num_pieces - m_picker->num_have_filtered()) - * m_torrent_file->piece_length(); + * m_torrent_file.piece_length(); size_type total_done - = m_num_pieces * m_torrent_file->piece_length(); - assert(m_num_pieces < m_torrent_file->num_pieces()); + = m_num_pieces * m_torrent_file.piece_length(); + assert(m_num_pieces < m_torrent_file.num_pieces()); // if we have the last piece, we have to correct // the amount we have, since the first calculation // assumed all pieces were of equal size if (m_have_pieces[last_piece]) { - int corr = m_torrent_file->piece_size(last_piece) - - m_torrent_file->piece_length(); + int corr = m_torrent_file.piece_size(last_piece) + - m_torrent_file.piece_length(); total_done += corr; if (m_picker->piece_priority(last_piece) != 0) wanted_done += corr; } - assert(total_done <= m_torrent_file->total_size()); - assert(wanted_done <= m_torrent_file->total_size()); + assert(total_done <= m_torrent_file.total_size()); + assert(wanted_done <= m_torrent_file.total_size()); const std::vector& dl_queue = m_picker->get_download_queue(); const int blocks_per_piece = static_cast( - m_torrent_file->piece_length() / m_block_size); + m_torrent_file.piece_length() / m_block_size); for (std::vector::const_iterator i = dl_queue.begin(); i != dl_queue.end(); ++i) @@ -716,15 +724,15 @@ namespace libtorrent == piece_picker::block_info::state_finished) { corr -= m_block_size; - corr += m_torrent_file->piece_size(last_piece) % m_block_size; + corr += m_torrent_file.piece_size(last_piece) % m_block_size; } total_done += corr; if (m_picker->piece_priority(index) != 0) wanted_done += corr; } - assert(total_done <= m_torrent_file->total_size()); - assert(wanted_done <= m_torrent_file->total_size()); + assert(total_done <= m_torrent_file.total_size()); + assert(wanted_done <= m_torrent_file.total_size()); std::map downloading_piece; for (const_peer_iterator i = begin(); i != end(); ++i) @@ -754,10 +762,10 @@ namespace libtorrent } #ifndef NDEBUG assert(p->bytes_downloaded <= p->full_block_bytes); - int last_piece = m_torrent_file->num_pieces() - 1; + int last_piece = m_torrent_file.num_pieces() - 1; if (p->piece_index == last_piece - && p->block_index == m_torrent_file->piece_size(last_piece) / block_size()) - assert(p->full_block_bytes == m_torrent_file->piece_size(last_piece) % block_size()); + && p->block_index == m_torrent_file.piece_size(last_piece) / block_size()) + assert(p->full_block_bytes == m_torrent_file.piece_size(last_piece) % block_size()); else assert(p->full_block_bytes == block_size()); #endif @@ -773,7 +781,7 @@ namespace libtorrent #ifndef NDEBUG - if (total_done >= m_torrent_file->total_size()) + if (total_done >= m_torrent_file.total_size()) { std::copy(m_have_pieces.begin(), m_have_pieces.end() , std::ostream_iterator(std::cerr, " ")); @@ -804,8 +812,8 @@ namespace libtorrent } - assert(total_done <= m_torrent_file->total_size()); - assert(wanted_done <= m_torrent_file->total_size()); + assert(total_done <= m_torrent_file.total_size()); + assert(wanted_done <= m_torrent_file.total_size()); #endif @@ -902,14 +910,14 @@ namespace libtorrent // think that it has received all of it until this function // resets the download queue. So, we cannot do the // invariant check here since it assumes: - // (total_done == m_torrent_file->total_size()) => is_seed() + // (total_done == m_torrent_file.total_size()) => is_seed() // INVARIANT_CHECK; assert(m_storage); assert(m_storage->refcount() > 0); assert(m_picker.get()); assert(index >= 0); - assert(index < m_torrent_file->num_pieces()); + assert(index < m_torrent_file.num_pieces()); if (m_ses.m_alerts.should_post(alert::info)) { @@ -918,7 +926,7 @@ namespace libtorrent m_ses.m_alerts.post_alert(hash_failed_alert(get_handle(), index, s.str())); } // increase the total amount of failed bytes - m_total_failed_bytes += m_torrent_file->piece_size(index); + m_total_failed_bytes += m_torrent_file.piece_size(index); std::vector downloaders; m_picker->get_downloaders(downloaders, index); @@ -1012,15 +1020,6 @@ namespace libtorrent m_event = tracker_request::stopped; // disconnect all peers and close all // files belonging to the torrents - -#if defined(TORRENT_VERBOSE_LOGGING) - for (peer_iterator i = m_connections.begin(); - i != m_connections.end(); ++i) - { - (*i->second->m_logger) << "*** ABORTING TORRENT\n"; - } -#endif - disconnect_all(); if (m_owning_storage.get()) m_storage->async_release_files(); m_owning_storage = 0; @@ -1041,7 +1040,7 @@ namespace libtorrent // INVARIANT_CHECK; assert(index >= 0); - assert(index < m_torrent_file->num_pieces()); + assert(index < m_torrent_file.num_pieces()); std::vector downloaders; m_picker->get_downloaders(downloaders, index); @@ -1084,7 +1083,7 @@ namespace libtorrent if (is_seed()) { m_picker.reset(); - m_torrent_file->seed_free(); + m_torrent_file.seed_free(); } } @@ -1118,7 +1117,7 @@ namespace libtorrent // this call is only valid on torrents with metadata assert(m_picker.get()); assert(index >= 0); - assert(index < m_torrent_file->num_pieces()); + assert(index < m_torrent_file.num_pieces()); bool filter_updated = m_picker->set_piece_priority(index, priority); if (filter_updated) update_peer_interest(); @@ -1134,7 +1133,7 @@ namespace libtorrent // this call is only valid on torrents with metadata assert(m_picker.get()); assert(index >= 0); - assert(index < m_torrent_file->num_pieces()); + assert(index < m_torrent_file.num_pieces()); return m_picker->piece_priority(index); } @@ -1170,7 +1169,7 @@ namespace libtorrent if (is_seed()) { pieces.clear(); - pieces.resize(m_torrent_file->num_pieces(), 1); + pieces.resize(m_torrent_file.num_pieces(), 1); return; } @@ -1195,20 +1194,20 @@ namespace libtorrent // the bitmask need to have exactly one bit for every file // in the torrent - assert(int(files.size()) == m_torrent_file->num_files()); + assert(int(files.size()) == m_torrent_file.num_files()); size_type position = 0; - if (m_torrent_file->num_pieces() == 0) return; + if (m_torrent_file.num_pieces() == 0) return; - int piece_length = m_torrent_file->piece_length(); + int piece_length = m_torrent_file.piece_length(); // initialize the piece priorities to 0, then only allow // setting higher priorities - std::vector pieces(m_torrent_file->num_pieces(), 0); + std::vector pieces(m_torrent_file.num_pieces(), 0); for (int i = 0; i < int(files.size()); ++i) { size_type start = position; - size_type size = m_torrent_file->file_at(i).size; + size_type size = m_torrent_file.file_at(i).size; if (size == 0) continue; position += size; // mark all pieces of the file with this file's priority @@ -1244,7 +1243,7 @@ namespace libtorrent // this call is only valid on torrents with metadata assert(m_picker.get()); assert(index >= 0); - assert(index < m_torrent_file->num_pieces()); + assert(index < m_torrent_file.num_pieces()); m_picker->set_piece_priority(index, filter ? 1 : 0); update_peer_interest(); @@ -1281,7 +1280,7 @@ namespace libtorrent assert(m_picker.get()); assert(index >= 0); - assert(index < m_torrent_file->num_pieces()); + assert(index < m_torrent_file.num_pieces()); return m_picker->piece_priority(index) == 0; } @@ -1295,7 +1294,7 @@ namespace libtorrent if (is_seed()) { bitmask.clear(); - bitmask.resize(m_torrent_file->num_pieces(), false); + bitmask.resize(m_torrent_file.num_pieces(), false); return; } @@ -1312,20 +1311,20 @@ namespace libtorrent // the bitmask need to have exactly one bit for every file // in the torrent - assert((int)bitmask.size() == m_torrent_file->num_files()); + assert((int)bitmask.size() == m_torrent_file.num_files()); size_type position = 0; - if (m_torrent_file->num_pieces()) + if (m_torrent_file.num_pieces()) { - int piece_length = m_torrent_file->piece_length(); + int piece_length = m_torrent_file.piece_length(); // mark all pieces as filtered, then clear the bits for files // that should be downloaded - std::vector piece_filter(m_torrent_file->num_pieces(), true); + std::vector piece_filter(m_torrent_file.num_pieces(), true); for (int i = 0; i < (int)bitmask.size(); ++i) { size_type start = position; - position += m_torrent_file->file_at(i).size; + position += m_torrent_file.file_at(i).size; // is the file selected for download? if (!bitmask[i]) { @@ -1360,7 +1359,7 @@ namespace libtorrent m_next_request = time_now() + seconds(tracker_retry_delay_max); tracker_request req; - req.info_hash = m_torrent_file->info_hash(); + req.info_hash = m_torrent_file.info_hash(); req.pid = m_ses.get_peer_id(); req.downloaded = m_stat.total_payload_download(); req.uploaded = m_stat.total_payload_upload(); @@ -1384,27 +1383,6 @@ namespace libtorrent return req; } - void torrent::choke_peer(peer_connection& c) - { - INVARIANT_CHECK; - - assert(!c.is_choked()); - assert(m_num_uploads > 0); - c.send_choke(); - --m_num_uploads; - } - - bool torrent::unchoke_peer(peer_connection& c) - { - INVARIANT_CHECK; - - assert(c.is_choked()); - if (m_num_uploads >= m_max_uploads) return false; - c.send_unchoke(); - ++m_num_uploads; - return true; - } - void torrent::cancel_block(piece_block block) { for (peer_iterator i = m_connections.begin() @@ -1416,7 +1394,7 @@ namespace libtorrent void torrent::remove_peer(peer_connection* p) try { -// INVARIANT_CHECK; + INVARIANT_CHECK; assert(p != 0); @@ -1455,9 +1433,6 @@ namespace libtorrent } } - if (!p->is_choked()) - --m_num_uploads; - m_policy->connection_closed(*p); p->set_peer_info(0); m_connections.erase(i); @@ -1653,7 +1628,6 @@ namespace libtorrent assert(m_connections.find(a) == m_connections.end()); // add the newly connected peer to this torrent's peer list - assert(m_connections.find(a) == m_connections.end()); m_connections.insert( std::make_pair(a, boost::get_pointer(c))); m_ses.m_connections.insert(std::make_pair(s, c)); @@ -1670,8 +1644,8 @@ namespace libtorrent #endif // TODO: post an error alert! -// std::map::iterator i = m_connections.find(a); -// if (i != m_connections.end()) m_connections.erase(i); + std::map::iterator i = m_connections.find(a); + if (i != m_connections.end()) m_connections.erase(i); m_ses.connection_failed(s, a, e.what()); c->disconnect(); } @@ -1833,7 +1807,6 @@ namespace libtorrent #endif assert(want_more_peers()); - assert(m_ses.num_connections() < m_ses.max_connections()); tcp::endpoint const& a(peerinfo->ip); assert((m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked) == 0); @@ -1858,8 +1831,6 @@ namespace libtorrent try { - assert(m_connections.find(a) == m_connections.end()); - // add the newly connected peer to this torrent's peer list m_connections.insert( std::make_pair(a, boost::get_pointer(c))); @@ -1872,7 +1843,6 @@ namespace libtorrent } catch (std::exception& e) { - assert(false); // TODO: post an error alert! std::map::iterator i = m_connections.find(a); if (i != m_connections.end()) m_connections.erase(i); @@ -1888,8 +1858,8 @@ namespace libtorrent { INVARIANT_CHECK; - assert(!m_torrent_file->is_valid()); - m_torrent_file->parse_info_section(metadata); + assert(!m_torrent_file.is_valid()); + m_torrent_file.parse_info_section(metadata); init(); @@ -1899,12 +1869,12 @@ namespace libtorrent new aux::piece_checker_data); d->torrent_ptr = shared_from_this(); d->save_path = m_save_path; - d->info_hash = m_torrent_file->info_hash(); + d->info_hash = m_torrent_file.info_hash(); // add the torrent to the queue to be checked m_checker.m_torrents.push_back(d); typedef session_impl::torrent_map torrent_map; torrent_map::iterator i = m_ses.m_torrents.find( - m_torrent_file->info_hash()); + m_torrent_file.info_hash()); assert(i != m_ses.m_torrents.end()); m_ses.m_torrents.erase(i); // and notify the thread that it got another @@ -1920,7 +1890,7 @@ namespace libtorrent void torrent::attach_peer(peer_connection* p) { -// INVARIANT_CHECK; + INVARIANT_CHECK; assert(p != 0); assert(!p->is_local()); @@ -1929,7 +1899,6 @@ namespace libtorrent = m_connections.find(p->remote()); if (c != m_connections.end()) { - assert(p != c->second); // we already have a peer_connection to this ip. // It may currently be waiting for completing a // connection attempt that might fail. So, @@ -1953,7 +1922,6 @@ namespace libtorrent throw protocol_error("session is closing"); } - assert(m_connections.find(p->remote()) == m_connections.end()); peer_iterator ci = m_connections.insert( std::make_pair(p->remote(), p)).first; try @@ -1987,7 +1955,7 @@ namespace libtorrent bool torrent::want_more_peers() const { - return int(m_connections.size()) < m_max_connections + return int(m_connections.size()) < m_connections_quota.given && m_ses.m_half_open.free_slots() && !m_paused; } @@ -2026,9 +1994,7 @@ namespace libtorrent , boost::intrusive_ptr const& p , bool non_prioritized) { - assert(m_bandwidth_limit[channel].throttle() > 0); int block_size = m_bandwidth_limit[channel].throttle() / 10; - if (block_size <= 0) block_size = 1; if (m_bandwidth_limit[channel].max_assignable() > 0) { @@ -2156,7 +2122,7 @@ namespace libtorrent if ((unsigned)m_currently_trying_tracker >= m_trackers.size()) { int delay = tracker_retry_delay_min - + (std::min)(m_failed_trackers, (int)tracker_failed_max) + + std::min(m_failed_trackers, (int)tracker_failed_max) * (tracker_retry_delay_max - tracker_retry_delay_min) / tracker_failed_max; @@ -2215,12 +2181,14 @@ namespace libtorrent } pause(); } +#ifndef NDEBUG + m_initial_done = boost::get<0>(bytes_done()); +#endif return done; } std::pair torrent::check_files() { - assert(m_torrent_file->is_valid()); INVARIANT_CHECK; assert(m_owning_storage.get()); @@ -2248,6 +2216,9 @@ namespace libtorrent pause(); } +#ifndef NDEBUG + m_initial_done = boost::get<0>(bytes_done()); +#endif return progress; } @@ -2256,7 +2227,6 @@ namespace libtorrent { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); - assert(m_torrent_file->is_valid()); INVARIANT_CHECK; if (!is_seed()) @@ -2287,7 +2257,7 @@ namespace libtorrent if (is_seed()) { m_picker.reset(); - m_torrent_file->seed_free(); + m_torrent_file.seed_free(); } if (!m_connections_initialized) @@ -2316,6 +2286,9 @@ namespace libtorrent } } } +#ifndef NDEBUG + m_initial_done = boost::get<0>(bytes_done()); +#endif } alert_manager& torrent::alerts() const @@ -2367,7 +2340,7 @@ namespace libtorrent torrent_handle torrent::get_handle() const { - return torrent_handle(&m_ses, &m_checker, m_torrent_file->info_hash()); + return torrent_handle(&m_ses, &m_checker, m_torrent_file.info_hash()); } session_settings const& torrent::settings() const @@ -2378,7 +2351,9 @@ namespace libtorrent #ifndef NDEBUG void torrent::check_invariant() const { - int num_uploads = 0; +// size_type download = m_stat.total_payload_download(); +// size_type done = boost::get<0>(bytes_done()); +// assert(download >= done - m_initial_done); std::map num_requests; for (const_peer_iterator i = begin(); i != end(); ++i) { @@ -2389,12 +2364,10 @@ namespace libtorrent for (std::deque::const_iterator i = p.download_queue().begin() , end(p.download_queue().end()); i != end; ++i) ++num_requests[*i]; - if (!p.is_choked()) ++num_uploads; torrent* associated_torrent = p.associated_torrent().lock().get(); if (associated_torrent != this) assert(false); } - assert(num_uploads == m_num_uploads); if (has_picker()) { @@ -2407,26 +2380,20 @@ namespace libtorrent if (valid_metadata()) { - assert(m_abort || int(m_have_pieces.size()) == m_torrent_file->num_pieces()); + assert(m_abort || int(m_have_pieces.size()) == m_torrent_file.num_pieces()); } else { assert(m_abort || m_have_pieces.empty()); } -/* for (policy::const_iterator i = m_policy->begin_peer() - , end(m_policy->end_peer()); i != end; ++i) - { - assert(i->connection == const_cast(this)->connection_for(i->ip)); - } -*/ size_type total_done = quantized_bytes_done(); - if (m_torrent_file->is_valid()) + if (m_torrent_file.is_valid()) { if (is_seed()) - assert(total_done == m_torrent_file->total_size()); + assert(total_done == m_torrent_file.total_size()); else - assert(total_done != m_torrent_file->total_size()); + assert(total_done != m_torrent_file.total_size()); } else { @@ -2437,7 +2404,7 @@ namespace libtorrent assert(m_num_pieces == std::count(m_have_pieces.begin(), m_have_pieces.end(), true)); assert(!valid_metadata() || m_block_size > 0); - assert(!valid_metadata() || (m_torrent_file->piece_length() % m_block_size) == 0); + assert(!valid_metadata() || (m_torrent_file.piece_length() % m_block_size) == 0); // if (is_seed()) assert(m_picker.get() == 0); } #endif @@ -2458,15 +2425,15 @@ namespace libtorrent void torrent::set_max_uploads(int limit) { assert(limit >= -1); - if (limit <= 0) limit = (std::numeric_limits::max)(); - m_max_uploads = limit; + if (limit == -1) limit = std::numeric_limits::max(); + m_uploads_quota.max = std::max(m_uploads_quota.min, limit); } void torrent::set_max_connections(int limit) { assert(limit >= -1); - if (limit <= 0) limit = (std::numeric_limits::max)(); - m_max_connections = limit; + if (limit == -1) limit = std::numeric_limits::max(); + m_connections_quota.max = std::max(m_connections_quota.min, limit); } void torrent::set_peer_upload_limit(tcp::endpoint ip, int limit) @@ -2488,7 +2455,7 @@ namespace libtorrent void torrent::set_upload_limit(int limit) { assert(limit >= -1); - if (limit <= 0) limit = (std::numeric_limits::max)(); + if (limit == -1) limit = std::numeric_limits::max(); if (limit < num_peers() * 10) limit = num_peers() * 10; m_bandwidth_limit[peer_connection::upload_channel].throttle(limit); } @@ -2496,14 +2463,14 @@ namespace libtorrent int torrent::upload_limit() const { int limit = m_bandwidth_limit[peer_connection::upload_channel].throttle(); - if (limit == (std::numeric_limits::max)()) limit = -1; + if (limit == std::numeric_limits::max()) limit = -1; return limit; } void torrent::set_download_limit(int limit) { assert(limit >= -1); - if (limit <= 0) limit = (std::numeric_limits::max)(); + if (limit == -1) limit = std::numeric_limits::max(); if (limit < num_peers() * 10) limit = num_peers() * 10; m_bandwidth_limit[peer_connection::download_channel].throttle(limit); } @@ -2511,7 +2478,7 @@ namespace libtorrent int torrent::download_limit() const { int limit = m_bandwidth_limit[peer_connection::download_channel].throttle(); - if (limit == (std::numeric_limits::max)()) limit = -1; + if (limit == std::numeric_limits::max()) limit = -1; return limit; } @@ -2529,14 +2496,6 @@ namespace libtorrent } #endif -#if defined(TORRENT_VERBOSE_LOGGING) - for (peer_iterator i = m_connections.begin(); - i != m_connections.end(); ++i) - { - (*i->second->m_logger) << "*** PAUSING TORRENT\n"; - } -#endif - disconnect_all(); m_paused = true; // tell the tracker that we stopped @@ -2569,6 +2528,10 @@ namespace libtorrent #endif m_paused = false; + m_uploads_quota.min = 0; + m_connections_quota.min = 2; + m_uploads_quota.max = std::numeric_limits::max(); + m_connections_quota.max = std::numeric_limits::max(); // tell the tracker that we're back m_event = tracker_request::started; @@ -2582,6 +2545,10 @@ namespace libtorrent { INVARIANT_CHECK; + m_connections_quota.used = (int)m_connections.size(); + m_uploads_quota.used = m_policy->num_uploads(); + m_uploads_quota.max = (int)m_connections.size(); + #ifndef TORRENT_DISABLE_EXTENSIONS for (extension_list_t::iterator i = m_extensions.begin() , end(m_extensions.end()); i != end; ++i) @@ -2594,6 +2561,10 @@ namespace libtorrent { // let the stats fade out to 0 m_stat.second_tick(tick_interval); + m_connections_quota.min = 0; + m_connections_quota.max = 0; + m_uploads_quota.min = 0; + m_uploads_quota.max = 0; return; } @@ -2652,13 +2623,6 @@ namespace libtorrent } accumulator += m_stat; m_stat.second_tick(tick_interval); - - m_time_scaler--; - if (m_time_scaler <= 0) - { - m_time_scaler = 10; - m_policy->pulse(); - } } bool torrent::try_connect_peer() @@ -2667,6 +2631,18 @@ namespace libtorrent return m_policy->connect_one_peer(); } + void torrent::distribute_resources(float tick_interval) + { + INVARIANT_CHECK; + + m_time_scaler--; + if (m_time_scaler <= 0) + { + m_time_scaler = settings().unchoke_interval; + m_policy->pulse(); + } + } + void torrent::async_verify_piece(int piece_index, boost::function const& f) { INVARIANT_CHECK; @@ -2674,7 +2650,7 @@ namespace libtorrent assert(m_storage); assert(m_storage->refcount() > 0); assert(piece_index >= 0); - assert(piece_index < m_torrent_file->num_pieces()); + assert(piece_index < m_torrent_file.num_pieces()); assert(piece_index < (int)m_have_pieces.size()); m_storage->async_hash(piece_index, bind(&torrent::on_piece_verified @@ -2686,7 +2662,7 @@ namespace libtorrent { sha1_hash h(j.str); session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); - f(m_torrent_file->hash_for_piece(j.piece) == h); + f(m_torrent_file.hash_for_piece(j.piece) == h); } const tcp::endpoint& torrent::current_tracker() const @@ -2702,12 +2678,12 @@ namespace libtorrent assert(valid_metadata()); fp.clear(); - fp.resize(m_torrent_file->num_files(), 0.f); + fp.resize(m_torrent_file.num_files(), 0.f); - for (int i = 0; i < m_torrent_file->num_files(); ++i) + for (int i = 0; i < m_torrent_file.num_files(); ++i) { - peer_request ret = m_torrent_file->map_file(i, 0, 0); - size_type size = m_torrent_file->file_at(i).size; + peer_request ret = m_torrent_file.map_file(i, 0, 0); + size_type size = m_torrent_file.file_at(i).size; // zero sized files are considered // 100% done all the time @@ -2720,7 +2696,7 @@ namespace libtorrent size_type done = 0; while (size > 0) { - size_type bytes_step = (std::min)(m_torrent_file->piece_size(ret.piece) + size_type bytes_step = std::min(m_torrent_file.piece_size(ret.piece) - ret.start, size); if (m_have_pieces[ret.piece]) done += bytes_step; ++ret.piece; @@ -2729,7 +2705,7 @@ namespace libtorrent } assert(size == 0); - fp[i] = static_cast(done) / m_torrent_file->file_at(i).size; + fp[i] = static_cast(done) / m_torrent_file.file_at(i).size; } } @@ -2788,10 +2764,10 @@ namespace libtorrent = m_trackers[m_last_working_tracker].url; } - st.num_uploads = m_num_uploads; - st.uploads_limit = m_max_uploads; - st.num_connections = int(m_connections.size()); - st.connections_limit = m_max_connections; + st.num_uploads = m_uploads_quota.used; + st.uploads_limit = m_uploads_quota.given; + st.num_connections = m_connections_quota.used; + st.connections_limit = m_connections_quota.given; // if we don't have any metadata, stop here if (!valid_metadata()) @@ -2804,7 +2780,7 @@ namespace libtorrent // TODO: add a progress member to the torrent that will be used in this case // and that may be set by a plugin // if (m_metadata_size == 0) st.progress = 0.f; -// else st.progress = (std::min)(1.f, m_metadata_progress / (float)m_metadata_size); +// else st.progress = std::min(1.f, m_metadata_progress / (float)m_metadata_size); st.progress = 0.f; st.block_size = 0; @@ -2816,21 +2792,21 @@ namespace libtorrent // fill in status that depends on metadata - st.total_wanted = m_torrent_file->total_size(); + st.total_wanted = m_torrent_file.total_size(); if (m_picker.get() && (m_picker->num_filtered() > 0 || m_picker->num_have_filtered() > 0)) { int filtered_pieces = m_picker->num_filtered() + m_picker->num_have_filtered(); - int last_piece_index = m_torrent_file->num_pieces() - 1; + int last_piece_index = m_torrent_file.num_pieces() - 1; if (m_picker->piece_priority(last_piece_index) == 0) { - st.total_wanted -= m_torrent_file->piece_size(last_piece_index); + st.total_wanted -= m_torrent_file.piece_size(last_piece_index); --filtered_pieces; } - st.total_wanted -= filtered_pieces * m_torrent_file->piece_length(); + st.total_wanted -= filtered_pieces * m_torrent_file.piece_length(); } assert(st.total_wanted >= st.total_wanted_done); @@ -2848,7 +2824,7 @@ namespace libtorrent } else if (is_seed()) { - assert(st.total_done == m_torrent_file->total_size()); + assert(st.total_done == m_torrent_file.total_size()); st.state = torrent_status::seeding; } else if (st.total_wanted_done == st.total_wanted) diff --git a/libtorrent/src/torrent_handle.cpp b/libtorrent/src/torrent_handle.cpp index ebef802a8..4538e66e8 100755 --- a/libtorrent/src/torrent_handle.cpp +++ b/libtorrent/src/torrent_handle.cpp @@ -89,16 +89,27 @@ namespace libtorrent throw invalid_handle(); } - boost::shared_ptr find_torrent( + template + Ret call_member( session_impl* ses , aux::checker_impl* chk - , sha1_hash const& hash) + , sha1_hash const& hash + , F f) { - aux::piece_checker_data* d = chk->find_torrent(hash); - if (d != 0) return d->torrent_ptr; + if (ses == 0) throw_invalid_handle(); - boost::shared_ptr t = ses->find_torrent(hash).lock(); - if (t) return t; + if (chk) + { + mutex::scoped_lock l(chk->m_mutex); + aux::piece_checker_data* d = chk->find_torrent(hash); + if (d != 0) return f(*d->torrent_ptr); + } + + { + session_impl::mutex_t::scoped_lock l(ses->m_mutex); + boost::shared_ptr t = ses->find_torrent(hash).lock(); + if (t) return f(*t); + } // throwing directly instead of calling // the throw_invalid_handle() function @@ -111,7 +122,7 @@ namespace libtorrent void torrent_handle::check_invariant() const { - assert((m_ses == 0 && m_chk == 0) || (m_ses != 0 && m_chk != 0)); + assert((m_ses == 0 && m_chk == 0) || (m_ses != 0)); } #endif @@ -120,40 +131,28 @@ namespace libtorrent { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - assert(max_uploads >= 2 || max_uploads == -1); - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->set_max_uploads(max_uploads); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::set_max_uploads, _1, max_uploads)); } void torrent_handle::use_interface(const char* net_interface) const { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->use_interface(net_interface); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::use_interface, _1, net_interface)); } void torrent_handle::set_max_connections(int max_connections) const { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - assert(max_connections >= 2 || max_connections == -1); - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->set_max_connections(max_connections); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::set_max_connections, _1, max_connections)); } void torrent_handle::set_peer_upload_limit(tcp::endpoint ip, int limit) const @@ -161,12 +160,8 @@ namespace libtorrent INVARIANT_CHECK; assert(limit >= -1); - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->set_peer_upload_limit(ip, limit); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::set_peer_upload_limit, _1, ip, limit)); } void torrent_handle::set_peer_download_limit(tcp::endpoint ip, int limit) const @@ -174,64 +169,42 @@ namespace libtorrent INVARIANT_CHECK; assert(limit >= -1); - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->set_peer_download_limit(ip, limit); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::set_peer_download_limit, _1, ip, limit)); } void torrent_handle::set_upload_limit(int limit) const { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - assert(limit >= -1); - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->set_upload_limit(limit); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::set_upload_limit, _1, limit)); } int torrent_handle::upload_limit() const { INVARIANT_CHECK; - - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - return find_torrent(m_ses, m_chk, m_info_hash)->upload_limit(); + return call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::upload_limit, _1)); } void torrent_handle::set_download_limit(int limit) const { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - assert(limit >= -1); - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->set_download_limit(limit); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::set_download_limit, _1, limit)); } int torrent_handle::download_limit() const { INVARIANT_CHECK; - - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - return find_torrent(m_ses, m_chk, m_info_hash)->download_limit(); + return call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::download_limit, _1)); } void torrent_handle::move_storage( @@ -239,72 +212,48 @@ namespace libtorrent { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->move_storage(save_path); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::move_storage, _1, save_path)); } bool torrent_handle::has_metadata() const { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - return find_torrent(m_ses, m_chk, m_info_hash)->valid_metadata(); + return call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::valid_metadata, _1)); } bool torrent_handle::is_seed() const { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - return find_torrent(m_ses, m_chk, m_info_hash)->is_seed(); + return call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::is_seed, _1)); } bool torrent_handle::is_paused() const { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - return find_torrent(m_ses, m_chk, m_info_hash)->is_paused(); + return call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::is_paused, _1)); } void torrent_handle::pause() const { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->pause(); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::pause, _1)); } void torrent_handle::resume() const { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->resume(); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::resume, _1)); } void torrent_handle::set_tracker_login(std::string const& name @@ -312,12 +261,8 @@ namespace libtorrent { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->set_tracker_login(name, password); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::set_tracker_login, _1, name, password)); } void torrent_handle::file_progress(std::vector& progress) @@ -325,27 +270,31 @@ namespace libtorrent INVARIANT_CHECK; if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash); - if (d != 0) + if (m_chk) { - if (!d->processing) + mutex::scoped_lock l(m_chk->m_mutex); + + aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash); + if (d != 0) { - torrent_info const& info = d->torrent_ptr->torrent_file(); - progress.clear(); - progress.resize(info.num_files(), 0.f); + if (!d->processing) + { + torrent_info const& info = d->torrent_ptr->torrent_file(); + progress.clear(); + progress.resize(info.num_files(), 0.f); + return; + } + d->torrent_ptr->file_progress(progress); return; } - d->torrent_ptr->file_progress(progress); - return; } - boost::shared_ptr t = m_ses->find_torrent(m_info_hash).lock(); - if (t) return t->file_progress(progress); + { + session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); + boost::shared_ptr t = m_ses->find_torrent(m_info_hash).lock(); + if (t) return t->file_progress(progress); + } throw_invalid_handle(); } @@ -355,32 +304,36 @@ namespace libtorrent INVARIANT_CHECK; if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash); - if (d != 0) + if (m_chk) { - torrent_status st; + mutex::scoped_lock l(m_chk->m_mutex); - if (d->processing) + aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash); + if (d != 0) { - if (d->torrent_ptr->is_allocating()) - st.state = torrent_status::allocating; + torrent_status st; + + if (d->processing) + { + if (d->torrent_ptr->is_allocating()) + st.state = torrent_status::allocating; + else + st.state = torrent_status::checking_files; + } else - st.state = torrent_status::checking_files; + st.state = torrent_status::queued_for_checking; + st.progress = d->progress; + st.paused = d->torrent_ptr->is_paused(); + return st; } - else - st.state = torrent_status::queued_for_checking; - st.progress = d->progress; - st.paused = d->torrent_ptr->is_paused(); - return st; } - boost::shared_ptr t = m_ses->find_torrent(m_info_hash).lock(); - if (t) return t->status(); + { + session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); + boost::shared_ptr t = m_ses->find_torrent(m_info_hash).lock(); + if (t) return t->status(); + } throw_invalid_handle(); return torrent_status(); @@ -389,25 +342,15 @@ namespace libtorrent void torrent_handle::set_sequenced_download_threshold(int threshold) const { INVARIANT_CHECK; - - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->set_sequenced_download_threshold(threshold); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::set_sequenced_download_threshold, _1, threshold)); } std::string torrent_handle::name() const { INVARIANT_CHECK; - - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - return find_torrent(m_ses, m_chk, m_info_hash)->name(); + return call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::name, _1)); } @@ -415,61 +358,40 @@ namespace libtorrent { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->piece_availability(avail); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::piece_availability, _1, boost::ref(avail))); } void torrent_handle::piece_priority(int index, int priority) const { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->set_piece_priority(index, priority); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::set_piece_priority, _1, index, priority)); } int torrent_handle::piece_priority(int index) const { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - return find_torrent(m_ses, m_chk, m_info_hash)->piece_priority(index); + return call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::piece_priority, _1, index)); } void torrent_handle::prioritize_pieces(std::vector const& pieces) const { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->prioritize_pieces(pieces); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::prioritize_pieces, _1, boost::cref(pieces))); } std::vector torrent_handle::piece_priorities() const { INVARIANT_CHECK; - - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - std::vector ret; - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->piece_priorities(ret); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::piece_priorities, _1, boost::ref(ret))); return ret; } @@ -477,12 +399,8 @@ namespace libtorrent { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->prioritize_files(files); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::prioritize_files, _1, boost::cref(files))); } // ============ start deprecation =============== @@ -490,63 +408,38 @@ namespace libtorrent void torrent_handle::filter_piece(int index, bool filter) const { INVARIANT_CHECK; - - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->filter_piece(index, filter); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::filter_piece, _1, index, filter)); } void torrent_handle::filter_pieces(std::vector const& pieces) const { INVARIANT_CHECK; - - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->filter_pieces(pieces); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::filter_pieces, _1, boost::cref(pieces))); } bool torrent_handle::is_piece_filtered(int index) const { INVARIANT_CHECK; - - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - return find_torrent(m_ses, m_chk, m_info_hash)->is_piece_filtered(index); + return call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::is_piece_filtered, _1, index)); } std::vector torrent_handle::filtered_pieces() const { INVARIANT_CHECK; - - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - std::vector ret; - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->filtered_pieces(ret); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::filtered_pieces, _1, boost::ref(ret))); return ret; } void torrent_handle::filter_files(std::vector const& files) const { INVARIANT_CHECK; - - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->filter_files(files); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::filter_files, _1, files)); } // ============ end deprecation =============== @@ -556,48 +449,16 @@ namespace libtorrent { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - return find_torrent(m_ses, m_chk, m_info_hash)->trackers(); + return call_member const&>(m_ses + , m_chk, m_info_hash, bind(&torrent::trackers, _1)); } - void torrent_handle::add_url_seed(std::string const& url) const + void torrent_handle::add_url_seed(std::string const& url) { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->add_url_seed(url); - } - - void torrent_handle::remove_url_seed(std::string const& url) const - { - INVARIANT_CHECK; - - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->remove_url_seed(url); - } - - std::set torrent_handle::url_seeds() const - { - INVARIANT_CHECK; - - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - return find_torrent(m_ses, m_chk, m_info_hash)->url_seeds(); + return call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::add_url_seed, _1, url)); } void torrent_handle::replace_trackers( @@ -605,26 +466,17 @@ namespace libtorrent { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->replace_trackers(urls); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::replace_trackers, _1, urls)); } torrent_info const& torrent_handle::get_torrent_info() const { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - boost::shared_ptr t = find_torrent(m_ses, m_chk, m_info_hash); - if (!t->valid_metadata()) throw_invalid_handle(); - return t->torrent_file(); + if (!has_metadata()) throw_invalid_handle(); + return call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::torrent_file, _1)); } bool torrent_handle::is_valid() const @@ -632,14 +484,16 @@ namespace libtorrent INVARIANT_CHECK; if (m_ses == 0) return false; - assert(m_chk); - session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash); - if (d != 0) return true; + if (m_chk) + { + mutex::scoped_lock l(m_chk->m_mutex); + aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash); + if (d != 0) return true; + } { + session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); boost::weak_ptr t = m_ses->find_torrent(m_info_hash); if (!t.expired()) return true; } @@ -653,7 +507,6 @@ namespace libtorrent std::vector piece_index; if (m_ses == 0) return entry(); - assert(m_chk); session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); boost::shared_ptr t = m_ses->find_torrent(m_info_hash).lock(); @@ -708,12 +561,12 @@ namespace libtorrent std::string bitmask; const int num_bitmask_bytes - = (std::max)(num_blocks_per_piece / 8, 1); + = std::max(num_blocks_per_piece / 8, 1); for (int j = 0; j < num_bitmask_bytes; ++j) { unsigned char v = 0; - int bits = (std::min)(num_blocks_per_piece - j*8, 8); + int bits = std::min(num_blocks_per_piece - j*8, 8); for (int k = 0; k < bits; ++k) v |= (i->info[j*8+k].state == piece_picker::block_info::state_finished) ? (1 << k) : 0; @@ -772,12 +625,8 @@ namespace libtorrent { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - return find_torrent(m_ses, m_chk, m_info_hash)->save_path(); + return call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::save_path, _1)); } void torrent_handle::connect_peer(tcp::endpoint const& adr, int source) const @@ -785,7 +634,6 @@ namespace libtorrent INVARIANT_CHECK; if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); boost::shared_ptr t = m_ses->find_torrent(m_info_hash).lock(); @@ -814,7 +662,6 @@ namespace libtorrent INVARIANT_CHECK; if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); boost::shared_ptr t = m_ses->find_torrent(m_info_hash).lock(); @@ -829,7 +676,6 @@ namespace libtorrent INVARIANT_CHECK; if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); boost::shared_ptr t = m_ses->find_torrent(m_info_hash).lock(); @@ -842,41 +688,28 @@ namespace libtorrent { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - assert(ratio >= 0.f); + if (ratio < 1.f && ratio > 0.f) ratio = 1.f; - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->set_ratio(ratio); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::set_ratio, _1, ratio)); } #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES void torrent_handle::resolve_countries(bool r) { INVARIANT_CHECK; - - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - find_torrent(m_ses, m_chk, m_info_hash)->resolve_countries(r); + call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::resolve_countries, _1, r)); } bool torrent_handle::resolve_countries() const { INVARIANT_CHECK; - - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - - session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); - mutex::scoped_lock l2(m_chk->m_mutex); - return find_torrent(m_ses, m_chk, m_info_hash)->resolving_countries(); + return call_member(m_ses, m_chk, m_info_hash + , bind(&torrent::resolving_countries, _1)); } #endif @@ -884,10 +717,8 @@ namespace libtorrent { INVARIANT_CHECK; - if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); - v.clear(); + if (m_ses == 0) throw_invalid_handle(); session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); @@ -919,7 +750,6 @@ namespace libtorrent INVARIANT_CHECK; if (m_ses == 0) throw_invalid_handle(); - assert(m_chk); session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); boost::shared_ptr t = m_ses->find_torrent(m_info_hash).lock(); diff --git a/libtorrent/src/torrent_info.cpp b/libtorrent/src/torrent_info.cpp index d6dc27fa2..4ea09aefd 100755 --- a/libtorrent/src/torrent_info.cpp +++ b/libtorrent/src/torrent_info.cpp @@ -400,9 +400,7 @@ namespace libtorrent { if (i->first == "pieces" || i->first == "piece length" - || i->first == "length" -// || i->first == "files" - || i->first == "name") + || i->first == "length") continue; m_extra_info[i->first] = i->second; } @@ -676,7 +674,7 @@ namespace libtorrent { assert(m_piece_length > 0); - if (m_files.empty()) + if ((m_urls.empty() && m_nodes.empty()) || m_files.empty()) { // TODO: throw something here // throw @@ -826,33 +824,8 @@ namespace libtorrent m_nodes.push_back(node); } - bool torrent_info::remap_files(std::vector > const& map) - { - typedef std::vector > files_t; - - size_type offset = 0; - m_remapped_files.resize(map.size()); - - for (int i = 0; i < int(map.size()); ++i) - { - file_entry& fe = m_remapped_files[i]; - fe.path = map[i].first; - fe.offset = offset; - fe.size = map[i].second; - offset += fe.size; - } - if (offset != total_size()) - { - m_remapped_files.clear(); - return false; - } - - return true; - } - std::vector torrent_info::map_block(int piece, size_type offset - , int size, bool storage) const + , int size) const { assert(num_files() > 0); std::vector ret; @@ -866,9 +839,9 @@ namespace libtorrent std::vector::const_iterator file_iter; int counter = 0; - for (file_iter = begin_files(storage);; ++counter, ++file_iter) + for (file_iter = begin_files();; ++counter, ++file_iter) { - assert(file_iter != end_files(storage)); + assert(file_iter != end_files()); if (file_offset < file_iter->size) { file_slice f; @@ -889,11 +862,11 @@ namespace libtorrent } peer_request torrent_info::map_file(int file_index, size_type file_offset - , int size, bool storage) const + , int size) const { - assert(file_index < num_files(storage)); + assert(file_index < (int)m_files.size()); assert(file_index >= 0); - size_type offset = file_offset + file_at(file_index, storage).offset; + size_type offset = file_offset + m_files[file_index].offset; peer_request ret; ret.piece = offset / piece_length(); diff --git a/libtorrent/src/tracker_manager.cpp b/libtorrent/src/tracker_manager.cpp index 981eb4caf..7bd511588 100755 --- a/libtorrent/src/tracker_manager.cpp +++ b/libtorrent/src/tracker_manager.cpp @@ -256,7 +256,7 @@ namespace libtorrent { // available input is 1,2 or 3 bytes // since we read 3 bytes at a time at most - int available_input = (std::min)(3, (int)std::distance(i, s.end())); + int available_input = std::min(3, (int)std::distance(i, s.end())); // clear input buffer std::fill(inbuf, inbuf+3, 0); @@ -305,7 +305,7 @@ namespace libtorrent m_start_time = time_now(); m_read_time = time_now(); - m_timeout.expires_at((std::min)( + m_timeout.expires_at(std::min( m_read_time + seconds(m_read_timeout) , m_start_time + seconds(m_completion_timeout))); m_timeout.async_wait(m_strand.wrap(bind( @@ -341,7 +341,7 @@ namespace libtorrent return; } - m_timeout.expires_at((std::min)( + m_timeout.expires_at(std::min( m_read_time + seconds(m_read_timeout) , m_start_time + seconds(m_completion_timeout))); m_timeout.async_wait(m_strand.wrap( @@ -365,22 +365,23 @@ namespace libtorrent , m_req(req) {} - boost::shared_ptr tracker_connection::requester() + request_callback& tracker_connection::requester() { - return m_requester.lock(); + boost::shared_ptr r = m_requester.lock(); + assert(r); + return *r; } void tracker_connection::fail(int code, char const* msg) { - boost::shared_ptr cb = requester(); - if (cb) cb->tracker_request_error(m_req, code, msg); + if (has_requester()) requester().tracker_request_error( + m_req, code, msg); close(); } void tracker_connection::fail_timeout() { - boost::shared_ptr cb = requester(); - if (cb) cb->tracker_request_timed_out(m_req); + if (has_requester()) requester().tracker_request_timed_out(m_req); close(); } @@ -547,8 +548,7 @@ namespace libtorrent m_connections.push_back(con); - boost::shared_ptr cb = con->requester(); - if (cb) cb->m_manager = this; + if (con->has_requester()) con->requester().m_manager = this; } catch (std::exception& e) { diff --git a/libtorrent/src/udp_tracker_connection.cpp b/libtorrent/src/udp_tracker_connection.cpp index cd500d98c..d08abd359 100755 --- a/libtorrent/src/udp_tracker_connection.cpp +++ b/libtorrent/src/udp_tracker_connection.cpp @@ -110,9 +110,8 @@ namespace libtorrent return; } - boost::shared_ptr cb = requester(); #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (cb) cb->debug_log("udp tracker name lookup successful"); + if (has_requester()) requester().debug_log("udp tracker name lookup successful"); #endif restart_read_timeout(); @@ -127,11 +126,11 @@ namespace libtorrent if (target == end) { assert(target_address.address().is_v4() != bind_interface().is_v4()); - if (cb) + if (has_requester()) { std::string tracker_address_type = target_address.address().is_v4() ? "IPv4" : "IPv6"; std::string bind_address_type = bind_interface().is_v4() ? "IPv4" : "IPv6"; - cb->tracker_warning("the tracker only resolves to an " + requester().tracker_warning("the tracker only resolves to an " + tracker_address_type + " address, and you're listening on an " + bind_address_type + " socket. This may prevent you from receiving incoming connections."); } @@ -141,7 +140,7 @@ namespace libtorrent target_address = *target; } - if (cb) cb->m_tracker_address = tcp::endpoint(target_address.address(), target_address.port()); + if (has_requester()) requester().m_tracker_address = tcp::endpoint(target_address.address(), target_address.port()); m_target = target_address; m_socket.reset(new datagram_socket(m_name_lookup.io_service())); m_socket->open(target_address.protocol()); @@ -164,10 +163,9 @@ namespace libtorrent void udp_tracker_connection::send_udp_connect() { #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - boost::shared_ptr cb = requester(); - if (cb) + if (has_requester()) { - cb->debug_log("==> UDP_TRACKER_CONNECT [" + requester().debug_log("==> UDP_TRACKER_CONNECT [" + lexical_cast(tracker_req().info_hash) + "]"); } #endif @@ -261,10 +259,9 @@ namespace libtorrent m_connection_id = detail::read_int64(ptr); #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - boost::shared_ptr cb = requester(); - if (cb) + if (has_requester()) { - cb->debug_log("<== UDP_TRACKER_CONNECT_RESPONSE [" + requester().debug_log("<== UDP_TRACKER_CONNECT_RESPONSE [" + lexical_cast(m_connection_id) + "]"); } #endif @@ -324,10 +321,9 @@ namespace libtorrent detail::write_uint16(0, out); #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - boost::shared_ptr cb = requester(); - if (cb) + if (has_requester()) { - cb->debug_log("==> UDP_TRACKER_ANNOUNCE [" + requester().debug_log("==> UDP_TRACKER_ANNOUNCE [" + lexical_cast(req.info_hash) + "]"); } #endif @@ -435,15 +431,14 @@ namespace libtorrent return; } - boost::shared_ptr cb = requester(); #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (cb) + if (has_requester()) { - cb->debug_log("<== UDP_TRACKER_ANNOUNCE_RESPONSE"); + requester().debug_log("<== UDP_TRACKER_ANNOUNCE_RESPONSE"); } #endif - if (!cb) + if (!has_requester()) { m_man.remove_request(this); return; @@ -464,7 +459,7 @@ namespace libtorrent peer_list.push_back(e); } - cb->tracker_response(tracker_req(), peer_list, interval + requester().tracker_response(tracker_req(), peer_list, interval , complete, incomplete); m_man.remove_request(this); @@ -539,15 +534,14 @@ namespace libtorrent /*int downloaded = */detail::read_int32(buf); int incomplete = detail::read_int32(buf); - boost::shared_ptr cb = requester(); - if (!cb) + if (!has_requester()) { m_man.remove_request(this); return; } std::vector peer_list; - cb->tracker_response(tracker_req(), peer_list, 0 + requester().tracker_response(tracker_req(), peer_list, 0 , complete, incomplete); m_man.remove_request(this); diff --git a/libtorrent/src/upnp.cpp b/libtorrent/src/upnp.cpp index 87f950b48..aefff41b1 100644 --- a/libtorrent/src/upnp.cpp +++ b/libtorrent/src/upnp.cpp @@ -53,10 +53,38 @@ POSSIBILITY OF SUCH DAMAGE. using boost::bind; using namespace libtorrent; +address_v4 upnp::upnp_multicast_address; +udp::endpoint upnp::upnp_multicast_endpoint; + namespace libtorrent { - bool is_local(address const& a); - address_v4 guess_local_address(asio::io_service&); + bool is_local(address const& a) + { + if (a.is_v6()) return false; + address_v4 a4 = a.to_v4(); + unsigned long ip = a4.to_ulong(); + return ((ip & 0xff000000) == 0x0a000000 + || (ip & 0xfff00000) == 0xac100000 + || (ip & 0xffff0000) == 0xc0a80000); + } + + address_v4 guess_local_address(asio::io_service& ios) + { + // make a best guess of the interface we're using and its IP + udp::resolver r(ios); + udp::resolver::iterator i = r.resolve(udp::resolver::query(asio::ip::host_name(), "0")); + for (;i != udp::resolver_iterator(); ++i) + { + // ignore the loopback + if (i->endpoint().address() == address_v4((127 << 24) + 1)) continue; + // ignore addresses that are not on a local network + if (!is_local(i->endpoint().address())) continue; + // ignore non-IPv4 addresses + if (i->endpoint().address().is_v4()) break; + } + if (i == udp::resolver_iterator()) return address_v4::any(); + return i->endpoint().address().to_v4(); + } } upnp::upnp(io_service& ios, connection_queue& cc @@ -67,27 +95,89 @@ upnp::upnp(io_service& ios, connection_queue& cc , m_user_agent(user_agent) , m_callback(cb) , m_retry_count(0) - , m_io_service(ios) - , m_strand(ios) - , m_socket(ios, udp::endpoint(address_v4::from_string("239.255.255.250"), 1900) - , m_strand.wrap(bind(&upnp::on_reply, this, _1, _2, _3)), false) + , m_socket(ios) , m_broadcast_timer(ios) , m_refresh_timer(ios) + , m_strand(ios) , m_disabled(false) , m_closing(false) , m_cc(cc) { + // UPnP multicast address and port + upnp_multicast_address = address_v4::from_string("239.255.255.250"); + upnp_multicast_endpoint = udp::endpoint(upnp_multicast_address, 1900); + #ifdef TORRENT_UPNP_LOGGING m_log.open("upnp.log", std::ios::in | std::ios::out | std::ios::trunc); #endif - m_retry_count = 0; - discover_device(); + rebind(listen_interface); } upnp::~upnp() { } +void upnp::rebind(address const& listen_interface) try +{ + address_v4 bind_to = address_v4::any(); + if (listen_interface.is_v4() && listen_interface != address_v4::any()) + { + m_local_ip = listen_interface.to_v4(); + bind_to = listen_interface.to_v4(); + if (!is_local(m_local_ip)) + { + // the local address seems to be an external + // internet address. Assume it is not behind a NAT + throw std::runtime_error("local IP is not on a local network"); + } + } + else + { + m_local_ip = guess_local_address(m_socket.io_service()); + bind_to = address_v4::any(); + } + + if (!is_local(m_local_ip)) + { + throw std::runtime_error("local host is probably not on a NATed " + "network. disabling UPnP"); + } + +#ifdef TORRENT_UPNP_LOGGING + m_log << time_now_string() + << " local ip: " << m_local_ip.to_string() + << " bind to: " << bind_to.to_string() << std::endl; +#endif + + // the local interface hasn't changed + if (m_socket.is_open() + && m_socket.local_endpoint().address() == m_local_ip) + return; + + m_socket.close(); + + using namespace asio::ip::multicast; + + m_socket.open(udp::v4()); + m_socket.set_option(datagram_socket::reuse_address(true)); + m_socket.bind(udp::endpoint(bind_to, 0)); + + m_socket.set_option(join_group(upnp_multicast_address)); + m_socket.set_option(outbound_interface(bind_to)); + m_socket.set_option(hops(255)); + m_disabled = false; + + m_retry_count = 0; + discover_device(); +} +catch (std::exception& e) +{ + disable(); + std::stringstream msg; + msg << "UPnP portmapping disabled: " << e.what(); + m_callback(0, 0, msg.str()); +}; + void upnp::discover_device() try { const char msearch[] = @@ -98,20 +188,20 @@ void upnp::discover_device() try "MX:3\r\n" "\r\n\r\n"; + m_socket.async_receive_from(asio::buffer(m_receive_buffer + , sizeof(m_receive_buffer)), m_remote, m_strand.wrap(bind( + &upnp::on_reply, this, _1, _2))); + asio::error_code ec; #ifdef TORRENT_DEBUG_UPNP // simulate packet loss if (m_retry_count & 1) #endif - m_socket.send(msearch, sizeof(msearch) - 1, ec); + m_socket.send_to(asio::buffer(msearch, sizeof(msearch) - 1) + , upnp_multicast_endpoint, 0, ec); if (ec) { -#ifdef TORRENT_UPNP_LOGGING - m_log << time_now_string() - << " ==> Broadcast FAILED: " << ec.message() << std::endl - << "aborting" << std::endl; -#endif disable(); return; } @@ -129,7 +219,7 @@ void upnp::discover_device() try catch (std::exception&) { disable(); -}; +} void upnp::set_mappings(int tcp, int udp) { @@ -202,7 +292,7 @@ try rootdevice& d = const_cast(*i); try { - d.upnp_connection.reset(new http_connection(m_io_service + d.upnp_connection.reset(new http_connection(m_socket.io_service() , m_cc, m_strand.wrap(bind(&upnp::on_upnp_xml, this, _1, _2 , boost::ref(d))))); d.upnp_connection->get(d.url); @@ -223,16 +313,17 @@ try catch (std::exception&) { assert(false); -}; +} #endif -void upnp::on_reply(udp::endpoint const& from, char* buffer +void upnp::on_reply(asio::error_code const& e , std::size_t bytes_transferred) #ifndef NDEBUG try #endif { using namespace libtorrent::detail; + if (e) return; // parse out the url for the device @@ -247,45 +338,29 @@ try EXT: Cache-Control:max-age=180 DATE: Fri, 02 Jan 1970 08:10:38 GMT - - a notification looks like this: - - NOTIFY * HTTP/1.1 - Host:239.255.255.250:1900 - NT:urn:schemas-upnp-org:device:MediaServer:1 - NTS:ssdp:alive - Location:http://10.0.3.169:2869/upnphost/udhisapi.dll?content=uuid:c17f0c32-d19b-4938-ae94-65f945c3a26e - USN:uuid:c17f0c32-d19b-4938-ae94-65f945c3a26e::urn:schemas-upnp-org:device:MediaServer:1 - Cache-Control:max-age=900 - Server:Microsoft-Windows-NT/5.1 UPnP/1.0 UPnP-Device-Host/1.0 - */ http_parser p; try { - p.incoming(buffer::const_interval(buffer - , buffer + bytes_transferred)); + p.incoming(buffer::const_interval(m_receive_buffer + , m_receive_buffer + bytes_transferred)); } catch (std::exception& e) { #ifdef TORRENT_UPNP_LOGGING m_log << time_now_string() - << " <== Rootdevice responded with incorrect HTTP packet. Ignoring device (" << e.what() << ")" << std::endl; + << " <== Rootdevice responded with incorrect HTTP packet: " + << e.what() << ". Ignoring device" << std::endl; #endif return; } - if (p.status_code() != 200 && p.method() != "notify") + if (p.status_code() != 200) { #ifdef TORRENT_UPNP_LOGGING - if (p.method().empty()) - m_log << time_now_string() - << " <== Device responded with HTTP status: " << p.status_code() - << ". Ignoring device" << std::endl; - else - m_log << time_now_string() - << " <== Device with HTTP method: " << p.method() - << ". Ignoring device" << std::endl; + m_log << time_now_string() + << " <== Rootdevice responded with HTTP status: " << p.status_code() + << ". Ignoring device" << std::endl; #endif return; } @@ -356,8 +431,6 @@ try { d.mapping[0].need_update = true; d.mapping[0].local_port = m_tcp_local_port; - if (d.mapping[0].external_port == 0) - d.mapping[0].external_port = d.mapping[0].local_port; #ifdef TORRENT_UPNP_LOGGING m_log << time_now_string() << " *** Mapping 0 will be updated" << std::endl; #endif @@ -366,8 +439,6 @@ try { d.mapping[1].need_update = true; d.mapping[1].local_port = m_udp_local_port; - if (d.mapping[1].external_port == 0) - d.mapping[1].external_port = d.mapping[1].local_port; #ifdef TORRENT_UPNP_LOGGING m_log << time_now_string() << " *** Mapping 1 will be updated" << std::endl; #endif @@ -392,7 +463,7 @@ try rootdevice& d = const_cast(*i); try { - d.upnp_connection.reset(new http_connection(m_io_service + d.upnp_connection.reset(new http_connection(m_socket.io_service() , m_cc, m_strand.wrap(bind(&upnp::on_upnp_xml, this, _1, _2 , boost::ref(d))))); d.upnp_connection->get(d.url); @@ -417,7 +488,7 @@ catch (std::exception&) }; #endif -void upnp::post(upnp::rootdevice const& d, std::string const& soap +void upnp::post(rootdevice& d, std::stringstream const& soap , std::string const& soap_action) { std::stringstream header; @@ -425,40 +496,12 @@ void upnp::post(upnp::rootdevice const& d, std::string const& soap header << "POST " << d.control_url << " HTTP/1.1\r\n" "Host: " << d.hostname << ":" << d.port << "\r\n" "Content-Type: text/xml; charset=\"utf-8\"\r\n" - "Content-Length: " << soap.size() << "\r\n" - "Soapaction: \"" << d.service_namespace << "#" << soap_action << "\"\r\n\r\n" << soap; + "Content-Length: " << soap.str().size() << "\r\n" + "Soapaction: \"" << d.service_namespace << "#" << soap_action << "\"\r\n\r\n" << soap.str(); d.upnp_connection->sendbuffer = header.str(); - -#ifdef TORRENT_UPNP_LOGGING - m_log << time_now_string() - << " ==> sending: " << header.str() << std::endl; -#endif - -} - -void upnp::create_port_mapping(http_connection& c, rootdevice& d, int i) -{ - std::string soap_action = "AddPortMapping"; - - std::stringstream soap; - - soap << "\n" - "" - ""; - - soap << "" - "" << d.mapping[i].external_port << "" - "" << (d.mapping[i].protocol ? "UDP" : "TCP") << "" - "" << d.mapping[i].local_port << "" - "" << c.socket().local_endpoint().address().to_string() << "" - "1" - "" << m_user_agent << "" - "" << d.lease_duration << ""; - soap << ""; - - post(d, soap.str(), soap_action); + d.upnp_connection->start(d.hostname, boost::lexical_cast(d.port) + , seconds(10)); } void upnp::map_port(rootdevice& d, int i) @@ -479,21 +522,14 @@ void upnp::map_port(rootdevice& d, int i) assert(!d.upnp_connection); assert(d.service_namespace); - d.upnp_connection.reset(new http_connection(m_io_service + d.upnp_connection.reset(new http_connection(m_socket.io_service() , m_cc, m_strand.wrap(bind(&upnp::on_upnp_map_response, this, _1, _2 - , boost::ref(d), i)), true - , bind(&upnp::create_port_mapping, this, _1, boost::ref(d), i))); + , boost::ref(d), i)))); - d.upnp_connection->start(d.hostname, boost::lexical_cast(d.port) - , seconds(10)); -} + std::string soap_action = "AddPortMapping"; -void upnp::delete_port_mapping(rootdevice& d, int i) -{ std::stringstream soap; - std::string soap_action = "DeletePortMapping"; - soap << "\n" "" @@ -501,10 +537,20 @@ void upnp::delete_port_mapping(rootdevice& d, int i) soap << "" "" << d.mapping[i].external_port << "" - "" << (d.mapping[i].protocol ? "UDP" : "TCP") << ""; + "" << (d.mapping[i].protocol ? "UDP" : "TCP") << "" + "" << d.mapping[i].local_port << "" + "" << m_local_ip.to_string() << "" + "1" + "" << m_user_agent << "" + "" << d.lease_duration << ""; soap << ""; + + post(d, soap, soap_action); +#ifdef TORRENT_UPNP_LOGGING + m_log << time_now_string() + << " ==> AddPortMapping: " << soap.str() << std::endl; +#endif - post(d, soap.str(), soap_action); } // requires the mutex to be locked @@ -522,13 +568,29 @@ void upnp::unmap_port(rootdevice& d, int i) } return; } - d.upnp_connection.reset(new http_connection(m_io_service + d.upnp_connection.reset(new http_connection(m_socket.io_service() , m_cc, m_strand.wrap(bind(&upnp::on_upnp_unmap_response, this, _1, _2 - , boost::ref(d), i)), true - , bind(&upnp::delete_port_mapping, this, boost::ref(d), i))); + , boost::ref(d), i)))); - d.upnp_connection->start(d.hostname, boost::lexical_cast(d.port) - , seconds(10)); + std::string soap_action = "DeletePortMapping"; + + std::stringstream soap; + + soap << "\n" + "" + ""; + + soap << "" + "" << d.mapping[i].external_port << "" + "" << (d.mapping[i].protocol ? "UDP" : "TCP") << ""; + soap << ""; + + post(d, soap, soap_action); +#ifdef TORRENT_UPNP_LOGGING + m_log << time_now_string() + << " ==> DeletePortMapping: " << soap.str() << std::endl; +#endif } namespace @@ -776,9 +838,16 @@ void upnp::on_upnp_map_response(asio::error_code const& e m_devices.erase(d); return; } - - // We don't want to ignore responses with return codes other than 200 - // since those might contain valid UPnP error codes + + if (p.status_code() != 200) + { +#ifdef TORRENT_UPNP_LOGGING + m_log << time_now_string() + << " <== error while adding portmap: " << p.message() << std::endl; +#endif + m_devices.erase(d); + return; + } error_code_parse_state s; xml_parse((char*)p.get_body().begin, (char*)p.get_body().end diff --git a/libtorrent/src/ut_pex.cpp b/libtorrent/src/ut_pex.cpp index 18fe715ee..18cbf6c2f 100644 --- a/libtorrent/src/ut_pex.cpp +++ b/libtorrent/src/ut_pex.cpp @@ -67,6 +67,8 @@ namespace libtorrent { namespace if (!p.is_local()) return false; // don't send out peers that we haven't successfully connected to if (p.is_connecting()) return false; + // ut pex does not support IPv6 + if (!p.remote().address().is_v4()) return false; return true; } @@ -96,15 +98,9 @@ namespace libtorrent { namespace std::string& pla = pex["added"].string(); std::string& pld = pex["dropped"].string(); std::string& plf = pex["added.f"].string(); - std::string& pla6 = pex["added6"].string(); - std::string& pld6 = pex["dropped6"].string(); - std::string& plf6 = pex["added6.f"].string(); std::back_insert_iterator pla_out(pla); std::back_insert_iterator pld_out(pld); std::back_insert_iterator plf_out(plf); - std::back_insert_iterator pla6_out(pla6); - std::back_insert_iterator pld6_out(pld6); - std::back_insert_iterator plf6_out(plf6); std::set dropped; m_old_peers.swap(dropped); @@ -127,6 +123,8 @@ namespace libtorrent { namespace bt_peer_connection* p = dynamic_cast(i->second); if (!p) continue; + // i->first was added since the last time + detail::write_endpoint(i->first, pla_out); // no supported flags to set yet // 0x01 - peer supports encryption // 0x02 - peer is a seed @@ -134,17 +132,7 @@ namespace libtorrent { namespace #ifndef TORRENT_DISABLE_ENCRYPTION flags |= p->supports_encryption() ? 1 : 0; #endif - // i->first was added since the last time - if (i->first.address().is_v4()) - { - detail::write_endpoint(i->first, pla_out); - detail::write_uint8(flags, plf_out); - } - else - { - detail::write_endpoint(i->first, pla6_out); - detail::write_uint8(flags, plf6_out); - } + detail::write_uint8(flags, plf_out); ++num_added; } else @@ -158,10 +146,8 @@ namespace libtorrent { namespace for (std::set::const_iterator i = dropped.begin() , end(dropped.end());i != end; ++i) { - if (i->address().is_v4()) - detail::write_endpoint(*i, pld_out); - else - detail::write_endpoint(*i, pld6_out); + if (!i->address().is_v4()) continue; + detail::write_endpoint(*i, pld_out); } m_ut_pex_msg.clear(); @@ -241,28 +227,6 @@ namespace libtorrent { namespace char flags = detail::read_uint8(fin); p.peer_from_tracker(adr, pid, peer_info::pex, flags); } - - if (entry const* p6 = pex_msg.find_key("added6")) - { - std::string const& peers6 = p6->string(); - std::string const& peer6_flags = pex_msg["added6.f"].string(); - - int num_peers = peers6.length() / 18; - char const* in = peers6.c_str(); - char const* fin = peer6_flags.c_str(); - - if (int(peer6_flags.size()) != num_peers) - return true; - - peer_id pid(0); - policy& p = m_torrent.get_policy(); - for (int i = 0; i < num_peers; ++i) - { - tcp::endpoint adr = detail::read_v6_endpoint(in); - char flags = detail::read_uint8(fin); - p.peer_from_tracker(adr, pid, peer_info::pex, flags); - } - } } catch (std::exception&) { @@ -315,13 +279,8 @@ namespace libtorrent { namespace pex["dropped"].string(); std::string& pla = pex["added"].string(); std::string& plf = pex["added.f"].string(); - pex["dropped6"].string(); - std::string& pla6 = pex["added6"].string(); - std::string& plf6 = pex["added6.f"].string(); std::back_insert_iterator pla_out(pla); std::back_insert_iterator plf_out(plf); - std::back_insert_iterator pla6_out(pla6); - std::back_insert_iterator plf6_out(plf6); int num_added = 0; for (torrent::peer_iterator i = m_torrent.begin() @@ -336,6 +295,8 @@ namespace libtorrent { namespace bt_peer_connection* p = dynamic_cast(i->second); if (!p) continue; + // i->first was added since the last time + detail::write_endpoint(i->first, pla_out); // no supported flags to set yet // 0x01 - peer supports encryption // 0x02 - peer is a seed @@ -343,17 +304,7 @@ namespace libtorrent { namespace #ifndef TORRENT_DISABLE_ENCRYPTION flags |= p->supports_encryption() ? 1 : 0; #endif - // i->first was added since the last time - if (i->first.address().is_v4()) - { - detail::write_endpoint(i->first, pla_out); - detail::write_uint8(flags, plf_out); - } - else - { - detail::write_endpoint(i->first, pla6_out); - detail::write_uint8(flags, plf6_out); - } + detail::write_uint8(flags, plf_out); ++num_added; } std::vector pex_msg; @@ -396,7 +347,7 @@ namespace libtorrent { namespace namespace libtorrent { - boost::shared_ptr create_ut_pex_plugin(torrent* t, void*) + boost::shared_ptr create_ut_pex_plugin(torrent* t) { if (t->torrent_file().priv()) { diff --git a/libtorrent/src/web_peer_connection.cpp b/libtorrent/src/web_peer_connection.cpp index a307fc9cb..6c6745f30 100755 --- a/libtorrent/src/web_peer_connection.cpp +++ b/libtorrent/src/web_peer_connection.cpp @@ -69,6 +69,9 @@ namespace libtorrent { INVARIANT_CHECK; + // we always prefer downloading entire + // pieces from web seeds + prefer_whole_pieces(true); // we want large blocks as well, so // we can request more bytes at once request_large_blocks(true); @@ -77,10 +80,6 @@ namespace libtorrent shared_ptr tor = t.lock(); assert(tor); int blocks_per_piece = tor->torrent_file().piece_length() / tor->block_size(); - - // we always prefer downloading 1 MB chunks - // from web seeds - prefer_whole_pieces((1024 * 1024) / tor->torrent_file().piece_length()); // multiply with the blocks per piece since that many requests are // merged into one http request @@ -179,16 +178,13 @@ namespace libtorrent int size = r.length; const int block_size = t->block_size(); - const int piece_size = t->torrent_file().piece_length(); - peer_request pr; while (size > 0) { - int request_offset = r.start + r.length - size; - pr.start = request_offset % piece_size; - pr.length = (std::min)(block_size, size); - pr.piece = r.piece + request_offset / piece_size; + int request_size = std::min(block_size, size); + peer_request pr = {r.piece, r.start + r.length - size + , request_size}; m_requests.push_back(pr); - size -= pr.length; + size -= request_size; } proxy_settings const& ps = m_ses.web_seed_proxy(); @@ -481,11 +477,8 @@ namespace libtorrent peer_request front_request = m_requests.front(); - size_type rs = size_type(in_range.piece) * info.piece_length() + in_range.start; - size_type re = rs + in_range.length; - size_type fs = size_type(front_request.piece) * info.piece_length() + front_request.start; - size_type fe = fs + front_request.length; - if (fs < rs || fe > re) + if (in_range.piece != front_request.piece + || in_range.start > front_request.start + int(m_piece.size())) { throw std::runtime_error("invalid range in HTTP response"); } @@ -493,7 +486,7 @@ namespace libtorrent // skip the http header and the blocks we've already read. The // http_body.begin is now in sync with the request at the front // of the request queue -// assert(in_range.start - int(m_piece.size()) <= front_request.start); + assert(in_range.start - int(m_piece.size()) <= front_request.start); // the http response body consists of 3 parts // 1. the middle of a block or the ending of a block @@ -517,7 +510,7 @@ namespace libtorrent // m_piece as buffer. int piece_size = int(m_piece.size()); - int copy_size = (std::min)((std::min)(front_request.length - piece_size + int copy_size = std::min(std::min(front_request.length - piece_size , recv_buffer.left()), int(range_end - range_start - m_received_body)); m_piece.resize(piece_size + copy_size); assert(copy_size > 0); @@ -575,7 +568,7 @@ namespace libtorrent && (m_received_body + recv_buffer.left() >= range_end - range_start)) { int piece_size = int(m_piece.size()); - int copy_size = (std::min)((std::min)(m_requests.front().length - piece_size + int copy_size = std::min(std::min(m_requests.front().length - piece_size , recv_buffer.left()), int(range_end - range_start - m_received_body)); assert(copy_size >= 0); if (copy_size > 0)