From b2fe562dd4fa667fa27d9026c33c2da8552af1a7 Mon Sep 17 00:00:00 2001 From: Marcos Pinto Date: Thu, 20 Sep 2007 23:43:07 +0000 Subject: [PATCH] libtorrent sync 1592 --- 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/CVS/Entries | 45 - libtorrent/include/asio/CVS/Repository | 1 - libtorrent/include/asio/CVS/Root | 1 - libtorrent/include/asio/basic_socket.hpp | 6 + libtorrent/include/asio/buffer.hpp | 7 +- .../include/asio/completion_condition.hpp | 44 + libtorrent/include/asio/detail/CVS/Entries | 74 - libtorrent/include/asio/detail/CVS/Repository | 1 - libtorrent/include/asio/detail/CVS/Root | 1 - .../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 | 346 ++-- libtorrent/include/asio/error_code.hpp | 44 +- libtorrent/include/asio/impl/CVS/Entries | 6 - libtorrent/include/asio/impl/CVS/Repository | 1 - libtorrent/include/asio/impl/CVS/Root | 1 - 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/CVS/Entries | 17 - libtorrent/include/asio/ip/CVS/Repository | 1 - libtorrent/include/asio/ip/CVS/Root | 1 - libtorrent/include/asio/ip/basic_endpoint.hpp | 34 +- libtorrent/include/asio/ssl/CVS/Entries | 8 - libtorrent/include/asio/ssl/CVS/Repository | 1 - libtorrent/include/asio/ssl/CVS/Root | 1 - .../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 | 52 + .../include/libtorrent/aux_/session_impl.hpp | 52 +- .../include/libtorrent/bandwidth_manager.hpp | 34 +- libtorrent/include/libtorrent/bencode.hpp | 2 + .../include/libtorrent/broadcast_socket.hpp | 80 + .../include/libtorrent/bt_peer_connection.hpp | 30 +- libtorrent/include/libtorrent/buffer.hpp | 3 +- libtorrent/include/libtorrent/config.hpp | 1 + .../include/libtorrent/connection_queue.hpp | 5 + libtorrent/include/libtorrent/debug.hpp | 1 + libtorrent/include/libtorrent/entry.hpp | 2 +- libtorrent/include/libtorrent/enum_net.hpp | 44 + libtorrent/include/libtorrent/extensions.hpp | 9 + libtorrent/include/libtorrent/fingerprint.hpp | 2 + libtorrent/include/libtorrent/hasher.hpp | 2 +- .../include/libtorrent/http_connection.hpp | 12 +- .../libtorrent/http_tracker_connection.hpp | 5 + .../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 | 12 +- .../include/libtorrent/piece_picker.hpp | 48 +- libtorrent/include/libtorrent/policy.hpp | 31 +- libtorrent/include/libtorrent/session.hpp | 27 +- .../include/libtorrent/session_settings.hpp | 12 +- libtorrent/include/libtorrent/stat.hpp | 1 + libtorrent/include/libtorrent/storage.hpp | 28 +- libtorrent/include/libtorrent/time.hpp | 7 +- libtorrent/include/libtorrent/torrent.hpp | 57 +- .../include/libtorrent/torrent_handle.hpp | 5 +- .../include/libtorrent/torrent_info.hpp | 84 +- libtorrent/include/libtorrent/upnp.hpp | 28 +- .../libtorrent/web_peer_connection.hpp | 3 +- libtorrent/src/Makefile.am | 9 +- libtorrent/src/assert.cpp | 65 + libtorrent/src/broadcast_socket.cpp | 144 ++ libtorrent/src/bt_peer_connection.cpp | 229 ++- libtorrent/src/connection_queue.cpp | 26 +- libtorrent/src/deluge_core.cpp | 1439 ----------------- libtorrent/src/disk_io_thread.cpp | 30 +- libtorrent/src/enum_net.cpp | 133 ++ libtorrent/src/escape_string.cpp | 3 +- libtorrent/src/http_connection.cpp | 7 +- libtorrent/src/http_tracker_connection.cpp | 102 +- 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 | 2 +- libtorrent/src/natpmp.cpp | 6 +- libtorrent/src/pe_crypto.cpp | 2 +- libtorrent/src/peer_connection.cpp | 583 +++++-- libtorrent/src/piece_picker.cpp | 484 ++++-- libtorrent/src/policy.cpp | 262 +-- libtorrent/src/session.cpp | 29 +- libtorrent/src/session_impl.cpp | 510 ++++-- libtorrent/src/socks5_stream.cpp | 1 + libtorrent/src/storage.cpp | 232 ++- libtorrent/src/torrent.cpp | 366 +++-- libtorrent/src/torrent_handle.cpp | 227 ++- libtorrent/src/torrent_info.cpp | 43 +- libtorrent/src/tracker_manager.cpp | 6 +- libtorrent/src/upnp.cpp | 270 ++-- libtorrent/src/web_peer_connection.cpp | 31 +- 133 files changed, 4077 insertions(+), 3744 deletions(-) delete mode 100644 libtorrent/include/asio/CVS/Entries delete mode 100644 libtorrent/include/asio/CVS/Repository delete mode 100644 libtorrent/include/asio/CVS/Root delete mode 100644 libtorrent/include/asio/detail/CVS/Entries delete mode 100644 libtorrent/include/asio/detail/CVS/Repository delete mode 100644 libtorrent/include/asio/detail/CVS/Root delete mode 100644 libtorrent/include/asio/impl/CVS/Entries delete mode 100644 libtorrent/include/asio/impl/CVS/Repository delete mode 100644 libtorrent/include/asio/impl/CVS/Root delete mode 100644 libtorrent/include/asio/ip/CVS/Entries delete mode 100644 libtorrent/include/asio/ip/CVS/Repository delete mode 100644 libtorrent/include/asio/ip/CVS/Root delete mode 100644 libtorrent/include/asio/ssl/CVS/Entries delete mode 100644 libtorrent/include/asio/ssl/CVS/Repository delete mode 100644 libtorrent/include/asio/ssl/CVS/Root create mode 100644 libtorrent/include/libtorrent/assert.hpp create mode 100644 libtorrent/include/libtorrent/broadcast_socket.hpp create mode 100644 libtorrent/include/libtorrent/enum_net.hpp create mode 100644 libtorrent/src/assert.cpp create mode 100644 libtorrent/src/broadcast_socket.cpp delete mode 100644 libtorrent/src/deluge_core.cpp create mode 100644 libtorrent/src/enum_net.cpp diff --git a/libtorrent/bindings/python/src/alert.cpp b/libtorrent/bindings/python/src/alert.cpp index f34cf4b5d..3e188a3ce 100755 --- a/libtorrent/bindings/python/src/alert.cpp +++ b/libtorrent/bindings/python/src/alert.cpp @@ -25,6 +25,8 @@ 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; @@ -140,7 +142,18 @@ 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 fbd0a157c..e4a99ba31 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_start_natpmp_doc = + ""; +char const* session_stop_natpmp_doc = ""; -char const* session_stop_natpmp_doc = - ""; // -- alert ----------------------------------------------------------------- char const* alert_doc = @@ -257,6 +257,17 @@ 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 10d18ff94..f8fb30bdf 100755 --- a/libtorrent/bindings/python/src/extensions.cpp +++ b/libtorrent/bindings/python/src/extensions.cpp @@ -142,7 +142,6 @@ 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 4ea7a1711..480659537 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,11 +86,10 @@ namespace torrent_handle add_torrent(session& s, torrent_info const& ti , boost::filesystem::path const& save, entry const& resume - , bool compact, int block_size) + , bool compact, bool paused) { allow_threading_guard guard; - return s.add_torrent(ti, save, resume, compact, block_size - , default_storage_constructor); + return s.add_torrent(ti, save, resume, compact, paused, default_storage_constructor); } } // namespace unnamed @@ -175,7 +174,7 @@ void bind_session() "add_torrent", &add_torrent , ( arg("torrent_info"), "save_path", arg("resume_data") = entry() - , arg("compact_mode") = true, arg("block_size") = 16 * 1024 + , arg("compact_mode") = true, arg("paused") = false ) , session_add_torrent_doc ) diff --git a/libtorrent/bindings/python/src/session_settings.cpp b/libtorrent/bindings/python/src/session_settings.cpp index f584956b2..c19dfa4d4 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 301c4a5bf..a17c449e3 100755 --- a/libtorrent/bindings/python/src/torrent_info.cpp +++ b/libtorrent/bindings/python/src/torrent_info.cpp @@ -16,7 +16,6 @@ namespace return i.trackers().begin(); } - std::vector::const_iterator end_trackers(torrent_info& i) { return i.trackers().end(); @@ -41,6 +40,29 @@ 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() @@ -71,9 +93,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) + .def("num_files", &torrent_info::num_files, (arg("storage")=false)) .def("file_at", &torrent_info::file_at, return_internal_reference<>()) - .def("files", range(&torrent_info::begin_files, &torrent_info::end_files)) + .def("files", &files, (arg("storage")=false)) .def("priv", &torrent_info::priv) .def("set_priv", &torrent_info::set_priv) @@ -84,9 +106,8 @@ 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/CVS/Entries b/libtorrent/include/asio/CVS/Entries deleted file mode 100644 index 43749a985..000000000 --- a/libtorrent/include/asio/CVS/Entries +++ /dev/null @@ -1,45 +0,0 @@ -/basic_datagram_socket.hpp/1.40/Thu Jan 4 05:44:43 2007// -/basic_deadline_timer.hpp/1.23/Sun May 20 00:49:02 2007// -/basic_io_object.hpp/1.8/Thu Jan 4 05:44:43 2007// -/basic_socket.hpp/1.16/Mon Jan 8 22:12:45 2007// -/basic_socket_acceptor.hpp/1.58/Fri Feb 9 05:47:48 2007// -/basic_socket_iostream.hpp/1.8/Thu Jan 18 11:41:36 2007// -/basic_socket_streambuf.hpp/1.6/Thu Jan 18 11:41:36 2007// -/basic_stream_socket.hpp/1.69/Mon Jan 8 22:12:45 2007// -/basic_streambuf.hpp/1.12/Thu Jan 4 10:23:31 2007// -/buffer.hpp/1.23/Thu Jun 21 14:03:36 2007// -/buffered_read_stream.hpp/1.17/Thu Jan 4 05:44:43 2007// -/buffered_read_stream_fwd.hpp/1.5/Thu Jan 4 05:44:43 2007// -/buffered_stream.hpp/1.32/Thu Jan 4 05:44:43 2007// -/buffered_stream_fwd.hpp/1.9/Thu Jan 4 05:44:43 2007// -/buffered_write_stream.hpp/1.17/Thu Jan 4 05:44:43 2007// -/buffered_write_stream_fwd.hpp/1.5/Thu Jan 4 05:44:43 2007// -/completion_condition.hpp/1.5/Thu Jan 4 05:44:43 2007// -/datagram_socket_service.hpp/1.34/Mon Jan 8 22:12:45 2007// -/deadline_timer.hpp/1.6/Thu Jan 4 05:44:43 2007// -/deadline_timer_service.hpp/1.29/Mon Jan 8 02:47:13 2007// -/error.hpp/1.39/Mon Jan 8 22:12:45 2007// -/error_code.hpp/1.4/Mon Jan 8 22:12:45 2007// -/handler_alloc_hook.hpp/1.11/Thu Jan 4 05:44:43 2007// -/handler_invoke_hook.hpp/1.3/Thu Jan 4 05:44:43 2007// -/io_service.hpp/1.24/Sun May 20 00:49:02 2007// -/is_read_buffered.hpp/1.6/Thu Jan 4 05:44:43 2007// -/is_write_buffered.hpp/1.6/Thu Jan 4 05:44:43 2007// -/placeholders.hpp/1.10/Thu Jan 4 05:44:43 2007// -/read.hpp/1.22/Thu Jan 4 05:44:43 2007// -/read_until.hpp/1.8/Thu Jan 4 05:44:44 2007// -/socket_acceptor_service.hpp/1.34/Fri Feb 9 05:47:48 2007// -/socket_base.hpp/1.23/Mon Jan 8 23:45:36 2007// -/ssl.hpp/1.4/Thu Jan 4 05:44:44 2007// -/strand.hpp/1.6/Tue May 8 13:13:55 2007// -/stream_socket_service.hpp/1.35/Mon Jan 8 22:12:46 2007// -/streambuf.hpp/1.3/Thu Jan 4 05:44:44 2007// -/system_error.hpp/1.3/Thu Jan 4 05:44:44 2007// -/thread.hpp/1.15/Thu Jan 4 05:44:44 2007// -/time_traits.hpp/1.9/Thu Jan 4 05:44:44 2007// -/version.hpp/1.1/Tue May 8 12:17:36 2007// -/write.hpp/1.21/Thu Jan 4 05:44:44 2007// -D/detail//// -D/impl//// -D/ip//// -D/ssl//// diff --git a/libtorrent/include/asio/CVS/Repository b/libtorrent/include/asio/CVS/Repository deleted file mode 100644 index 2a32176a2..000000000 --- a/libtorrent/include/asio/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -asio/include/asio diff --git a/libtorrent/include/asio/CVS/Root b/libtorrent/include/asio/CVS/Root deleted file mode 100644 index a7505d52a..000000000 --- a/libtorrent/include/asio/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:pserver:anonymous@asio.cvs.sourceforge.net:/cvsroot/asio diff --git a/libtorrent/include/asio/basic_socket.hpp b/libtorrent/include/asio/basic_socket.hpp index b0dc52e48..2b2521b69 100644 --- a/libtorrent/include/asio/basic_socket.hpp +++ b/libtorrent/include/asio/basic_socket.hpp @@ -238,6 +238,9 @@ 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() { @@ -265,6 +268,9 @@ 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 7e5dc76c8..9fe76178c 100644 --- a/libtorrent/include/asio/buffer.hpp +++ b/libtorrent/include/asio/buffer.hpp @@ -542,9 +542,10 @@ inline const_buffers_1 buffer(const PodType (&data)[N], ? N * sizeof(PodType) : max_size_in_bytes)); } -#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x582)) \ + || BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x590)) -// Borland C++ thinks the overloads: +// Borland C++ and Sun Studio think the overloads: // // unspecified buffer(boost::array& array ...); // @@ -610,6 +611,7 @@ 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 @@ -650,6 +652,7 @@ 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 42696d599..939a4a8f3 100644 --- a/libtorrent/include/asio/completion_condition.hpp +++ b/libtorrent/include/asio/completion_condition.hpp @@ -71,6 +71,28 @@ 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 @@ -83,6 +105,28 @@ 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/CVS/Entries b/libtorrent/include/asio/detail/CVS/Entries deleted file mode 100644 index e6deb1bfd..000000000 --- a/libtorrent/include/asio/detail/CVS/Entries +++ /dev/null @@ -1,74 +0,0 @@ -/bind_handler.hpp/1.18/Thu Jan 4 05:44:44 2007// -/buffer_resize_guard.hpp/1.9/Thu Jan 4 05:44:44 2007// -/buffered_stream_storage.hpp/1.5/Thu Jan 4 05:44:44 2007// -/call_stack.hpp/1.3/Thu Jan 4 05:44:44 2007// -/const_buffers_iterator.hpp/1.3/Thu Jan 4 05:44:44 2007// -/consuming_buffers.hpp/1.7/Sat Jan 13 13:41:09 2007// -/deadline_timer_service.hpp/1.7/Mon Jan 8 02:47:13 2007// -/epoll_reactor.hpp/1.40/Thu Jan 4 05:44:44 2007// -/epoll_reactor_fwd.hpp/1.3/Thu Jan 4 05:44:44 2007// -/event.hpp/1.13/Thu Jan 4 05:44:44 2007// -/fd_set_adapter.hpp/1.5/Thu Jan 4 05:44:44 2007// -/handler_alloc_helpers.hpp/1.8/Thu Jan 4 05:44:44 2007// -/handler_invoke_helpers.hpp/1.2/Thu Jan 4 05:44:44 2007// -/hash_map.hpp/1.19/Thu Mar 22 21:13:13 2007// -/io_control.hpp/1.5/Thu Jan 4 05:44:44 2007// -/kqueue_reactor.hpp/1.30/Thu Mar 22 21:08:02 2007// -/kqueue_reactor_fwd.hpp/1.3/Thu Jan 4 05:44:44 2007// -/local_free_on_block_exit.hpp/1.2/Thu Jan 4 05:44:44 2007// -/mutex.hpp/1.13/Thu Jan 4 05:44:44 2007// -/noncopyable.hpp/1.3/Thu Jan 4 05:44:44 2007// -/null_event.hpp/1.3/Thu Jan 4 05:44:44 2007// -/null_mutex.hpp/1.3/Thu Jan 4 05:44:44 2007// -/null_signal_blocker.hpp/1.3/Thu Jan 4 05:44:44 2007// -/null_thread.hpp/1.5/Mon Jan 8 22:12:46 2007// -/null_tss_ptr.hpp/1.3/Thu Jan 4 05:44:44 2007// -/old_win_sdk_compat.hpp/1.5/Sat May 12 08:16:25 2007// -/pipe_select_interrupter.hpp/1.11/Thu Jan 4 05:44:44 2007// -/pop_options.hpp/1.10/Thu Jan 4 05:44:44 2007// -/posix_event.hpp/1.16/Thu Jan 4 05:44:44 2007// -/posix_fd_set_adapter.hpp/1.4/Tue Feb 13 07:13:29 2007// -/posix_mutex.hpp/1.15/Thu Jan 4 05:44:44 2007// -/posix_signal_blocker.hpp/1.10/Sat Feb 17 22:57:37 2007// -/posix_thread.hpp/1.17/Thu Jan 4 05:44:45 2007// -/posix_tss_ptr.hpp/1.10/Thu Jan 4 05:44:45 2007// -/push_options.hpp/1.16/Thu Jan 4 05:44:45 2007// -/reactive_socket_service.hpp/1.59/Sun May 13 23:00:01 2007// -/reactor_op_queue.hpp/1.24/Thu Jan 4 05:44:45 2007// -/resolver_service.hpp/1.11/Thu Jan 4 09:06:56 2007// -/scoped_lock.hpp/1.9/Thu Jan 4 05:44:45 2007// -/select_interrupter.hpp/1.10/Thu Jan 4 05:44:45 2007// -/select_reactor.hpp/1.49/Thu Jan 4 05:44:45 2007// -/select_reactor_fwd.hpp/1.2/Thu Jan 4 05:44:45 2007// -/service_base.hpp/1.2/Thu Jan 4 05:44:45 2007// -/service_id.hpp/1.2/Thu Jan 4 05:44:45 2007// -/service_registry.hpp/1.19/Tue Feb 13 12:06:43 2007// -/service_registry_fwd.hpp/1.2/Thu Jan 4 05:44:45 2007// -/signal_blocker.hpp/1.10/Thu Jan 4 05:44:45 2007// -/signal_init.hpp/1.11/Thu Jan 4 05:44:45 2007// -/socket_holder.hpp/1.10/Thu Jan 4 05:44:45 2007// -/socket_ops.hpp/1.74/Mon May 21 12:34:39 2007// -/socket_option.hpp/1.7/Sat Feb 17 22:57:37 2007// -/socket_select_interrupter.hpp/1.15/Thu May 10 23:48:52 2007// -/socket_types.hpp/1.41/Sun May 13 07:59:21 2007// -/strand_service.hpp/1.15/Thu Jan 4 05:44:45 2007// -/task_io_service.hpp/1.18/Wed Feb 14 13:26:21 2007// -/task_io_service_fwd.hpp/1.2/Thu Jan 4 05:44:45 2007// -/thread.hpp/1.13/Thu Jan 4 05:44:45 2007// -/throw_error.hpp/1.3/Thu Jan 4 05:44:45 2007// -/timer_queue.hpp/1.6/Sun Apr 22 07:07:15 2007// -/timer_queue_base.hpp/1.2/Thu Jan 4 05:44:45 2007// -/tss_ptr.hpp/1.8/Thu Jan 4 05:44:45 2007// -/win_event.hpp/1.14/Thu Jan 4 05:44:45 2007// -/win_fd_set_adapter.hpp/1.4/Thu Jan 4 05:44:45 2007// -/win_iocp_io_service.hpp/1.24/Mon Jan 8 01:09:14 2007// -/win_iocp_io_service_fwd.hpp/1.4/Thu Jan 4 05:44:45 2007// -/win_iocp_operation.hpp/1.16/Thu Jan 4 05:44:45 2007// -/win_iocp_socket_service.hpp/1.75/Sat May 12 09:07:32 2007// -/win_mutex.hpp/1.16/Thu Jan 4 05:44:45 2007// -/win_signal_blocker.hpp/1.9/Thu Jan 4 05:44:45 2007// -/win_thread.hpp/1.20/Thu Jan 4 05:44:45 2007// -/win_tss_ptr.hpp/1.10/Thu Jan 4 05:44:45 2007// -/winsock_init.hpp/1.16/Thu Jan 4 05:44:45 2007// -/wrapped_handler.hpp/1.11/Thu Jan 4 05:44:45 2007// -D diff --git a/libtorrent/include/asio/detail/CVS/Repository b/libtorrent/include/asio/detail/CVS/Repository deleted file mode 100644 index 711cf30c4..000000000 --- a/libtorrent/include/asio/detail/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -asio/include/asio/detail diff --git a/libtorrent/include/asio/detail/CVS/Root b/libtorrent/include/asio/detail/CVS/Root deleted file mode 100644 index a7505d52a..000000000 --- a/libtorrent/include/asio/detail/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:pserver:anonymous@asio.cvs.sourceforge.net:/cvsroot/asio diff --git a/libtorrent/include/asio/detail/epoll_reactor.hpp b/libtorrent/include/asio/detail/epoll_reactor.hpp index d55e86454..e260c5194 100644 --- a/libtorrent/include/asio/detail/epoll_reactor.hpp +++ b/libtorrent/include/asio/detail/epoll_reactor.hpp @@ -157,7 +157,8 @@ public: int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); if (result != 0) { - asio::error_code ec(errno, asio::native_ecat); + asio::error_code ec(errno, + asio::error::system_category); read_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -190,7 +191,8 @@ public: int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); if (result != 0) { - asio::error_code ec(errno, asio::native_ecat); + asio::error_code ec(errno, + asio::error::system_category); write_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -219,7 +221,8 @@ public: int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); if (result != 0) { - asio::error_code ec(errno, asio::native_ecat); + asio::error_code ec(errno, + asio::error::system_category); except_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -250,7 +253,8 @@ public: int result = epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, descriptor, &ev); if (result != 0) { - asio::error_code ec(errno, asio::native_ecat); + asio::error_code ec(errno, + asio::error::system_category); write_op_queue_.dispatch_all_operations(descriptor, ec); except_op_queue_.dispatch_all_operations(descriptor, ec); } @@ -331,7 +335,10 @@ public: std::size_t cancel_timer(timer_queue& timer_queue, void* token) { asio::detail::mutex::scoped_lock lock(mutex_); - return timer_queue.cancel_timer(token); + std::size_t n = timer_queue.cancel_timer(token); + if (n > 0) + interrupter_.interrupt(); + return n; } private: @@ -347,16 +354,13 @@ 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_) { - // 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(); + cleanup_operations_and_timers(lock); return; } @@ -365,12 +369,7 @@ private: if (!block && read_op_queue_.empty() && write_op_queue_.empty() && except_op_queue_.empty() && all_timer_queues_are_empty()) { - // 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(); + cleanup_operations_and_timers(lock); return; } @@ -398,59 +397,45 @@ private: } else { - if (events[i].events & (EPOLLERR | EPOLLHUP)) + 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) { - asio::error_code ec; - except_op_queue_.dispatch_all_operations(descriptor, ec); + ec = asio::error_code(errno, + asio::error::system_category); read_op_queue_.dispatch_all_operations(descriptor, ec); write_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); - } + except_op_queue_.dispatch_all_operations(descriptor, ec); } } } @@ -458,19 +443,17 @@ 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(); - // 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(); + cleanup_operations_and_timers(lock); } // Run the select loop in the thread. @@ -507,8 +490,10 @@ private: int fd = epoll_create(epoll_size); if (fd == -1) { - boost::throw_exception(asio::system_error( - asio::error_code(errno, asio::native_ecat), + boost::throw_exception( + asio::system_error( + asio::error_code(errno, + asio::error::system_category), "epoll")); } return fd; @@ -566,6 +551,22 @@ 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_; @@ -590,6 +591,10 @@ 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 6628803af..5fffc6788 100644 --- a/libtorrent/include/asio/detail/kqueue_reactor.hpp +++ b/libtorrent/include/asio/detail/kqueue_reactor.hpp @@ -150,7 +150,8 @@ 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::native_ecat); + asio::error_code ec(errno, + asio::error::system_category); read_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -176,7 +177,8 @@ 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::native_ecat); + asio::error_code ec(errno, + asio::error::system_category); write_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -201,7 +203,8 @@ 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::native_ecat); + asio::error_code ec(errno, + asio::error::system_category); except_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -224,7 +227,8 @@ 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::native_ecat); + asio::error_code ec(errno, + asio::error::system_category); write_op_queue_.dispatch_all_operations(descriptor, ec); } } @@ -238,7 +242,8 @@ 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::native_ecat); + asio::error_code ec(errno, + asio::error::system_category); except_op_queue_.dispatch_all_operations(descriptor, ec); write_op_queue_.dispatch_all_operations(descriptor, ec); } @@ -321,7 +326,10 @@ public: std::size_t cancel_timer(timer_queue& timer_queue, void* token) { asio::detail::mutex::scoped_lock lock(mutex_); - return timer_queue.cancel_timer(token); + std::size_t n = timer_queue.cancel_timer(token); + if (n > 0) + interrupter_.interrupt(); + return n; } private: @@ -337,16 +345,13 @@ 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_) { - // 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(); + cleanup_operations_and_timers(lock); return; } @@ -355,12 +360,7 @@ private: if (!block && read_op_queue_.empty() && write_op_queue_.empty() && except_op_queue_.empty() && all_timer_queues_are_empty()) { - // 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(); + cleanup_operations_and_timers(lock); return; } @@ -397,7 +397,7 @@ private: if (events[i].flags & EV_ERROR) { asio::error_code error( - events[i].data, asio::native_ecat); + events[i].data, asio::error::system_category); except_op_queue_.dispatch_all_operations(descriptor, error); read_op_queue_.dispatch_all_operations(descriptor, error); } @@ -427,7 +427,8 @@ 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::native_ecat); + asio::error_code error(errno, + asio::error::system_category); except_op_queue_.dispatch_all_operations(descriptor, error); read_op_queue_.dispatch_all_operations(descriptor, error); } @@ -439,7 +440,7 @@ private: if (events[i].flags & EV_ERROR) { asio::error_code error( - events[i].data, asio::native_ecat); + events[i].data, asio::error::system_category); write_op_queue_.dispatch_all_operations(descriptor, error); } else @@ -456,7 +457,8 @@ 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::native_ecat); + asio::error_code error(errno, + asio::error::system_category); write_op_queue_.dispatch_all_operations(descriptor, error); } } @@ -466,19 +468,17 @@ 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(); - // 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(); + cleanup_operations_and_timers(lock); } // Run the select loop in the thread. @@ -512,8 +512,10 @@ private: int fd = kqueue(); if (fd == -1) { - boost::throw_exception(asio::system_error( - asio::error_code(errno, asio::native_ecat), + boost::throw_exception( + asio::system_error( + asio::error_code(errno, + asio::error::system_category), "kqueue")); } return fd; @@ -573,6 +575,22 @@ 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_; @@ -597,6 +615,10 @@ 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 df522ce0f..99bcbc6a4 100644 --- a/libtorrent/include/asio/detail/null_event.hpp +++ b/libtorrent/include/asio/detail/null_event.hpp @@ -43,17 +43,20 @@ public: } // Signal the event. - void signal() + template + void signal(Lock&) { } // Reset the event. - void clear() + template + void clear(Lock&) { } // Wait for the event to become signalled. - void wait() + template + void wait(Lock&) { } }; diff --git a/libtorrent/include/asio/detail/posix_event.hpp b/libtorrent/include/asio/detail/posix_event.hpp index 408c23bb9..b48586f15 100644 --- a/libtorrent/include/asio/detail/posix_event.hpp +++ b/libtorrent/include/asio/detail/posix_event.hpp @@ -24,10 +24,12 @@ #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" @@ -42,21 +44,11 @@ public: posix_event() : signalled_(false) { - int error = ::pthread_mutex_init(&mutex_, 0); + int error = ::pthread_cond_init(&cond_, 0); if (error != 0) { asio::system_error e( - 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), + asio::error_code(error, asio::error::system_category), "event"); boost::throw_exception(e); } @@ -66,37 +58,37 @@ public: ~posix_event() { ::pthread_cond_destroy(&cond_); - ::pthread_mutex_destroy(&mutex_); } // Signal the event. - void signal() + template + void signal(Lock& lock) { - ::pthread_mutex_lock(&mutex_); // Ignore EINVAL and EDEADLK. + BOOST_ASSERT(lock.locked()); + (void)lock; signalled_ = true; ::pthread_cond_signal(&cond_); // Ignore EINVAL. - ::pthread_mutex_unlock(&mutex_); // Ignore EINVAL and EPERM. } // Reset the event. - void clear() + template + void clear(Lock& lock) { - ::pthread_mutex_lock(&mutex_); // Ignore EINVAL and EDEADLK. + BOOST_ASSERT(lock.locked()); + (void)lock; signalled_ = false; - ::pthread_mutex_unlock(&mutex_); // Ignore EINVAL and EPERM. } // Wait for the event to become signalled. - void wait() + template + void wait(Lock& lock) { - ::pthread_mutex_lock(&mutex_); // Ignore EINVAL and EDEADLK. + BOOST_ASSERT(lock.locked()); while (!signalled_) - ::pthread_cond_wait(&cond_, &mutex_); // Ignore EINVAL. - ::pthread_mutex_unlock(&mutex_); // Ignore EINVAL and EPERM. + ::pthread_cond_wait(&cond_, &lock.mutex().mutex_); // Ignore EINVAL. } 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 154089f3c..6067880fb 100644 --- a/libtorrent/include/asio/detail/posix_mutex.hpp +++ b/libtorrent/include/asio/detail/posix_mutex.hpp @@ -28,6 +28,7 @@ #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" @@ -35,6 +36,8 @@ namespace asio { namespace detail { +class posix_event; + class posix_mutex : private noncopyable { @@ -48,7 +51,7 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::native_ecat), + asio::error_code(error, asio::error::system_category), "mutex"); boost::throw_exception(e); } @@ -67,7 +70,7 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::native_ecat), + asio::error_code(error, asio::error::system_category), "mutex"); boost::throw_exception(e); } @@ -80,13 +83,14 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::native_ecat), + asio::error_code(error, asio::error::system_category), "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 f01b40428..6e5815426 100644 --- a/libtorrent/include/asio/detail/posix_thread.hpp +++ b/libtorrent/include/asio/detail/posix_thread.hpp @@ -29,6 +29,7 @@ #include #include "asio/detail/pop_options.hpp" +#include "asio/error.hpp" #include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" @@ -52,7 +53,7 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::native_ecat), + asio::error_code(error, asio::error::system_category), "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 93fce3479..dda329c40 100644 --- a/libtorrent/include/asio/detail/posix_tss_ptr.hpp +++ b/libtorrent/include/asio/detail/posix_tss_ptr.hpp @@ -28,6 +28,7 @@ #include #include "asio/detail/pop_options.hpp" +#include "asio/error.hpp" #include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" @@ -46,7 +47,7 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::native_ecat), + asio::error_code(error, asio::error::system_category), "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 d5b8e4fc8..9c0075821 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 = 16 }; + enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; // 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::native_ecat); + ec = asio::error_code(err, asio::error::system_category); return ec; } @@ -181,7 +181,7 @@ public: if (int err = reactor_.register_descriptor(native_socket)) { - ec = asio::error_code(err, asio::native_ecat); + ec = asio::error_code(err, asio::error::system_category); return ec; } @@ -1124,7 +1124,7 @@ public: bool operator()(const asio::error_code& result) { // Check whether the operation was successful. - if (result != 0) + if (result) { 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::native_ecat); + asio::error::system_category); 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 64c77cbab..57f8cb8f6 100644 --- a/libtorrent/include/asio/detail/scoped_lock.hpp +++ b/libtorrent/include/asio/detail/scoped_lock.hpp @@ -63,6 +63,18 @@ 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 83f093ae6..079ec2de8 100644 --- a/libtorrent/include/asio/detail/select_reactor.hpp +++ b/libtorrent/include/asio/detail/select_reactor.hpp @@ -229,7 +229,10 @@ public: std::size_t cancel_timer(timer_queue& timer_queue, void* token) { asio::detail::mutex::scoped_lock lock(mutex_); - return timer_queue.cancel_timer(token); + std::size_t n = timer_queue.cancel_timer(token); + if (n > 0) + interrupter_.interrupt(); + return n; } private: @@ -245,16 +248,13 @@ 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_) { - // 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(); + cleanup_operations_and_timers(lock); return; } @@ -263,12 +263,7 @@ private: if (!block && read_op_queue_.empty() && write_op_queue_.empty() && except_op_queue_.empty() && all_timer_queues_are_empty()) { - // 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(); + cleanup_operations_and_timers(lock); return; } @@ -321,19 +316,17 @@ 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(); - // 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(); + cleanup_operations_and_timers(lock); } // Run the select loop in the thread. @@ -414,6 +407,22 @@ 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_; @@ -435,6 +444,10 @@ 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 bd1c3ea5b..3a9e9f620 100644 --- a/libtorrent/include/asio/detail/service_registry.hpp +++ b/libtorrent/include/asio/detail/service_registry.hpp @@ -166,7 +166,8 @@ private: } // Check if a service matches the given id. - bool service_id_matches(const asio::io_service::service& service, + static bool service_id_matches( + const asio::io_service::service& service, const asio::io_service::id& id) { return service.id_ == &id; @@ -174,7 +175,8 @@ private: // Check if a service matches the given id. template - bool service_id_matches(const asio::io_service::service& service, + static 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 4b38c6ee8..98f3b0f64 100644 --- a/libtorrent/include/asio/detail/socket_ops.hpp +++ b/libtorrent/include/asio/detail/socket_ops.hpp @@ -52,9 +52,10 @@ inline ReturnType error_wrapper(ReturnType return_value, asio::error_code& ec) { #if defined(BOOST_WINDOWS) || defined(__CYGWIN__) - ec = asio::error_code(WSAGetLastError(), asio::native_ecat); + ec = asio::error_code(WSAGetLastError(), + asio::error::system_category); #else - ec = asio::error_code(errno, asio::native_ecat); + ec = asio::error_code(errno, asio::error::system_category); #endif return return_value; } @@ -923,6 +924,13 @@ 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, @@ -1292,14 +1300,15 @@ 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) { - canon = gai_alloc(strlen(hptr->h_name) + 1); + std::size_t canon_len = strlen(hptr->h_name) + 1; + canon = gai_alloc(canon_len); if (canon == 0) { freeaddrinfo_emulation(aihead); socket_ops::freehostent(hptr); return EAI_MEMORY; } - strcpy(canon, hptr->h_name); + gai_strcpy(canon, hptr->h_name, canon_len); } // Create an addrinfo structure for each returned address. @@ -1335,13 +1344,14 @@ inline int getaddrinfo_emulation(const char* host, const char* service, } else { - aihead->ai_canonname = gai_alloc(strlen(search[0].host) + 1); + std::size_t canonname_len = strlen(search[0].host) + 1; + aihead->ai_canonname = gai_alloc(canonname_len); if (aihead->ai_canonname == 0) { freeaddrinfo_emulation(aihead); return EAI_MEMORY; } - strcpy(aihead->ai_canonname, search[0].host); + gai_strcpy(aihead->ai_canonname, search[0].host, canonname_len); } } gai_free(canon); @@ -1424,8 +1434,7 @@ inline asio::error_code getnameinfo_emulation( *dot = 0; } } - *host = '\0'; - strncat(host, hptr->h_name, hostlen); + gai_strcpy(host, hptr->h_name, hostlen); socket_ops::freehostent(hptr); } else @@ -1463,8 +1472,7 @@ 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') { - *serv = '\0'; - strncat(serv, sptr->s_name, servlen); + gai_strcpy(serv, sptr->s_name, servlen); } else { @@ -1504,6 +1512,12 @@ 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; @@ -1512,10 +1526,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::native_ecat); + WSAGetLastError(), asio::error::system_category); #else return asio::error_code( - errno, asio::native_ecat); + errno, asio::error::system_category); #endif } } diff --git a/libtorrent/include/asio/detail/socket_option.hpp b/libtorrent/include/asio/detail/socket_option.hpp index ee867e6b2..1a03936ab 100644 --- a/libtorrent/include/asio/detail/socket_option.hpp +++ b/libtorrent/include/asio/detail/socket_option.hpp @@ -110,8 +110,19 @@ public: template void resize(const Protocol&, std::size_t s) { - if (s != sizeof(value_)) + // 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: 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 49d1c7fc2..02c3a78d5 100644 --- a/libtorrent/include/asio/detail/socket_types.hpp +++ b/libtorrent/include/asio/detail/socket_types.hpp @@ -98,6 +98,7 @@ # include # include # include +# include # if defined(__sun) # include # include @@ -141,6 +142,11 @@ 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; @@ -166,6 +172,7 @@ 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 f10289090..d987cb98d 100644 --- a/libtorrent/include/asio/detail/strand_service.hpp +++ b/libtorrent/include/asio/detail/strand_service.hpp @@ -239,6 +239,7 @@ public: #else BOOST_ASSERT(size <= strand_impl::handler_storage_type::size); #endif + (void)size; return impl_->handler_storage_.address(); } @@ -415,14 +416,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. @@ -455,14 +456,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 07df1c18a..802d7ea95 100644 --- a/libtorrent/include/asio/detail/task_io_service.hpp +++ b/libtorrent/include/asio/detail/task_io_service.hpp @@ -40,6 +40,7 @@ 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_), @@ -80,8 +81,7 @@ public: typename call_stack::context ctx(this); idle_thread_info this_idle_thread; - this_idle_thread.prev = &this_idle_thread; - this_idle_thread.next = &this_idle_thread; + this_idle_thread.next = 0; asio::detail::mutex::scoped_lock lock(mutex_); @@ -98,8 +98,7 @@ public: typename call_stack::context ctx(this); idle_thread_info this_idle_thread; - this_idle_thread.prev = &this_idle_thread; - this_idle_thread.next = &this_idle_thread; + this_idle_thread.next = 0; asio::detail::mutex::scoped_lock lock(mutex_); @@ -134,7 +133,7 @@ public: void stop() { asio::detail::mutex::scoped_lock lock(mutex_); - stop_all_threads(); + stop_all_threads(lock); } // Reset in preparation for a subsequent run invocation. @@ -156,7 +155,7 @@ public: { asio::detail::mutex::scoped_lock lock(mutex_); if (--outstanding_work_ == 0) - stop_all_threads(); + stop_all_threads(lock); } // Request invocation of the given handler. @@ -201,9 +200,14 @@ public: ++outstanding_work_; // Wake up a thread to execute the handler. - if (!interrupt_one_idle_thread()) - if (task_handler_.next_ == 0 && handler_queue_end_ != &task_handler_) + if (!interrupt_one_idle_thread(lock)) + { + if (!task_interrupted_) + { + task_interrupted_ = true; task_.interrupt(); + } + } } private: @@ -214,7 +218,7 @@ private: { if (outstanding_work_ == 0 && !stopped_) { - stop_all_threads(); + stop_all_threads(lock); ec = asio::error_code(); return 0; } @@ -230,11 +234,14 @@ private: handler_queue_ = h->next_; if (handler_queue_ == 0) handler_queue_end_ = 0; - bool more_handlers = (handler_queue_ != 0); - lock.unlock(); + h->next_ = 0; 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) { @@ -252,6 +259,7 @@ private: } else { + lock.unlock(); handler_cleanup c(lock, *this); // Invoke the handler. May throw an exception. @@ -264,31 +272,10 @@ private: else if (this_idle_thread) { // Nothing to run right now, so just wait for work to do. - 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; - } + this_idle_thread->next = first_idle_thread_; first_idle_thread_ = this_idle_thread; - 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; - } + this_idle_thread->wakeup_event.clear(lock); + this_idle_thread->wakeup_event.wait(lock); } else { @@ -302,39 +289,44 @@ private: } // Stop the task and all idle threads. - void stop_all_threads() + void stop_all_threads( + asio::detail::mutex::scoped_lock& lock) { stopped_ = true; - interrupt_all_idle_threads(); - if (task_handler_.next_ == 0 && handler_queue_end_ != &task_handler_) + interrupt_all_idle_threads(lock); + if (!task_interrupted_) + { + task_interrupted_ = true; 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() + bool interrupt_one_idle_thread( + asio::detail::mutex::scoped_lock& lock) { if (first_idle_thread_) { - first_idle_thread_->wakeup_event.signal(); - first_idle_thread_ = first_idle_thread_->next; + idle_thread_info* idle_thread = first_idle_thread_; + first_idle_thread_ = idle_thread->next; + idle_thread->next = 0; + idle_thread->wakeup_event.signal(lock); return true; } return false; } // Interrupt all idle threads. - void interrupt_all_idle_threads() + void interrupt_all_idle_threads( + asio::detail::mutex::scoped_lock& lock) { - if (first_idle_thread_) + while (first_idle_thread_) { - 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; - } + idle_thread_info* idle_thread = first_idle_thread_; + first_idle_thread_ = idle_thread->next; + idle_thread->next = 0; + idle_thread->wakeup_event.signal(lock); } } @@ -440,6 +432,7 @@ 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_) { @@ -478,7 +471,7 @@ private: { lock_.lock(); if (--task_io_service_.outstanding_work_ == 0) - task_io_service_.stop_all_threads(); + task_io_service_.stop_all_threads(lock_); } private: @@ -503,6 +496,9 @@ private: } } task_handler_; + // Whether the task has been interrupted. + bool task_interrupted_; + // The count of unfinished work. int outstanding_work_; @@ -522,7 +518,6 @@ 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 af1e36bd5..7735e87cf 100644 --- a/libtorrent/include/asio/detail/timer_queue.hpp +++ b/libtorrent/include/asio/detail/timer_queue.hpp @@ -48,7 +48,9 @@ public: // Constructor. timer_queue() : timers_(), - heap_() + heap_(), + cancelled_timers_(0), + cleanup_timers_(0) { } @@ -111,12 +113,17 @@ 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 timer with the given token. The handler will be invoked - // immediately with the result operation_aborted. + // 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. std::size_t cancel_timer(void* timer_token) { std::size_t num_cancelled = 0; @@ -129,7 +136,9 @@ public: { timer_base* next = t->next_; remove_timer(t); - t->invoke(asio::error::operation_aborted); + t->prev_ = 0; + t->next_ = cancelled_timers_; + cancelled_timers_ = t; t = next; ++num_cancelled; } @@ -137,6 +146,31 @@ 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() { @@ -151,6 +185,7 @@ public: } heap_.clear(); timers_.clear(); + cleanup_timers(); } private: @@ -238,8 +273,7 @@ private: static void invoke_handler(timer_base* base, const asio::error_code& result) { - std::auto_ptr > t(static_cast*>(base)); - t->handler_(result); + static_cast*>(base)->handler_(result); } // Destroy the handler. @@ -338,6 +372,12 @@ 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 c8be49748..6cf25747a 100644 --- a/libtorrent/include/asio/detail/timer_queue_base.hpp +++ b/libtorrent/include/asio/detail/timer_queue_base.hpp @@ -44,6 +44,12 @@ 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 8de9383da..c73ed56ea 100644 --- a/libtorrent/include/asio/detail/win_event.hpp +++ b/libtorrent/include/asio/detail/win_event.hpp @@ -23,11 +23,13 @@ #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" @@ -46,7 +48,8 @@ public: { DWORD last_error = ::GetLastError(); asio::system_error e( - asio::error_code(last_error, asio::native_ecat), + asio::error_code(last_error, + asio::error::system_category), "event"); boost::throw_exception(e); } @@ -59,21 +62,31 @@ public: } // Signal the event. - void signal() + template + void signal(Lock& lock) { + BOOST_ASSERT(lock.locked()); + (void)lock; ::SetEvent(event_); } // Reset the event. - void clear() + template + void clear(Lock& lock) { + BOOST_ASSERT(lock.locked()); + (void)lock; ::ResetEvent(event_); } // Wait for the event to become signalled. - void wait() + template + void wait(Lock& lock) { + 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 4957fb01a..61eeb1745 100644 --- a/libtorrent/include/asio/detail/win_iocp_io_service.hpp +++ b/libtorrent/include/asio/detail/win_iocp_io_service.hpp @@ -63,7 +63,8 @@ public: { DWORD last_error = ::GetLastError(); asio::system_error e( - asio::error_code(last_error, asio::native_ecat), + asio::error_code(last_error, + asio::error::system_category), "iocp"); boost::throw_exception(e); } @@ -173,7 +174,8 @@ public: { DWORD last_error = ::GetLastError(); asio::system_error e( - asio::error_code(last_error, asio::native_ecat), + asio::error_code(last_error, + asio::error::system_category), "pqcs"); boost::throw_exception(e); } @@ -228,7 +230,8 @@ public: { DWORD last_error = ::GetLastError(); asio::system_error e( - asio::error_code(last_error, asio::native_ecat), + asio::error_code(last_error, + asio::error::system_category), "pqcs"); boost::throw_exception(e); } @@ -247,7 +250,8 @@ public: { DWORD last_error = ::GetLastError(); asio::system_error e( - asio::error_code(last_error, asio::native_ecat), + asio::error_code(last_error, + asio::error::system_category), "pqcs"); boost::throw_exception(e); } @@ -312,7 +316,7 @@ private: { DWORD last_error = ::GetLastError(); ec = asio::error_code(last_error, - asio::native_ecat); + asio::error::system_category); 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 184fdfa18..26eacae2a 100644 --- a/libtorrent/include/asio/detail/win_iocp_io_service_fwd.hpp +++ b/libtorrent/include/asio/detail/win_iocp_io_service_fwd.hpp @@ -21,6 +21,8 @@ #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 007286e8d..17d1d5887 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. - user_set_linger = 2, // The user set the linger option. + close_might_block = 2, // User set linger option for blocking close. 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 = 16 }; + enum { max_buffers = 64 < max_iov_len ? 64 : max_iov_len }; // Constructor. win_iocp_socket_service(asio::io_service& io_service) @@ -192,7 +192,7 @@ public: while (impl) { asio::error_code ignored_ec; - close(*impl, ignored_ec); + close_for_destruction(*impl); impl = impl->next_; } } @@ -217,34 +217,7 @@ public: // Destroy a socket implementation. void destroy(implementation_type& 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; - } + close_for_destruction(impl); // Remove implementation from linked list of all implementations. asio::detail::mutex::scoped_lock lock(mutex_); @@ -353,6 +326,25 @@ 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. @@ -367,7 +359,8 @@ public: if (!::CancelIo(sock_as_handle)) { DWORD last_error = ::GetLastError(); - ec = asio::error_code(last_error, asio::native_ecat); + ec = asio::error_code(last_error, + asio::error::system_category); } else { @@ -475,7 +468,12 @@ public: if (option.level(impl.protocol_) == SOL_SOCKET && option.name(impl.protocol_) == SO_LINGER) { - impl.flags_ |= implementation_type::user_set_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; } socket_ops::setsockopt(impl.socket_, @@ -668,7 +666,8 @@ public: last_error = WSAECONNRESET; else if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; - ec = asio::error_code(last_error, asio::native_ecat); + ec = asio::error_code(last_error, + asio::error::system_category); return 0; } @@ -719,7 +718,8 @@ public: #endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) // Map non-portable errors to their portable counterparts. - asio::error_code ec(last_error, asio::native_ecat); + asio::error_code ec(last_error, + asio::error::system_category); if (ec.value() == ERROR_NETNAME_DELETED) { if (handler_op->cancel_token_.expired()) @@ -821,7 +821,8 @@ public: { asio::io_service::work work(this->io_service()); ptr.reset(); - asio::error_code ec(last_error, asio::native_ecat); + asio::error_code ec(last_error, + asio::error::system_category); iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else @@ -865,7 +866,8 @@ public: DWORD last_error = ::WSAGetLastError(); if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; - ec = asio::error_code(last_error, asio::native_ecat); + ec = asio::error_code(last_error, + asio::error::system_category); return 0; } @@ -914,7 +916,8 @@ public: #endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) // Map non-portable errors to their portable counterparts. - asio::error_code ec(last_error, asio::native_ecat); + asio::error_code ec(last_error, + asio::error::system_category); if (ec.value() == ERROR_PORT_UNREACHABLE) { ec = asio::error::connection_refused; @@ -997,7 +1000,8 @@ public: { asio::io_service::work work(this->io_service()); ptr.reset(); - asio::error_code ec(last_error, asio::native_ecat); + asio::error_code ec(last_error, + asio::error::system_category); iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else @@ -1051,7 +1055,8 @@ public: last_error = WSAECONNRESET; else if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; - ec = asio::error_code(last_error, asio::native_ecat); + ec = asio::error_code(last_error, + asio::error::system_category); return 0; } if (bytes_transferred == 0) @@ -1109,7 +1114,8 @@ public: #endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) // Map non-portable errors to their portable counterparts. - asio::error_code ec(last_error, asio::native_ecat); + asio::error_code ec(last_error, + asio::error::system_category); if (ec.value() == ERROR_NETNAME_DELETED) { if (handler_op->cancel_token_.expired()) @@ -1216,7 +1222,8 @@ public: { asio::io_service::work work(this->io_service()); ptr.reset(); - asio::error_code ec(last_error, asio::native_ecat); + asio::error_code ec(last_error, + asio::error::system_category); iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else @@ -1262,7 +1269,8 @@ public: DWORD last_error = ::WSAGetLastError(); if (last_error == ERROR_PORT_UNREACHABLE) last_error = WSAECONNREFUSED; - ec = asio::error_code(last_error, asio::native_ecat); + ec = asio::error_code(last_error, + asio::error::system_category); return 0; } if (bytes_transferred == 0) @@ -1328,7 +1336,8 @@ public: #endif // defined(ASIO_ENABLE_BUFFER_DEBUGGING) // Map non-portable errors to their portable counterparts. - asio::error_code ec(last_error, asio::native_ecat); + asio::error_code ec(last_error, + asio::error::system_category); if (ec.value() == ERROR_PORT_UNREACHABLE) { ec = asio::error::connection_refused; @@ -1422,7 +1431,8 @@ public: { asio::io_service::work work(this->io_service()); ptr.reset(); - asio::error_code ec(last_error, asio::native_ecat); + asio::error_code ec(last_error, + asio::error::system_category); iocp_service_.post(bind_handler(handler, ec, bytes_transferred)); } else @@ -1659,7 +1669,8 @@ public: ptr.reset(); // Call the handler. - asio::error_code ec(last_error, asio::native_ecat); + asio::error_code ec(last_error, + asio::error::system_category); asio_handler_invoke_helpers::invoke( detail::bind_handler(handler, ec), &handler); } @@ -1759,7 +1770,8 @@ public: { asio::io_service::work work(this->io_service()); ptr.reset(); - asio::error_code ec(last_error, asio::native_ecat); + asio::error_code ec(last_error, + asio::error::system_category); iocp_service_.post(bind_handler(handler, ec)); } } @@ -1835,8 +1847,8 @@ public: // If connection failed then post the handler with the error code. if (connect_error) { - ec = asio::error_code( - connect_error, asio::native_ecat); + ec = asio::error_code(connect_error, + asio::error::system_category); io_service_.post(bind_handler(handler_, ec)); return true; } @@ -1950,26 +1962,66 @@ public: } private: - // Helper function to provide InterlockedCompareExchangePointer functionality - // on very old Platform SDKs. + // 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. void* interlocked_compare_exchange_pointer(void** dest, void* exch, void* cmp) { -#if defined(_WIN32_WINNT) && (_WIN32_WINNT <= 0x400) && (_M_IX86) +#if defined(_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 provide InterlockedExchangePointer functionality on very - // old Platform SDKs. + // Helper function to emulate InterlockedExchangePointer functionality for: + // - very old Platform SDKs; and + // - platform SDKs where MSVC's /Wp64 option causes spurious warnings. void* interlocked_exchange_pointer(void** dest, void* val) { -#if defined(_WIN32_WINNT) && (_WIN32_WINNT <= 0x400) && (_M_IX86) +#if defined(_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 82659831f..4d1bc20c2 100644 --- a/libtorrent/include/asio/detail/win_mutex.hpp +++ b/libtorrent/include/asio/detail/win_mutex.hpp @@ -23,6 +23,7 @@ #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,7 +49,7 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::native_ecat), + asio::error_code(error, asio::error::system_category), "mutex"); boost::throw_exception(e); } @@ -67,7 +68,7 @@ public: if (error != 0) { asio::system_error e( - asio::error_code(error, asio::native_ecat), + asio::error_code(error, asio::error::system_category), "mutex"); boost::throw_exception(e); } diff --git a/libtorrent/include/asio/detail/win_thread.hpp b/libtorrent/include/asio/detail/win_thread.hpp index a6c9b15d2..c6bd61af5 100644 --- a/libtorrent/include/asio/detail/win_thread.hpp +++ b/libtorrent/include/asio/detail/win_thread.hpp @@ -23,6 +23,7 @@ #if defined(BOOST_WINDOWS) +#include "asio/error.hpp" #include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" @@ -54,7 +55,8 @@ public: { DWORD last_error = ::GetLastError(); asio::system_error e( - asio::error_code(last_error, asio::native_ecat), + asio::error_code(last_error, + asio::error::system_category), "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 d3e2f8161..d84810d41 100644 --- a/libtorrent/include/asio/detail/win_tss_ptr.hpp +++ b/libtorrent/include/asio/detail/win_tss_ptr.hpp @@ -23,6 +23,7 @@ #if defined(BOOST_WINDOWS) +#include "asio/error.hpp" #include "asio/system_error.hpp" #include "asio/detail/noncopyable.hpp" #include "asio/detail/socket_types.hpp" @@ -47,7 +48,8 @@ public: { DWORD last_error = ::GetLastError(); asio::system_error e( - asio::error_code(last_error, asio::native_ecat), + asio::error_code(last_error, + asio::error::system_category), "tss"); boost::throw_exception(e); } diff --git a/libtorrent/include/asio/detail/winsock_init.hpp b/libtorrent/include/asio/detail/winsock_init.hpp index 67c69e8ce..874d2b77b 100644 --- a/libtorrent/include/asio/detail/winsock_init.hpp +++ b/libtorrent/include/asio/detail/winsock_init.hpp @@ -85,7 +85,8 @@ public: if (this != &instance_ && ref_->result() != 0) { asio::system_error e( - asio::error_code(ref_->result(), asio::native_ecat), + asio::error_code(ref_->result(), + asio::error::system_category), "winsock"); boost::throw_exception(e); } diff --git a/libtorrent/include/asio/detail/wrapped_handler.hpp b/libtorrent/include/asio/detail/wrapped_handler.hpp index f757fd3dc..913a795dc 100644 --- a/libtorrent/include/asio/detail/wrapped_handler.hpp +++ b/libtorrent/include/asio/detail/wrapped_handler.hpp @@ -17,6 +17,10 @@ #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" @@ -30,7 +34,9 @@ class wrapped_handler public: typedef void result_type; - wrapped_handler(Dispatcher& dispatcher, Handler handler) + wrapped_handler( + typename boost::add_reference::type dispatcher, + Handler handler) : dispatcher_(dispatcher), handler_(handler) { @@ -117,7 +123,7 @@ public: } //private: - Dispatcher& dispatcher_; + Dispatcher dispatcher_; Handler handler_; }; @@ -171,9 +177,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 935cc6796..a8316be2c 100644 --- a/libtorrent/include/asio/error.hpp +++ b/libtorrent/include/asio/error.hpp @@ -37,327 +37,195 @@ /// INTERNAL ONLY. # define ASIO_WIN_OR_POSIX(e_win, e_posix) implementation_defined #elif defined(BOOST_WINDOWS) || defined(__CYGWIN__) -# 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_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_WIN_OR_POSIX(e_win, e_posix) e_win #else -# 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_NATIVE_ERROR(e) e +# define ASIO_SOCKET_ERROR(e) e +# define ASIO_NETDB_ERROR(e) e +# define ASIO_GETADDRINFO_ERROR(e) e # define ASIO_WIN_OR_POSIX(e_win, e_posix) e_posix #endif namespace asio { +namespace error { -namespace detail { - -/// Hack to keep asio library header-file-only. -template -class error_base +enum basic_errors { -public: - // boostify: error category declarations go here. - /// Permission denied. - static const asio::error_code access_denied; + access_denied = ASIO_SOCKET_ERROR(EACCES), /// Address family not supported by protocol. - static const asio::error_code address_family_not_supported; + address_family_not_supported = ASIO_SOCKET_ERROR(EAFNOSUPPORT), /// Address already in use. - static const asio::error_code address_in_use; + address_in_use = ASIO_SOCKET_ERROR(EADDRINUSE), /// Transport endpoint is already connected. - static const asio::error_code already_connected; - - /// Already open. - static const asio::error_code already_open; + already_connected = ASIO_SOCKET_ERROR(EISCONN), /// Operation already in progress. - static const asio::error_code already_started; + already_started = ASIO_SOCKET_ERROR(EALREADY), /// A connection has been aborted. - static const asio::error_code connection_aborted; + connection_aborted = ASIO_SOCKET_ERROR(ECONNABORTED), /// Connection refused. - static const asio::error_code connection_refused; + connection_refused = ASIO_SOCKET_ERROR(ECONNREFUSED), /// Connection reset by peer. - static const asio::error_code connection_reset; + connection_reset = ASIO_SOCKET_ERROR(ECONNRESET), /// Bad file descriptor. - static const asio::error_code bad_descriptor; - - /// End of file or stream. - static const asio::error_code eof; + bad_descriptor = ASIO_SOCKET_ERROR(EBADF), /// 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; + fault = ASIO_SOCKET_ERROR(EFAULT), /// No route to host. - static const asio::error_code host_unreachable; + host_unreachable = ASIO_SOCKET_ERROR(EHOSTUNREACH), /// Operation now in progress. - static const asio::error_code in_progress; + in_progress = ASIO_SOCKET_ERROR(EINPROGRESS), /// Interrupted system call. - static const asio::error_code interrupted; + interrupted = ASIO_SOCKET_ERROR(EINTR), /// Invalid argument. - static const asio::error_code invalid_argument; + invalid_argument = ASIO_SOCKET_ERROR(EINVAL), /// Message too long. - static const asio::error_code message_size; + message_size = ASIO_SOCKET_ERROR(EMSGSIZE), /// Network is down. - static const asio::error_code network_down; + network_down = ASIO_SOCKET_ERROR(ENETDOWN), /// Network dropped connection on reset. - static const asio::error_code network_reset; + network_reset = ASIO_SOCKET_ERROR(ENETRESET), /// Network is unreachable. - static const asio::error_code network_unreachable; + network_unreachable = ASIO_SOCKET_ERROR(ENETUNREACH), /// Too many open files. - static const asio::error_code no_descriptors; + no_descriptors = ASIO_SOCKET_ERROR(EMFILE), /// 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; + no_buffer_space = ASIO_SOCKET_ERROR(ENOBUFS), /// Cannot allocate memory. - static const asio::error_code no_memory; + no_memory = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(ERROR_OUTOFMEMORY), + ASIO_NATIVE_ERROR(ENOMEM)), /// Operation not permitted. - static const asio::error_code no_permission; + no_permission = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(ERROR_ACCESS_DENIED), + ASIO_NATIVE_ERROR(EPERM)), /// Protocol not available. - static const asio::error_code no_protocol_option; - - /// A non-recoverable error occurred. - static const asio::error_code no_recovery; + no_protocol_option = ASIO_SOCKET_ERROR(ENOPROTOOPT), /// Transport endpoint is not connected. - static const asio::error_code not_connected; - - /// Element not found. - static const asio::error_code not_found; + not_connected = ASIO_SOCKET_ERROR(ENOTCONN), /// Socket operation on non-socket. - static const asio::error_code not_socket; + not_socket = ASIO_SOCKET_ERROR(ENOTSOCK), /// Operation cancelled. - static const asio::error_code operation_aborted; + operation_aborted = ASIO_WIN_OR_POSIX( + ASIO_NATIVE_ERROR(ERROR_OPERATION_ABORTED), + ASIO_NATIVE_ERROR(ECANCELED)), /// 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; + operation_not_supported = ASIO_SOCKET_ERROR(EOPNOTSUPP), /// Cannot send after transport endpoint shutdown. - static const asio::error_code shut_down; + shut_down = ASIO_SOCKET_ERROR(ESHUTDOWN), /// Connection timed out. - static const asio::error_code timed_out; + timed_out = ASIO_SOCKET_ERROR(ETIMEDOUT), /// Resource temporarily unavailable. - static const asio::error_code try_again; + 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. - static const asio::error_code would_block; + would_block = ASIO_SOCKET_ERROR(EWOULDBLOCK) +}; -private: - error_base(); +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, + + /// End of file or stream. + eof, + + /// Element not found. + not_found }; // boostify: error category definitions go here. -template const asio::error_code -error_base::access_denied = ASIO_SOCKET_ERROR(EACCES); - -template const asio::error_code -error_base::address_family_not_supported = ASIO_SOCKET_ERROR( - EAFNOSUPPORT); - -template const asio::error_code -error_base::address_in_use = ASIO_SOCKET_ERROR(EADDRINUSE); - -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 +inline asio::error_code make_error_code(basic_errors e) { -private: - error(); -}; + return asio::error_code(static_cast(e), system_category); +} +inline asio::error_code make_error_code(netdb_errors e) +{ + return asio::error_code(static_cast(e), netdb_category); +} + +inline asio::error_code make_error_code(addrinfo_errors e) +{ + return asio::error_code(static_cast(e), addrinfo_category); +} + +inline asio::error_code make_error_code(misc_errors e) +{ + return asio::error_code(static_cast(e), misc_category); +} + +} // 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 0614490e2..0941a8c00 100644 --- a/libtorrent/include/asio/error_code.hpp +++ b/libtorrent/include/asio/error_code.hpp @@ -32,24 +32,27 @@ namespace asio { -/// Available error code categories. -enum error_category +namespace error { - /// Native error codes. - native_ecat = ASIO_WIN_OR_POSIX(0, 0), + /// Available error code categories. + enum error_category + { + /// System error codes. + system_category = ASIO_WIN_OR_POSIX(0, 0), - /// Error codes from NetDB functions. - netdb_ecat = ASIO_WIN_OR_POSIX(native_ecat, 1), + /// Error codes from NetDB functions. + netdb_category = ASIO_WIN_OR_POSIX(system_category, 1), - /// Error codes from getaddrinfo. - addrinfo_ecat = ASIO_WIN_OR_POSIX(native_ecat, 2), + /// Error codes from getaddrinfo. + addrinfo_category = ASIO_WIN_OR_POSIX(system_category, 2), - /// Miscellaneous error codes. - misc_ecat = ASIO_WIN_OR_POSIX(3, 3), + /// Miscellaneous error codes. + misc_category = ASIO_WIN_OR_POSIX(3, 3), - /// SSL error codes. - ssl_ecat = ASIO_WIN_OR_POSIX(4, 4) -}; + /// SSL error codes. + ssl_category = ASIO_WIN_OR_POSIX(4, 4) + }; +} // namespace error /// Class to represent an error code value. class error_code @@ -61,17 +64,24 @@ public: /// Default constructor. error_code() : value_(0), - category_(native_ecat) + category_(error::system_category) { } /// Construct with specific error code and category. - error_code(value_type v, error_category c) + error_code(value_type v, error::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 { @@ -79,7 +89,7 @@ public: } /// Get the error category. - error_category category() const + error::error_category category() const { return category_; } @@ -125,7 +135,7 @@ private: value_type value_; // The category associated with the error code. - error_category category_; + error::error_category category_; }; } // namespace asio diff --git a/libtorrent/include/asio/impl/CVS/Entries b/libtorrent/include/asio/impl/CVS/Entries deleted file mode 100644 index eadcea08f..000000000 --- a/libtorrent/include/asio/impl/CVS/Entries +++ /dev/null @@ -1,6 +0,0 @@ -/error_code.ipp/1.6/Sun Mar 25 14:06:36 2007// -/io_service.ipp/1.12/Mon Jan 8 01:04:08 2007// -/read.ipp/1.16/Sat Jan 13 13:30:12 2007// -/read_until.ipp/1.10/Sun Jan 7 08:05:53 2007// -/write.ipp/1.14/Sat Jan 13 13:30:12 2007// -D diff --git a/libtorrent/include/asio/impl/CVS/Repository b/libtorrent/include/asio/impl/CVS/Repository deleted file mode 100644 index c5e1b5327..000000000 --- a/libtorrent/include/asio/impl/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -asio/include/asio/impl diff --git a/libtorrent/include/asio/impl/CVS/Root b/libtorrent/include/asio/impl/CVS/Root deleted file mode 100644 index a7505d52a..000000000 --- a/libtorrent/include/asio/impl/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:pserver:anonymous@asio.cvs.sourceforge.net:/cvsroot/asio diff --git a/libtorrent/include/asio/impl/error_code.ipp b/libtorrent/include/asio/impl/error_code.ipp index da2f98833..f66b6fd94 100644 --- a/libtorrent/include/asio/impl/error_code.ipp +++ b/libtorrent/include/asio/impl/error_code.ipp @@ -35,10 +35,12 @@ inline std::string error_code::message() const return "Already open."; if (*this == error::not_found) return "Not found."; - if (category_ == ssl_ecat) + if (category_ == error::ssl_category) 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; @@ -76,6 +78,8 @@ 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 e973619d1..f51d3697d 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 64c15ec7d..8b69a11c6 100644 --- a/libtorrent/include/asio/impl/read_until.ipp +++ b/libtorrent/include/asio/impl/read_until.ipp @@ -311,7 +311,8 @@ namespace detail if (streambuf_.size() == streambuf_.max_size()) { std::size_t bytes = 0; - handler_(error::not_found, bytes); + asio::error_code ec(error::not_found); + handler_(ec, bytes); return; } @@ -388,7 +389,8 @@ void async_read_until(AsyncReadStream& s, // No match. Check if buffer is full. if (b.size() == b.max_size()) { - s.io_service().post(detail::bind_handler(handler, error::not_found, 0)); + asio::error_code ec(error::not_found); + s.io_service().post(detail::bind_handler(handler, ec, 0)); return; } @@ -469,7 +471,8 @@ namespace detail if (streambuf_.size() == streambuf_.max_size()) { std::size_t bytes = 0; - handler_(error::not_found, bytes); + asio::error_code ec(error::not_found); + handler_(ec, bytes); return; } @@ -559,7 +562,8 @@ void async_read_until(AsyncReadStream& s, // Check if buffer is full. if (b.size() == b.max_size()) { - s.io_service().post(detail::bind_handler(handler, error::not_found, 0)); + asio::error_code ec(error::not_found); + s.io_service().post(detail::bind_handler(handler, ec, 0)); return; } @@ -641,7 +645,8 @@ namespace detail if (streambuf_.size() == streambuf_.max_size()) { std::size_t bytes = 0; - handler_(error::not_found, bytes); + asio::error_code ec(error::not_found); + handler_(ec, bytes); return; } @@ -731,7 +736,8 @@ void async_read_until(AsyncReadStream& s, // Check if buffer is full. if (b.size() == b.max_size()) { - s.io_service().post(detail::bind_handler(handler, error::not_found, 0)); + asio::error_code ec(error::not_found); + s.io_service().post(detail::bind_handler(handler, ec, 0)); return; } diff --git a/libtorrent/include/asio/io_service.hpp b/libtorrent/include/asio/io_service.hpp index b694545db..2101e56c4 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/CVS/Entries b/libtorrent/include/asio/ip/CVS/Entries deleted file mode 100644 index 5da45ff93..000000000 --- a/libtorrent/include/asio/ip/CVS/Entries +++ /dev/null @@ -1,17 +0,0 @@ -/address.hpp/1.9/Thu Jan 4 05:44:46 2007// -/address_v4.hpp/1.11/Thu Jan 4 05:44:46 2007// -/address_v6.hpp/1.11/Mon Feb 19 01:46:31 2007// -/basic_endpoint.hpp/1.16/Wed Feb 14 13:26:26 2007// -/basic_resolver.hpp/1.5/Thu Jan 4 05:44:46 2007// -/basic_resolver_entry.hpp/1.5/Thu Jan 4 05:44:46 2007// -/basic_resolver_iterator.hpp/1.10/Sun Apr 8 23:47:05 2007// -/basic_resolver_query.hpp/1.12/Thu Jan 4 05:44:46 2007// -/host_name.hpp/1.5/Thu Jan 4 05:44:46 2007// -/multicast.hpp/1.8/Sat Feb 17 22:57:39 2007// -/resolver_query_base.hpp/1.3/Thu Jan 4 05:44:46 2007// -/resolver_service.hpp/1.7/Thu Jan 4 05:44:46 2007// -/tcp.hpp/1.14/Sun May 20 00:49:02 2007// -/udp.hpp/1.12/Sun May 20 00:49:02 2007// -/unicast.hpp/1.2/Sat Feb 17 22:57:39 2007// -/v6_only.hpp/1.2/Sun May 13 07:59:22 2007// -D/detail//// diff --git a/libtorrent/include/asio/ip/CVS/Repository b/libtorrent/include/asio/ip/CVS/Repository deleted file mode 100644 index 96de0dd58..000000000 --- a/libtorrent/include/asio/ip/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -asio/include/asio/ip diff --git a/libtorrent/include/asio/ip/CVS/Root b/libtorrent/include/asio/ip/CVS/Root deleted file mode 100644 index a7505d52a..000000000 --- a/libtorrent/include/asio/ip/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:pserver:anonymous@asio.cvs.sourceforge.net:/cvsroot/asio diff --git a/libtorrent/include/asio/ip/basic_endpoint.hpp b/libtorrent/include/asio/ip/basic_endpoint.hpp index 3ca91dc03..3d1316e22 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()) + if (is_v4(data_)) 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()) + if (is_v4(data_)) 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()) + if (is_v4(data_)) { 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()) + if (is_v4(data_)) { 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()) + if (is_v4(data_)) { const asio::detail::sockaddr_in4_type& data = reinterpret_cast( @@ -306,15 +306,27 @@ public: private: // Helper function to determine whether the endpoint is IPv4. - bool is_v4() const - { #if defined(_AIX) - return data_.__ss_family == AF_INET; -#else - return data_.ss_family == AF_INET; -#endif + 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; + } +#else + static bool is_v4(const asio::detail::sockaddr_storage_type& ss) + { + return ss.ss_family == AF_INET; + } +#endif + // The underlying IP socket address. asio::detail::sockaddr_storage_type data_; }; diff --git a/libtorrent/include/asio/ssl/CVS/Entries b/libtorrent/include/asio/ssl/CVS/Entries deleted file mode 100644 index b15450e7b..000000000 --- a/libtorrent/include/asio/ssl/CVS/Entries +++ /dev/null @@ -1,8 +0,0 @@ -/basic_context.hpp/1.11/Thu Dec 21 12:29:03 2006// -/context.hpp/1.3/Mon Apr 10 12:17:44 2006// -/context_base.hpp/1.6/Sun Sep 24 07:46:22 2006// -/context_service.hpp/1.11/Fri Dec 29 02:01:24 2006// -/stream.hpp/1.13/Thu Dec 21 12:29:03 2006// -/stream_base.hpp/1.4/Wed Nov 30 01:57:07 2005// -/stream_service.hpp/1.10/Fri Dec 29 02:01:24 2006// -D/detail//// diff --git a/libtorrent/include/asio/ssl/CVS/Repository b/libtorrent/include/asio/ssl/CVS/Repository deleted file mode 100644 index a0555e83a..000000000 --- a/libtorrent/include/asio/ssl/CVS/Repository +++ /dev/null @@ -1 +0,0 @@ -asio/include/asio/ssl diff --git a/libtorrent/include/asio/ssl/CVS/Root b/libtorrent/include/asio/ssl/CVS/Root deleted file mode 100644 index a7505d52a..000000000 --- a/libtorrent/include/asio/ssl/CVS/Root +++ /dev/null @@ -1 +0,0 @@ -:pserver:anonymous@asio.cvs.sourceforge.net:/cvsroot/asio diff --git a/libtorrent/include/asio/ssl/detail/openssl_operation.hpp b/libtorrent/include/asio/ssl/detail/openssl_operation.hpp index b7a564464..5fd3ebba4 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::native_ecat), rc); + sys_error_code, asio::error::system_category), rc); } else { return handler_(asio::error_code( - error_code, asio::ssl_ecat), rc); + error_code, asio::error::ssl_category), rc); } } diff --git a/libtorrent/include/libtorrent/alert.hpp b/libtorrent/include/libtorrent/alert.hpp index b6b6711dc..954e39ef5 100755 --- a/libtorrent/include/libtorrent/alert.hpp +++ b/libtorrent/include/libtorrent/alert.hpp @@ -36,7 +36,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include #include #ifdef _MSC_VER @@ -56,6 +55,7 @@ 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 48491bca4..36c13c5ab 100755 --- a/libtorrent/include/libtorrent/alert_types.hpp +++ b/libtorrent/include/libtorrent/alert_types.hpp @@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket.hpp" #include "libtorrent/peer_connection.hpp" #include "libtorrent/config.hpp" +#include "libtorrent/assert.hpp" namespace libtorrent { @@ -223,7 +224,7 @@ namespace libtorrent { block_downloading_alert( const torrent_handle& h - , std::string& speedmsg + , char const* speedmsg , int block_num , int piece_num , const std::string& msg) @@ -261,6 +262,17 @@ 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 new file mode 100644 index 000000000..62425809e --- /dev/null +++ b/libtorrent/include/libtorrent/assert.hpp @@ -0,0 +1,52 @@ +/* + +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 __GNUC__ +#ifdef assert +#undef assert +#endif + +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 207016898..0389bf3dc 100644 --- a/libtorrent/include/libtorrent/aux_/session_impl.hpp +++ b/libtorrent/include/libtorrent/aux_/session_impl.hpp @@ -83,6 +83,7 @@ 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 { @@ -240,12 +241,12 @@ namespace libtorrent bool is_listening() const; torrent_handle add_torrent( - torrent_info const& ti + boost::intrusive_ptr ti , fs::path const& save_path , entry const& resume_data , bool compact_mode - , int block_size - , storage_constructor_type sc); + , storage_constructor_type sc + , bool paused); torrent_handle add_torrent( char const* tracker_url @@ -254,8 +255,8 @@ namespace libtorrent , fs::path const& save_path , entry const& resume_data , bool compact_mode - , int block_size - , storage_constructor_type sc); + , storage_constructor_type sc + , bool paused); void remove_torrent(torrent_handle const& h); @@ -273,8 +274,21 @@ namespace libtorrent void set_max_connections(int limit); void set_max_uploads(int limit); - int num_uploads() const; - int num_connections() const; + 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; + } session_status status() const; void set_peer_id(peer_id const& id); @@ -417,6 +431,28 @@ 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; @@ -459,7 +495,7 @@ namespace libtorrent // This implements a round robin. int m_next_connect_torrent; #ifndef NDEBUG - void check_invariant(const char *place = 0); + void check_invariant() const; #endif #ifdef TORRENT_STATS diff --git a/libtorrent/include/libtorrent/bandwidth_manager.hpp b/libtorrent/include/libtorrent/bandwidth_manager.hpp index 75e1f1d4e..03d4f65ae 100644 --- a/libtorrent/include/libtorrent/bandwidth_manager.hpp +++ b/libtorrent/include/libtorrent/bandwidth_manager.hpp @@ -33,9 +33,6 @@ 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 @@ -44,11 +41,17 @@ 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 @@ -237,8 +240,10 @@ struct bandwidth_manager i = j; } } - - if (m_queue.size() == 1) hand_out_bandwidth(); +#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(); } #ifndef NDEBUG @@ -337,10 +342,18 @@ 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(); @@ -374,13 +387,12 @@ 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.max_block_size - , (std::min)(qe.peer->bandwidth_throttle(m_channel) - , m_limit / 10)); + int block_size = (std::min)(qe.peer->bandwidth_throttle(m_channel) + , m_limit / 10); if (block_size < min_bandwidth_block_size) { - block_size = min_bandwidth_block_size; + block_size = (std::min)(int(min_bandwidth_block_size), m_limit); } else if (block_size > max_bandwidth_block_size) { @@ -399,7 +411,11 @@ private: / (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); diff --git a/libtorrent/include/libtorrent/bencode.hpp b/libtorrent/include/libtorrent/bencode.hpp index a142b5864..9e670c10b 100755 --- a/libtorrent/include/libtorrent/bencode.hpp +++ b/libtorrent/include/libtorrent/bencode.hpp @@ -79,6 +79,8 @@ 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 new file mode 100644 index 000000000..bdfe30b6e --- /dev/null +++ b/libtorrent/include/libtorrent/broadcast_socket.hpp @@ -0,0 +1,80 @@ +/* + +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); + 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); + + 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 beec94979..0fcba89a8 100755 --- a/libtorrent/include/libtorrent/bt_peer_connection.hpp +++ b/libtorrent/include/libtorrent/bt_peer_connection.hpp @@ -65,7 +65,6 @@ 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" @@ -122,8 +121,16 @@ namespace libtorrent msg_request, msg_piece, msg_cancel, + // DHT extension msg_dht_port, - // extension protocol message + // FAST extension + msg_suggest_piece = 0xd, + msg_have_all, + msg_have_none, + msg_reject_request, + msg_allowed_fast, + + // extension protocol message msg_extended = 20, num_supported_messages @@ -174,8 +181,17 @@ 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(); @@ -201,7 +217,16 @@ 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(); @@ -325,6 +350,7 @@ 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 0cb44225a..0f37edcbd 100644 --- a/libtorrent/include/libtorrent/buffer.hpp +++ b/libtorrent/include/libtorrent/buffer.hpp @@ -34,8 +34,9 @@ POSSIBILITY OF SUCH DAMAGE. //#define TORRENT_BUFFER_DEBUG -#include "libtorrent/invariant_check.hpp" #include +#include "libtorrent/invariant_check.hpp" +#include "libtorrent/assert.hpp" namespace libtorrent { diff --git a/libtorrent/include/libtorrent/config.hpp b/libtorrent/include/libtorrent/config.hpp index b36d4da22..1281ab84c 100755 --- a/libtorrent/include/libtorrent/config.hpp +++ b/libtorrent/include/libtorrent/config.hpp @@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_CONFIG_HPP_INCLUDED #include +#include "libtorrent/assert.hpp" #if defined(__GNUC__) && __GNUC__ >= 4 diff --git a/libtorrent/include/libtorrent/connection_queue.hpp b/libtorrent/include/libtorrent/connection_queue.hpp index 17be248bf..b3b7cde86 100644 --- a/libtorrent/include/libtorrent/connection_queue.hpp +++ b/libtorrent/include/libtorrent/connection_queue.hpp @@ -36,6 +36,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include "libtorrent/socket.hpp" #include "libtorrent/time.hpp" @@ -88,6 +89,10 @@ 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 436b695f6..1bb645a8e 100755 --- a/libtorrent/include/libtorrent/debug.hpp +++ b/libtorrent/include/libtorrent/debug.hpp @@ -80,3 +80,4 @@ namespace libtorrent } #endif // TORRENT_DEBUG_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/entry.hpp b/libtorrent/include/libtorrent/entry.hpp index 59e29803d..7fd6c8c53 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 new file mode 100644 index 000000000..0c6063a2b --- /dev/null +++ b/libtorrent/include/libtorrent/enum_net.hpp @@ -0,0 +1,44 @@ +/* + +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 5f8172649..44fff9c36 100644 --- a/libtorrent/include/libtorrent/extensions.hpp +++ b/libtorrent/include/libtorrent/extensions.hpp @@ -131,6 +131,15 @@ 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; } diff --git a/libtorrent/include/libtorrent/fingerprint.hpp b/libtorrent/include/libtorrent/fingerprint.hpp index d7e5a5fc6..712be6979 100755 --- a/libtorrent/include/libtorrent/fingerprint.hpp +++ b/libtorrent/include/libtorrent/fingerprint.hpp @@ -37,6 +37,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include "libtorrent/peer_id.hpp" +#include "libtorrent/assert.hpp" namespace libtorrent { @@ -91,3 +92,4 @@ namespace libtorrent } #endif // TORRENT_FINGERPRINT_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/hasher.hpp b/libtorrent/include/libtorrent/hasher.hpp index 932f2b100..71b7f9ede 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 409213857..ccc145413 100644 --- a/libtorrent/include/libtorrent/http_connection.hpp +++ b/libtorrent/include/libtorrent/http_connection.hpp @@ -44,13 +44,18 @@ 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 @@ -58,11 +63,13 @@ typedef boost::function, boost::noncopyable { http_connection(asio::io_service& ios, connection_queue& cc - , http_handler handler, bool bottled = true) + , http_handler const& handler, bool bottled = true + , http_connect_handler const& ch = http_connect_handler()) : 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) @@ -92,6 +99,8 @@ 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 @@ -112,6 +121,7 @@ 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 35d529504..b3f35084c 100755 --- a/libtorrent/include/libtorrent/http_tracker_connection.hpp +++ b/libtorrent/include/libtorrent/http_tracker_connection.hpp @@ -73,6 +73,8 @@ 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; } @@ -85,6 +87,8 @@ 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; @@ -176,3 +180,4 @@ namespace libtorrent #endif // TORRENT_HTTP_TRACKER_CONNECTION_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/intrusive_ptr_base.hpp b/libtorrent/include/libtorrent/intrusive_ptr_base.hpp index a432bc350..ed6944ebb 100644 --- a/libtorrent/include/libtorrent/intrusive_ptr_base.hpp +++ b/libtorrent/include/libtorrent/intrusive_ptr_base.hpp @@ -34,14 +34,17 @@ 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(const intrusive_ptr_base& b) + : 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 c6eacf338..3eaacf34c 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 +#include "libtorrent/assert.hpp" namespace libtorrent { diff --git a/libtorrent/include/libtorrent/ip_filter.hpp b/libtorrent/include/libtorrent/ip_filter.hpp index 8b1793c3a..7b8cc0e17 100644 --- a/libtorrent/include/libtorrent/ip_filter.hpp +++ b/libtorrent/include/libtorrent/ip_filter.hpp @@ -33,6 +33,9 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_IP_FILTER_HPP #define TORRENT_IP_FILTER_HPP +#include +#include + #ifdef _MSC_VER #pragma warning(push, 1) #endif @@ -48,8 +51,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/config.hpp" #include "libtorrent/socket.hpp" -#include -#include +#include "libtorrent/assert.hpp" namespace libtorrent { diff --git a/libtorrent/include/libtorrent/kademlia/node.hpp b/libtorrent/include/libtorrent/kademlia/node.hpp index 850333043..ee75e7f0a 100644 --- a/libtorrent/include/libtorrent/kademlia/node.hpp +++ b/libtorrent/include/libtorrent/kademlia/node.hpp @@ -34,7 +34,6 @@ POSSIBILITY OF SUCH DAMAGE. #define NODE_HPP #include -#include #include #include @@ -45,6 +44,7 @@ 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 eb4d6c539..5e732acac 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 45a7dd762..9e10a3483 100644 --- a/libtorrent/include/libtorrent/kademlia/routing_table.hpp +++ b/libtorrent/include/libtorrent/kademlia/routing_table.hpp @@ -50,6 +50,7 @@ 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 9ffbcdfc3..e8eaf0df1 100644 --- a/libtorrent/include/libtorrent/lsd.hpp +++ b/libtorrent/include/libtorrent/lsd.hpp @@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket.hpp" #include "libtorrent/peer_id.hpp" +#include "libtorrent/broadcast_socket.hpp" #include #include @@ -58,35 +59,26 @@ 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(asio::error_code const& e + void on_announce(udp::endpoint const& from, char* buffer , 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 - datagram_socket m_socket; + broadcast_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 91616c42d..e2276dee6 100644 --- a/libtorrent/include/libtorrent/pe_crypto.hpp +++ b/libtorrent/include/libtorrent/pe_crypto.hpp @@ -35,13 +35,12 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_PE_CRYPTO_HPP_INCLUDED #define TORRENT_PE_CRYPTO_HPP_INCLUDED -#include - #include #include #include -#include "peer_id.hpp" // For sha1_hash +#include "libtorrent/peer_id.hpp" // For sha1_hash +#include "libtorrent/assert.hpp" namespace libtorrent { diff --git a/libtorrent/include/libtorrent/peer_connection.hpp b/libtorrent/include/libtorrent/peer_connection.hpp index 31bcde94a..ea16a8d0a 100755 --- a/libtorrent/include/libtorrent/peer_connection.hpp +++ b/libtorrent/include/libtorrent/peer_connection.hpp @@ -64,7 +64,6 @@ 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" @@ -73,6 +72,7 @@ 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,6 +131,8 @@ 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 @@ -151,11 +153,17 @@ namespace libtorrent int upload_limit() const { return m_upload_limit; } int download_limit() const { return m_download_limit; } - bool prefer_whole_pieces() const - { return m_prefer_whole_pieces; } + int prefer_whole_pieces() const + { + if (on_parole()) return 1; + return m_prefer_whole_pieces; + } - void prefer_whole_pieces(bool b) - { m_prefer_whole_pieces = b; } + bool on_parole() const + { return peer_info_struct() && peer_info_struct()->on_parole; } + + void prefer_whole_pieces(int num) + { m_prefer_whole_pieces = num; } bool request_large_blocks() const { return m_request_large_blocks; } @@ -186,9 +194,9 @@ namespace libtorrent void set_pid(const peer_id& pid) { m_peer_id = pid; } bool has_piece(int i) const; - const std::deque& download_queue() const; - const std::deque& request_queue() const; - const std::deque& upload_queue() const; + std::deque const& download_queue() const; + std::deque const& request_queue() const; + std::deque const& upload_queue() const; bool is_interesting() const { return m_interesting; } bool is_choked() const { return m_choked; } @@ -211,12 +219,14 @@ 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); + void second_tick(float tick_interval) throw(); 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. @@ -294,7 +304,14 @@ 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 @@ -373,6 +390,9 @@ 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() {} @@ -482,6 +502,11 @@ 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; @@ -529,7 +554,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 incomming connection + // and false if we got an incoming connection // could be considered: true = local, false = remote bool m_active; @@ -563,6 +588,10 @@ 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 @@ -575,7 +604,7 @@ namespace libtorrent std::deque m_requests; // the blocks we have reserved in the piece - // picker and will send to this peer. + // picker and will request from this peer. std::deque m_request_queue; // the queue of blocks we have requested @@ -643,12 +672,13 @@ namespace libtorrent bool m_writing; bool m_reading; - // 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 + // 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 // will be used to determine if whole pieces // are preferred. - bool m_prefer_whole_pieces; + int m_prefer_whole_pieces; // if this is true, the blocks picked by the piece // picker will be merged before passed to the @@ -695,6 +725,18 @@ 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 b66c1d4bc..57303e2fd 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 15ad34a7a..046df2a6b 100755 --- a/libtorrent/include/libtorrent/peer_info.hpp +++ b/libtorrent/include/libtorrent/peer_info.hpp @@ -56,10 +56,11 @@ namespace libtorrent connecting = 0x80, queued = 0x100, on_parole = 0x200, - seed = 0x400 + seed = 0x400, + optimistic_unchoke = 0x800 #ifndef TORRENT_DISABLE_ENCRYPTION - , rc4_encrypted = 0x800, - plaintext_encrypted = 0x1000 + , rc4_encrypted = 0x100000, + plaintext_encrypted = 0x200000 #endif }; @@ -116,6 +117,11 @@ 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 54df003ef..94f274a27 100755 --- a/libtorrent/include/libtorrent/piece_picker.hpp +++ b/libtorrent/include/libtorrent/piece_picker.hpp @@ -35,7 +35,6 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include -#include #include #ifdef _MSC_VER @@ -52,6 +51,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket.hpp" #include "libtorrent/session_settings.hpp" #include "libtorrent/config.hpp" +#include "libtorrent/assert.hpp" namespace libtorrent { @@ -191,11 +191,33 @@ 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(const std::vector& pieces + void pick_pieces(std::vector const& pieces , std::vector& interesting_blocks - , int num_pieces, bool prefer_whole_pieces + , int num_pieces, int prefer_whole_pieces , void* peer, piece_state_t speed - , bool rarest_first) const; + , 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; // clears the peer pointer in all downloading pieces with this // peer pointer @@ -253,6 +275,8 @@ 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 @@ -271,6 +295,10 @@ 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() {} @@ -320,9 +348,9 @@ namespace libtorrent int priority(int limit) const { - if (filtered() || have()) return 0; + if (downloading || filtered() || have()) return 0; // pieces we are currently downloading have high priority - int prio = downloading ? (std::min)(1, int(peer_count)) : peer_count * 2; + int prio = 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; @@ -358,14 +386,6 @@ 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 6c976d047..7a789ec8c 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); + void connection_closed(const peer_connection& c) throw(); // the peer has got at least one interesting piece void peer_is_interesting(peer_connection& c); @@ -155,6 +155,13 @@ 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; @@ -203,25 +210,18 @@ 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,8 +233,7 @@ 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(); @@ -242,10 +241,6 @@ 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; @@ -253,7 +248,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 38206f32c..2ce19349e 100755 --- a/libtorrent/include/libtorrent/session.hpp +++ b/libtorrent/include/libtorrent/session.hpp @@ -53,6 +53,7 @@ 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" @@ -60,7 +61,6 @@ 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,22 +141,16 @@ namespace libtorrent , fs::path const& save_path , entry const& resume_data = entry() , bool compact_mode = true - , int block_size = 16 * 1024 - , storage_constructor_type sc = default_storage_constructor); + , bool paused = false + , storage_constructor_type sc = default_storage_constructor) TORRENT_DEPRECATED; - // ==== deprecated, this is for backwards compatibility only - // instead, use one of the other add_torrent overloads torrent_handle add_torrent( - entry const& e + boost::intrusive_ptr ti , fs::path const& save_path , entry const& resume_data = entry() , bool compact_mode = true - , 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); - } + , bool paused = false + , storage_constructor_type sc = default_storage_constructor); torrent_handle add_torrent( char const* tracker_url @@ -165,7 +159,7 @@ namespace libtorrent , fs::path const& save_path , entry const& resume_data = entry() , bool compact_mode = true - , int block_size = 16 * 1024 + , bool paused = false , storage_constructor_type sc = default_storage_constructor); session_proxy abort() { return session_proxy(m_impl); } @@ -243,6 +237,7 @@ 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); @@ -265,12 +260,6 @@ 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_settings.hpp b/libtorrent/include/libtorrent/session_settings.hpp index ebc30eae3..3a145c687 100644 --- a/libtorrent/include/libtorrent/session_settings.hpp +++ b/libtorrent/include/libtorrent/session_settings.hpp @@ -105,9 +105,11 @@ namespace libtorrent , send_redundant_have(false) , lazy_bitfields(true) , inactivity_timeout(600) - , unchoke_interval(20) + , unchoke_interval(15) + , optimistic_unchoke_multiplier(4) , 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) @@ -241,6 +243,10 @@ 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; @@ -252,6 +258,10 @@ 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 2424d5d6c..24e477a37 100755 --- a/libtorrent/include/libtorrent/stat.hpp +++ b/libtorrent/include/libtorrent/stat.hpp @@ -40,6 +40,7 @@ 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 8a10c7148..e52196c76 100755 --- a/libtorrent/include/libtorrent/storage.hpp +++ b/libtorrent/include/libtorrent/storage.hpp @@ -43,6 +43,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #ifdef _MSC_VER @@ -147,10 +148,11 @@ namespace libtorrent }; typedef storage_interface* (&storage_constructor_type)( - torrent_info const&, fs::path const& + boost::intrusive_ptr, fs::path const& , file_pool&); - TORRENT_EXPORT storage_interface* default_storage_constructor(torrent_info const& ti + TORRENT_EXPORT storage_interface* default_storage_constructor( + boost::intrusive_ptr ti , fs::path const& path, file_pool& fp); // returns true if the filesystem the path relies on supports @@ -169,7 +171,7 @@ namespace libtorrent piece_manager( boost::shared_ptr const& torrent - , torrent_info const& ti + , boost::intrusive_ptr ti , fs::path const& path , file_pool& fp , disk_io_thread& io @@ -199,7 +201,8 @@ namespace libtorrent void async_read( peer_request const& r - , boost::function const& handler); + , boost::function const& handler + , char* buffer = 0); void async_write( peer_request const& r @@ -227,7 +230,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: @@ -283,7 +286,7 @@ namespace libtorrent // a bitmask representing the pieces we have std::vector m_have_piece; - torrent_info const& m_info; + boost::intrusive_ptr m_info; // slots that haven't had any file storage allocated std::vector m_unallocated_slots; @@ -313,12 +316,6 @@ 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, @@ -333,6 +330,11 @@ 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 @@ -340,6 +342,8 @@ namespace libtorrent // isn't needed) std::multimap m_hash_to_piece; + // this map contains partial hashes for downloading + // pieces. 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 2227fc932..27d61af9d 100644 --- a/libtorrent/include/libtorrent/time.hpp +++ b/libtorrent/include/libtorrent/time.hpp @@ -55,6 +55,7 @@ namespace libtorrent || _POSIX_MONOTONIC_CLOCK < 0)) || defined (TORRENT_USE_BOOST_DATE_TIME) #include +#include "libtorrent/assert.hpp" namespace libtorrent { @@ -85,6 +86,7 @@ namespace libtorrent #include #include +#include "libtorrent/assert.hpp" namespace libtorrent { @@ -170,6 +172,7 @@ namespace asio #include #include +#include "libtorrent/assert.hpp" // high precision timer for darwin intel and ppc @@ -249,6 +252,7 @@ namespace libtorrent #define WIN32_LEAN_AND_MEAN #endif #include +#include "libtorrent/assert.hpp" namespace libtorrent { @@ -335,6 +339,7 @@ namespace libtorrent #elif defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0 #include +#include "libtorrent/assert.hpp" namespace libtorrent { @@ -385,4 +390,4 @@ namespace libtorrent #endif #endif - + diff --git a/libtorrent/include/libtorrent/torrent.hpp b/libtorrent/include/libtorrent/torrent.hpp index 2eef2656b..bcc54899f 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 - , torrent_info const& tf + , boost::intrusive_ptr tf , fs::path const& save_path , tcp::endpoint const& net_interface , bool compact_mode , int block_size - , session_settings const& s - , storage_constructor_type sc); + , storage_constructor_type sc + , bool paused); // 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 - , session_settings const& s - , storage_constructor_type sc); + , storage_constructor_type sc + , bool paused); ~torrent(); @@ -154,10 +154,6 @@ 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 @@ -254,6 +250,15 @@ 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. @@ -465,14 +470,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; } @@ -494,7 +499,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; } @@ -516,11 +521,6 @@ 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,7 +530,9 @@ 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 @@ -538,7 +540,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 @@ -562,7 +564,7 @@ namespace libtorrent void update_peer_interest(); - torrent_info m_torrent_file; + boost::intrusive_ptr m_torrent_file; // is set to true when the torrent has // been aborted. @@ -705,9 +707,9 @@ namespace libtorrent // determine the timeout until next try. int m_failed_trackers; - // 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. + // 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. int m_time_scaler; // the bitmask that says which pieces we have @@ -774,6 +776,15 @@ 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 3f7ae5bcc..31a39c38e 100755 --- a/libtorrent/include/libtorrent/torrent_handle.hpp +++ b/libtorrent/include/libtorrent/torrent_handle.hpp @@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_TORRENT_HANDLE_HPP_INCLUDED #include +#include #ifdef _MSC_VER #pragma warning(push, 1) @@ -273,7 +274,9 @@ namespace libtorrent std::vector const& trackers() const; void replace_trackers(std::vector const&) const; - void add_url_seed(std::string const& url); + void add_url_seed(std::string const& url) const; + void remove_url_seed(std::string const& url) const; + std::set url_seeds() const; bool has_metadata() const; const torrent_info& get_torrent_info() const; diff --git a/libtorrent/include/libtorrent/torrent_info.hpp b/libtorrent/include/libtorrent/torrent_info.hpp index a2d6c4ef9..492fda48d 100755 --- a/libtorrent/include/libtorrent/torrent_info.hpp +++ b/libtorrent/include/libtorrent/torrent_info.hpp @@ -57,6 +57,8 @@ 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 { @@ -71,7 +73,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 origianal corrupt encoded string. It is + // the original corrupt encoded string. It is // preserved in order to be able to reproduce // the correct info-hash boost::shared_ptr orig_path; @@ -96,7 +98,7 @@ namespace libtorrent virtual const char* what() const throw() { return "invalid torrent file"; } }; - class TORRENT_EXPORT torrent_info + class TORRENT_EXPORT torrent_info : public intrusive_ptr_base { public: @@ -115,8 +117,12 @@ namespace libtorrent void add_file(fs::path file, size_type size); void add_url_seed(std::string const& url); - std::vector map_block(int piece, size_type offset, int size) const; - peer_request map_file(int file, size_type offset, int size) const; + 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 const& url_seeds() const { @@ -128,15 +134,60 @@ namespace libtorrent typedef std::vector::const_reverse_iterator reverse_file_iterator; // list the files in the torrent file - 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 begin_files(bool storage = false) const + { + if (!storage || m_remapped_files.empty()) + return m_files.begin(); + else + return m_remapped_files.begin(); + } - 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]; } + 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]; + } + } const std::vector& trackers() const { return m_urls; } @@ -218,6 +269,13 @@ 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 @@ -264,8 +322,10 @@ 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/upnp.hpp b/libtorrent/include/libtorrent/upnp.hpp index d4b701aad..fc0650631 100644 --- a/libtorrent/include/libtorrent/upnp.hpp +++ b/libtorrent/include/libtorrent/upnp.hpp @@ -34,6 +34,7 @@ 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" @@ -56,9 +57,6 @@ 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 @@ -72,8 +70,6 @@ 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); @@ -90,7 +86,7 @@ private: void update_mapping(int i, int port); void resend_request(asio::error_code const& e); - void on_reply(asio::error_code const& e + void on_reply(udp::endpoint const& from, char* buffer , std::size_t bytes_transferred); void discover_device(); @@ -106,12 +102,15 @@ 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() @@ -198,18 +197,13 @@ private: // current retry count int m_retry_count; - // used to receive responses in - char m_receive_buffer[1024]; + asio::io_service& m_io_service; - // the endpoint we received the message from - udp::endpoint m_remote; + asio::strand m_strand; - // 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 - datagram_socket m_socket; + broadcast_socket m_socket; // used to resend udp packets in case // they time out @@ -217,8 +211,6 @@ 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 ba7450c0a..1290f14a1 100755 --- a/libtorrent/include/libtorrent/web_peer_connection.hpp +++ b/libtorrent/include/libtorrent/web_peer_connection.hpp @@ -65,7 +65,6 @@ 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" @@ -126,6 +125,8 @@ 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/Makefile.am b/libtorrent/src/Makefile.am index fabe68b65..671cb75e5 100644 --- a/libtorrent/src/Makefile.am +++ b/libtorrent/src/Makefile.am @@ -12,8 +12,8 @@ kademlia/rpc_manager.cpp \ kademlia/traversal_algorithm.cpp endif -libtorrent_la_SOURCES = allocate_resources.cpp \ -entry.cpp escape_string.cpp \ +libtorrent_la_SOURCES = entry.cpp escape_string.cpp \ +enum_net.cpp broadcast_socket.cpp \ peer_connection.cpp bt_peer_connection.cpp web_peer_connection.cpp \ natpmp.cpp piece_picker.cpp policy.cpp session.cpp session_impl.cpp sha1.cpp \ stat.cpp storage.cpp torrent.cpp torrent_handle.cpp pe_crypto.cpp \ @@ -28,16 +28,16 @@ $(kademlia_sources) noinst_HEADERS = \ $(top_srcdir)/include/libtorrent/alert.hpp \ $(top_srcdir)/include/libtorrent/alert_types.hpp \ -$(top_srcdir)/include/libtorrent/allocate_resources.hpp \ -$(top_srcdir)/include/libtorrent/aux_/allocate_resources_impl.hpp \ $(top_srcdir)/include/libtorrent/aux_/session_impl.hpp \ $(top_srcdir)/include/libtorrent/bandwidth_manager.hpp \ $(top_srcdir)/include/libtorrent/bencode.hpp \ +$(top_srcdir)/include/libtorrent/broadcast_socket.hpp \ $(top_srcdir)/include/libtorrent/buffer.hpp \ $(top_srcdir)/include/libtorrent/connection_queue.hpp \ $(top_srcdir)/include/libtorrent/debug.hpp \ $(top_srcdir)/include/libtorrent/disk_io_thread.hpp \ $(top_srcdir)/include/libtorrent/entry.hpp \ +$(top_srcdir)/include/libtorrent/enum_net.hpp \ $(top_srcdir)/include/libtorrent/escape_string.hpp \ $(top_srcdir)/include/libtorrent/extensions.hpp \ $(top_srcdir)/include/libtorrent/extensions/metadata_transfer.hpp \ @@ -71,7 +71,6 @@ $(top_srcdir)/include/libtorrent/peer_request.hpp \ $(top_srcdir)/include/libtorrent/piece_block_progress.hpp \ $(top_srcdir)/include/libtorrent/piece_picker.hpp \ $(top_srcdir)/include/libtorrent/policy.hpp \ -$(top_srcdir)/include/libtorrent/resource_request.hpp \ $(top_srcdir)/include/libtorrent/session.hpp \ $(top_srcdir)/include/libtorrent/size_type.hpp \ $(top_srcdir)/include/libtorrent/socket.hpp \ diff --git a/libtorrent/src/assert.cpp b/libtorrent/src/assert.cpp new file mode 100644 index 000000000..da79a745b --- /dev/null +++ b/libtorrent/src/assert.cpp @@ -0,0 +1,65 @@ +/* + +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 + +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); + + 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); + exit(1); +} + +#endif + diff --git a/libtorrent/src/broadcast_socket.cpp b/libtorrent/src/broadcast_socket.cpp new file mode 100644 index 000000000..a937fc11b --- /dev/null +++ b/libtorrent/src/broadcast_socket.cpp @@ -0,0 +1,144 @@ +/* + +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 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(); + } + + broadcast_socket::broadcast_socket(asio::io_service& ios + , udp::endpoint const& multicast_endpoint + , receive_handler_t const& handler) + : m_multicast_endpoint(multicast_endpoint) + , m_on_receive(handler) + { + assert(m_multicast_endpoint.address().is_v4()); + assert(m_multicast_endpoint.address().to_v4().is_multicast()); + + 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 (!i->is_v4() || !is_local(*i)) continue; + // ignore the loopback interface + if (i->to_v4() == address_v4((127 << 24) + 1)) continue; + + boost::shared_ptr s(new datagram_socket(ios)); + s->open(udp::v4(), ec); + if (ec) continue; + s->set_option(datagram_socket::reuse_address(true), ec); + if (ec) continue; + s->bind(udp::endpoint(*i, 0), 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; + s->set_option(hops(255)); + 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)); + } + } + + 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); +// std::cerr << " sending on " << i->socket->local_endpoint().address().to_string() << std::endl; + 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 5b63f26cd..11a39675f 100755 --- a/libtorrent/src/bt_peer_connection.cpp +++ b/libtorrent/src/bt_peer_connection.cpp @@ -75,7 +75,14 @@ namespace libtorrent &bt_peer_connection::on_piece, &bt_peer_connection::on_cancel, &bt_peer_connection::on_dht_port, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 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, &bt_peer_connection::on_extended }; @@ -93,6 +100,7 @@ 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) @@ -124,6 +132,7 @@ 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) @@ -226,6 +235,10 @@ 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) @@ -246,6 +259,75 @@ 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()); @@ -628,14 +710,17 @@ 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 @@ -721,6 +806,20 @@ 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); + } + } } // ----------------------------- @@ -939,6 +1038,9 @@ 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"); @@ -953,6 +1055,80 @@ 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 ---------- // ----------------------------- @@ -1175,6 +1351,22 @@ 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; @@ -1183,7 +1375,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) { @@ -1251,6 +1443,9 @@ namespace libtorrent #endif } } + + if (m_supports_fast) + send_allowed_set(); } #ifndef TORRENT_DISABLE_EXTENSIONS @@ -1546,7 +1741,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; @@ -1684,7 +1879,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; @@ -2016,6 +2211,9 @@ 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) @@ -2049,10 +2247,10 @@ namespace libtorrent assert(t); // if this is a local connection, we have already - // send the handshake + // sent 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)); @@ -2125,11 +2323,6 @@ 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")) @@ -2181,6 +2374,14 @@ 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 859205ed0..0b3f5ff54 100644 --- a/libtorrent/src/connection_queue.cpp +++ b/libtorrent/src/connection_queue.cpp @@ -54,6 +54,8 @@ namespace libtorrent , boost::function const& on_timeout , time_duration timeout) { + mutex_t::scoped_lock l(m_mutex); + INVARIANT_CHECK; m_queue.push_back(entry()); @@ -68,6 +70,8 @@ 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() @@ -148,6 +152,8 @@ 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); @@ -158,21 +164,35 @@ 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) { - boost::function on_timeout = i->on_timeout; - m_queue.erase(i++); + std::list::iterator j = i; + ++i; + timed_out.splice(timed_out.end(), m_queue, j, 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/deluge_core.cpp b/libtorrent/src/deluge_core.cpp deleted file mode 100644 index 930c7d496..000000000 --- a/libtorrent/src/deluge_core.cpp +++ /dev/null @@ -1,1439 +0,0 @@ -/* - * Copyright 2006 Alon Zakai ('Kripken') - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2, or (at your option) - * any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - * - * In addition, as a special exception, the copyright holders give - * permission to link the code of portions of this program with the OpenSSL - * library. - * You must obey the GNU General Public License in all respects for all of - * the code used other than OpenSSL. If you modify file(s) with this - * exception, you may extend this exception to your version of the file(s), - * but you are not obligated to do so. If you do not wish to do so, delete - * this exception statement from your version. If you delete this exception - * statement from all source files in the program, then also delete it here. - * - * Thank You: Some code portions were derived from BSD-licensed work by - * Arvid Norberg, and GPL-licensed work by Christophe Dumez - */ - -//------------------ -// TODO: -// -// The DHT capability requires UDP. We need to check that this port is in fact -// open, just like the normal TCP port for bittorrent. -// -//----------------- -#include - -#include -#include -#include - -#include "libtorrent/entry.hpp" -#include "libtorrent/bencode.hpp" -#include "libtorrent/session.hpp" -#include "libtorrent/identify_client.hpp" -#include "libtorrent/alert_types.hpp" -#include "libtorrent/storage.hpp" -#include "libtorrent/hasher.hpp" -#include "libtorrent/ip_filter.hpp" -#include "libtorrent/upnp.hpp" -#include "libtorrent/file_pool.hpp" -#include "libtorrent/natpmp.hpp" -#include "libtorrent/extensions/metadata_transfer.hpp" -#include "libtorrent/extensions/ut_pex.hpp" -using namespace boost::filesystem; -using namespace libtorrent; - -//---------------- -// CONSTANTS -//---------------- - -#ifdef AMD64 -#define python_long int -#else -#define python_long long -#endif - -#define EVENT_NULL 0 -#define EVENT_FINISHED 1 -#define EVENT_PEER_ERROR 2 -#define EVENT_INVALID_REQUEST 3 -#define EVENT_FILE_ERROR 4 -#define EVENT_HASH_FAILED_ERROR 5 -#define EVENT_PEER_BAN_ERROR 6 -#define EVENT_FASTRESUME_REJECTED_ERROR 8 -#define EVENT_TRACKER 9 -#define EVENT_OTHER 10 - -#define STATE_QUEUED 0 -#define STATE_CHECKING 1 -#define STATE_CONNECTING 2 -#define STATE_DOWNLOADING_META 3 -#define STATE_DOWNLOADING 4 -#define STATE_FINISHED 5 -#define STATE_SEEDING 6 -#define STATE_ALLOCATING 7 - -#define DHT_ROUTER_PORT 6881 - -//----------------- -// TYPES -//----------------- - -typedef long unique_ID_t; -typedef std::vector filter_out_t; -typedef std::string torrent_name_t; - -struct torrent_t -{ - torrent_handle handle; - unique_ID_t unique_ID; -}; - -typedef std::vector torrents_t; -typedef torrents_t::iterator torrents_t_iterator; - -//--------------------------- -// MODULE-GLOBAL VARIABLES -//--------------------------- - -long M_unique_counter = 0; -session_settings *M_settings = NULL; -pe_settings *M_pe_settings = NULL; -proxy_settings *M_proxy_settings = NULL; -session *M_ses = NULL; -PyObject *M_constants = NULL; -ip_filter *M_the_filter = NULL; -torrents_t *M_torrents = NULL; - -//------------------------ -// Exception types & macro -//------------------------ - -static PyObject *DelugeError = NULL; -static PyObject *InvalidEncodingError = NULL; -static PyObject *FilesystemError = NULL; -static PyObject *DuplicateTorrentError = NULL; -static PyObject *InvalidTorrentError = NULL; - -#define RAISE_PTR(e,s) { printf("Raising error: %s\r\n", s); PyErr_SetString(e, s); return NULL; } -#define RAISE_INT(e,s) { printf("Raising error: %s\r\n", s); PyErr_SetString(e, s); return -1; } - -//--------------------- -// Internal functions -//--------------------- - -bool empty_name_check(const std::string & name) -{ - return 1; -} - - -long handle_exists(torrent_handle &handle) -{ - for (unsigned long i = 0; i < M_torrents->size(); i++) - if ((*M_torrents)[i].handle == handle) - return 1; - - return 0; -} - - -long get_torrent_index(torrent_handle &handle) -{ - for (unsigned long i = 0; i < M_torrents->size(); i++) - if ((*M_torrents)[i].handle == handle) - { - // printf("Found: %li\r\n", i); - return i; - } - - RAISE_INT(DelugeError, "Handle not found."); -} - - -long get_index_from_unique_ID(long unique_ID) -{ - assert(M_handles->size() == M_unique_IDs->size()); - - for (unsigned long i = 0; i < M_torrents->size(); i++) - if ((*M_torrents)[i].unique_ID == unique_ID) - return i; - - RAISE_INT(DelugeError, "No such unique_ID."); -} - - -long internal_add_torrent(std::string const& torrent_name, -float preferred_ratio, -bool compact_mode, -boost::filesystem::path const& save_path) -{ - - std::ifstream in(torrent_name.c_str(), std::ios_base::binary); - in.unsetf(std::ios_base::skipws); - entry e; - e = bdecode(std::istream_iterator(in), std::istream_iterator()); - - torrent_info t(e); - - entry resume_data; - try - { - std::stringstream s; - s << torrent_name << ".fastresume"; - boost::filesystem::ifstream resumeFile(s.str(), std::ios_base::binary); - resumeFile.unsetf(std::ios_base::skipws); - resume_data = bdecode(std::istream_iterator(resumeFile), - std::istream_iterator()); - } - catch (invalid_encoding&) - { - } - catch (boost::filesystem::filesystem_error&) {} - - // Create new torrent object - - torrent_t new_torrent; - - torrent_handle h = M_ses->add_torrent(t, save_path, resume_data, compact_mode, 16 * 1024); - // h.set_max_connections(60); // at some point we should use this - h.set_max_uploads(-1); - h.set_ratio(preferred_ratio); - new_torrent.handle = h; - - new_torrent.unique_ID = M_unique_counter; - M_unique_counter++; - - M_torrents->push_back(new_torrent); - - return (new_torrent.unique_ID); -} - - -void internal_remove_torrent(long index) -{ - assert(index < M_torrents->size()); - - torrent_handle& h = M_torrents->at(index).handle; - - M_ses->remove_torrent(h); - - torrents_t_iterator it = M_torrents->begin() + index; - M_torrents->erase(it); -} - - -long get_peer_index(tcp::endpoint addr, std::vector const& peers) -{ - long index = -1; - - for (unsigned long i = 0; i < peers.size(); i++) - if (peers[i].ip == addr) - index = i; - - return index; -} - - -// The following function contains code by Christophe Dumez and Arvid Norberg -void internal_add_files(torrent_info& t, -boost::filesystem::path const& p, -boost::filesystem::path const& l) -{ - // change default checker, perhaps? - boost::filesystem::path f(p / l); - if (is_directory(f)) - { - for (boost::filesystem::directory_iterator i(f), end; i != end; ++i) - internal_add_files(t, p, l / i->leaf()); - } else - t.add_file(l, file_size(f)); -} - - -long count_DHT_peers(entry &state) -{ - long num_peers = 0; - entry *nodes = state.find_key("nodes"); - if (nodes) - { - entry::list_type &peers = nodes->list(); - entry::list_type::const_iterator i; - i = peers.begin(); - - while (i != peers.end()) - { - num_peers++; - i++; - } - } - - return num_peers; -} - - -//===================== -// External functions -//===================== - -static PyObject *torrent_pre_init(PyObject *self, PyObject *args) -{ - if (!PyArg_ParseTuple(args, "OOOOO", &DelugeError, - &InvalidEncodingError, - &FilesystemError, - &DuplicateTorrentError, - &InvalidTorrentError)) - return NULL; - - Py_INCREF(Py_None); return Py_None; -} - - -static PyObject *torrent_init(PyObject *self, PyObject *args) -{ - printf("deluge_core; using libtorrent %s. Compiled with NDEBUG value: %d\r\n", - LIBTORRENT_VERSION, - NDEBUG); - - // Tell Boost that we are on *NIX, so bloody '.'s are ok inside a directory name! - boost::filesystem::path::default_name_check(empty_name_check); - - char *client_ID, *user_agent; - python_long v1,v2,v3,v4; - - if (!PyArg_ParseTuple(args, "siiiis", &client_ID, &v1, &v2, &v3, &v4, &user_agent)) - return NULL; - - M_settings = new session_settings; - M_ses = new session(fingerprint(client_ID, v1, v2, v3, v4)); - - M_torrents = new torrents_t; - M_torrents->reserve(10); // pretty cheap, just 10 - - // Init values - - M_settings->user_agent = std::string(user_agent); - - M_ses->set_max_half_open_connections(-1); - M_ses->set_download_rate_limit(-1); - M_ses->set_upload_rate_limit(-1); - - M_ses->set_settings(*M_settings); - M_ses->set_severity_level(alert::debug); - - M_ses->add_extension(&libtorrent::create_metadata_plugin); - - M_constants = Py_BuildValue("{s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i,s:i}", - "EVENT_NULL", EVENT_NULL, - "EVENT_FINISHED", EVENT_FINISHED, - "EVENT_PEER_ERROR", EVENT_PEER_ERROR, - "EVENT_INVALID_REQUEST", EVENT_INVALID_REQUEST, - "EVENT_FILE_ERROR", EVENT_FILE_ERROR, - "EVENT_HASH_FAILED_ERROR", EVENT_HASH_FAILED_ERROR, - "EVENT_PEER_BAN_ERROR", EVENT_PEER_BAN_ERROR, - "EVENT_FASTRESUME_REJECTED_ERROR", EVENT_FASTRESUME_REJECTED_ERROR, - "EVENT_TRACKER", EVENT_TRACKER, - "EVENT_OTHER", EVENT_OTHER, - "STATE_QUEUED", STATE_QUEUED, - "STATE_CHECKING", STATE_CHECKING, - "STATE_CONNECTING", STATE_CONNECTING, - "STATE_DOWNLOADING_META", STATE_DOWNLOADING_META, - "STATE_DOWNLOADING", STATE_DOWNLOADING, - "STATE_FINISHED", STATE_FINISHED, - "STATE_SEEDING", STATE_SEEDING, - "STATE_ALLOCATING", STATE_ALLOCATING); - - Py_INCREF(Py_None); return Py_None; -}; - -static PyObject *torrent_quit(PyObject *self, PyObject *args) -{ - M_settings->stop_tracker_timeout = 5; - M_ses->set_settings(*M_settings); - printf("core: removing torrents...\r\n"); - delete M_torrents; - printf("core: removing settings...\r\n"); - delete M_settings; - printf("core: shutting down session...\r\n"); - delete M_ses; // 100% CPU... - Py_DECREF(M_constants); - - printf("core shut down.\r\n"); - - Py_INCREF(Py_None); return Py_None; -}; - -static PyObject *torrent_save_fastresume(PyObject *self, PyObject *args) -{ - python_long unique_ID; - const char *torrent_name; - if (!PyArg_ParseTuple(args, "is", &unique_ID, &torrent_name)) - return NULL; - - long index = get_index_from_unique_ID(unique_ID); - if (PyErr_Occurred()) - return NULL; - - torrent_handle& h = M_torrents->at(index).handle; - // For valid torrents, save fastresume data - if (h.is_valid() && h.has_metadata()) - { - h.pause(); - - entry data = h.write_resume_data(); - - std::stringstream s; - s << torrent_name << ".fastresume"; - - boost::filesystem::ofstream out(s.str(), std::ios_base::binary); - - out.unsetf(std::ios_base::skipws); - - bencode(std::ostream_iterator(out), data); - - h.resume(); - - Py_INCREF(Py_None); return Py_None; - } else - RAISE_PTR(DelugeError, "Invalid handle or no metadata for fastresume."); -} - - -static PyObject *torrent_set_max_half_open(PyObject *self, PyObject *args) -{ - python_long arg; - if (!PyArg_ParseTuple(args, "i", &arg)) - return NULL; - - M_ses->set_max_half_open_connections(arg); - - Py_INCREF(Py_None); return Py_None; -} - - -static PyObject *torrent_set_download_rate_limit(PyObject *self, PyObject *args) -{ - python_long arg; - if (!PyArg_ParseTuple(args, "i", &arg)) - return NULL; - - // printf("Capping download to %d bytes per second\r\n", (int)arg); - M_ses->set_download_rate_limit(arg); - - Py_INCREF(Py_None); return Py_None; -} - - -static PyObject *torrent_set_upload_rate_limit(PyObject *self, PyObject *args) -{ - python_long arg; - if (!PyArg_ParseTuple(args, "i", &arg)) - return NULL; - - // printf("Capping upload to %d bytes per second\r\n", (int)arg); - M_ses->set_upload_rate_limit(arg); - - Py_INCREF(Py_None); return Py_None; -} - - -static PyObject *torrent_set_listen_on(PyObject *self, PyObject *args) -{ - PyObject *port_vec; - if (!PyArg_ParseTuple(args, "O", &port_vec)) - return NULL; - - M_ses->listen_on(std::make_pair( PyInt_AsLong(PyList_GetItem(port_vec, 0)), - PyInt_AsLong(PyList_GetItem(port_vec, 1))), ""); - - Py_INCREF(Py_None); return Py_None; -} - - -static PyObject *torrent_is_listening(PyObject *self, PyObject *args) -{ - long ret = (M_ses->is_listening() != 0); - - return Py_BuildValue("i", ret); -} - - -static PyObject *torrent_listening_port(PyObject *self, PyObject *args) -{ - return Py_BuildValue("i", (python_long)M_ses->listen_port()); -} - - -static PyObject *torrent_set_max_uploads(PyObject *self, PyObject *args) -{ - python_long max_up; - if (!PyArg_ParseTuple(args, "i", &max_up)) - return NULL; - - M_ses->set_max_uploads(max_up); - - Py_INCREF(Py_None); return Py_None; -} - - -static PyObject *torrent_set_max_connections(PyObject *self, PyObject *args) -{ - python_long max_conn; - if (!PyArg_ParseTuple(args, "i", &max_conn)) - return NULL; - - // printf("Setting max connections: %d\r\n", max_conn); - M_ses->set_max_connections(max_conn); - - Py_INCREF(Py_None); return Py_None; -} - - -static PyObject *torrent_add_torrent(PyObject *self, PyObject *args) -{ - const char *name, *save_dir; - python_long compact; - if (!PyArg_ParseTuple(args, "ssi", &name, &save_dir, &compact)) - return NULL; - - boost::filesystem::path save_dir_2 (save_dir, empty_name_check); - try - { - long ret = internal_add_torrent(name, 0, compact, save_dir_2); - if (PyErr_Occurred()) - return NULL; - else - return Py_BuildValue("i", ret); - } - catch (invalid_encoding&) - { RAISE_PTR(InvalidEncodingError, ""); } - catch (invalid_torrent_file&) - { RAISE_PTR(InvalidTorrentError, ""); } - catch (boost::filesystem::filesystem_error&) - { RAISE_PTR(FilesystemError, ""); } - catch (duplicate_torrent&) - { RAISE_PTR(DuplicateTorrentError, "libtorrent reports this is a duplicate torrent"); } -} - - -static PyObject *torrent_remove_torrent(PyObject *self, PyObject *args) -{ - python_long unique_ID; - if (!PyArg_ParseTuple(args, "i", &unique_ID)) - return NULL; - - long index = get_index_from_unique_ID(unique_ID); - if (PyErr_Occurred()) - return NULL; - - internal_remove_torrent(index); - - Py_INCREF(Py_None); return Py_None; -} - - -static PyObject *torrent_get_num_torrents(PyObject *self, PyObject *args) -{ - return Py_BuildValue("i", M_torrents->size()); -} - - -static PyObject *torrent_reannounce(PyObject *self, PyObject *args) -{ - python_long unique_ID; - if (!PyArg_ParseTuple(args, "i", &unique_ID)) - return NULL; - - long index = get_index_from_unique_ID(unique_ID); - if (PyErr_Occurred()) - return NULL; - - M_torrents->at(index).handle.force_reannounce(); - - Py_INCREF(Py_None); return Py_None; -} - - -static PyObject *torrent_pause(PyObject *self, PyObject *args) -{ - python_long unique_ID; - if (!PyArg_ParseTuple(args, "i", &unique_ID)) - return NULL; - - long index = get_index_from_unique_ID(unique_ID); - if (PyErr_Occurred()) - return NULL; - - M_torrents->at(index).handle.pause(); - - Py_INCREF(Py_None); return Py_None; -} - - -static PyObject *torrent_resume(PyObject *self, PyObject *args) -{ - python_long unique_ID; - if (!PyArg_ParseTuple(args, "i", &unique_ID)) - return NULL; - - long index = get_index_from_unique_ID(unique_ID); - if (PyErr_Occurred()) - return NULL; - - M_torrents->at(index).handle.resume(); - - Py_INCREF(Py_None); return Py_None; -} - - -static PyObject *torrent_get_torrent_state(PyObject *self, PyObject *args) -{ - python_long unique_ID; - if (!PyArg_ParseTuple(args, "i", &unique_ID)) - return NULL; - - long index = get_index_from_unique_ID(unique_ID); - if (PyErr_Occurred()) - return NULL; - - torrent_t &t = M_torrents->at(index); - torrent_status s = t.handle.status(); - const torrent_info &i = t.handle.get_torrent_info(); - - std::vector peers; - t.handle.get_peer_info(peers); - - long connected_seeds = 0; - long connected_peers = 0; - long total_seeds = 0; - long total_peers = 0; - - for (unsigned long i = 0; i < peers.size(); i++) { - - connected_peers = s.num_peers - s.num_seeds; - - connected_seeds = s.num_seeds; - - total_seeds = s.num_complete != -1? s.num_complete : connected_seeds; - - total_peers = s.num_incomplete != -1? s.num_incomplete : connected_peers; - } - - return Py_BuildValue("{s:s,s:i,s:i,s:l,s:l,s:f,s:f,s:f,s:L,s:L,s:b,s:s,s:s,s:f,s:L,s:L,s:l,s:i,s:i,s:L,s:L,s:i,s:l,s:l,s:b,s:b,s:L,s:L,s:L}", - "name", t.handle.get_torrent_info().name().c_str(), - "num_files", t.handle.get_torrent_info().num_files(), - "state", s.state, - "num_peers", connected_peers, - "num_seeds", connected_seeds, - "distributed_copies", s.distributed_copies, - "download_rate", s.download_rate, - "upload_rate", s.upload_rate, - "total_download", s.total_download, - "total_upload", s.total_upload, - "tracker_ok", !s.current_tracker.empty(), - "next_announce", boost::posix_time::to_simple_string(s.next_announce).c_str(), - "tracker", s.current_tracker.c_str(), - "progress", s.progress, - "total_payload_download", s.total_payload_download, - "total_payload_upload", s.total_payload_upload, - "pieces", long(s.pieces), // this is really a std::vector* - "pieces_done", s.num_pieces, - "block_size", s.block_size, - "total_size", i.total_size(), - "piece_length", i.piece_length(), - "num_pieces", i.num_pieces(), - "total_peers", total_peers, - "total_seeds", total_seeds, - "is_paused", t.handle.is_paused(), - "is_seed", t.handle.is_seed(), - "total_done", s.total_done, - "total_wanted", s.total_wanted, - "total_wanted_done", s.total_wanted_done); -}; - -static PyObject *torrent_pop_event(PyObject *self, PyObject *args) -{ - std::auto_ptr a; - - a = M_ses->pop_alert(); - - alert *popped_alert = a.get(); - - if (!popped_alert) - { - Py_INCREF(Py_None); return Py_None; - } else if (dynamic_cast(popped_alert)) - { - torrent_handle handle = (dynamic_cast(popped_alert))->handle; - - long index = get_torrent_index(handle); - if (PyErr_Occurred()) - return NULL; - - if (handle_exists(handle)) - return Py_BuildValue("{s:i,s:i}", "event_type", EVENT_FINISHED, - "unique_ID", - M_torrents->at(index).unique_ID); - else - { Py_INCREF(Py_None); return Py_None; } - } else if (dynamic_cast(popped_alert)) - { - peer_id peer_ID = (dynamic_cast(popped_alert))->pid; - std::string peer_IP = - (dynamic_cast(popped_alert))->ip.address().to_string(); - - return Py_BuildValue("{s:i,s:s,s:s,s:s}", "event_type", EVENT_PEER_ERROR, - "client_ID", identify_client(peer_ID).c_str(), - "ip", peer_IP.c_str(), - "message", a->msg().c_str()); - } else if (dynamic_cast(popped_alert)) - { - peer_id peer_ID = (dynamic_cast(popped_alert))->pid; - - return Py_BuildValue("{s:i,s:s,s:s}", - "event_type", EVENT_INVALID_REQUEST, - "client_ID", identify_client(peer_ID).c_str(), - "message", a->msg().c_str()); - } else if (dynamic_cast(popped_alert)) - { - torrent_handle handle = (dynamic_cast(popped_alert))->handle; - long index = get_torrent_index(handle); - if (PyErr_Occurred()) - return NULL; - - if (handle_exists(handle)) - return Py_BuildValue("{s:i,s:i,s:s}", - "event_type", EVENT_FILE_ERROR, - "unique_ID", M_torrents->at(index).unique_ID, - "message", a->msg().c_str()); - else - { Py_INCREF(Py_None); return Py_None; } - } else if (dynamic_cast(popped_alert)) - { - torrent_handle handle = (dynamic_cast(popped_alert))->handle; - long index = get_torrent_index(handle); - if (PyErr_Occurred()) - return NULL; - - if (handle_exists(handle)) - return Py_BuildValue("{s:i,s:i,s:i,s:s}", - "event_type", EVENT_HASH_FAILED_ERROR, - "unique_ID", M_torrents->at(index).unique_ID, - "piece_index", - long((dynamic_cast(popped_alert))->piece_index), - "message", a->msg().c_str()); - else - { Py_INCREF(Py_None); return Py_None; } - } else if (dynamic_cast(popped_alert)) - { - torrent_handle handle = (dynamic_cast(popped_alert))->handle; - long index = get_torrent_index(handle); - if (PyErr_Occurred()) - return NULL; - std::string peer_IP = (dynamic_cast(popped_alert))->ip.address().to_string(); - - if (handle_exists(handle)) - return Py_BuildValue("{s:i,s:i,s:s,s:s}", - "event_type", EVENT_PEER_BAN_ERROR, - "unique_ID", M_torrents->at(index).unique_ID, - "ip", peer_IP.c_str(), - "message", a->msg().c_str()); - else - { Py_INCREF(Py_None); return Py_None; } - } else if (dynamic_cast(popped_alert)) - { - torrent_handle handle = (dynamic_cast(popped_alert))->handle; - long index = get_torrent_index(handle); - if (PyErr_Occurred()) - return NULL; - - if (handle_exists(handle)) - return Py_BuildValue("{s:i,s:i,s:s}", - "event_type", EVENT_FASTRESUME_REJECTED_ERROR, - "unique_ID", M_torrents->at(index).unique_ID, - "message", a->msg().c_str()); - else - { Py_INCREF(Py_None); return Py_None; } - } else if (dynamic_cast(popped_alert)) - { - torrent_handle handle = (dynamic_cast(popped_alert))->handle; - long index = get_torrent_index(handle); - if (PyErr_Occurred()) - return NULL; - - if (handle_exists(handle)) - return Py_BuildValue("{s:i,s:i,s:s,s:s}", - "event_type", EVENT_TRACKER, - "unique_ID", - M_torrents->at(index).unique_ID, - "tracker_status", "Announce sent", - "message", a->msg().c_str()); - else - { Py_INCREF(Py_None); return Py_None; } - } else if (dynamic_cast(popped_alert)) - { - torrent_handle handle = (dynamic_cast(popped_alert))->handle; - long index = get_torrent_index(handle); - if (PyErr_Occurred()) - return NULL; - - if (handle_exists(handle)) - return Py_BuildValue("{s:i,s:i,s:s,s:s}", - "event_type", EVENT_TRACKER, - "unique_ID", - M_torrents->at(index).unique_ID, - "tracker_status", "Bad response (status code=?)", - "message", a->msg().c_str()); - else - { Py_INCREF(Py_None); return Py_None; } - } else if (dynamic_cast(popped_alert)) - { - torrent_handle handle = (dynamic_cast(popped_alert))->handle; - long index = get_torrent_index(handle); - if (PyErr_Occurred()) - return NULL; - - if (handle_exists(handle)) - return Py_BuildValue("{s:i,s:i,s:s,s:s}", - "event_type", EVENT_TRACKER, - "unique_ID", - M_torrents->at(index).unique_ID, - "tracker_status", "Announce succeeded", - "message", a->msg().c_str()); - else - { Py_INCREF(Py_None); return Py_None; } - } else if (dynamic_cast(popped_alert)) - { - torrent_handle handle = (dynamic_cast(popped_alert))->handle; - long index = get_torrent_index(handle); - if (PyErr_Occurred()) - return NULL; - - if (handle_exists(handle)) - return Py_BuildValue("{s:i,s:i,s:s,s:s}", - "event_type", EVENT_TRACKER, - "unique_ID", - M_torrents->at(index).unique_ID, - "tracker_status", "Warning in response", - "message", a->msg().c_str()); - else - { Py_INCREF(Py_None); return Py_None; } - } - - return Py_BuildValue("{s:i,s:s}", "event_type", EVENT_OTHER, - "message", a->msg().c_str() ); -} - - -static PyObject *torrent_get_session_info(PyObject *self, PyObject *args) -{ - session_status s = M_ses->status(); - - return Py_BuildValue("{s:l,s:f,s:f,s:f,s:f,s:l}", - "has_incoming_connections", long(s.has_incoming_connections), - "upload_rate", float(s.upload_rate), - "download_rate", float(s.download_rate), - "payload_upload_rate", float(s.payload_upload_rate), - "payload_download_rate", float(s.payload_download_rate), - "num_peers", long(s.num_peers)); -} - - -static PyObject *torrent_get_peer_info(PyObject *self, PyObject *args) -{ - python_long unique_ID; - if (!PyArg_ParseTuple(args, "i", &unique_ID)) - return NULL; - - long index = get_index_from_unique_ID(unique_ID); - if (PyErr_Occurred()) - return NULL; - - std::vector peers; - M_torrents->at(index).handle.get_peer_info(peers); - - PyObject *peer_info; - PyObject *ret = PyTuple_New(peers.size()); - PyObject *curr_piece, *py_pieces; - - for (unsigned long i = 0; i < peers.size(); i++) - { - std::vector &pieces = peers[i].pieces; - unsigned long pieces_had = 0; - - py_pieces = PyTuple_New(pieces.size()); - - for (unsigned long piece = 0; piece < pieces.size(); piece++) - { - if (pieces[piece]) - pieces_had++; - - curr_piece = Py_BuildValue("i", long(pieces[piece])); - PyTuple_SetItem(py_pieces, piece, curr_piece); - } - - peer_info = Py_BuildValue( - "{s:f,s:L,s:f,s:L,s:i,s:i,s:b,s:b,s:b,s:b,s:b,s:b,s:b,s:b,s:b,s:s,s:b,s:s,s:f,s:O,s:b,s:b}", - "download_speed", peers[i].down_speed, - "total_download", peers[i].total_download, - "upload_speed", peers[i].up_speed, - "total_upload", peers[i].total_upload, - "download_queue_length", peers[i].download_queue_length, - "upload_queue_length", peers[i].upload_queue_length, - "is_interesting", ((peers[i].flags & peer_info::interesting) != 0), - "is_choked", ((peers[i].flags & peer_info::choked) != 0), - "is_remote_interested", ((peers[i].flags & peer_info::remote_interested) != 0), - "is_remote_choked", ((peers[i].flags & peer_info::remote_choked) != 0), - "supports_extensions", ((peers[i].flags & peer_info::supports_extensions) != 0), - "is_local_connection", ((peers[i].flags & peer_info::local_connection) != 0), - "is_awaiting_handshake", ((peers[i].flags & peer_info::handshake) != 0), - "is_connecting", ((peers[i].flags & peer_info::connecting) != 0), - "is_queued", ((peers[i].flags & peer_info::queued) != 0), - "client", peers[i].client.c_str(), - "is_seed", ((peers[i].flags & peer_info::seed) != 0), - "ip", peers[i].ip.address().to_string().c_str(), - "peer_has", float(float(pieces_had)*100.0/pieces.size()), - "pieces", py_pieces, - "rc4_encrypted", ((peers[i].flags & peer_info::rc4_encrypted) != 0), - "plaintext_encrypted", ((peers[i].flags & peer_info::plaintext_encrypted) != 0) - ); - - Py_DECREF(py_pieces); // Assuming the previous line does NOT steal the ref, then this is - // needed! - - PyTuple_SetItem(ret, i, peer_info); - }; - - return ret; -}; - -static PyObject *torrent_get_file_info(PyObject *self, PyObject *args) -{ - python_long unique_ID; - if (!PyArg_ParseTuple(args, "i", &unique_ID)) - return NULL; - - long index = get_index_from_unique_ID(unique_ID); - if (PyErr_Occurred()) - return NULL; - - std::vector temp_files; - - PyObject *file_info; - - std::vector progresses; - - torrent_t &t = M_torrents->at(index); - t.handle.file_progress(progresses); - - torrent_info::file_iterator start = - t.handle.get_torrent_info().begin_files(); - torrent_info::file_iterator end = - t.handle.get_torrent_info().end_files(); - - long fileIndex = 0; - - for(torrent_info::file_iterator i = start; i != end; ++i) - { - file_entry const &currFile = (*i); - - file_info = Py_BuildValue( - "{s:s,s:d,s:d,s:f}", - "path", currFile.path.string().c_str(), - "offset", double(currFile.offset), - "size", double(currFile.size), - "progress", progresses[i - start]*100.0 - ); - - fileIndex++; - - temp_files.push_back(file_info); - }; - - PyObject *ret = PyTuple_New(temp_files.size()); - - for (unsigned long i = 0; i < temp_files.size(); i++) - PyTuple_SetItem(ret, i, temp_files[i]); - - return ret; -}; - -static PyObject *torrent_set_filter_out(PyObject *self, PyObject *args) -{ - python_long unique_ID; - PyObject *filter_out_object; - if (!PyArg_ParseTuple(args, "iO", &unique_ID, &filter_out_object)) - return NULL; - - long index = get_index_from_unique_ID(unique_ID); - if (PyErr_Occurred()) - return NULL; - - torrent_t &t = M_torrents->at(index); - long num_files = t.handle.get_torrent_info().num_files(); - assert(PyList_Size(filter_out_object) == num_files); - - filter_out_t filter_out(num_files); - - for (long i = 0; i < num_files; i++) - { - filter_out.at(i) = - PyInt_AsLong(PyList_GetItem(filter_out_object, i)); - }; - - t.handle.filter_files(filter_out); - - Py_INCREF(Py_None); return Py_None; -} - - -/*static PyObject *torrent_get_unique_IDs(PyObject *self, PyObject *args) -{ - PyObject *ret = PyTuple_New(M_torrents.size()); - PyObject *temp; - - for (unsigned long i = 0; i < M_torrents.size(); i++) - { - temp = Py_BuildValue("i", M_torrents->at(i).unique_ID) - - PyTuple_SetItem(ret, i, temp); - }; - - return ret; -};*/ - -static PyObject *torrent_constants(PyObject *self, PyObject *args) -{ - Py_INCREF(M_constants); return M_constants; -} - - -static PyObject *torrent_start_DHT(PyObject *self, PyObject *args) -{ - const char *DHT_path; - if (!PyArg_ParseTuple(args, "s", &DHT_path)) - return NULL; - - // printf("Loading DHT state from %s\r\n", DHT_path); - - boost::filesystem::path tempPath(DHT_path, empty_name_check); - boost::filesystem::ifstream DHT_state_file(tempPath, std::ios_base::binary); - DHT_state_file.unsetf(std::ios_base::skipws); - - entry DHT_state; - try - { - DHT_state = bdecode(std::istream_iterator(DHT_state_file), - std::istream_iterator()); - M_ses->start_dht(DHT_state); - // printf("DHT state recovered.\r\n"); - - // // Print out the state data from the FILE (not the session!) - // printf("Number of DHT peers in recovered state: %ld\r\n", count_DHT_peers(DHT_state)); - - } - catch (std::exception&) - { - printf("No DHT file to resume\r\n"); - M_ses->start_dht(); - } - - M_ses->add_dht_router(std::make_pair(std::string("router.bittorrent.com"), - DHT_ROUTER_PORT)); - M_ses->add_dht_router(std::make_pair(std::string("router.utorrent.com"), - DHT_ROUTER_PORT)); - M_ses->add_dht_router(std::make_pair(std::string("router.bitcomet.com"), - DHT_ROUTER_PORT)); - - Py_INCREF(Py_None); return Py_None; -} - - -static PyObject *torrent_stop_DHT(PyObject *self, PyObject *args) -{ - const char *DHT_path; - if (!PyArg_ParseTuple(args, "s", &DHT_path)) - return NULL; - - // printf("Saving DHT state to %s\r\n", DHT_path); - - boost::filesystem::path tempPath = boost::filesystem::path(DHT_path, empty_name_check); - - try - { - entry DHT_state = M_ses->dht_state(); - - // printf("Number of DHT peers in state, saving: %ld\r\n", count_DHT_peers(DHT_state)); - - boost::filesystem::ofstream out(tempPath, std::ios_base::binary); - out.unsetf(std::ios_base::skipws); - bencode(std::ostream_iterator(out), DHT_state); - } - catch (std::exception& e) - { - printf("An error occured in saving DHT\r\n"); - std::cerr << e.what() << "\n"; - } - - Py_INCREF(Py_None); return Py_None; -} - - -static PyObject *torrent_get_DHT_info(PyObject *self, PyObject *args) -{ - entry DHT_state = M_ses->dht_state(); - - return Py_BuildValue("l", python_long(count_DHT_peers(DHT_state))); - - /* - // DHT_state.print(cout); - entry *nodes = DHT_state.find_key("nodes"); - if (!nodes) - return Py_BuildValue("l", -1); // No nodes - we are just starting up... - - entry::list_type &peers = nodes->list(); - entry::list_type::const_iterator i; - - python_long num_peers = 0; - - i = peers.begin(); - while (i != peers.end()) - { - num_peers++; - i++; - } - - return Py_BuildValue("l", num_peers); - */ -} - - -// Create Torrents: call with something like: -// create_torrent("mytorrent.torrent", "directory or file to make a torrent out of", -// "tracker1\ntracker2\ntracker3", "no comment", 256, "Deluge"); -// That makes a torrent with pieces of 256K, with "Deluge" as the creator string. -// -// The following function contains code by Christophe Dumez and Arvid Norberg -static PyObject *torrent_create_torrent(PyObject *self, PyObject *args) -{ - using namespace libtorrent; - using namespace boost::filesystem; - - //path::default_name_check(no_check); - - char *destination, *comment, *creator_str, *input, *trackers; - python_long piece_size; - if (!PyArg_ParseTuple(args, "ssssis", - &destination, &input, &trackers, &comment, &piece_size, &creator_str)) - return NULL; - - piece_size = piece_size * 1024; - - try - { - torrent_info t; - boost::filesystem::path full_path = complete(boost::filesystem::path(input)); - boost::filesystem::ofstream out(complete(boost::filesystem::path(destination)), std::ios_base::binary); - - internal_add_files(t, full_path.branch_path(), full_path.leaf()); - t.set_piece_size(piece_size); - - file_pool fp; - boost::scoped_ptr st(default_storage_constructor(t, full_path.branch_path(), fp)); - - std::string stdTrackers(trackers); - unsigned long index = 0, next = stdTrackers.find("\n"); - while (1 == 1) - { - t.add_tracker(stdTrackers.substr(index, next-index)); - index = next + 1; - if (next >= stdTrackers.length()) - break; - next = stdTrackers.find("\n", index); - if (next == std::string::npos) - break; - } - - int num = t.num_pieces(); - std::vector buf(piece_size); - for (int i = 0; i < num; ++i) - { - st->read(&buf[0], i, 0, t.piece_size(i)); - hasher h(&buf[0], t.piece_size(i)); - t.set_hash(i, h.final()); - } - - t.set_creator(creator_str); - t.set_comment(comment); - - entry e = t.create_torrent(); - bencode(std::ostream_iterator(out), e); - return Py_BuildValue("l", 1); - } catch (std::exception& e) - { - // std::cerr << e.what() << "\n"; - // return Py_BuildValue("l", 0); - RAISE_PTR(DelugeError, e.what()); - return Py_BuildValue("l", 0); - } -} - - -static PyObject *torrent_reset_IP_filter(PyObject *self, PyObject *args) -{ - // Remove existing filter, if there is one - if (M_the_filter != NULL) - delete M_the_filter; - - M_the_filter = new ip_filter(); - - M_ses->set_ip_filter(*M_the_filter); - - Py_INCREF(Py_None); return Py_None; -} - - -static PyObject *torrent_add_range_to_IP_filter(PyObject *self, PyObject *args) -{ - if (M_the_filter == NULL) { - RAISE_PTR(DelugeError, "No filter defined, use reset_IP_filter"); - } - - char *start, *end; - if (!PyArg_ParseTuple(args, "ss", &start, &end)) - return NULL; - - address_v4 inet_start = address_v4::from_string(start); - address_v4 inet_end = address_v4::from_string(end); - M_the_filter->add_rule(inet_start, inet_end, ip_filter::blocked); - - Py_INCREF(Py_None); return Py_None; -} - -static PyObject *torrent_use_upnp(PyObject *self, PyObject *args) -{ - python_long action; - PyArg_ParseTuple(args, "i", &action); - - if (action){ - M_ses->start_upnp(); - } - else{ - M_ses->stop_upnp(); - } - - Py_INCREF(Py_None); return Py_None; - -} - -static PyObject *torrent_use_natpmp(PyObject *self, PyObject *args) -{ - python_long action; - - PyArg_ParseTuple(args, "i", &action); - - if (action){ - M_ses->start_natpmp(); - } - else{ - M_ses->stop_natpmp(); - } - - Py_INCREF(Py_None); return Py_None; -} - -static PyObject *torrent_use_utpex(PyObject *self, PyObject *args) -{ - python_long action; - - PyArg_ParseTuple(args, "i", &action); - - if (action){ - M_ses->add_extension(&libtorrent::create_ut_pex_plugin); - } - - Py_INCREF(Py_None); return Py_None; -} - -static PyObject *torrent_pe_settings(PyObject *self, PyObject *args) -{ - M_pe_settings = new pe_settings(); - libtorrent::pe_settings::enc_policy out, in, prefer; - libtorrent::pe_settings::enc_level level; - - PyArg_ParseTuple(args, "iiii", &out, &in, &level, &prefer); - - M_pe_settings->out_enc_policy = out; - M_pe_settings->in_enc_policy = in; - M_pe_settings->allowed_enc_level = level; - M_pe_settings->prefer_rc4 = prefer; - - M_ses->set_pe_settings(*M_pe_settings); - - return Py_None; -} - -static PyObject *torrent_set_ratio(PyObject *self, PyObject *args) -{ - python_long unique_ID; - float num; - if (!PyArg_ParseTuple(args, "if", &unique_ID, &num)) - return NULL; - - long index = get_index_from_unique_ID(unique_ID); - if (PyErr_Occurred()) - return NULL; - - M_torrents->at(index).handle.set_ratio(num); - - Py_INCREF(Py_None); return Py_None; -} - -static PyObject *torrent_proxy_settings(PyObject *self, PyObject *args) -{ - M_proxy_settings = new proxy_settings(); - - char *server, *login, *pasw; - int portnum; - libtorrent::proxy_settings::proxy_type proxytype; - bool peerproxy, trackerproxy, dhtproxy; - - PyArg_ParseTuple(args, "sssiibbb", &server, &login, &pasw, &portnum, &proxytype, &peerproxy, &trackerproxy, &dhtproxy); - - M_proxy_settings->type = proxytype; - M_proxy_settings->username = login; - M_proxy_settings->password = pasw; - M_proxy_settings->hostname = server; - M_proxy_settings->port = portnum; - - if (peerproxy) { - M_ses->set_peer_proxy(*M_proxy_settings); - } - - if (trackerproxy) { - M_ses->set_tracker_proxy(*M_proxy_settings); - } - - if (dhtproxy) { - M_ses->set_dht_proxy(*M_proxy_settings); - } - - return Py_None; -} - -static PyObject *torrent_get_trackers(PyObject *self, PyObject *args) -{ - python_long unique_ID; - if (!PyArg_ParseTuple(args, "i", &unique_ID)) - return NULL; - - long index = get_index_from_unique_ID(unique_ID); - if (PyErr_Occurred()) - return NULL; - - torrent_handle& h = M_torrents->at(index).handle; - std::string trackerslist; - if (h.is_valid() && h.has_metadata()) - { - for (std::vector::const_iterator i = h.trackers().begin(); - i != h.trackers().end(); ++i) - { - trackerslist = trackerslist + i->url +"\n"; - } - } - return Py_BuildValue("s",trackerslist.c_str()); -} - -static PyObject *torrent_replace_trackers(PyObject *self, PyObject *args) -{ - python_long unique_ID; - const char* tracker; - if (!PyArg_ParseTuple(args, "iz", &unique_ID, &tracker)) - return NULL; - long index = get_index_from_unique_ID(unique_ID); - if (PyErr_Occurred()) - return NULL; - - torrent_handle& h = M_torrents->at(index).handle; - - std::vector trackerlist; - - std::istringstream trackers(tracker); - std::string line; - - while (std::getline(trackers, line)) { - libtorrent::announce_entry a_entry(line); - trackerlist.push_back(a_entry); - } - h.replace_trackers(trackerlist); - h.force_reannounce(); - return Py_None; -} -//==================== -// Python Module data -//==================== - -static PyMethodDef deluge_core_methods[] = -{ - {"pe_settings", torrent_pe_settings, METH_VARARGS, "."}, - {"pre_init", torrent_pre_init, METH_VARARGS, "."}, - {"init", torrent_init, METH_VARARGS, "."}, - {"quit", torrent_quit, METH_VARARGS, "."}, - {"save_fastresume", torrent_save_fastresume, METH_VARARGS, "."}, - {"set_max_half_open", torrent_set_max_half_open, METH_VARARGS, "."}, - {"set_download_rate_limit", torrent_set_download_rate_limit, METH_VARARGS, "."}, - {"set_upload_rate_limit", torrent_set_upload_rate_limit, METH_VARARGS, "."}, - {"set_listen_on", torrent_set_listen_on, METH_VARARGS, "."}, - {"is_listening", torrent_is_listening, METH_VARARGS, "."}, - {"listening_port", torrent_listening_port, METH_VARARGS, "."}, - {"set_max_uploads", torrent_set_max_uploads, METH_VARARGS, "."}, - {"set_max_connections", torrent_set_max_connections, METH_VARARGS, "."}, - {"add_torrent", torrent_add_torrent, METH_VARARGS, "."}, - {"remove_torrent", torrent_remove_torrent, METH_VARARGS, "."}, - {"get_num_torrents", torrent_get_num_torrents, METH_VARARGS, "."}, - {"reannounce", torrent_reannounce, METH_VARARGS, "."}, - {"pause", torrent_pause, METH_VARARGS, "."}, - {"resume", torrent_resume, METH_VARARGS, "."}, - {"get_torrent_state", torrent_get_torrent_state, METH_VARARGS, "."}, - {"pop_event", torrent_pop_event, METH_VARARGS, "."}, - {"get_session_info", torrent_get_session_info, METH_VARARGS, "."}, - {"get_peer_info", torrent_get_peer_info, METH_VARARGS, "."}, - {"get_file_info", torrent_get_file_info, METH_VARARGS, "."}, - {"set_filter_out", torrent_set_filter_out, METH_VARARGS, "."}, - {"constants", torrent_constants, METH_VARARGS, "."}, - {"start_DHT", torrent_start_DHT, METH_VARARGS, "."}, - {"stop_DHT", torrent_stop_DHT, METH_VARARGS, "."}, - {"get_DHT_info", torrent_get_DHT_info, METH_VARARGS, "."}, - {"create_torrent", torrent_create_torrent, METH_VARARGS, "."}, - {"reset_IP_filter", torrent_reset_IP_filter, METH_VARARGS, "."}, - {"add_range_to_IP_filter", torrent_add_range_to_IP_filter, METH_VARARGS, "."}, - {"use_upnp", torrent_use_upnp, METH_VARARGS, "."}, - {"use_natpmp", torrent_use_natpmp, METH_VARARGS, "."}, - {"use_utpex", torrent_use_utpex, METH_VARARGS, "."}, - {"set_ratio", torrent_set_ratio, METH_VARARGS, "."}, - {"proxy_settings", torrent_proxy_settings, METH_VARARGS, "."}, - {"get_trackers", torrent_get_trackers, METH_VARARGS, "."}, - {"replace_trackers", torrent_replace_trackers, METH_VARARGS, "."}, - {NULL} -}; - -PyMODINIT_FUNC -initdeluge_core(void) -{ - Py_InitModule("deluge_core", deluge_core_methods); -}; diff --git a/libtorrent/src/disk_io_thread.cpp b/libtorrent/src/disk_io_thread.cpp index 6bc357506..e07a884cf 100644 --- a/libtorrent/src/disk_io_thread.cpp +++ b/libtorrent/src/disk_io_thread.cpp @@ -179,29 +179,35 @@ namespace libtorrent int ret = 0; + bool free_buffer = true; try { // std::cerr << "DISK THREAD: executing job: " << j.action << std::endl; switch (j.action) { case disk_io_job::read: - l.lock(); - j.buffer = (char*)m_pool.ordered_malloc(); - l.unlock(); if (j.buffer == 0) { - ret = -1; - j.str = "out of memory"; + 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; + } } else { - 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); + free_buffer = false; } + ret = j.storage->read_impl(j.buffer, j.piece, j.offset + , j.buffer_size); + + // simulates slow drives + // usleep(300); break; case disk_io_job::write: assert(j.buffer); @@ -240,7 +246,7 @@ namespace libtorrent try { if (handler) handler(ret, j); } catch (std::exception&) {} - if (j.buffer) + if (j.buffer && free_buffer) { l.lock(); m_pool.ordered_free(j.buffer); diff --git a/libtorrent/src/enum_net.cpp b/libtorrent/src/enum_net.cpp new file mode 100644 index 000000000..54af814d6 --- /dev/null +++ b/libtorrent/src/enum_net.cpp @@ -0,0 +1,133 @@ +/* + +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) + { + ret.push_back(address::from_string( + inet_ntoa(((sockaddr_in const*)&item.ifr_addr)->sin_addr))); + } + +#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 02a4fa085..faff3de95 100755 --- a/libtorrent/src/escape_string.cpp +++ b/libtorrent/src/escape_string.cpp @@ -33,13 +33,14 @@ 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/http_connection.cpp b/libtorrent/src/http_connection.cpp index 53798cae1..2b306ca6d 100644 --- a/libtorrent/src/http_connection.cpp +++ b/libtorrent/src/http_connection.cpp @@ -42,6 +42,8 @@ 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) { @@ -165,6 +167,7 @@ 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)); } @@ -310,8 +313,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, 1024*500)); - if (m_read_pos == 1024 * 500) + m_recvbuffer.resize((std::min)(m_read_pos + 2048, int(max_bottled_buffer))); + if (m_read_pos == max_bottled_buffer) { close(); if (m_bottled && m_called) return; diff --git a/libtorrent/src/http_tracker_connection.cpp b/libtorrent/src/http_tracker_connection.cpp index 936f8292a..2a3c4449a 100755 --- a/libtorrent/src/http_tracker_connection.cpp +++ b/libtorrent/src/http_tracker_connection.cpp @@ -148,13 +148,19 @@ namespace libtorrent pos = newline; line >> m_protocol; - if (m_protocol.substr(0, 5) != "HTTP/") + if (m_protocol.substr(0, 5) == "HTTP/") { - 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); + } + 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; } - line >> m_status_code; - std::getline(line, m_server_message); m_state = read_header; } @@ -250,7 +256,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 @@ -408,7 +414,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")) @@ -459,14 +465,16 @@ namespace libtorrent m_send_buffer += "\r\n\r\n"; #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (has_requester()) + + boost::shared_ptr cb = requester(); + if (cb) { - requester().debug_log("==> TRACKER_REQUEST [ str: " + m_send_buffer + " ]"); + cb->debug_log("==> TRACKER_REQUEST [ str: " + m_send_buffer + " ]"); std::stringstream info_hash_str; info_hash_str << req.info_hash; - requester().debug_log("info_hash: " + cb->debug_log("info_hash: " + boost::lexical_cast(req.info_hash)); - requester().debug_log("name lookup: " + hostname); + cb->debug_log("name lookup: " + hostname); } #endif @@ -491,8 +499,9 @@ 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 (has_requester()) requester().debug_log("tracker name lookup handler called"); + if (cb) cb->debug_log("tracker name lookup handler called"); #endif if (error == asio::error::operation_aborted) return; if (m_timed_out) return; @@ -504,7 +513,7 @@ namespace libtorrent } #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (has_requester()) requester().debug_log("tracker name lookup successful"); + if (cb) cb->debug_log("tracker name lookup successful"); #endif restart_read_timeout(); @@ -519,11 +528,11 @@ namespace libtorrent if (target == end) { assert(target_address.address().is_v4() != bind_interface().is_v4()); - if (has_requester()) + if (cb) { std::string tracker_address_type = target_address.address().is_v4() ? "IPv4" : "IPv6"; std::string bind_address_type = bind_interface().is_v4() ? "IPv4" : "IPv6"; - requester().tracker_warning("the tracker only resolves to an " + cb->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."); } @@ -533,7 +542,7 @@ namespace libtorrent target_address = *target; } - if (has_requester()) requester().m_tracker_address = target_address; + if (cb) cb->m_tracker_address = target_address; m_socket = instantiate_connection(m_name_lookup.io_service(), m_proxy); if (m_proxy.type == proxy_settings::http @@ -574,7 +583,8 @@ namespace libtorrent } #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (has_requester()) requester().debug_log("tracker connection successful"); + boost::shared_ptr cb = requester(); + if (cb) cb->debug_log("tracker connection successful"); #endif restart_read_timeout(); @@ -598,7 +608,8 @@ namespace libtorrent } #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (has_requester()) requester().debug_log("tracker send data completed"); + boost::shared_ptr cb = requester(); + if (cb) cb->debug_log("tracker send data completed"); #endif restart_read_timeout(); assert(m_buffer.size() - m_recv_pos > 0); @@ -634,7 +645,8 @@ namespace libtorrent restart_read_timeout(); assert(bytes_transferred > 0); #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (has_requester()) requester().debug_log("tracker connection reading " + boost::shared_ptr cb = requester(); + if (cb) cb->debug_log("tracker connection reading " + boost::lexical_cast(bytes_transferred)); #endif @@ -700,6 +712,8 @@ 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) { @@ -720,9 +734,9 @@ namespace libtorrent } #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (has_requester()) requester().debug_log("Redirecting to \"" + location + "\""); + if (cb) cb->debug_log("Redirecting to \"" + location + "\""); #endif - if (has_requester()) requester().tracker_warning("Redirecting to \"" + location + "\""); + if (cb) cb->tracker_warning("Redirecting to \"" + location + "\""); tracker_request req = tracker_req(); req.url = location; @@ -745,20 +759,18 @@ namespace libtorrent std::string content_encoding = m_parser.header("content-encoding"); #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) - if (has_requester()) requester().debug_log("content-encoding: \"" + content_encoding + "\""); + if (cb) cb->debug_log("content-encoding: \"" + content_encoding + "\""); #endif if (content_encoding == "gzip" || content_encoding == "x-gzip") { - boost::shared_ptr r = m_requester.lock(); - - if (!r) + if (!cb) { close(); return; } m_buffer.erase(m_buffer.begin(), m_buffer.begin() + m_parser.body_start()); - if (inflate_gzip(m_buffer, tracker_request(), r.get(), + if (inflate_gzip(m_buffer, tracker_request(), cb.get(), m_settings.tracker_maximum_response_length)) { close(); @@ -835,7 +847,8 @@ namespace libtorrent void http_tracker_connection::parse(entry const& e) { - if (!has_requester()) return; + boost::shared_ptr cb = requester(); + if (!cb) return; try { @@ -852,8 +865,7 @@ namespace libtorrent try { entry const& warning = e["warning message"]; - if (has_requester()) - requester().tracker_warning(warning.string()); + cb->tracker_warning(warning.string()); } catch(type_error const&) {} @@ -867,7 +879,7 @@ namespace libtorrent entry scrape_data = e["files"][ih]; int complete = scrape_data["complete"].integer(); int incomplete = scrape_data["incomplete"].integer(); - requester().tracker_response(tracker_request(), peer_list, 0, complete + cb->tracker_response(tracker_request(), peer_list, 0, complete , incomplete); return; } @@ -884,12 +896,7 @@ namespace libtorrent peer_entry p; p.pid.clear(); - 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.ip = detail::read_v4_address(i).to_string(); p.port = detail::read_uint16(i); peer_list.push_back(p); } @@ -904,6 +911,22 @@ 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; @@ -914,18 +937,19 @@ namespace libtorrent try { incomplete = e["incomplete"].integer(); } catch(type_error&) {} - requester().tracker_response(tracker_request(), peer_list, interval, complete + cb->tracker_response(tracker_request(), peer_list, interval, complete , incomplete); } catch(type_error& e) { - requester().tracker_request_error(tracker_request(), m_parser.status_code(), e.what()); + cb->tracker_request_error(tracker_request(), m_parser.status_code(), e.what()); } catch(std::runtime_error& e) { - requester().tracker_request_error(tracker_request(), m_parser.status_code(), e.what()); + cb->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 26ddb51dc..7fa808f20 100755 --- a/libtorrent/src/identify_client.cpp +++ b/libtorrent/src/identify_client.cpp @@ -184,6 +184,7 @@ namespace , {"SB", "Swiftbit"} , {"SN", "ShareNet"} , {"SS", "SwarmScope"} + , {"ST", "SymTorrent"} , {"SZ", "Shareaza"} , {"S~", "Shareaza (beta)"} , {"T", "BitTornado"} @@ -194,12 +195,57 @@ 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) @@ -281,30 +327,13 @@ namespace libtorrent // non standard encodings // ---------------------- - 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"; + 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, "-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 0c7d9d276..a3849ed69 100644 --- a/libtorrent/src/kademlia/closest_nodes.cpp +++ b/libtorrent/src/kademlia/closest_nodes.cpp @@ -35,6 +35,7 @@ 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 eda6cd864..c9908a163 100644 --- a/libtorrent/src/kademlia/dht_tracker.cpp +++ b/libtorrent/src/kademlia/dht_tracker.cpp @@ -237,6 +237,7 @@ 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))); @@ -254,6 +255,7 @@ 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( @@ -276,8 +278,9 @@ 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, this, _1))); + m_timer.async_wait(m_strand.wrap(bind(&dht_tracker::tick, self(), _1))); ptime now = time_now(); if (now - m_last_new_key > minutes(key_refresh)) @@ -388,6 +391,7 @@ 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; @@ -716,6 +720,7 @@ 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&) @@ -734,6 +739,7 @@ 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 4ed413714..ad06c515d 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 76f25548d..d7590ec47 100644 --- a/libtorrent/src/lsd.cpp +++ b/libtorrent/src/lsd.cpp @@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/lsd.hpp" #include "libtorrent/io.hpp" #include "libtorrent/http_tracker_connection.hpp" + #include #include #include @@ -52,76 +53,22 @@ 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) + , m_socket(ios, udp::endpoint(address_v4::from_string("239.192.152.143"), 6771) + , bind(&lsd::on_announce, this, _1, _2, _3)) , 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; @@ -136,8 +83,7 @@ void lsd::announce(sha1_hash const& ih, int listen_port) m_retry_count = 0; asio::error_code ec; - m_socket.send_to(asio::buffer(msg.c_str(), msg.size() - 1) - , lsd_multicast_endpoint, 0, ec); + m_socket.send(msg.c_str(), int(msg.size()), ec); if (ec) { m_disabled = true; @@ -157,8 +103,8 @@ void lsd::resend_announce(asio::error_code const& e, std::string msg) try { if (e) return; - m_socket.send_to(asio::buffer(msg, msg.size() - 1) - , lsd_multicast_endpoint); + asio::error_code ec; + m_socket.send(msg.c_str(), int(msg.size()), ec); ++m_retry_count; if (m_retry_count >= 5) @@ -170,14 +116,13 @@ void lsd::resend_announce(asio::error_code const& e, std::string msg) try catch (std::exception&) {} -void lsd::on_announce(asio::error_code const& e +void lsd::on_announce(udp::endpoint const& from, char* buffer , std::size_t bytes_transferred) { using namespace libtorrent::detail; - if (e) return; - char* p = m_receive_buffer; - char* end = m_receive_buffer + bytes_transferred; + char* p = buffer; + char* end = 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) @@ -190,7 +135,6 @@ void lsd::on_announce(asio::error_code const& e m_log << time_now_string() << " *** assumed 'bt-search', ignoring" << std::endl; #endif - setup_receive(); return; } p = line + 1; @@ -223,25 +167,15 @@ void lsd::on_announce(asio::error_code const& e { #if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) m_log << time_now_string() - << " *** incoming local announce " << m_remote.address() + << " *** incoming local announce " << from.address() << ":" << port << " ih: " << ih << std::endl; #endif // we got an announce, pass it on through the callback - try { m_callback(tcp::endpoint(m_remote.address(), port), ih); } + try { m_callback(tcp::endpoint(from.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 97635cdb9..a19dd3d3f 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) { diff --git a/libtorrent/src/natpmp.cpp b/libtorrent/src/natpmp.cpp index 0a5932a56..bdcabce9a 100644 --- a/libtorrent/src/natpmp.cpp +++ b/libtorrent/src/natpmp.cpp @@ -32,11 +32,13 @@ 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 437c93e2c..981eca63d 100644 --- a/libtorrent/src/pe_crypto.cpp +++ b/libtorrent/src/pe_crypto.cpp @@ -32,13 +32,13 @@ POSSIBILITY OF SUCH DAMAGE. #ifndef TORRENT_DISABLE_ENCRYPTION -#include #include #include #include #include "libtorrent/pe_crypto.hpp" +#include "libtorrent/assert.hpp" namespace libtorrent { diff --git a/libtorrent/src/peer_connection.cpp b/libtorrent/src/peer_connection.cpp index b73e32896..ad2102f0d 100755 --- a/libtorrent/src/peer_connection.cpp +++ b/libtorrent/src/peer_connection.cpp @@ -51,6 +51,7 @@ 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; @@ -76,6 +77,8 @@ 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) @@ -93,6 +96,7 @@ 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) @@ -108,8 +112,8 @@ namespace libtorrent , m_prefer_whole_pieces(false) , m_request_large_blocks(false) , m_non_prioritized(false) - , m_upload_limit(resource_request::inf) - , m_download_limit(resource_request::inf) + , m_upload_limit(bandwidth_limit::inf) + , m_download_limit(bandwidth_limit::inf) , m_peer_info(peerinfo) , m_speed(slow) , m_connection_ticket(-1) @@ -153,6 +157,8 @@ 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) @@ -168,6 +174,7 @@ 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) @@ -183,10 +190,11 @@ namespace libtorrent , m_prefer_whole_pieces(false) , m_request_large_blocks(false) , m_non_prioritized(false) - , m_upload_limit(resource_request::inf) - , m_download_limit(resource_request::inf) + , m_upload_limit(bandwidth_limit::inf) + , m_download_limit(bandwidth_limit::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()) @@ -251,6 +259,67 @@ 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; @@ -260,7 +329,7 @@ namespace libtorrent assert(t->valid_metadata()); assert(t->ready_for_connections()); - m_have_piece.resize(t->torrent_file().num_pieces(), false); + m_have_piece.resize(t->torrent_file().num_pieces(), m_have_all); // now that we have a piece_picker, // update it with this peers pieces @@ -274,7 +343,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_seed()) + if (t->is_finished()) { throw std::runtime_error("seed to seed connection redundant, disconnecting"); } @@ -331,7 +400,12 @@ 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 @@ -378,8 +452,6 @@ namespace libtorrent void peer_connection::add_stat(size_type downloaded, size_type uploaded) { - INVARIANT_CHECK; - m_statistics.add_stat(downloaded, uploaded); } @@ -449,6 +521,7 @@ 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() @@ -456,35 +529,30 @@ namespace libtorrent && p.start >= 0 && (p.length == t->block_size() || (p.length < t->block_size() - && p.piece == t->torrent_file().num_pieces()-1 - && p.start + p.length == t->torrent_file().piece_size(p.piece)) + && p.piece == ti.num_pieces()-1 + && p.start + p.length == ti.piece_size(p.piece)) || (m_request_large_blocks - && p.length <= t->torrent_file().piece_size(p.piece))) - && p.start + p.length <= t->torrent_file().piece_size(p.piece) + && 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.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); - m_torrent = m_ses.find_torrent(ih); - - boost::shared_ptr t = m_torrent.lock(); + assert(m_torrent.expired()); + boost::weak_ptr wpt = m_ses.find_torrent(ih); + boost::shared_ptr t = wpt.lock(); if (t && t->is_aborted()) { - m_torrent.reset(); +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << " *** the torrent has been aborted\n"; +#endif t.reset(); } @@ -492,12 +560,18 @@ 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) << " *** 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"; + } #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 @@ -508,21 +582,27 @@ 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); - disconnect.cancel(); + assert(!m_torrent.expired()); } // message handlers @@ -588,6 +668,101 @@ 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); + + 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; + + 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 ---------- // ----------------------------- @@ -742,7 +917,7 @@ namespace libtorrent { assert(m_peer_info); m_peer_info->seed = true; - if (t->is_seed()) + if (t->is_finished()) { throw protocol_error("seed to seed connection redundant, disconnecting"); } @@ -798,11 +973,12 @@ namespace libtorrent { m_have_piece = bitfield; m_num_pieces = std::count(bitfield.begin(), bitfield.end(), true); - - if (m_peer_info) m_peer_info->seed = true; + if (m_peer_info) m_peer_info->seed = (m_num_pieces == int(bitfield.size())); return; } + assert(t->valid_metadata()); + int num_pieces = std::count(bitfield.begin(), bitfield.end(), true); if (num_pieces == int(m_have_piece.size())) { @@ -812,7 +988,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_seed()) + if (t->is_finished()) { throw protocol_error("seed to seed connection redundant, disconnecting"); } @@ -906,6 +1082,7 @@ namespace libtorrent "t: " << (int)t->torrent_file().piece_size(r.piece) << " | " "n: " << t->torrent_file().num_pieces() << " ]\n"; #endif + write_reject_request(r); return; } @@ -925,6 +1102,7 @@ namespace libtorrent "t: " << (int)t->torrent_file().piece_size(r.piece) << " | " "n: " << t->torrent_file().num_pieces() << " ]\n"; #endif + write_reject_request(r); return; } @@ -947,11 +1125,20 @@ namespace libtorrent #endif // if we have choked the client // ignore the request - if (m_choked) - return; - - m_requests.push_back(r); - fill_send_buffer(); + 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(); + } } else { @@ -968,6 +1155,7 @@ namespace libtorrent "block_limit: " << t->block_size() << " ]\n"; #endif + write_reject_request(r); ++m_num_invalid_requests; if (t->alerts().should_post(alert::debug)) @@ -977,7 +1165,7 @@ namespace libtorrent , t->get_handle() , m_remote , m_peer_id - , "peer sent an illegal piece request, ignoring")); + , "peer sent an illegal piece request")); } } } @@ -1131,11 +1319,8 @@ namespace libtorrent "request queue ***\n"; #endif t->received_redundant_data(p.length); - if (!has_peer_choked()) - { - request_a_block(*t, *this); - send_block_requests(); - } + request_a_block(*t, *this); + send_block_requests(); return; } @@ -1144,11 +1329,8 @@ namespace libtorrent { t->received_redundant_data(p.length); - if (!has_peer_choked()) - { - request_a_block(*t, *this); - send_block_requests(); - } + request_a_block(*t, *this); + send_block_requests(); return; } @@ -1205,15 +1387,11 @@ namespace libtorrent block_finished.block_index, block_finished.piece_index, "block finished")); } - if (!has_peer_choked() && !t->is_seed() && !m_torrent.expired()) + if (!t->is_seed() && !m_torrent.expired()) { // this is a free function defined in policy.cpp request_a_block(*t, *this); - try - { - send_block_requests(); - } - catch (std::exception const&) {} + send_block_requests(); } #ifndef NDEBUG @@ -1295,6 +1473,146 @@ 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; @@ -1308,10 +1626,11 @@ 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(); - std::string speedmsg; + char const* speedmsg = 0; if (speed == fast) { speedmsg = "fast"; @@ -1329,7 +1648,7 @@ namespace libtorrent } t->picker().mark_as_downloading(block, peer_info_struct(), state); - if (t->alerts().should_post(alert::info)) + 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")); @@ -1380,7 +1699,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()); @@ -1403,6 +1722,8 @@ namespace libtorrent { INVARIANT_CHECK; + assert(!m_peer_info || !m_peer_info->optimistically_unchoked); + if (m_choked) return; write_choke(); m_choked = true; @@ -1421,15 +1742,8 @@ 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; @@ -1470,13 +1784,9 @@ 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() @@ -1485,7 +1795,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()); @@ -1509,23 +1819,29 @@ namespace libtorrent // blocks that are in the same piece into larger requests if (m_request_large_blocks) { - while (!m_request_queue.empty() - && m_request_queue.front().piece_index == r.piece - && m_request_queue.front().block_index == block.block_index + 1) + int blocks_per_piece = t->torrent_file().piece_length() / t->block_size(); + + while (!m_request_queue.empty()) { + // 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() - << " *** REQUEST-QUEUE** [ " + << " *** MERGING REQUEST ** [ " "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()); @@ -1628,7 +1944,7 @@ namespace libtorrent void peer_connection::set_upload_limit(int limit) { assert(limit >= -1); - if (limit == -1) limit = resource_request::inf; + if (limit == -1) limit = (std::numeric_limits::max)(); if (limit < 10) limit = 10; m_upload_limit = limit; m_bandwidth_limit[upload_channel].throttle(m_upload_limit); @@ -1637,7 +1953,7 @@ namespace libtorrent void peer_connection::set_download_limit(int limit) { assert(limit >= -1); - if (limit == -1) limit = resource_request::inf; + if (limit == -1) limit = (std::numeric_limits::max)(); if (limit < 10) limit = 10; m_download_limit = limit; m_bandwidth_limit[download_channel].throttle(m_download_limit); @@ -1655,7 +1971,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) @@ -1703,8 +2019,9 @@ namespace libtorrent p.load_balancing = total_free_upload(); - p.download_queue_length = (int)download_queue().size(); - p.upload_queue_length = (int)upload_queue().size(); + 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()); if (boost::optional ret = downloading_piece_progress()) { @@ -1724,7 +2041,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; @@ -1737,6 +2054,7 @@ 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 @@ -1772,10 +2090,13 @@ namespace libtorrent if (m_packet_size >= m_recv_pos) m_recv_buffer.resize(m_packet_size); } - void peer_connection::second_tick(float tick_interval) + void peer_connection::second_tick(float tick_interval) throw() { INVARIANT_CHECK; + try + { + ptime now(time_now()); boost::shared_ptr t = m_torrent.lock(); @@ -1854,11 +2175,8 @@ namespace libtorrent m_assume_fifo = true; - if (!has_peer_choked()) - { - request_a_block(*t, *this); - send_block_requests(); - } + request_a_block(*t, *this); + send_block_requests(); } } @@ -1869,7 +2187,7 @@ namespace libtorrent // maintain the share ratio given by m_ratio // with all peers. - if (t->is_seed() || is_choked() || t->ratio() == 0.0f) + if (t->is_finished() || 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 @@ -1891,14 +2209,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)); } @@ -1917,43 +2235,14 @@ namespace libtorrent } fill_send_buffer(); -/* - 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()) - { - // 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 + catch (std::exception& e) { - 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; +#ifdef TORRENT_VERBOSE_LOGGING + (*m_logger) << "**ERROR**: " << e.what() << "\n"; +#endif + m_ses.connection_failed(m_socket, remote(), e.what()); } -*/ } void peer_connection::fill_send_buffer() @@ -1988,20 +2277,6 @@ 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(); - } -*/ } } @@ -2542,9 +2817,14 @@ 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) { @@ -2632,9 +2912,20 @@ 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 = time_now() - m_last_receive; + d = now - m_last_receive; if (d > seconds(m_timeout)) 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 ddc2c2f5a..8fa623fa3 100755 --- a/libtorrent/src/piece_picker.cpp +++ b/libtorrent/src/piece_picker.cpp @@ -167,6 +167,7 @@ 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; @@ -191,22 +192,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) + if (int(m_piece_info.size()) > old_limit * 2) { - info_t& in = m_piece_info[old_limit]; + info_t& in = m_piece_info[old_limit * 2]; 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); + assert(m_piece_map[*i].priority(old_limit) == old_limit * 2); } } } - else if (int(m_piece_info.size()) > sequenced_download_threshold) + else if (int(m_piece_info.size()) > sequenced_download_threshold * 2) { - info_t& in = m_piece_info[sequenced_download_threshold]; + info_t& in = m_piece_info[sequenced_download_threshold * 2]; std::sort(in.begin(), in.end()); int c = 0; for (info_t::iterator i = in.begin() @@ -214,7 +215,7 @@ namespace libtorrent { m_piece_map[*i].index = c++; assert(m_piece_map[*i].priority( - sequenced_download_threshold) == sequenced_download_threshold); + sequenced_download_threshold) == sequenced_download_threshold * 2); } } } @@ -262,8 +263,23 @@ 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); @@ -394,6 +410,7 @@ 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]; @@ -447,7 +464,7 @@ namespace libtorrent if (i->have()) ++peer_count; if (min_availability > peer_count) { - min_availability = i->peer_count; + min_availability = peer_count; fraction_part += integer_part; integer_part = 1; } @@ -638,12 +655,13 @@ 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() && j != m_downloads.begin(); --i, --j) + i != 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; } } @@ -739,6 +757,7 @@ 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 @@ -828,6 +847,8 @@ 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 @@ -879,6 +900,7 @@ 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++; @@ -913,6 +935,7 @@ 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); @@ -937,6 +960,7 @@ 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()); @@ -980,6 +1004,7 @@ 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 @@ -1003,6 +1028,7 @@ 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; @@ -1068,8 +1094,9 @@ namespace libtorrent // or slow once they're started. void piece_picker::pick_pieces(const std::vector& pieces , std::vector& interesting_blocks - , int num_blocks, bool prefer_whole_pieces - , void* peer, piece_state_t speed, bool rarest_first) const + , 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 { TORRENT_PIECE_PICKER_INVARIANT_CHECK; assert(num_blocks > 0); @@ -1085,59 +1112,84 @@ 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 - bool ignore_downloading_pieces = false; - if (prefer_whole_pieces) + + 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) { - 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) + // 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) { - downloading_pieces.push_back(i->index); + 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); } - add_interesting_blocks(downloading_pieces, pieces - , backup_blocks, backup_blocks, num_blocks - , prefer_whole_pieces, peer, speed, ignore_downloading_pieces); - ignore_downloading_pieces = true; } - - // 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) + else { - 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) { - 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) + while (!can_pick(piece, pieces)) { ++piece; if (piece == int(m_piece_map.size())) piece = 0; @@ -1145,27 +1197,44 @@ namespace libtorrent 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); + 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; } - if (num_blocks == 0) return; - break; + } - assert(num_blocks > 0); + if (num_blocks <= 0) return; 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 + { + 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() @@ -1203,17 +1272,12 @@ namespace libtorrent } } - int piece_picker::add_interesting_blocks(std::vector const& piece_list + int piece_picker::add_blocks(std::vector const& piece_list , std::vector const& 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 + , int num_blocks, int prefer_whole_pieces + , void* peer, std::vector const& ignore) 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) { @@ -1224,111 +1288,196 @@ 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); - if (m_piece_map[*i].downloading == 1) + 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 (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()); - - // 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(*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; - } - - for (int j = 0; j < num_blocks_in_piece; ++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; - } - else - { - if (!prefer_whole_pieces && num_blocks_in_piece > num_blocks) + 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 -= (std::min)(num_blocks_in_piece, num_blocks); + 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; } - assert(num_blocks >= 0); - if (num_blocks == 0) return num_blocks; } +#ifndef NDEBUG + verify_pick(interesting_blocks, pieces); +#endif return num_blocks; } + 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_finished + || info.state == block_info::state_writing + || info.state == block_info::state_requested) + 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; + + 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 { assert(index < (int)m_piece_map.size()); @@ -1414,11 +1563,14 @@ 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); @@ -1529,6 +1681,7 @@ 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); @@ -1650,9 +1803,12 @@ namespace libtorrent { erase_download_piece(i); piece_pos& p = m_piece_map[block.piece_index]; - int prio = p.priority(m_sequenced_download_threshold); + int prev_prio = p.priority(m_sequenced_download_threshold); + assert(prev_prio < int(m_piece_info.size())); p.downloading = 0; - if (prio > 0) move(prio, p.index); + 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); 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 572f48d35..6e81da0d5 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 { @@ -187,17 +187,19 @@ 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) { - assert(!t.is_seed()); - assert(!c.has_peer_choked()); + if (t.is_seed()) return; + + assert(t.valid_metadata()); 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 @@ -207,16 +209,15 @@ namespace libtorrent std::vector interesting_pieces; interesting_pieces.reserve(100); - bool prefer_whole_pieces = c.prefer_whole_pieces() - || (c.peer_info_struct() && c.peer_info_struct()->on_parole); + int prefer_whole_pieces = c.prefer_whole_pieces(); bool rarest_first = t.num_pieces() >= t.settings().initial_picker_threshold; - if (!prefer_whole_pieces) + if (prefer_whole_pieces == 0) { prefer_whole_pieces = c.statistics().download_payload_rate() * t.settings().whole_pieces_threshold - > t.torrent_file().piece_length(); + > t.torrent_file().piece_length() ? 1 : 0; } // if we prefer whole pieces, the piece picker will pick at least @@ -231,18 +232,6 @@ 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 @@ -251,14 +240,56 @@ 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; @@ -277,13 +308,13 @@ namespace libtorrent num_requests--; } - // 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) + 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. + c.send_block_requests(); return; } @@ -308,9 +339,8 @@ 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 @@ -352,7 +382,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. @@ -361,7 +391,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; @@ -434,13 +464,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(); @@ -483,7 +513,8 @@ namespace libtorrent policy::iterator policy::find_connect_candidate() { - INVARIANT_CHECK; +// too expensive +// INVARIANT_CHECK; ptime now = time_now(); ptime min_connect_time(now); @@ -491,6 +522,7 @@ 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(); @@ -499,7 +531,7 @@ namespace libtorrent if (i->connection) continue; if (i->banned) continue; if (i->type == peer::not_connectable) continue; - if (i->seed && m_torrent->is_seed()) continue; + if (i->seed && finished) continue; if (i->failcount >= max_failcount) continue; if (now - i->connected < seconds(i->failcount * min_reconnect_time)) continue; @@ -519,7 +551,7 @@ namespace libtorrent return candidate; } - +/* policy::iterator policy::find_seed_choke_candidate() { INVARIANT_CHECK; @@ -625,7 +657,7 @@ namespace libtorrent --m_num_unchoked; } } - +*/ void policy::pulse() { INVARIANT_CHECK; @@ -657,7 +689,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; @@ -669,10 +701,9 @@ namespace libtorrent ++num_connected_peers; } - if (m_torrent->m_connections_quota.given != std::numeric_limits::max()) + if (m_torrent->max_connections() != (std::numeric_limits::max)()) { - - int max_connections = m_torrent->m_connections_quota.given; + int max_connections = m_torrent->max_connections(); if (num_connected_peers >= max_connections) { @@ -700,7 +731,7 @@ namespace libtorrent --num_connected_peers; } } - +*/ // ------------------------ // upload shift // ------------------------ @@ -731,7 +762,7 @@ namespace libtorrent , m_torrent->end() , m_available_free_upload); } - +/* // ------------------------ // seed choking policy // ------------------------ @@ -847,6 +878,7 @@ namespace libtorrent while (m_num_unchoked < m_torrent->m_uploads_quota.given && unchoke_one_peer()); } +*/ } int policy::count_choked() const @@ -879,7 +911,8 @@ namespace libtorrent // override at a time assert(c.remote() == c.get_socket()->remote_endpoint()); - if (m_torrent->num_peers() >= m_torrent->m_connections_quota.given + if (m_torrent->num_peers() >= m_torrent->max_connections() + && m_torrent->session().num_connections() >= m_torrent->session().max_connections() && c.remote().address() != m_torrent->current_tracker().address()) { throw protocol_error("too many connections, refusing incoming connection"); // cause a disconnect @@ -961,16 +994,17 @@ 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) { - INVARIANT_CHECK; +// too expensive +// 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(); @@ -1056,7 +1090,10 @@ namespace libtorrent if (i->failcount > 0 && src != peer_info::dht) --i->failcount; - if (flags & 0x02) i->seed = true; + // 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 (i->connection) { @@ -1146,14 +1183,38 @@ 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_num_unchoked < m_torrent->m_uploads_quota.given + && m_torrent->session().num_uploads() < m_torrent->session().max_uploads() && (m_torrent->ratio() == 0 || c.share_diff() >= -free_upload_amount - || m_torrent->is_seed())) + || m_torrent->is_finished())) { - c.send_unchoke(); - ++m_num_unchoked; + m_torrent->session().unchoke_peer(c); } +#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 @@ -1163,7 +1224,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()) { @@ -1185,7 +1246,7 @@ namespace libtorrent } */ } - +/* bool policy::unchoke_one_peer() { INVARIANT_CHECK; @@ -1214,7 +1275,7 @@ namespace libtorrent p->connection->send_choke(); --m_num_unchoked; } - +*/ bool policy::connect_one_peer() { INVARIANT_CHECK; @@ -1230,7 +1291,7 @@ namespace libtorrent try { - p->connected = m_last_optimistic_disconnect = time_now(); + p->connected = time_now(); p->connection = m_torrent->connect_to_peer(&*p); if (p->connection == 0) return false; p->connection->add_stat(p->prev_amount_download, p->prev_amount_upload); @@ -1263,33 +1324,33 @@ namespace libtorrent } // this is called whenever a peer connection is closed - void policy::connection_closed(const peer_connection& c) try + void policy::connection_closed(const peer_connection& c) throw() { - INVARIANT_CHECK; +// too expensive +// INVARIANT_CHECK; -// assert(c.is_disconnecting()); - bool unchoked = false; + peer* p = c.peer_info_struct(); - iterator i = std::find_if( + assert((std::find_if( m_peers.begin() , m_peers.end() - , match_peer_connection(c)); - + , match_peer_connection(c)) + != m_peers.end()) == (p != 0)); + // if we couldn't find the connection in our list, just ignore it. - if (i == m_peers.end()) return; - assert(i->connection == &c); - i->connection = 0; + if (p == 0) return; - i->connected = time_now(); - if (!c.is_choked() && !m_torrent->is_aborted()) - { - unchoked = true; - } + assert(p->connection == &c); + + p->connection = 0; + p->optimistically_unchoked = false; + + p->connected = time_now(); if (c.failed()) { - ++i->failcount; -// i->connected = time_now(); + ++p->failcount; +// p->connected = time_now(); } // if the share ratio is 0 (infinite), the @@ -1298,28 +1359,11 @@ 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(); } - 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); + p->prev_amount_download += c.statistics().total_payload_download(); + p->prev_amount_upload += c.statistics().total_payload_upload(); } void policy::peer_is_interesting(peer_connection& c) @@ -1327,17 +1371,21 @@ namespace libtorrent INVARIANT_CHECK; c.send_interested(); - if (c.has_peer_choked()) return; + if (c.has_peer_choked() + && c.allowed_fast().empty()) + return; request_a_block(*m_torrent, c); } #ifndef NDEBUG bool policy::has_connection(const peer_connection* c) { - INVARIANT_CHECK; +// too expensive +// INVARIANT_CHECK; assert(c); - assert(c->remote() == c->get_socket()->remote_endpoint()); + try { assert(c->remote() == c->get_socket()->remote_endpoint()); } + catch (std::exception&) {} return std::find_if( m_peers.begin() @@ -1348,12 +1396,11 @@ 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; for (const_iterator i = m_peers.begin(); i != m_peers.end(); ++i) @@ -1372,15 +1419,17 @@ 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(); @@ -1447,6 +1496,7 @@ 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 485c90d62..1d7a070c2 100755 --- a/libtorrent/src/session.cpp +++ b/libtorrent/src/session.cpp @@ -68,7 +68,6 @@ 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" @@ -180,11 +179,26 @@ namespace libtorrent , fs::path const& save_path , entry const& resume_data , bool compact_mode - , int block_size + , bool paused , 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); + } + + 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) + { + assert(!ti->m_half_metadata); return m_impl->add_torrent(ti, save_path, resume_data - , compact_mode, block_size, sc); + , compact_mode, sc, paused); } torrent_handle session::add_torrent( @@ -194,11 +208,11 @@ namespace libtorrent , fs::path const& save_path , entry const& e , bool compact_mode - , int block_size + , bool paused , storage_constructor_type sc) { return m_impl->add_torrent(tracker_url, info_hash, name, save_path, e - , compact_mode, block_size, sc); + , compact_mode, sc, paused); } void session::remove_torrent(const torrent_handle& h) @@ -337,6 +351,11 @@ 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 81f48a3ce..0aeb84bbe 100755 --- a/libtorrent/src/session_impl.cpp +++ b/libtorrent/src/session_impl.cpp @@ -68,7 +68,6 @@ 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" @@ -223,6 +222,12 @@ 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( @@ -345,6 +350,12 @@ 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)) { @@ -505,8 +516,12 @@ 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(-1) - , m_max_connections(-1) + , 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_incoming_connection(false) , m_last_tick(time_now()) #ifndef TORRENT_DISABLE_DHT @@ -517,6 +532,11 @@ 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; @@ -609,6 +629,9 @@ 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 @@ -621,6 +644,9 @@ 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); @@ -640,22 +666,25 @@ namespace detail try { // create listener socket - m_listen_socket = boost::shared_ptr(new socket_acceptor(m_io_service)); + m_listen_socket.reset(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) + if (e.code() == asio::error::host_not_found + || m_listen_interface.port() == 0) { if (m_alerts.should_post(alert::fatal)) { @@ -700,14 +729,18 @@ 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 - if (m_listen_socket) async_accept(); + 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); + } } void session_impl::async_accept() @@ -733,7 +766,6 @@ namespace detail if (m_abort) return; - async_accept(); if (e) { #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) @@ -742,8 +774,12 @@ 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; @@ -765,8 +801,30 @@ 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 @@ -787,6 +845,9 @@ namespace detail #endif { mutex_t::scoped_lock l(m_mutex); + +// too expensive +// INVARIANT_CHECK; connection_map::iterator p = m_connections.find(s); @@ -818,10 +879,16 @@ 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) @@ -840,6 +907,8 @@ namespace detail { session_impl::mutex_t::scoped_lock l(m_mutex); + INVARIANT_CHECK; + if (e) { #if defined(TORRENT_LOGGING) @@ -901,7 +970,9 @@ 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()) + if (!m_torrents.empty() + && m_half_open.free_slots() + && num_connections() < m_max_connections) { // this is the maximum number of connections we will // attempt this tick @@ -918,11 +989,13 @@ 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; @@ -940,6 +1013,8 @@ 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; } } @@ -976,18 +1051,7 @@ namespace detail continue; } - 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(); - } + c.keep_alive(); } // check each torrent for tracker updates @@ -1019,30 +1083,183 @@ namespace detail } m_stat.second_tick(tick_interval); - // distribute the maximum upload rate among the torrents - 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) + // -------------------------------------------------------------- + // unchoke set and optimistic unchoke calculations + // -------------------------------------------------------------- + m_unchoke_time_scaler--; + if (m_unchoke_time_scaler <= 0 && !m_connections.empty()) { -#ifndef NDEBUG - i->second->check_invariant(); -#endif - i->second->distribute_resources(tick_interval); + 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(); + } } } catch (std::exception& exc) @@ -1052,29 +1269,7 @@ 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(); @@ -1083,10 +1278,6 @@ 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(); @@ -1156,6 +1347,9 @@ namespace detail } } + // close listen socket + m_listen_socket.reset(); + ptime start(time_now()); l.unlock(); @@ -1275,47 +1469,36 @@ namespace detail } torrent_handle session_impl::add_torrent( - torrent_info const& ti + boost::intrusive_ptr ti , fs::path const& save_path , entry const& resume_data , bool compact_mode - , int block_size - , storage_constructor_type sc) + , storage_constructor_type sc + , bool paused) { // 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 @@ -1323,8 +1506,8 @@ namespace detail // the thread boost::shared_ptr torrent_ptr( new torrent(*this, m_checker_impl, ti, save_path - , m_listen_interface, compact_mode, block_size - , settings(), sc)); + , m_listen_interface, compact_mode, 16 * 1024 + , sc, paused)); torrent_ptr->start(); #ifndef TORRENT_DISABLE_EXTENSIONS @@ -1340,13 +1523,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 @@ -1360,7 +1543,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( @@ -1370,20 +1553,9 @@ namespace detail , fs::path const& save_path , entry const& , bool compact_mode - , int block_size - , storage_constructor_type sc) + , storage_constructor_type sc + , bool paused) { - // 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()); @@ -1399,6 +1571,8 @@ 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(); @@ -1411,8 +1585,8 @@ 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, block_size - , settings(), sc)); + , save_path, m_listen_interface, compact_mode, 16 * 1024 + , sc, paused)); torrent_ptr->start(); #ifndef TORRENT_DISABLE_EXTENSIONS @@ -1437,6 +1611,9 @@ 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()) @@ -1499,6 +1676,8 @@ 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); @@ -1522,21 +1701,6 @@ 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) { @@ -1578,6 +1742,8 @@ 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 @@ -1632,6 +1798,9 @@ 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(); @@ -1673,6 +1842,9 @@ 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(); @@ -1832,6 +2004,10 @@ 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; } @@ -1839,6 +2015,10 @@ 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; } @@ -1846,7 +2026,10 @@ 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); } @@ -1854,7 +2037,10 @@ namespace detail { assert(bytes_per_second > 0 || bytes_per_second == -1); mutex_t::scoped_lock l(m_mutex); - if (bytes_per_second == -1) bytes_per_second = bandwidth_limit::inf; + + INVARIANT_CHECK; + + if (bytes_per_second <= 0) bytes_per_second = bandwidth_limit::inf; m_bandwidth_manager[peer_connection::download_channel]->throttle(bytes_per_second); } @@ -1862,31 +2048,20 @@ namespace detail { assert(bytes_per_second > 0 || bytes_per_second == -1); mutex_t::scoped_lock l(m_mutex); - if (bytes_per_second == -1) bytes_per_second = bandwidth_limit::inf; + + INVARIANT_CHECK; + + if (bytes_per_second <= 0) 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); @@ -1901,20 +2076,26 @@ 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))); @@ -1923,6 +2104,9 @@ 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 @@ -1938,6 +2122,9 @@ 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 @@ -1975,20 +2162,35 @@ namespace detail #ifndef NDEBUG - void session_impl::check_invariant(const char *place) + void session_impl::check_invariant() const { - assert(place); - for (connection_map::iterator i = m_connections.begin(); + 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(); i != m_connections.end(); ++i) { assert(i->second); boost::shared_ptr t = i->second->associated_torrent().lock(); - if (t) + 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()) { 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 @@ -2101,7 +2303,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()) + ")"; @@ -2110,7 +2312,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 b1679c4ac..a6b5544e4 100644 --- a/libtorrent/src/socks5_stream.cpp +++ b/libtorrent/src/socks5_stream.cpp @@ -33,6 +33,7 @@ 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 b23a2e858..e1ddd20ae 100755 --- a/libtorrent/src/storage.cpp +++ b/libtorrent/src/storage.cpp @@ -88,6 +88,12 @@ POSSIBILITY OF SUCH DAMAGE. #include #endif +#if defined(__FreeBSD__) +// for statfs() +#include +#include +#endif + #if defined(_WIN32) && defined(UNICODE) #include @@ -247,8 +253,8 @@ namespace libtorrent { p = complete(p); std::vector > sizes; - for (torrent_info::file_iterator i = t.begin_files(); - i != t.end_files(); ++i) + for (torrent_info::file_iterator i = t.begin_files(true); + i != t.end_files(true); ++i) { size_type size = 0; std::time_t time = 0; @@ -287,7 +293,7 @@ namespace libtorrent , bool compact_mode , std::string* error) { - if ((int)sizes.size() != t.num_files()) + if ((int)sizes.size() != t.num_files(true)) { if (error) *error = "mismatching number of files"; return false; @@ -296,8 +302,8 @@ namespace libtorrent std::vector >::const_iterator s = sizes.begin(); - for (torrent_info::file_iterator i = t.begin_files(); - i != t.end_files(); ++i, ++s) + for (torrent_info::file_iterator i = t.begin_files(true); + i != t.end_files(true); ++i, ++s) { size_type size = 0; std::time_t time = 0; @@ -342,50 +348,14 @@ namespace libtorrent return true; } - 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 + class storage : public storage_interface, boost::noncopyable { public: - storage(torrent_info const& info, fs::path const& path, file_pool& fp) - : thread_safe_storage(info.num_pieces()) - , m_info(info) + storage(boost::intrusive_ptr info, fs::path const& path, file_pool& fp) + : m_info(info) , m_files(fp) { - assert(info.begin_files() != info.end_files()); + assert(info->begin_files(true) != info->end_files(true)); m_save_path = fs::complete(path); assert(m_save_path.is_complete()); } @@ -405,11 +375,9 @@ 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); } - torrent_info const& m_info; + boost::intrusive_ptr m_info; fs::path m_save_path; // the file pool is typically stored in // the session, to make all storage @@ -448,8 +416,8 @@ namespace libtorrent { // first, create all missing directories fs::path last_path; - for (torrent_info::file_iterator file_iter = m_info.begin_files(), - end_iter = m_info.end_files(); file_iter != end_iter; ++file_iter) + 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) { fs::path dir = (m_save_path / file_iter->path).branch_path(); @@ -497,7 +465,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(); @@ -531,7 +499,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) @@ -546,11 +514,11 @@ namespace libtorrent if (seed) { - if (m_info.num_files() != (int)file_sizes.size()) + if (m_info->num_files(true) != (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()) + ")"; + + boost::lexical_cast(m_info->num_files(true)) + ")"; return false; } @@ -558,8 +526,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() - , end(m_info.end_files()); i != end; ++i, ++fs) + for (torrent_info::file_iterator i = m_info->begin_files(true) + , end(m_info->end_files(true)); i != end; ++i, ++fs) { if (i->size != fs->first) { @@ -572,7 +540,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); } @@ -611,11 +579,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 @@ -637,7 +605,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(); @@ -654,7 +622,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); @@ -665,7 +633,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); @@ -674,9 +642,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); @@ -687,10 +655,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); @@ -717,27 +685,25 @@ 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); + = m_info->map_block(slot, offset, size, true); 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();;) + for (file_iter = m_info->begin_files(true);;) { if (file_offset < file_iter->size) break; @@ -770,7 +736,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; @@ -795,7 +761,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).path + assert(m_info->file_at(slices[counter].file_index, true).path == file_iter->path); #endif @@ -845,32 +811,30 @@ 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); + = m_info->map_block(slot, offset, size, true); 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();;) + for (file_iter = m_info->begin_files(true);;) { if (file_offset < file_iter->size) break; file_offset -= file_iter->size; ++file_iter; - assert(file_iter != m_info.end_files()); + assert(file_iter != m_info->end_files(true)); } fs::path p(m_save_path / file_iter->path); @@ -890,7 +854,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; @@ -914,7 +878,7 @@ namespace libtorrent { assert(int(slices.size()) > counter); assert(slices[counter].size == write_bytes); - assert(m_info.file_at(slices[counter].file_index).path + assert(m_info->file_at(slices[counter].file_index, true).path == file_iter->path); assert(buf_pos >= 0); @@ -942,7 +906,7 @@ namespace libtorrent #endif ++file_iter; - assert(file_iter != m_info.end_files()); + assert(file_iter != m_info->end_files(true)); fs::path p = m_save_path / file_iter->path; file_offset = 0; out = m_files.open_file( @@ -953,7 +917,7 @@ namespace libtorrent } } - storage_interface* default_storage_constructor(torrent_info const& ti + storage_interface* default_storage_constructor(boost::intrusive_ptr ti , fs::path const& path, file_pool& fp) { return new storage(ti, path, fp); @@ -1067,7 +1031,7 @@ namespace libtorrent piece_manager::piece_manager( boost::shared_ptr const& torrent - , torrent_info const& ti + , boost::intrusive_ptr ti , fs::path const& save_path , file_pool& fp , disk_io_thread& io @@ -1077,7 +1041,7 @@ namespace libtorrent , m_fill_mode(true) , m_info(ti) , m_save_path(complete(save_path)) - , m_allocating(false) + , m_storage_constructor(sc) , m_io_thread(io) , m_torrent(torrent) { @@ -1119,7 +1083,8 @@ namespace libtorrent void piece_manager::async_read( peer_request const& r - , boost::function const& handler) + , boost::function const& handler + , char* buffer) { disk_io_job j; j.storage = this; @@ -1127,7 +1092,10 @@ namespace libtorrent j.piece = r.piece; j.offset = r.start; j.buffer_size = r.length; - assert(r.length <= 16 * 1024); + j.buffer = buffer; + // 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); m_io_thread.add_job(j, handler); } @@ -1180,7 +1148,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() @@ -1240,7 +1208,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]; } @@ -1251,13 +1219,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) @@ -1350,11 +1318,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); @@ -1510,7 +1478,7 @@ namespace libtorrent INVARIANT_CHECK; - assert(m_info.piece_length() > 0); + assert(m_info->piece_length() > 0); m_compact_mode = compact_mode; @@ -1520,13 +1488,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 @@ -1631,7 +1599,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 @@ -1673,8 +1641,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; } @@ -1694,15 +1662,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); @@ -1905,9 +1873,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(); - i != m_info.end_files(); ++i) + 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) { file_offset += i->size; if (file_offset > current_offset) break; @@ -1915,8 +1883,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) { @@ -1929,9 +1897,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); @@ -1943,7 +1911,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) @@ -1985,7 +1953,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); @@ -2090,13 +2058,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; } @@ -2116,8 +2084,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) @@ -2139,7 +2107,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) @@ -2227,7 +2195,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 13309c1e7..ddf8a9164 100755 --- a/libtorrent/src/torrent.cpp +++ b/libtorrent/src/torrent.cpp @@ -72,6 +72,7 @@ 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; @@ -150,16 +151,16 @@ namespace libtorrent torrent::torrent( session_impl& ses , aux::checker_impl& checker - , torrent_info const& tf + , boost::intrusive_ptr tf , fs::path const& save_path , tcp::endpoint const& net_interface , bool compact_mode , int block_size - , session_settings const& s - , storage_constructor_type sc) + , storage_constructor_type sc + , bool paused) : m_torrent_file(tf) , m_abort(false) - , m_paused(false) + , m_paused(paused) , m_just_paused(false) , m_event(tracker_request::started) , m_block_size(0) @@ -181,7 +182,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) @@ -197,24 +198,15 @@ namespace libtorrent , m_compact_mode(compact_mode) , m_default_block_size(block_size) , m_connections_initialized(true) - , m_settings(s) + , m_settings(ses.settings()) , 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 @@ -225,11 +217,11 @@ namespace libtorrent , tcp::endpoint const& net_interface , bool compact_mode , int block_size - , session_settings const& s - , storage_constructor_type sc) - : m_torrent_file(info_hash) + , storage_constructor_type sc + , bool paused) + : m_torrent_file(new torrent_info(info_hash)) , m_abort(false) - , m_paused(false) + , m_paused(paused) , m_just_paused(false) , m_event(tracker_request::started) , m_block_size(0) @@ -266,28 +258,20 @@ namespace libtorrent , m_compact_mode(compact_mode) , m_default_block_size(block_size) , m_connections_initialized(false) - , m_settings(s) + , m_settings(ses.settings()) , 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)); @@ -296,7 +280,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))); @@ -306,7 +290,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; @@ -329,6 +313,14 @@ 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(); @@ -336,7 +328,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 ""; } @@ -352,22 +344,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())); } @@ -395,7 +387,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)); @@ -403,7 +395,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 { @@ -421,7 +413,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))); } @@ -467,7 +459,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) { @@ -617,7 +609,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(); } @@ -627,23 +619,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; @@ -656,42 +648,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) @@ -724,15 +716,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) @@ -762,10 +754,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 @@ -781,7 +773,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, " ")); @@ -812,8 +804,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 @@ -910,14 +902,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)) { @@ -926,7 +918,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); @@ -1020,6 +1012,15 @@ 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; @@ -1040,7 +1041,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); @@ -1083,7 +1084,7 @@ namespace libtorrent if (is_seed()) { m_picker.reset(); - m_torrent_file.seed_free(); + m_torrent_file->seed_free(); } } @@ -1117,7 +1118,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(); @@ -1133,7 +1134,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); } @@ -1169,7 +1170,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; } @@ -1194,20 +1195,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 @@ -1243,7 +1244,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(); @@ -1280,7 +1281,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; } @@ -1294,7 +1295,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; } @@ -1311,20 +1312,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]) { @@ -1359,7 +1360,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(); @@ -1383,6 +1384,27 @@ 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() @@ -1394,7 +1416,7 @@ namespace libtorrent void torrent::remove_peer(peer_connection* p) try { - INVARIANT_CHECK; +// INVARIANT_CHECK; assert(p != 0); @@ -1433,6 +1455,9 @@ namespace libtorrent } } + if (!p->is_choked()) + --m_num_uploads; + m_policy->connection_closed(*p); p->set_peer_info(0); m_connections.erase(i); @@ -1807,6 +1832,7 @@ 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 +1884,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(); @@ -1869,12 +1895,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 @@ -1890,7 +1916,7 @@ namespace libtorrent void torrent::attach_peer(peer_connection* p) { - INVARIANT_CHECK; +// INVARIANT_CHECK; assert(p != 0); assert(!p->is_local()); @@ -1955,7 +1981,7 @@ namespace libtorrent bool torrent::want_more_peers() const { - return int(m_connections.size()) < m_connections_quota.given + return int(m_connections.size()) < m_max_connections && m_ses.m_half_open.free_slots() && !m_paused; } @@ -1994,7 +2020,9 @@ 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) { @@ -2122,7 +2150,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; @@ -2181,14 +2209,12 @@ 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()); @@ -2216,9 +2242,6 @@ namespace libtorrent pause(); } -#ifndef NDEBUG - m_initial_done = boost::get<0>(bytes_done()); -#endif return progress; } @@ -2227,6 +2250,7 @@ namespace libtorrent { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); + assert(m_torrent_file->is_valid()); INVARIANT_CHECK; if (!is_seed()) @@ -2257,7 +2281,7 @@ namespace libtorrent if (is_seed()) { m_picker.reset(); - m_torrent_file.seed_free(); + m_torrent_file->seed_free(); } if (!m_connections_initialized) @@ -2286,9 +2310,6 @@ namespace libtorrent } } } -#ifndef NDEBUG - m_initial_done = boost::get<0>(bytes_done()); -#endif } alert_manager& torrent::alerts() const @@ -2340,7 +2361,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 @@ -2351,9 +2372,7 @@ namespace libtorrent #ifndef NDEBUG void torrent::check_invariant() const { -// size_type download = m_stat.total_payload_download(); -// size_type done = boost::get<0>(bytes_done()); -// assert(download >= done - m_initial_done); + int num_uploads = 0; std::map num_requests; for (const_peer_iterator i = begin(); i != end(); ++i) { @@ -2364,10 +2383,12 @@ 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()) { @@ -2380,7 +2401,7 @@ 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 { @@ -2388,12 +2409,12 @@ namespace libtorrent } 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 { @@ -2404,7 +2425,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 @@ -2425,15 +2446,15 @@ namespace libtorrent void torrent::set_max_uploads(int limit) { assert(limit >= -1); - if (limit == -1) limit = std::numeric_limits::max(); - m_uploads_quota.max = std::max(m_uploads_quota.min, limit); + if (limit <= 0) limit = (std::numeric_limits::max)(); + m_max_uploads = limit; } void torrent::set_max_connections(int limit) { assert(limit >= -1); - if (limit == -1) limit = std::numeric_limits::max(); - m_connections_quota.max = std::max(m_connections_quota.min, limit); + if (limit <= 0) limit = (std::numeric_limits::max)(); + m_max_connections = limit; } void torrent::set_peer_upload_limit(tcp::endpoint ip, int limit) @@ -2455,7 +2476,7 @@ namespace libtorrent void torrent::set_upload_limit(int limit) { assert(limit >= -1); - if (limit == -1) limit = std::numeric_limits::max(); + if (limit <= 0) limit = (std::numeric_limits::max)(); if (limit < num_peers() * 10) limit = num_peers() * 10; m_bandwidth_limit[peer_connection::upload_channel].throttle(limit); } @@ -2463,14 +2484,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 == -1) limit = std::numeric_limits::max(); + if (limit <= 0) limit = (std::numeric_limits::max)(); if (limit < num_peers() * 10) limit = num_peers() * 10; m_bandwidth_limit[peer_connection::download_channel].throttle(limit); } @@ -2478,7 +2499,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; } @@ -2496,6 +2517,14 @@ 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 @@ -2528,10 +2557,6 @@ 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; @@ -2545,10 +2570,6 @@ 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) @@ -2561,10 +2582,6 @@ 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; } @@ -2623,6 +2640,13 @@ 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() @@ -2631,18 +2655,6 @@ 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; @@ -2650,7 +2662,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 @@ -2662,7 +2674,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 @@ -2678,12 +2690,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 @@ -2696,7 +2708,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; @@ -2705,7 +2717,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; } } @@ -2764,10 +2776,10 @@ namespace libtorrent = m_trackers[m_last_working_tracker].url; } - 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; + 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; // if we don't have any metadata, stop here if (!valid_metadata()) @@ -2780,7 +2792,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; @@ -2792,21 +2804,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); @@ -2824,7 +2836,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 4538e66e8..3cf1f2bac 100755 --- a/libtorrent/src/torrent_handle.cpp +++ b/libtorrent/src/torrent_handle.cpp @@ -89,26 +89,22 @@ namespace libtorrent throw invalid_handle(); } - template - Ret call_member( + boost::shared_ptr find_torrent( session_impl* ses , aux::checker_impl* chk - , sha1_hash const& hash - , F f) + , sha1_hash const& hash) { if (ses == 0) throw_invalid_handle(); 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); + if (d != 0) return 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); + if (t) return t; } // throwing directly instead of calling @@ -133,16 +129,18 @@ namespace libtorrent assert(max_uploads >= 2 || max_uploads == -1); - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::set_max_uploads, _1, max_uploads)); + 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); } void torrent_handle::use_interface(const char* net_interface) const { INVARIANT_CHECK; - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::use_interface, _1, net_interface)); + 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); } void torrent_handle::set_max_connections(int max_connections) const @@ -151,8 +149,9 @@ namespace libtorrent assert(max_connections >= 2 || max_connections == -1); - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::set_max_connections, _1, max_connections)); + 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); } void torrent_handle::set_peer_upload_limit(tcp::endpoint ip, int limit) const @@ -160,8 +159,9 @@ namespace libtorrent INVARIANT_CHECK; assert(limit >= -1); - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::set_peer_upload_limit, _1, ip, limit)); + 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); } void torrent_handle::set_peer_download_limit(tcp::endpoint ip, int limit) const @@ -169,8 +169,9 @@ namespace libtorrent INVARIANT_CHECK; assert(limit >= -1); - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::set_peer_download_limit, _1, ip, limit)); + 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); } void torrent_handle::set_upload_limit(int limit) const @@ -179,15 +180,17 @@ namespace libtorrent assert(limit >= -1); - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::set_upload_limit, _1, limit)); + 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); } int torrent_handle::upload_limit() const { INVARIANT_CHECK; - return call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::upload_limit, _1)); + 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(); } void torrent_handle::set_download_limit(int limit) const @@ -196,15 +199,18 @@ namespace libtorrent assert(limit >= -1); - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::set_download_limit, _1, limit)); + 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); } int torrent_handle::download_limit() const { INVARIANT_CHECK; - return call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::download_limit, _1)); + + 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(); } void torrent_handle::move_storage( @@ -212,48 +218,54 @@ namespace libtorrent { INVARIANT_CHECK; - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::move_storage, _1, save_path)); + 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); } bool torrent_handle::has_metadata() const { INVARIANT_CHECK; - return call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::valid_metadata, _1)); + 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(); } bool torrent_handle::is_seed() const { INVARIANT_CHECK; - return call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::is_seed, _1)); + 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(); } bool torrent_handle::is_paused() const { INVARIANT_CHECK; - return call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::is_paused, _1)); + 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(); } void torrent_handle::pause() const { INVARIANT_CHECK; - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::pause, _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)->pause(); } void torrent_handle::resume() const { INVARIANT_CHECK; - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::resume, _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)->resume(); } void torrent_handle::set_tracker_login(std::string const& name @@ -261,8 +273,9 @@ namespace libtorrent { INVARIANT_CHECK; - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::set_tracker_login, _1, name, password)); + 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); } void torrent_handle::file_progress(std::vector& progress) @@ -342,15 +355,18 @@ namespace libtorrent void torrent_handle::set_sequenced_download_threshold(int threshold) const { INVARIANT_CHECK; - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::set_sequenced_download_threshold, _1, threshold)); + 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); } std::string torrent_handle::name() const { INVARIANT_CHECK; - return call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::name, _1)); + + 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(); } @@ -358,40 +374,45 @@ namespace libtorrent { INVARIANT_CHECK; - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::piece_availability, _1, boost::ref(avail))); + 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); } void torrent_handle::piece_priority(int index, int priority) const { INVARIANT_CHECK; - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::set_piece_priority, _1, index, priority)); + 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); } int torrent_handle::piece_priority(int index) const { INVARIANT_CHECK; - return call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::piece_priority, _1, index)); + 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); } void torrent_handle::prioritize_pieces(std::vector const& pieces) const { INVARIANT_CHECK; - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::prioritize_pieces, _1, boost::cref(pieces))); + 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); } std::vector torrent_handle::piece_priorities() const { INVARIANT_CHECK; std::vector ret; - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::piece_priorities, _1, boost::ref(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); return ret; } @@ -399,8 +420,9 @@ namespace libtorrent { INVARIANT_CHECK; - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::prioritize_files, _1, boost::cref(files))); + 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); } // ============ start deprecation =============== @@ -408,38 +430,43 @@ namespace libtorrent void torrent_handle::filter_piece(int index, bool filter) const { INVARIANT_CHECK; - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::filter_piece, _1, index, filter)); + 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); } void torrent_handle::filter_pieces(std::vector const& pieces) const { INVARIANT_CHECK; - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::filter_pieces, _1, boost::cref(pieces))); + 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); } bool torrent_handle::is_piece_filtered(int index) const { INVARIANT_CHECK; - return call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::is_piece_filtered, _1, index)); + 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); } std::vector torrent_handle::filtered_pieces() const { INVARIANT_CHECK; std::vector ret; - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::filtered_pieces, _1, boost::ref(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); return ret; } void torrent_handle::filter_files(std::vector const& files) const { INVARIANT_CHECK; - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::filter_files, _1, files)); + 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); } // ============ end deprecation =============== @@ -449,16 +476,36 @@ namespace libtorrent { INVARIANT_CHECK; - return call_member const&>(m_ses - , m_chk, m_info_hash, bind(&torrent::trackers, _1)); + 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(); } - void torrent_handle::add_url_seed(std::string const& url) + void torrent_handle::add_url_seed(std::string const& url) const { INVARIANT_CHECK; - return call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::add_url_seed, _1, url)); + 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; + + 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; + + 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(); } void torrent_handle::replace_trackers( @@ -466,17 +513,19 @@ namespace libtorrent { INVARIANT_CHECK; - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::replace_trackers, _1, urls)); + 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); } torrent_info const& torrent_handle::get_torrent_info() const { INVARIANT_CHECK; - - if (!has_metadata()) throw_invalid_handle(); - return call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::torrent_file, _1)); + 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(); } bool torrent_handle::is_valid() const @@ -561,12 +610,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; @@ -625,8 +674,9 @@ namespace libtorrent { INVARIANT_CHECK; - return call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::save_path, _1)); + 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(); } void torrent_handle::connect_peer(tcp::endpoint const& adr, int source) const @@ -693,23 +743,26 @@ namespace libtorrent if (ratio < 1.f && ratio > 0.f) ratio = 1.f; - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::set_ratio, _1, ratio)); + 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); } #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES void torrent_handle::resolve_countries(bool r) { INVARIANT_CHECK; - call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::resolve_countries, _1, r)); + 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); } bool torrent_handle::resolve_countries() const { INVARIANT_CHECK; - return call_member(m_ses, m_chk, m_info_hash - , bind(&torrent::resolving_countries, _1)); + 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(); } #endif diff --git a/libtorrent/src/torrent_info.cpp b/libtorrent/src/torrent_info.cpp index 4ea09aefd..d6dc27fa2 100755 --- a/libtorrent/src/torrent_info.cpp +++ b/libtorrent/src/torrent_info.cpp @@ -400,7 +400,9 @@ namespace libtorrent { if (i->first == "pieces" || i->first == "piece length" - || i->first == "length") + || i->first == "length" +// || i->first == "files" + || i->first == "name") continue; m_extra_info[i->first] = i->second; } @@ -674,7 +676,7 @@ namespace libtorrent { assert(m_piece_length > 0); - if ((m_urls.empty() && m_nodes.empty()) || m_files.empty()) + if (m_files.empty()) { // TODO: throw something here // throw @@ -824,8 +826,33 @@ 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) const + , int size, bool storage) const { assert(num_files() > 0); std::vector ret; @@ -839,9 +866,9 @@ namespace libtorrent std::vector::const_iterator file_iter; int counter = 0; - for (file_iter = begin_files();; ++counter, ++file_iter) + for (file_iter = begin_files(storage);; ++counter, ++file_iter) { - assert(file_iter != end_files()); + assert(file_iter != end_files(storage)); if (file_offset < file_iter->size) { file_slice f; @@ -862,11 +889,11 @@ namespace libtorrent } peer_request torrent_info::map_file(int file_index, size_type file_offset - , int size) const + , int size, bool storage) const { - assert(file_index < (int)m_files.size()); + assert(file_index < num_files(storage)); assert(file_index >= 0); - size_type offset = file_offset + m_files[file_index].offset; + size_type offset = file_offset + file_at(file_index, storage).offset; peer_request ret; ret.piece = offset / piece_length(); diff --git a/libtorrent/src/tracker_manager.cpp b/libtorrent/src/tracker_manager.cpp index 7bd511588..358ac3838 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( diff --git a/libtorrent/src/upnp.cpp b/libtorrent/src/upnp.cpp index aefff41b1..33168c2bd 100644 --- a/libtorrent/src/upnp.cpp +++ b/libtorrent/src/upnp.cpp @@ -53,38 +53,10 @@ 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) - { - 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(); - } + bool is_local(address const& a); + address_v4 guess_local_address(asio::io_service&); } upnp::upnp(io_service& ios, connection_queue& cc @@ -95,89 +67,27 @@ upnp::upnp(io_service& ios, connection_queue& cc , m_user_agent(user_agent) , m_callback(cb) , m_retry_count(0) - , m_socket(ios) + , 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_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 - rebind(listen_interface); + m_retry_count = 0; + discover_device(); } 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[] = @@ -188,20 +98,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_to(asio::buffer(msearch, sizeof(msearch) - 1) - , upnp_multicast_endpoint, 0, ec); + m_socket.send(msearch, sizeof(msearch) - 1, ec); if (ec) { +#ifdef TORRENT_UPNP_LOGGING + m_log << time_now_string() + << " ==> Broadcast FAILED: " << ec.message() << std::endl + << "aborting" << std::endl; +#endif disable(); return; } @@ -219,7 +129,7 @@ void upnp::discover_device() try catch (std::exception&) { disable(); -} +}; void upnp::set_mappings(int tcp, int udp) { @@ -292,7 +202,7 @@ try rootdevice& d = const_cast(*i); try { - d.upnp_connection.reset(new http_connection(m_socket.io_service() + d.upnp_connection.reset(new http_connection(m_io_service , m_cc, m_strand.wrap(bind(&upnp::on_upnp_xml, this, _1, _2 , boost::ref(d))))); d.upnp_connection->get(d.url); @@ -313,17 +223,16 @@ try catch (std::exception&) { assert(false); -} +}; #endif -void upnp::on_reply(asio::error_code const& e +void upnp::on_reply(udp::endpoint const& from, char* buffer , std::size_t bytes_transferred) #ifndef NDEBUG try #endif { using namespace libtorrent::detail; - if (e) return; // parse out the url for the device @@ -338,29 +247,45 @@ 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(m_receive_buffer - , m_receive_buffer + bytes_transferred)); + p.incoming(buffer::const_interval(buffer + , buffer + bytes_transferred)); } catch (std::exception& e) { #ifdef TORRENT_UPNP_LOGGING m_log << time_now_string() - << " <== Rootdevice responded with incorrect HTTP packet: " - << e.what() << ". Ignoring device" << std::endl; + << " <== Rootdevice responded with incorrect HTTP packet. Ignoring device (" << e.what() << ")" << std::endl; #endif return; } - if (p.status_code() != 200) + if (p.status_code() != 200 && p.method() != "notify") { #ifdef TORRENT_UPNP_LOGGING - m_log << time_now_string() - << " <== Rootdevice responded with HTTP status: " << p.status_code() - << ". Ignoring device" << std::endl; + 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; #endif return; } @@ -431,6 +356,8 @@ 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 @@ -439,6 +366,8 @@ 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 @@ -463,7 +392,7 @@ try rootdevice& d = const_cast(*i); try { - d.upnp_connection.reset(new http_connection(m_socket.io_service() + d.upnp_connection.reset(new http_connection(m_io_service , m_cc, m_strand.wrap(bind(&upnp::on_upnp_xml, this, _1, _2 , boost::ref(d))))); d.upnp_connection->get(d.url); @@ -488,7 +417,7 @@ catch (std::exception&) }; #endif -void upnp::post(rootdevice& d, std::stringstream const& soap +void upnp::post(upnp::rootdevice const& d, std::string const& soap , std::string const& soap_action) { std::stringstream header; @@ -496,12 +425,40 @@ void upnp::post(rootdevice& d, std::stringstream 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.str().size() << "\r\n" - "Soapaction: \"" << d.service_namespace << "#" << soap_action << "\"\r\n\r\n" << soap.str(); + "Content-Length: " << soap.size() << "\r\n" + "Soapaction: \"" << d.service_namespace << "#" << soap_action << "\"\r\n\r\n" << soap; d.upnp_connection->sendbuffer = header.str(); - d.upnp_connection->start(d.hostname, boost::lexical_cast(d.port) - , seconds(10)); + +#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); } void upnp::map_port(rootdevice& d, int i) @@ -522,14 +479,21 @@ void upnp::map_port(rootdevice& d, int i) assert(!d.upnp_connection); assert(d.service_namespace); - d.upnp_connection.reset(new http_connection(m_socket.io_service() + d.upnp_connection.reset(new http_connection(m_io_service , m_cc, m_strand.wrap(bind(&upnp::on_upnp_map_response, this, _1, _2 - , boost::ref(d), i)))); + , boost::ref(d), i)), true + , bind(&upnp::create_port_mapping, this, _1, boost::ref(d), i))); - std::string soap_action = "AddPortMapping"; + d.upnp_connection->start(d.hostname, boost::lexical_cast(d.port) + , seconds(10)); +} +void upnp::delete_port_mapping(rootdevice& d, int i) +{ std::stringstream soap; + std::string soap_action = "DeletePortMapping"; + soap << "\n" "" @@ -537,20 +501,10 @@ void upnp::map_port(rootdevice& d, int i) soap << "" "" << d.mapping[i].external_port << "" - "" << (d.mapping[i].protocol ? "UDP" : "TCP") << "" - "" << d.mapping[i].local_port << "" - "" << m_local_ip.to_string() << "" - "1" - "" << m_user_agent << "" - "" << d.lease_duration << ""; + "" << (d.mapping[i].protocol ? "UDP" : "TCP") << ""; 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 @@ -568,29 +522,13 @@ void upnp::unmap_port(rootdevice& d, int i) } return; } - d.upnp_connection.reset(new http_connection(m_socket.io_service() + d.upnp_connection.reset(new http_connection(m_io_service , m_cc, m_strand.wrap(bind(&upnp::on_upnp_unmap_response, this, _1, _2 - , boost::ref(d), i)))); + , boost::ref(d), i)), true + , bind(&upnp::delete_port_mapping, this, boost::ref(d), i))); - 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 + d.upnp_connection->start(d.hostname, boost::lexical_cast(d.port) + , seconds(10)); } namespace @@ -838,16 +776,9 @@ void upnp::on_upnp_map_response(asio::error_code const& e m_devices.erase(d); return; } - - 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; - } + + // We don't want to ignore responses with return codes other than 200 + // since those might contain valid UPnP error codes error_code_parse_state s; xml_parse((char*)p.get_body().begin, (char*)p.get_body().end @@ -1066,3 +997,4 @@ void upnp::close() } } + diff --git a/libtorrent/src/web_peer_connection.cpp b/libtorrent/src/web_peer_connection.cpp index 6c6745f30..a307fc9cb 100755 --- a/libtorrent/src/web_peer_connection.cpp +++ b/libtorrent/src/web_peer_connection.cpp @@ -69,9 +69,6 @@ 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); @@ -80,6 +77,10 @@ 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 @@ -178,13 +179,16 @@ 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_size = std::min(block_size, size); - peer_request pr = {r.piece, r.start + r.length - size - , request_size}; + 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; m_requests.push_back(pr); - size -= request_size; + size -= pr.length; } proxy_settings const& ps = m_ses.web_seed_proxy(); @@ -477,8 +481,11 @@ namespace libtorrent peer_request front_request = m_requests.front(); - if (in_range.piece != front_request.piece - || in_range.start > front_request.start + int(m_piece.size())) + 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) { throw std::runtime_error("invalid range in HTTP response"); } @@ -486,7 +493,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 @@ -510,7 +517,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); @@ -568,7 +575,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)