diff --git a/deluge/core/torrent.py b/deluge/core/torrent.py index d3ab3067d..1521e499e 100644 --- a/deluge/core/torrent.py +++ b/deluge/core/torrent.py @@ -134,7 +134,7 @@ class Torrent: def set_private_flag(self, private): self.private = private - self.handle.get_torrent_info().set_priv(private) + #self.handle.get_torrent_info().set_priv(private) def set_prioritize_first_last(self, prioritize): self.prioritize_first_last = prioritize diff --git a/libtorrent/bindings/python/src/peer_plugin.cpp b/libtorrent/bindings/python/src/peer_plugin.cpp index 2689728b3..ddc94f16a 100755 --- a/libtorrent/bindings/python/src/peer_plugin.cpp +++ b/libtorrent/bindings/python/src/peer_plugin.cpp @@ -28,17 +28,17 @@ namespace this->peer_plugin::add_handshake(e); } - bool on_handshake() + bool on_handshake(char const* reserved_bits) { if (override f = this->get_override("on_handshake")) return f(); else - return peer_plugin::on_handshake(); + return peer_plugin::on_handshake(reserved_bits); } - bool default_on_handshake() + bool default_on_handshake(char const* reserved_bits) { - return this->peer_plugin::on_handshake(); + return this->peer_plugin::on_handshake(reserved_bits); } bool on_extension_handshake(entry const& e) diff --git a/libtorrent/bindings/python/src/torrent_info.cpp b/libtorrent/bindings/python/src/torrent_info.cpp index 716ecfdee..a9ba952d8 100755 --- a/libtorrent/bindings/python/src/torrent_info.cpp +++ b/libtorrent/bindings/python/src/torrent_info.cpp @@ -74,13 +74,7 @@ void bind_torrent_info() .def(init()) .def(init()) - .def("create_torrent", &torrent_info::create_torrent) - .def("set_comment", &torrent_info::set_comment) - .def("set_piece_size", &torrent_info::set_piece_size) - .def("set_creator", &torrent_info::set_creator) - .def("set_hash", &torrent_info::set_hash) .def("add_tracker", &torrent_info::add_tracker, (arg("url"), arg("tier")=0)) - .def("add_file", &torrent_info::add_file) .def("add_url_seed", &torrent_info::add_url_seed) .def("name", &torrent_info::name, copy) @@ -91,7 +85,7 @@ void bind_torrent_info() .def("num_pieces", &torrent_info::num_pieces) .def("info_hash", &torrent_info::info_hash, copy) - .def("hash_for_piece", &torrent_info::hash_for_piece, copy) + .def("hash_for_piece", &torrent_info::hash_for_piece) .def("piece_size", &torrent_info::piece_size) .def("num_files", &torrent_info::num_files, (arg("storage")=false)) @@ -99,7 +93,6 @@ void bind_torrent_info() .def("files", &files, (arg("storage")=false)) .def("priv", &torrent_info::priv) - .def("set_priv", &torrent_info::set_priv) .def("trackers", range(begin_trackers, end_trackers)) .def("creation_date", &torrent_info::creation_date) diff --git a/libtorrent/include/libtorrent/GeoIP.h b/libtorrent/include/libtorrent/GeoIP.h index 60b2c9750..d493eccb9 100644 --- a/libtorrent/include/libtorrent/GeoIP.h +++ b/libtorrent/include/libtorrent/GeoIP.h @@ -173,10 +173,6 @@ GEOIP_API const char * GeoIP_region_name_by_code(const char *country_code, const /* Get timezone from country and region code */ GEOIP_API const char * GeoIP_time_zone_by_country_and_region(const char *country_code, const char *region_code); -#ifdef BSD -#define memcpy(dest, src, n) bcopy(src, dest, n) -#endif - #ifdef __cplusplus } #endif diff --git a/libtorrent/include/libtorrent/alert_types.hpp b/libtorrent/include/libtorrent/alert_types.hpp index 4d82641a6..cb72cc6aa 100755 --- a/libtorrent/include/libtorrent/alert_types.hpp +++ b/libtorrent/include/libtorrent/alert_types.hpp @@ -188,7 +188,7 @@ namespace libtorrent struct TORRENT_EXPORT peer_error_alert: alert { peer_error_alert(tcp::endpoint const& pip, peer_id const& pid_, std::string const& msg) - : alert(alert::debug, msg) + : alert(alert::info, msg) , ip(pip) , pid(pid_) {} @@ -200,6 +200,21 @@ namespace libtorrent peer_id pid; }; + struct TORRENT_EXPORT peer_disconnected_alert: alert + { + peer_disconnected_alert(tcp::endpoint const& pip, peer_id const& pid_, std::string const& msg) + : alert(alert::debug, msg) + , ip(pip) + , pid(pid_) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new peer_disconnected_alert(*this)); } + + tcp::endpoint ip; + peer_id pid; + }; + struct TORRENT_EXPORT invalid_request_alert: torrent_alert { invalid_request_alert( diff --git a/libtorrent/include/libtorrent/aux_/session_impl.hpp b/libtorrent/include/libtorrent/aux_/session_impl.hpp index 3689a8187..20e2a9860 100644 --- a/libtorrent/include/libtorrent/aux_/session_impl.hpp +++ b/libtorrent/include/libtorrent/aux_/session_impl.hpp @@ -151,7 +151,7 @@ namespace libtorrent void async_accept(boost::shared_ptr const& listener); void on_incoming_connection(boost::shared_ptr const& s - , boost::weak_ptr listener, asio::error_code const& e); + , boost::weak_ptr listener, error_code const& e); // must be locked to access the data // in this struct @@ -489,6 +489,11 @@ namespace libtorrent // from the torrent with the most peers int m_disconnect_time_scaler; + // when this scaler reaches zero, it will + // scrape one of the auto managed, paused, + // torrents. + int m_auto_scrape_time_scaler; + // statistics gathered from all torrents. stat m_stat; @@ -498,7 +503,7 @@ namespace libtorrent // NAT or not. bool m_incoming_connection; - void second_tick(asio::error_code const& e); + void second_tick(error_code const& e); void recalculate_auto_managed_torrents(); void recalculate_unchoke_slots(int congested_torrents , int uncongested_torrents); @@ -528,7 +533,7 @@ namespace libtorrent udp_socket m_dht_socket; - void on_receive_udp(asio::error_code const& e + void on_receive_udp(error_code const& e , udp::endpoint const& ep, char const* buf, int len); #endif diff --git a/libtorrent/include/libtorrent/bandwidth_manager.hpp b/libtorrent/include/libtorrent/bandwidth_manager.hpp index b34f4b993..ef58337c5 100644 --- a/libtorrent/include/libtorrent/bandwidth_manager.hpp +++ b/libtorrent/include/libtorrent/bandwidth_manager.hpp @@ -76,6 +76,8 @@ struct history_entry history_entry(intrusive_ptr p, weak_ptr t , int a, ptime exp) : expires_at(exp), amount(a), peer(p), tor(t) {} + history_entry(int a, ptime exp) + : expires_at(exp), amount(a), peer(), tor() {} ptime expires_at; int amount; intrusive_ptr peer; @@ -111,6 +113,7 @@ struct bandwidth_manager : m_ios(ios) , m_history_timer(m_ios) , m_limit(bandwidth_limit::inf) + , m_drain_quota(0) , m_current_quota(0) , m_channel(channel) , m_in_hand_out_bandwidth(false) @@ -123,6 +126,14 @@ struct bandwidth_manager #endif } + void drain(int bytes) + { + mutex_t::scoped_lock l(m_mutex); + TORRENT_ASSERT(bytes >= 0); + m_drain_quota += bytes; + if (m_drain_quota > m_limit * 5) m_drain_quota = m_limit * 5; + } + void throttle(int limit) { mutex_t::scoped_lock l(m_mutex); @@ -154,7 +165,6 @@ struct bandwidth_manager bool is_queued(PeerConnection const* peer, boost::mutex::scoped_lock& l) const { - TORRENT_ASSERT(l.locked()); for (typename queue_t::const_iterator i = m_queue.begin() , end(m_queue.end()); i != end; ++i) { @@ -171,7 +181,6 @@ struct bandwidth_manager bool is_in_history(PeerConnection const* peer, boost::mutex::scoped_lock& l) const { - TORRENT_ASSERT(l.locked()); for (typename history_t::const_iterator i = m_history.begin(), end(m_history.end()); i != end; ++i) { @@ -258,12 +267,12 @@ private: if (m_abort) return; - asio::error_code ec; + error_code ec; m_history_timer.expires_at(e.expires_at, ec); m_history_timer.async_wait(bind(&bandwidth_manager::on_history_expire, this, _1)); } - void on_history_expire(asio::error_code const& e) + void on_history_expire(error_code const& e) { if (e) return; @@ -290,6 +299,7 @@ private: << std::endl; #endif intrusive_ptr c = e.peer; + if (!c) continue; shared_ptr t = e.tor.lock(); l.unlock(); if (!c->is_disconnecting()) c->expire_bandwidth(m_channel, e.amount); @@ -300,7 +310,7 @@ private: // now, wait for the next chunk to expire if (!m_history.empty() && !m_abort) { - asio::error_code ec; + error_code ec; m_history_timer.expires_at(m_history.back().expires_at, ec); m_history_timer.async_wait(bind(&bandwidth_manager::on_history_expire, this, _1)); } @@ -313,7 +323,6 @@ private: void hand_out_bandwidth(boost::mutex::scoped_lock& l) { - TORRENT_ASSERT(l.locked()); // if we're already handing out bandwidth, just return back // to the loop further down on the callstack if (m_in_hand_out_bandwidth) return; @@ -332,6 +341,15 @@ private: if (amount <= 0) return; + if (m_drain_quota > 0) + { + int drain_amount = (std::min)(m_drain_quota, amount); + m_drain_quota -= drain_amount; + amount -= drain_amount; + add_history_entry(history_entry( + drain_amount, now + bw_window_size)); + } + queue_t tmp; while (!m_queue.empty() && amount > 0) { @@ -436,6 +454,10 @@ private: // the rate limit (bytes per second) int m_limit; + // bytes to drain without handing out to a peer + // used to deduct the IP overhead + int m_drain_quota; + // the sum of all recently handed out bandwidth blocks int m_current_quota; diff --git a/libtorrent/include/libtorrent/broadcast_socket.hpp b/libtorrent/include/libtorrent/broadcast_socket.hpp index 3afc23fa9..3a8d6a76e 100644 --- a/libtorrent/include/libtorrent/broadcast_socket.hpp +++ b/libtorrent/include/libtorrent/broadcast_socket.hpp @@ -51,7 +51,7 @@ namespace libtorrent int common_bits(unsigned char const* b1 , unsigned char const* b2, int n); - TORRENT_EXPORT address guess_local_address(asio::io_service&); + TORRENT_EXPORT address guess_local_address(io_service&); typedef boost::function receive_handler_t; @@ -59,11 +59,11 @@ namespace libtorrent class TORRENT_EXPORT broadcast_socket { public: - broadcast_socket(asio::io_service& ios, udp::endpoint const& multicast_endpoint + broadcast_socket(io_service& ios, udp::endpoint const& multicast_endpoint , receive_handler_t const& handler, bool loopback = true); ~broadcast_socket() { close(); } - void send(char const* buffer, int size, asio::error_code& ec); + void send(char const* buffer, int size, error_code& ec); void close(); private: @@ -77,12 +77,12 @@ namespace libtorrent void close() { if (!socket) return; - asio::error_code ec; + error_code ec; socket->close(ec); } }; - void on_receive(socket_entry* s, asio::error_code const& ec + void on_receive(socket_entry* s, error_code const& ec , std::size_t bytes_transferred); void open_unicast_socket(io_service& ios, address const& addr); void open_multicast_socket(io_service& ios, address const& addr diff --git a/libtorrent/include/libtorrent/bt_peer_connection.hpp b/libtorrent/include/libtorrent/bt_peer_connection.hpp index 4ef15631a..f82d5070c 100755 --- a/libtorrent/include/libtorrent/bt_peer_connection.hpp +++ b/libtorrent/include/libtorrent/bt_peer_connection.hpp @@ -100,6 +100,7 @@ namespace libtorrent bt_peer_connection( aux::session_impl& ses , boost::shared_ptr s + , tcp::endpoint const& remote , policy::peer* peerinfo); void start(); @@ -141,9 +142,9 @@ namespace libtorrent // called from the main loop when this connection has any // work to do. - void on_sent(asio::error_code const& error + void on_sent(error_code const& error , std::size_t bytes_transferred); - void on_receive(asio::error_code const& error + void on_receive(error_code const& error , std::size_t bytes_transferred); virtual void get_specific_peer_info(peer_info& p) const; @@ -363,6 +364,7 @@ private: // the peer indicated that it supports the // extension protocol bool m_supports_extensions; + char m_reserved_bits[20]; #endif bool m_supports_dht_port; bool m_supports_fast; diff --git a/libtorrent/include/libtorrent/chained_buffer.hpp b/libtorrent/include/libtorrent/chained_buffer.hpp index 82fcb65c5..22eba1e97 100644 --- a/libtorrent/include/libtorrent/chained_buffer.hpp +++ b/libtorrent/include/libtorrent/chained_buffer.hpp @@ -34,12 +34,19 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_CHAINED_BUFFER_HPP_INCLUDED #include +#if BOOST_VERSION < 103500 #include +#else +#include +#endif #include #include namespace libtorrent { +#if BOOST_VERSION >= 103500 + namespace asio = boost::asio; +#endif struct chained_buffer { chained_buffer(): m_bytes(0), m_capacity(0) {} diff --git a/libtorrent/include/libtorrent/connection_queue.hpp b/libtorrent/include/libtorrent/connection_queue.hpp index c0e229a40..527b862df 100644 --- a/libtorrent/include/libtorrent/connection_queue.hpp +++ b/libtorrent/include/libtorrent/connection_queue.hpp @@ -71,7 +71,7 @@ public: private: void try_connect(); - void on_timeout(asio::error_code const& e); + void on_timeout(error_code const& e); struct entry { diff --git a/libtorrent/include/libtorrent/disk_buffer_holder.hpp b/libtorrent/include/libtorrent/disk_buffer_holder.hpp index 1a60909f7..31be6b3c7 100644 --- a/libtorrent/include/libtorrent/disk_buffer_holder.hpp +++ b/libtorrent/include/libtorrent/disk_buffer_holder.hpp @@ -47,7 +47,13 @@ namespace libtorrent disk_buffer_holder(disk_io_thread& iothread, char* buf); ~disk_buffer_holder(); char* release(); - char* buffer() const { return m_buf; } + char* get() const { return m_buf; } + void reset(char* buf = 0); + + typedef char* (disk_buffer_holder::*unspecified_bool_type)(); + operator unspecified_bool_type() const + { return m_buf == 0? 0: &disk_buffer_holder::release; } + private: disk_io_thread& m_iothread; char* m_buf; diff --git a/libtorrent/include/libtorrent/disk_io_thread.hpp b/libtorrent/include/libtorrent/disk_io_thread.hpp index c01393d7e..b66cc6014 100644 --- a/libtorrent/include/libtorrent/disk_io_thread.hpp +++ b/libtorrent/include/libtorrent/disk_io_thread.hpp @@ -149,7 +149,7 @@ namespace libtorrent // of disk io jobs struct disk_io_thread : boost::noncopyable { - disk_io_thread(asio::io_service& ios, int block_size = 16 * 1024); + disk_io_thread(io_service& ios, int block_size = 16 * 1024); ~disk_io_thread(); #ifdef TORRENT_STATS @@ -292,7 +292,7 @@ namespace libtorrent size_type m_writes; size_type m_blocks_written; - asio::io_service& m_ios; + io_service& m_ios; // thread for performing blocking disk io operations boost::thread m_disk_io_thread; diff --git a/libtorrent/include/libtorrent/entry.hpp b/libtorrent/include/libtorrent/entry.hpp index dfd256d18..473eb1ca8 100755 --- a/libtorrent/include/libtorrent/entry.hpp +++ b/libtorrent/include/libtorrent/entry.hpp @@ -167,6 +167,8 @@ namespace libtorrent #endif entry* find_key(char const* key); entry const* find_key(char const* key) const; + entry* find_key(std::string const& key); + entry const* find_key(std::string const& key) const; void print(std::ostream& os, int indent = 0) const; diff --git a/libtorrent/include/libtorrent/enum_net.hpp b/libtorrent/include/libtorrent/enum_net.hpp index 577a7e308..643c4c0c0 100644 --- a/libtorrent/include/libtorrent/enum_net.hpp +++ b/libtorrent/include/libtorrent/enum_net.hpp @@ -43,7 +43,7 @@ namespace libtorrent { address interface_address; address netmask; - char name[32]; + char name[64]; }; struct ip_route @@ -51,15 +51,15 @@ namespace libtorrent address destination; address netmask; address gateway; - char name[32]; + char name[64]; }; // returns a list of the configured IP interfaces // on the machine - TORRENT_EXPORT std::vector enum_net_interfaces(asio::io_service& ios - , asio::error_code& ec); + TORRENT_EXPORT std::vector enum_net_interfaces(io_service& ios + , error_code& ec); - TORRENT_EXPORT std::vector enum_routes(asio::io_service& ios, asio::error_code& ec); + TORRENT_EXPORT std::vector enum_routes(io_service& ios, error_code& ec); // returns true if the specified address is on the same // local network as the specified interface @@ -67,11 +67,11 @@ namespace libtorrent // returns true if the specified address is on the same // local network as us - TORRENT_EXPORT bool in_local_network(asio::io_service& ios, address const& addr - , asio::error_code& ec); + TORRENT_EXPORT bool in_local_network(io_service& ios, address const& addr + , error_code& ec); - TORRENT_EXPORT address get_default_gateway(asio::io_service& ios - , asio::error_code& ec); + TORRENT_EXPORT address get_default_gateway(io_service& ios + , error_code& ec); } #endif diff --git a/libtorrent/include/libtorrent/escape_string.hpp b/libtorrent/include/libtorrent/escape_string.hpp index b663d094d..660dd4d08 100755 --- a/libtorrent/include/libtorrent/escape_string.hpp +++ b/libtorrent/include/libtorrent/escape_string.hpp @@ -51,6 +51,8 @@ namespace libtorrent TORRENT_EXPORT boost::optional url_has_argument( std::string const& url, std::string argument); + + TORRENT_EXPORT std::string to_hex(std::string const& s); } #endif // TORRENT_ESCAPE_STRING_HPP_INCLUDED diff --git a/libtorrent/include/libtorrent/extensions.hpp b/libtorrent/include/libtorrent/extensions.hpp index 8046d307d..c4c2c748d 100644 --- a/libtorrent/include/libtorrent/extensions.hpp +++ b/libtorrent/include/libtorrent/extensions.hpp @@ -99,7 +99,7 @@ namespace libtorrent // means that the other end doesn't support this extension and will remove // it from the list of plugins. // this is not called for web seeds - virtual bool on_handshake() { return true; } + virtual bool on_handshake(char const* reserved_bits) { return true; } // called when the extension handshake from the other end is received // if this returns false, it means that this extension isn't diff --git a/libtorrent/include/libtorrent/http_connection.hpp b/libtorrent/include/libtorrent/http_connection.hpp index f9b521862..b13b457fa 100644 --- a/libtorrent/include/libtorrent/http_connection.hpp +++ b/libtorrent/include/libtorrent/http_connection.hpp @@ -39,6 +39,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include #include "libtorrent/socket.hpp" @@ -59,8 +60,8 @@ namespace libtorrent struct http_connection; class connection_queue; -typedef boost::function http_handler; +typedef boost::function http_handler; typedef boost::function http_connect_handler; @@ -70,7 +71,7 @@ typedef boost::function http_connect_handler; // will always be 0 struct http_connection : boost::enable_shared_from_this, boost::noncopyable { - http_connection(asio::io_service& ios, connection_queue& cc + http_connection(io_service& ios, connection_queue& cc , http_handler const& handler, bool bottled = true , http_connect_handler const& ch = http_connect_handler()) : m_sock(ios) @@ -91,6 +92,7 @@ struct http_connection : boost::enable_shared_from_this, boost: , m_cc(cc) , m_ssl(false) , m_priority(0) + , m_abort(false) { TORRENT_ASSERT(!m_handler.empty()); } @@ -121,19 +123,19 @@ struct http_connection : boost::enable_shared_from_this, boost: private: - void on_resolve(asio::error_code const& e + void on_resolve(error_code const& e , tcp::resolver::iterator i); + void queue_connect(); void connect(int ticket, tcp::endpoint target_address); void on_connect_timeout(); - void on_connect(asio::error_code const& e -/* , tcp::resolver::iterator i*/); - void on_write(asio::error_code const& e); - void on_read(asio::error_code const& e, std::size_t bytes_transferred); + void on_connect(error_code const& e); + void on_write(error_code const& e); + void on_read(error_code const& e, std::size_t bytes_transferred); static void on_timeout(boost::weak_ptr p - , asio::error_code const& e); - void on_assign_bandwidth(asio::error_code const& e); + , error_code const& e); + void on_assign_bandwidth(error_code const& e); - void callback(asio::error_code const& e, char const* data = 0, int size = 0); + void callback(error_code const& e, char const* data = 0, int size = 0); std::vector m_recvbuffer; #ifdef TORRENT_USE_OPENSSL @@ -158,6 +160,9 @@ private: bool m_called; std::string m_hostname; std::string m_port; + std::string m_url; + + std::list m_endpoints; // the current download limit, in bytes per second // 0 is unlimited. @@ -195,6 +200,8 @@ private: // the priority we have in the connection queue. // 0 is normal, 1 is high int m_priority; + + bool m_abort; }; } diff --git a/libtorrent/include/libtorrent/http_stream.hpp b/libtorrent/include/libtorrent/http_stream.hpp index 041b7c84f..db1602120 100644 --- a/libtorrent/include/libtorrent/http_stream.hpp +++ b/libtorrent/include/libtorrent/http_stream.hpp @@ -41,7 +41,7 @@ class http_stream : public proxy_base { public: - explicit http_stream(asio::io_service& io_service) + explicit http_stream(io_service& io_service) : proxy_base(io_service) , m_no_connect(false) {} @@ -55,7 +55,7 @@ public: m_password = password; } - typedef boost::function handler_type; + typedef boost::function handler_type; template void async_connect(endpoint_type const& endpoint, Handler const& handler) @@ -80,11 +80,11 @@ public: private: - void name_lookup(asio::error_code const& e, tcp::resolver::iterator i + void name_lookup(error_code const& e, tcp::resolver::iterator i , boost::shared_ptr h); - void connected(asio::error_code const& e, boost::shared_ptr h); - void handshake1(asio::error_code const& e, boost::shared_ptr h); - void handshake2(asio::error_code const& e, boost::shared_ptr h); + void connected(error_code const& e, boost::shared_ptr h); + void handshake1(error_code const& e, boost::shared_ptr h); + void handshake2(error_code const& e, boost::shared_ptr h); // send and receive buffer std::vector m_buffer; diff --git a/libtorrent/include/libtorrent/http_tracker_connection.hpp b/libtorrent/include/libtorrent/http_tracker_connection.hpp index 2a61fef83..04701fc00 100755 --- a/libtorrent/include/libtorrent/http_tracker_connection.hpp +++ b/libtorrent/include/libtorrent/http_tracker_connection.hpp @@ -82,7 +82,7 @@ namespace libtorrent boost::intrusive_ptr self() { return boost::intrusive_ptr(this); } - void on_response(asio::error_code const& ec, http_parser const& parser + void on_response(error_code const& ec, http_parser const& parser , char const* data, int size); virtual void on_timeout() {} diff --git a/libtorrent/include/libtorrent/instantiate_connection.hpp b/libtorrent/include/libtorrent/instantiate_connection.hpp index 71282f993..26efcd6cf 100644 --- a/libtorrent/include/libtorrent/instantiate_connection.hpp +++ b/libtorrent/include/libtorrent/instantiate_connection.hpp @@ -34,14 +34,13 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_INSTANTIATE_CONNECTION #include "libtorrent/socket_type.hpp" -#include #include namespace libtorrent { struct proxy_settings; - bool instantiate_connection(asio::io_service& ios + bool instantiate_connection(io_service& ios , proxy_settings const& ps, socket_type& s); } diff --git a/libtorrent/include/libtorrent/kademlia/closest_nodes.hpp b/libtorrent/include/libtorrent/kademlia/closest_nodes.hpp index 244e4bb38..bd4771ea4 100644 --- a/libtorrent/include/libtorrent/kademlia/closest_nodes.hpp +++ b/libtorrent/include/libtorrent/kademlia/closest_nodes.hpp @@ -68,7 +68,7 @@ public: private: void done(); - void invoke(node_id const& id, asio::ip::udp::endpoint addr); + void invoke(node_id const& id, udp::endpoint addr); closest_nodes( node_id target diff --git a/libtorrent/include/libtorrent/kademlia/dht_tracker.hpp b/libtorrent/include/libtorrent/kademlia/dht_tracker.hpp index 0d0064af5..ef07b1b91 100644 --- a/libtorrent/include/libtorrent/kademlia/dht_tracker.hpp +++ b/libtorrent/include/libtorrent/kademlia/dht_tracker.hpp @@ -53,6 +53,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/session_settings.hpp" #include "libtorrent/session_status.hpp" #include "libtorrent/udp_socket.hpp" +#include "libtorrent/socket.hpp" namespace libtorrent { namespace dht { @@ -89,19 +90,20 @@ namespace libtorrent { namespace dht // translate bittorrent kademlia message into the generic kademlia message // used by the library void on_receive(udp::endpoint const& ep, char const* pkt, int size); + void on_unreachable(udp::endpoint const& ep); private: boost::intrusive_ptr self() { return boost::intrusive_ptr(this); } - void on_name_lookup(asio::error_code const& e + void on_name_lookup(error_code const& e , udp::resolver::iterator host); - void on_router_name_lookup(asio::error_code const& e + void on_router_name_lookup(error_code const& e , udp::resolver::iterator host); - void connection_timeout(asio::error_code const& e); - void refresh_timeout(asio::error_code const& e); - void tick(asio::error_code const& e); + void connection_timeout(error_code const& e); + void refresh_timeout(error_code const& e); + void tick(error_code const& e); void on_bootstrap(); void send_packet(msg const& m); diff --git a/libtorrent/include/libtorrent/kademlia/find_data.hpp b/libtorrent/include/libtorrent/kademlia/find_data.hpp index 39a945296..7772ca7c3 100644 --- a/libtorrent/include/libtorrent/kademlia/find_data.hpp +++ b/libtorrent/include/libtorrent/kademlia/find_data.hpp @@ -48,8 +48,6 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { namespace dht { -using asio::ip::udp; - typedef std::vector packet_t; class rpc_manager; diff --git a/libtorrent/include/libtorrent/kademlia/msg.hpp b/libtorrent/include/libtorrent/kademlia/msg.hpp index a205ce463..00db7305c 100644 --- a/libtorrent/include/libtorrent/kademlia/msg.hpp +++ b/libtorrent/include/libtorrent/kademlia/msg.hpp @@ -36,15 +36,17 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include "libtorrent/entry.hpp" +#if BOOST_VERSION < 103500 #include +#else +#include +#endif namespace libtorrent { namespace dht { typedef std::vector packet_t; -using asio::ip::udp; - namespace messages { enum { ping = 0, find_node = 1, get_peers = 2, announce_peer = 3, error = 4 }; diff --git a/libtorrent/include/libtorrent/kademlia/node.hpp b/libtorrent/include/libtorrent/kademlia/node.hpp index d93872db9..88a1677f1 100644 --- a/libtorrent/include/libtorrent/kademlia/node.hpp +++ b/libtorrent/include/libtorrent/kademlia/node.hpp @@ -56,8 +56,6 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { namespace dht { -using asio::ip::udp; - #ifdef TORRENT_DHT_VERBOSE_LOGGING TORRENT_DECLARE_LOG(node); #endif @@ -174,6 +172,7 @@ public: void(std::vector const&)> f); void add_router_node(udp::endpoint router); + void unreachable(udp::endpoint const& ep); void incoming(msg const& m); void refresh(); diff --git a/libtorrent/include/libtorrent/kademlia/node_entry.hpp b/libtorrent/include/libtorrent/kademlia/node_entry.hpp index edc5dff80..e31a60e3f 100644 --- a/libtorrent/include/libtorrent/kademlia/node_entry.hpp +++ b/libtorrent/include/libtorrent/kademlia/node_entry.hpp @@ -41,20 +41,33 @@ namespace libtorrent { namespace dht struct node_entry { - node_entry(node_id const& id_, asio::ip::udp::endpoint addr_) + node_entry(node_id const& id_, udp::endpoint addr_) : id(id_) , addr(addr_) - , fail_count(0) {} - node_entry(asio::ip::udp::endpoint addr_) + , fail_count(0) + { +#ifdef TORRENT_DHT_VERBOSE_LOGGING + first_seen = time_now(); +#endif + } + node_entry(udp::endpoint addr_) : id(0) , addr(addr_) - , fail_count(0) {} + , fail_count(0) + { +#ifdef TORRENT_DHT_VERBOSE_LOGGING + first_seen = time_now(); +#endif + } node_id id; udp::endpoint addr; // the number of times this node has failed to // respond in a row int fail_count; +#ifdef TORRENT_DHT_VERBOSE_LOGGING + ptime first_seen; +#endif }; } } // namespace libtorrent::dht diff --git a/libtorrent/include/libtorrent/kademlia/routing_table.hpp b/libtorrent/include/libtorrent/kademlia/routing_table.hpp index acb4c1885..e3f2e7ded 100644 --- a/libtorrent/include/libtorrent/kademlia/routing_table.hpp +++ b/libtorrent/include/libtorrent/kademlia/routing_table.hpp @@ -55,9 +55,10 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { namespace dht { -using asio::ip::udp; +#ifdef TORRENT_DHT_VERBOSE_LOGGING +TORRENT_DECLARE_LOG(table); +#endif -//TORRENT_DECLARE_LOG(table); typedef std::vector bucket_t; diff --git a/libtorrent/include/libtorrent/kademlia/rpc_manager.hpp b/libtorrent/include/libtorrent/kademlia/rpc_manager.hpp index ffcc90b5b..837c091dd 100644 --- a/libtorrent/include/libtorrent/kademlia/rpc_manager.hpp +++ b/libtorrent/include/libtorrent/kademlia/rpc_manager.hpp @@ -56,7 +56,6 @@ namespace libtorrent { namespace dht struct observer; -using asio::ip::udp; #ifdef TORRENT_DHT_VERBOSE_LOGGING TORRENT_DECLARE_LOG(rpc); #endif @@ -82,6 +81,8 @@ public: , routing_table& table, send_fun const& sf); ~rpc_manager(); + void unreachable(udp::endpoint const& ep); + // returns true if the node needs a refresh bool incoming(msg const&); time_duration tick(); diff --git a/libtorrent/include/libtorrent/lazy_entry.hpp b/libtorrent/include/libtorrent/lazy_entry.hpp index 7a8827887..c40d87bcc 100644 --- a/libtorrent/include/libtorrent/lazy_entry.hpp +++ b/libtorrent/include/libtorrent/lazy_entry.hpp @@ -179,6 +179,15 @@ namespace libtorrent void clear(); + // releases ownership of any memory allocated + void release() + { + m_data.start = 0; + m_size = 0; + m_capacity = 0; + m_type = none_t; + } + ~lazy_entry() { clear(); } @@ -186,6 +195,17 @@ namespace libtorrent // this entry has its bencoded data std::pair data_section() const; + void swap(lazy_entry& e) + { + using std::swap; + swap(m_type, e.m_type); + swap(m_data.start, e.m_data.start); + swap(m_size, e.m_size); + swap(m_capacity, e.m_capacity); + swap(m_begin, e.m_begin); + swap(m_end, e.m_end); + } + private: entry_type_t m_type; diff --git a/libtorrent/include/libtorrent/lsd.hpp b/libtorrent/include/libtorrent/lsd.hpp index 6fb6b7c7b..6e3ddea7d 100644 --- a/libtorrent/include/libtorrent/lsd.hpp +++ b/libtorrent/include/libtorrent/lsd.hpp @@ -67,7 +67,7 @@ public: private: - void resend_announce(asio::error_code const& e, std::string msg); + void resend_announce(error_code const& e, std::string msg); void on_announce(udp::endpoint const& from, char* buffer , std::size_t bytes_transferred); // void setup_receive(); diff --git a/libtorrent/include/libtorrent/natpmp.hpp b/libtorrent/include/libtorrent/natpmp.hpp index 2a52d4e8a..8ce54132b 100644 --- a/libtorrent/include/libtorrent/natpmp.hpp +++ b/libtorrent/include/libtorrent/natpmp.hpp @@ -70,12 +70,12 @@ private: void update_mapping(int i); void send_map_request(int i); - void resend_request(int i, asio::error_code const& e); - void on_reply(asio::error_code const& e + void resend_request(int i, error_code const& e); + void on_reply(error_code const& e , std::size_t bytes_transferred); void try_next_mapping(int i); void update_expiration_timer(); - void mapping_expired(asio::error_code const& e, int i); + void mapping_expired(error_code const& e, int i); void disable(char const* message); diff --git a/libtorrent/include/libtorrent/peer_connection.hpp b/libtorrent/include/libtorrent/peer_connection.hpp index 07fe96d4c..a0a799200 100755 --- a/libtorrent/include/libtorrent/peer_connection.hpp +++ b/libtorrent/include/libtorrent/peer_connection.hpp @@ -121,6 +121,7 @@ namespace libtorrent peer_connection( aux::session_impl& ses , boost::shared_ptr s + , tcp::endpoint const& remote , policy::peer* peerinfo); // this function is called after it has been constructed and properly @@ -197,6 +198,9 @@ namespace libtorrent bool is_seed() const; + void set_upload_only(bool u) { m_upload_only = u; } + bool upload_only() const { return m_upload_only; } + bool has_timed_out() const; // will send a keep-alive message to the peer @@ -230,6 +234,8 @@ namespace libtorrent const stat& statistics() const { return m_statistics; } void add_stat(size_type downloaded, size_type uploaded); + void calc_ip_overhead(); + // is called once every second by the main loop void second_tick(float tick_interval); @@ -240,15 +246,18 @@ namespace libtorrent std::vector const& allowed_fast(); std::vector const& suggested_pieces() const { return m_suggested_pieces; } + ptime connected_time() const { return m_connect; } + ptime last_received() const { return m_last_receive; } + void timed_out(); // this will cause this peer_connection to be disconnected. - void disconnect(char const* message); + void disconnect(char const* message, int error = 0); bool is_disconnecting() const { return m_disconnecting; } // this is called when the connection attempt has succeeded // and the peer_connection is supposed to set m_connecting // to false, and stop monitor writability - void on_connection_complete(asio::error_code const& e); + void on_connection_complete(error_code const& e); // returns true if this connection is still waiting to // finish the connection attempt @@ -288,7 +297,6 @@ namespace libtorrent bool ignore_bandwidth_limits() const { return m_ignore_bandwidth_limits; } - void set_failed() { m_failed = true; } bool failed() const { return m_failed; } int desired_queue_size() const { return m_desired_queue_size; } @@ -449,15 +457,15 @@ namespace libtorrent virtual void on_connected() = 0; virtual void on_tick() {} - virtual void on_receive(asio::error_code const& error + virtual void on_receive(error_code const& error , std::size_t bytes_transferred) = 0; - virtual void on_sent(asio::error_code const& error + virtual void on_sent(error_code const& error , std::size_t bytes_transferred) = 0; #ifndef TORRENT_DISABLE_ENCRYPTION buffer::interval wr_recv_buffer() { - TORRENT_ASSERT(m_disk_recv_buffer == 0); + TORRENT_ASSERT(!m_disk_recv_buffer); TORRENT_ASSERT(m_disk_recv_buffer_size == 0); if (m_recv_buffer.empty()) return buffer::interval(0,0); return buffer::interval(&m_recv_buffer[0] @@ -501,9 +509,9 @@ namespace libtorrent // called from the main loop when this connection has any // work to do. - void on_send_data(asio::error_code const& error + void on_send_data(error_code const& error , std::size_t bytes_transferred); - void on_receive_data(asio::error_code const& error + void on_receive_data(error_code const& error , std::size_t bytes_transferred); // this is the limit on the number of outstanding requests @@ -544,9 +552,6 @@ namespace libtorrent void on_disk_write_complete(int ret, disk_io_job const& j , peer_request r, boost::shared_ptr t); - // the timeout in seconds - int m_timeout; - // the time when we last got a part of a // piece packet from this peer ptime m_last_piece; @@ -559,28 +564,54 @@ namespace libtorrent // the time when we unchoked this peer ptime m_last_unchoke; - int m_packet_size; - int m_recv_pos; + // timeouts + ptime m_last_receive; + ptime m_last_sent; + + // a timestamp when the remote download rate + // was last updated + ptime m_remote_dl_update; + + // the time when async_connect was called + ptime m_connect; + + // the time when this peer sent us a not_interested message + // the last time. + ptime m_became_uninterested; + + // the time when we sent a not_interested message to + // this peer the last time. + ptime m_became_uninteresting; + + // the amount of data this peer has been given + // as free upload. This is distributed from + // peers from which we get free download + // this will be negative on a peer from which + // we get free download, and positive on peers + // that we give the free upload, to keep the balance. + size_type m_free_upload; + + // the total payload download bytes + // at the last unchoke cycle. This is used to + // measure the number of bytes transferred during + // an unchoke cycle, to unchoke peers the more bytes + // they sent us + size_type m_downloaded_at_last_unchoke; + +#ifndef TORRENT_DISABLE_GEO_IP + std::string m_inet_as_name; +#endif + buffer m_recv_buffer; // if this peer is receiving a piece, this // points to a disk buffer that the data is // read into. This eliminates a memcopy from // the receive buffer into the disk buffer - int m_disk_recv_buffer_size; - char* m_disk_recv_buffer; + disk_buffer_holder m_disk_recv_buffer; chained_buffer m_send_buffer; - // the number of bytes we are currently reading - // from disk, that will be added to the send - // buffer as soon as they complete - int m_reading_bytes; - - // timeouts - ptime m_last_receive; - ptime m_last_sent; - boost::shared_ptr m_socket; // this is the peer we're actually talking to // it may not necessarily be the peer we're @@ -593,51 +624,12 @@ namespace libtorrent // until the info_hash is received. Then it's // set to the torrent it belongs to. boost::weak_ptr m_torrent; - // is true if it was we that connected to the peer - // and false if we got an incoming connection - // could be considered: true = local, false = remote - bool m_active; // remote peer's id peer_id m_peer_id; - // other side says that it's interested in downloading - // from us. - bool m_peer_interested; - - // the other side has told us that it won't send anymore - // data to us for a while - bool m_peer_choked; - - // the peer has pieces we are interested in - bool m_interesting; - - // we have choked the upload to the peer - bool m_choked; - - // this is set to true if the connection timed - // out or closed the connection. In that - // case we will not try to reconnect to - // this peer - bool m_failed; - - // if this is set to true, the peer will not - // request bandwidth from the limiter, but instead - // just send and receive as much as possible. - bool m_ignore_bandwidth_limits; - // 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 - // std::count(m_have_piece.begin(), - // m_have_piece.end(), true) - int m_num_pieces; // the queue of requests we have got // from this peer @@ -651,25 +643,42 @@ namespace libtorrent // from this peer std::deque m_download_queue; - // the number of request we should queue up - // at the remote end. - int m_desired_queue_size; + // the pieces we will send to the peer + // if requested (regardless of choke state) + std::set m_accept_fast; - // the amount of data this peer has been given - // as free upload. This is distributed from - // peers from which we get free download - // this will be negative on a peer from which - // we get free download, and positive on peers - // that we give the free upload, to keep the balance. - size_type m_free_upload; + // the pieces the peer will send us if + // requested (regardless of choke state) + std::vector m_allowed_fast; - // if this is true, this peer is assumed to handle all piece - // requests in fifo order. All skipped blocks are re-requested - // immediately instead of having a looser requirement - // where blocks can be sent out of order. The default is to - // allow non-fifo order. - bool m_assume_fifo; + // pieces that has been suggested to be + // downloaded from this peer + std::vector m_suggested_pieces; + // the number of pieces this peer + // has. Must be the same as + // std::count(m_have_piece.begin(), + // m_have_piece.end(), true) + int m_num_pieces; + + // the timeout in seconds + int m_timeout; + + // the size (in bytes) of the bittorrent message + // we're currently receiving + int m_packet_size; + + // the number of bytes of the bittorrent payload + // we've received so far + int m_recv_pos; + + int m_disk_recv_buffer_size; + + // the number of bytes we are currently reading + // from disk, that will be added to the send + // buffer as soon as they complete + int m_reading_bytes; + // the number of invalid piece-requests // we have got from this peer. If the request // queue gets empty, and there have been @@ -679,49 +688,6 @@ namespace libtorrent // by sending choke, unchoke. int m_num_invalid_requests; - // this is true if this connection has been added - // to the list of connections that will be closed. - bool m_disconnecting; - - // the time when this peer sent us a not_interested message - // the last time. - ptime m_became_uninterested; - - // the time when we sent a not_interested message to - // this peer the last time. - ptime m_became_uninteresting; - - // this is true until this socket has become - // writable for the first time (i.e. the - // connection completed). While connecting - // the timeout will not be triggered. This is - // because windows XP SP2 may delay connection - // attempts, which means that the connection - // may not even have been attempted when the - // time out is reached. - bool m_connecting; - - // This is true until connect is called on the - // peer_connection's socket. It is false on incoming - // connections. - bool m_queued; - - // 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. - int m_prefer_whole_pieces; - - // if this is true, the blocks picked by the piece - // picker will be merged before passed to the - // request function. i.e. subsequent blocks are - // merged into larger blocks. This is used by - // the http-downloader, to request whole pieces - // at a time. - bool m_request_large_blocks; - // this is the priority with which this peer gets // download bandwidth quota assigned to it. int m_priority; @@ -753,60 +719,114 @@ namespace libtorrent // approximate peer download rate int m_remote_dl_rate; - // a timestamp when the remote download rate - // 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; + // max transfer rates seen on this peer + int m_download_rate_peak; + int m_upload_rate_peak; + + // estimated round trip time to this peer + // based on the time from when async_connect + // was called to when on_connection_complete + // was called. The rtt is specified in milliseconds + boost::uint16_t m_rtt; + + // 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. + boost::uint8_t m_prefer_whole_pieces; + + // the number of request we should queue up + // at the remote end. + boost::uint8_t m_desired_queue_size; + // if this is true, the disconnection // timestamp is not updated when the connection // is closed. This means the time until we can // reconnect to this peer is shorter, and likely // immediate. - bool m_fast_reconnect; + bool m_fast_reconnect:1; - // the time when async_connect was called - ptime m_connect; + // is true if it was we that connected to the peer + // and false if we got an incoming connection + // could be considered: true = local, false = remote + bool m_active:1; - // estimated round trip time to this peer - // based on the time from when async_connect - // was called to when on_connection_complete - // was called. The rtt is specified in milliseconds - int m_rtt; + // other side says that it's interested in downloading + // from us. + bool m_peer_interested:1; - // the total payload download bytes - // at the last unchoke cycle. This is used to - // measure the number of bytes transferred during - // an unchoke cycle, to unchoke peers the more bytes - // they sent us - size_type m_downloaded_at_last_unchoke; + // the other side has told us that it won't send anymore + // data to us for a while + bool m_peer_choked:1; -#ifndef TORRENT_DISABLE_GEO_IP - std::string m_inet_as_name; -#endif + // the peer has pieces we are interested in + bool m_interesting:1; - // max transfer rates seen on this peer - int m_download_rate_peak; - int m_upload_rate_peak; + // we have choked the upload to the peer + bool m_choked:1; + + // this is set to true if the connection timed + // out or closed the connection. In that + // case we will not try to reconnect to + // this peer + bool m_failed:1; + + // if this is set to true, the peer will not + // request bandwidth from the limiter, but instead + // just send and receive as much as possible. + bool m_ignore_bandwidth_limits:1; + + // 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:1; + + // if this is true, this peer is assumed to handle all piece + // requests in fifo order. All skipped blocks are re-requested + // immediately instead of having a looser requirement + // where blocks can be sent out of order. The default is to + // allow non-fifo order. + bool m_assume_fifo:1; + + // this is true if this connection has been added + // to the list of connections that will be closed. + bool m_disconnecting:1; + + // this is true until this socket has become + // writable for the first time (i.e. the + // connection completed). While connecting + // the timeout will not be triggered. This is + // because windows XP SP2 may delay connection + // attempts, which means that the connection + // may not even have been attempted when the + // time out is reached. + bool m_connecting:1; + + // This is true until connect is called on the + // peer_connection's socket. It is false on incoming + // connections. + bool m_queued:1; + + // if this is true, the blocks picked by the piece + // picker will be merged before passed to the + // request function. i.e. subsequent blocks are + // merged into larger blocks. This is used by + // the http-downloader, to request whole pieces + // at a time. + bool m_request_large_blocks:1; + + // set to true when this peer is only uploading + bool m_upload_only:1; #ifndef NDEBUG public: - bool m_in_constructor; + bool m_in_constructor:1; #endif }; } diff --git a/libtorrent/include/libtorrent/peer_id.hpp b/libtorrent/include/libtorrent/peer_id.hpp index b91717c0a..0ec096de3 100755 --- a/libtorrent/include/libtorrent/peer_id.hpp +++ b/libtorrent/include/libtorrent/peer_id.hpp @@ -142,6 +142,9 @@ namespace libtorrent iterator begin() { return m_number; } iterator end() { return m_number+number_size; } + std::string to_string() const + { return std::string((char const*)&m_number[0], number_size); } + private: unsigned char m_number[number_size]; diff --git a/libtorrent/include/libtorrent/policy.hpp b/libtorrent/include/libtorrent/policy.hpp index de0119de0..e95793826 100755 --- a/libtorrent/include/libtorrent/policy.hpp +++ b/libtorrent/include/libtorrent/policy.hpp @@ -248,7 +248,6 @@ namespace libtorrent const_iterator end_peer() const { return m_peers.end(); } bool connect_one_peer(); - bool disconnect_one_peer(); bool has_peer(policy::peer const* p) const; @@ -267,7 +266,6 @@ namespace libtorrent bool compare_peer(policy::peer const& lhs, policy::peer const& rhs , address const& external_ip) const; - iterator find_disconnect_candidate(); iterator find_connect_candidate(); bool is_connect_candidate(peer const& p, bool finished); diff --git a/libtorrent/include/libtorrent/proxy_base.hpp b/libtorrent/include/libtorrent/proxy_base.hpp index cdf5ff216..873e84190 100644 --- a/libtorrent/include/libtorrent/proxy_base.hpp +++ b/libtorrent/include/libtorrent/proxy_base.hpp @@ -38,9 +38,13 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#if BOOST_VERSION < 103500 #include #include - +#else +#include +#include +#endif namespace libtorrent { @@ -52,7 +56,7 @@ public: typedef stream_socket::endpoint_type endpoint_type; typedef stream_socket::protocol_type protocol_type; - explicit proxy_base(asio::io_service& io_service) + explicit proxy_base(io_service& io_service) : m_sock(io_service) , m_resolver(io_service) {} @@ -70,7 +74,7 @@ public: } template - std::size_t read_some(Mutable_Buffers const& buffers, asio::error_code& ec) + std::size_t read_some(Mutable_Buffers const& buffers, error_code& ec) { return m_sock.read_some(buffers, ec); } @@ -90,7 +94,7 @@ public: #endif template - void io_control(IO_Control_Command& ioc, asio::error_code& ec) + void io_control(IO_Control_Command& ioc, error_code& ec) { m_sock.io_control(ioc, ec); } @@ -110,7 +114,7 @@ public: #endif template - asio::error_code set_option(SettableSocketOption const& opt, asio::error_code& ec) + error_code set_option(SettableSocketOption const& opt, error_code& ec) { return m_sock.set_option(opt, ec); } @@ -122,7 +126,7 @@ public: } #endif - void bind(endpoint_type const& endpoint, asio::error_code& ec) + void bind(endpoint_type const& endpoint, error_code& ec) { m_sock.bind(endpoint, ec); } @@ -134,7 +138,7 @@ public: } #endif - void open(protocol_type const& p, asio::error_code& ec) + void open(protocol_type const& p, error_code& ec) { m_sock.open(p, ec); } @@ -148,7 +152,7 @@ public: } #endif - void close(asio::error_code& ec) + void close(error_code& ec) { m_sock.close(ec); m_resolver.cancel(); @@ -161,7 +165,7 @@ public: } #endif - endpoint_type remote_endpoint(asio::error_code& ec) const + endpoint_type remote_endpoint(error_code& ec) const { return m_remote_endpoint; } @@ -173,14 +177,14 @@ public: } #endif - endpoint_type local_endpoint(asio::error_code& ec) const + endpoint_type local_endpoint(error_code& ec) const { return m_sock.local_endpoint(ec); } - asio::io_service& io_service() + io_service& get_io_service() { - return m_sock.io_service(); + return m_sock.get_io_service(); } lowest_layer_type& lowest_layer() diff --git a/libtorrent/include/libtorrent/session.hpp b/libtorrent/include/libtorrent/session.hpp index ebd6b7ea5..fcae0be32 100755 --- a/libtorrent/include/libtorrent/session.hpp +++ b/libtorrent/include/libtorrent/session.hpp @@ -129,7 +129,7 @@ namespace libtorrent , resume_data(0) , storage_mode(storage_mode_sparse) , paused(true) - , auto_managed(false) + , auto_managed(true) , duplicate_is_error(false) , storage(sc) , userdata(0) diff --git a/libtorrent/include/libtorrent/session_settings.hpp b/libtorrent/include/libtorrent/session_settings.hpp index 069eea08d..30e76b825 100644 --- a/libtorrent/include/libtorrent/session_settings.hpp +++ b/libtorrent/include/libtorrent/session_settings.hpp @@ -102,11 +102,7 @@ namespace libtorrent , min_reconnect_time(60) , peer_connect_timeout(7) , ignore_limits_on_local_network(true) -#if !defined NDEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS - , connection_speed(2) -#else , connection_speed(20) -#endif , send_redundant_have(false) , lazy_bitfields(true) , inactivity_timeout(600) @@ -134,6 +130,11 @@ namespace libtorrent , share_ratio_limit(2.f) , seed_time_ratio_limit(7.f) , seed_time_limit(24 * 60 * 60) // 24 hours + , peer_turnover(1 / 50.f) + , peer_turnover_cutoff(1.f) + , close_redundant_connections(true) + , auto_scrape_interval(1800) + , auto_scrape_min_interval(300) {} // this is the user agent that will be sent to the tracker @@ -376,6 +377,31 @@ namespace libtorrent float share_ratio_limit; float seed_time_ratio_limit; int seed_time_limit; + + // the percentage of peers to disconnect every + // 90 seconds (if we're at the peer limit) + // defaults to 1/50:th + float peer_turnover; + + // when we are connected to more than + // limit * peer_turnover_enable peers + // disconnect peer_turnover fraction + // of the peers + float peer_turnover_cutoff; + + // if this is true (default) connections where both + // ends have no utility in keeping the connection open + // are closed. for instance if both ends have completed + // their downloads + bool close_redundant_connections; + + // the number of seconds between scrapes of + // queued torrents (auto managed and paused) + int auto_scrape_interval; + + // the minimum number of seconds between any + // automatic scrape (regardless of torrent) + int auto_scrape_min_interval; }; #ifndef TORRENT_DISABLE_DHT diff --git a/libtorrent/include/libtorrent/socket.hpp b/libtorrent/include/libtorrent/socket.hpp index 31c8525a0..0bca27da5 100755 --- a/libtorrent/include/libtorrent/socket.hpp +++ b/libtorrent/include/libtorrent/socket.hpp @@ -45,13 +45,25 @@ POSSIBILITY OF SUCH DAMAGE. #define Protocol Protocol_ #endif +#if BOOST_VERSION < 103500 #include #include #include #include #include +#include #include #include +#else +#include +#include +#include +#include +#include +#include +#include +#include +#endif #ifdef __OBJC__ #undef Protocol @@ -67,24 +79,12 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { -/* - namespace asio = boost::asio; - - using boost::asio::ipv4::tcp; - using boost::asio::ipv4::address; - using boost::asio::stream_socket; - using boost::asio::datagram_socket; - using boost::asio::socket_acceptor; - using boost::asio::io_service; - using boost::asio::ipv4::host_resolver; - using boost::asio::async_write; - using boost::asio::ipv4::host; - using boost::asio::deadline_timer; -*/ -// namespace asio = ::asio; - +#if BOOST_VERSION < 103500 using asio::ip::tcp; using asio::ip::udp; + using asio::async_write; + using asio::async_read; + typedef asio::ip::tcp::socket stream_socket; typedef asio::ip::address address; typedef asio::ip::address_v4 address_v4; @@ -92,14 +92,32 @@ namespace libtorrent typedef asio::ip::udp::socket datagram_socket; typedef asio::ip::tcp::acceptor socket_acceptor; typedef asio::io_service io_service; + typedef asio::error_code error_code; - using asio::async_write; - + namespace asio = ::asio; typedef asio::basic_deadline_timer deadline_timer; +#else + using boost::system::error_code; + using boost::asio::ip::tcp; + using boost::asio::ip::udp; + using boost::asio::async_write; + using boost::asio::async_read; + + typedef boost::asio::ip::tcp::socket stream_socket; + typedef boost::asio::ip::address address; + typedef boost::asio::ip::address_v4 address_v4; + typedef boost::asio::ip::address_v6 address_v6; + typedef boost::asio::ip::udp::socket datagram_socket; + typedef boost::asio::ip::tcp::acceptor socket_acceptor; + typedef boost::asio::io_service io_service; + + namespace asio = boost::asio; + typedef boost::asio::basic_deadline_timer deadline_timer; +#endif inline std::ostream& print_address(std::ostream& os, address const& addr) { - asio::error_code ec; + error_code ec; std::string a = addr.to_string(ec); if (ec) return os; os << a; @@ -109,7 +127,7 @@ namespace libtorrent inline std::ostream& print_endpoint(std::ostream& os, tcp::endpoint const& ep) { address const& addr = ep.address(); - asio::error_code ec; + error_code ec; std::string a = addr.to_string(ec); if (ec) return os; @@ -132,7 +150,7 @@ namespace libtorrent } else if (a.is_v6()) { - asio::ip::address_v6::bytes_type bytes + address_v6::bytes_type bytes = a.to_v6().to_bytes(); std::copy(bytes.begin(), bytes.end(), out); } @@ -142,18 +160,18 @@ namespace libtorrent address read_v4_address(InIt& in) { unsigned long ip = read_uint32(in); - return asio::ip::address_v4(ip); + return address_v4(ip); } template address read_v6_address(InIt& in) { - typedef asio::ip::address_v6::bytes_type bytes_t; + typedef address_v6::bytes_type bytes_t; bytes_t bytes; for (bytes_t::iterator i = bytes.begin() , end(bytes.end()); i != end; ++i) *i = read_uint8(in); - return asio::ip::address_v6(bytes); + return address_v6(bytes); } template diff --git a/libtorrent/include/libtorrent/socks4_stream.hpp b/libtorrent/include/libtorrent/socks4_stream.hpp index 9530f9d57..e7054595e 100644 --- a/libtorrent/include/libtorrent/socks4_stream.hpp +++ b/libtorrent/include/libtorrent/socks4_stream.hpp @@ -41,8 +41,8 @@ class socks4_stream : public proxy_base { public: - explicit socks4_stream(asio::io_service& io_service) - : proxy_base(io_service) + explicit socks4_stream(io_service& io_service_) + : proxy_base(io_service_) {} void set_username(std::string const& user) @@ -50,7 +50,7 @@ public: m_user = user; } - typedef boost::function handler_type; + typedef boost::function handler_type; template void async_connect(endpoint_type const& endpoint, Handler const& handler) @@ -74,11 +74,11 @@ public: private: - void name_lookup(asio::error_code const& e, tcp::resolver::iterator i + void name_lookup(error_code const& e, tcp::resolver::iterator i , boost::shared_ptr h); - void connected(asio::error_code const& e, boost::shared_ptr h); - void handshake1(asio::error_code const& e, boost::shared_ptr h); - void handshake2(asio::error_code const& e, boost::shared_ptr h); + void connected(error_code const& e, boost::shared_ptr h); + void handshake1(error_code const& e, boost::shared_ptr h); + void handshake2(error_code const& e, boost::shared_ptr h); // send and receive buffer std::vector m_buffer; diff --git a/libtorrent/include/libtorrent/socks5_stream.hpp b/libtorrent/include/libtorrent/socks5_stream.hpp index 622557cd2..24b27da85 100644 --- a/libtorrent/include/libtorrent/socks5_stream.hpp +++ b/libtorrent/include/libtorrent/socks5_stream.hpp @@ -41,7 +41,7 @@ class socks5_stream : public proxy_base { public: - explicit socks5_stream(asio::io_service& io_service) + explicit socks5_stream(io_service& io_service) : proxy_base(io_service) {} @@ -52,7 +52,7 @@ public: m_password = password; } - typedef boost::function handler_type; + typedef boost::function handler_type; template void async_connect(endpoint_type const& endpoint, Handler const& handler) @@ -79,17 +79,17 @@ public: private: - void name_lookup(asio::error_code const& e, tcp::resolver::iterator i + void name_lookup(error_code const& e, tcp::resolver::iterator i , boost::shared_ptr h); - void connected(asio::error_code const& e, boost::shared_ptr h); - void handshake1(asio::error_code const& e, boost::shared_ptr h); - void handshake2(asio::error_code const& e, boost::shared_ptr h); - void handshake3(asio::error_code const& e, boost::shared_ptr h); - void handshake4(asio::error_code const& e, boost::shared_ptr h); + void connected(error_code const& e, boost::shared_ptr h); + void handshake1(error_code const& e, boost::shared_ptr h); + void handshake2(error_code const& e, boost::shared_ptr h); + void handshake3(error_code const& e, boost::shared_ptr h); + void handshake4(error_code const& e, boost::shared_ptr h); void socks_connect(boost::shared_ptr h); - void connect1(asio::error_code const& e, boost::shared_ptr h); - void connect2(asio::error_code const& e, boost::shared_ptr h); - void connect3(asio::error_code const& e, boost::shared_ptr h); + void connect1(error_code const& e, boost::shared_ptr h); + void connect2(error_code const& e, boost::shared_ptr h); + void connect3(error_code const& e, boost::shared_ptr h); // send and receive buffer std::vector m_buffer; diff --git a/libtorrent/include/libtorrent/ssl_stream.hpp b/libtorrent/include/libtorrent/ssl_stream.hpp index b4cd62328..363c819f6 100644 --- a/libtorrent/include/libtorrent/ssl_stream.hpp +++ b/libtorrent/include/libtorrent/ssl_stream.hpp @@ -34,8 +34,11 @@ POSSIBILITY OF SUCH DAMAGE. #define TORRENT_SSL_STREAM_HPP_INCLUDED #include "libtorrent/socket.hpp" +#if BOOST_VERSION < 103500 #include - +#else +#include +#endif // openssl seems to believe it owns // this name in every single scope #undef set_key @@ -47,7 +50,7 @@ class ssl_stream { public: - explicit ssl_stream(asio::io_service& io_service) + explicit ssl_stream(io_service& io_service) : m_context(io_service, asio::ssl::context::sslv23_client) , m_sock(io_service, m_context) { @@ -60,7 +63,7 @@ public: typedef typename Stream::protocol_type protocol_type; typedef typename asio::ssl::stream sock_type; - typedef boost::function handler_type; + typedef boost::function handler_type; template void async_connect(endpoint_type const& endpoint, Handler const& handler) @@ -70,7 +73,7 @@ public: // 2. perform SSL client handshake // to avoid unnecessary copying of the handler, - // store it in a shaed_ptr + // store it in a shared_ptr boost::shared_ptr h(new handler_type(handler)); m_sock.next_layer().async_connect(endpoint @@ -84,7 +87,7 @@ public: } template - std::size_t read_some(Mutable_Buffers const& buffers, asio::error_code& ec) + std::size_t read_some(Mutable_Buffers const& buffers, error_code& ec) { return m_sock.read_some(buffers, ec); } @@ -104,7 +107,7 @@ public: #endif template - void io_control(IO_Control_Command& ioc, asio::error_code& ec) + void io_control(IO_Control_Command& ioc, error_code& ec) { m_sock.next_layer().io_control(ioc, ec); } @@ -122,7 +125,7 @@ public: } #endif - void bind(endpoint_type const& endpoint, asio::error_code& ec) + void bind(endpoint_type const& endpoint, error_code& ec) { m_sock.next_layer().bind(endpoint, ec); } @@ -134,7 +137,7 @@ public: } #endif - void open(protocol_type const& p, asio::error_code& ec) + void open(protocol_type const& p, error_code& ec) { m_sock.next_layer().open(p, ec); } @@ -151,7 +154,7 @@ public: } #endif - void close(asio::error_code& ec) + void close(error_code& ec) { m_sock.next_layer().close(ec); } @@ -163,7 +166,7 @@ public: } #endif - endpoint_type remote_endpoint(asio::error_code& ec) const + endpoint_type remote_endpoint(error_code& ec) const { return const_cast(m_sock).next_layer().remote_endpoint(ec); } @@ -175,14 +178,14 @@ public: } #endif - endpoint_type local_endpoint(asio::error_code& ec) const + endpoint_type local_endpoint(error_code& ec) const { return const_cast(m_sock).next_layer().local_endpoint(ec); } - asio::io_service& io_service() + io_service& get_io_service() { - return m_sock.io_service(); + return m_sock.get_io_service(); } lowest_layer_type& lowest_layer() @@ -197,7 +200,7 @@ public: private: - void connected(asio::error_code const& e, boost::shared_ptr h) + void connected(error_code const& e, boost::shared_ptr h) { if (e) { @@ -209,7 +212,7 @@ private: , boost::bind(&ssl_stream::handshake, this, _1, h)); } - void handshake(asio::error_code const& e, boost::shared_ptr h) + void handshake(error_code const& e, boost::shared_ptr h) { (*h)(e); } diff --git a/libtorrent/include/libtorrent/stat.hpp b/libtorrent/include/libtorrent/stat.hpp index 04f097fcd..ae29671e3 100755 --- a/libtorrent/include/libtorrent/stat.hpp +++ b/libtorrent/include/libtorrent/stat.hpp @@ -36,6 +36,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include "libtorrent/size_type.hpp" #include "libtorrent/invariant_check.hpp" @@ -44,88 +45,162 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { - - class TORRENT_EXPORT stat + class TORRENT_EXPORT stat_channel { friend class invariant_access; public: enum { history = 10 }; - stat() - : m_downloaded_payload(0) - , m_uploaded_payload(0) - , m_downloaded_protocol(0) - , m_uploaded_protocol(0) - , m_total_download_payload(0) - , m_total_upload_payload(0) - , m_total_download_protocol(0) - , m_total_upload_protocol(0) - , m_mean_download_rate(0) - , m_mean_upload_rate(0) - , m_mean_download_payload_rate(0) - , m_mean_upload_payload_rate(0) + stat_channel() + : m_counter(0) + , m_total_counter(0) + , m_rate_sum(0) { - std::fill(m_download_rate_history, m_download_rate_history+history, 0.f); - std::fill(m_upload_rate_history, m_upload_rate_history+history, 0.f); - std::fill(m_download_payload_rate_history, m_download_payload_rate_history+history, 0.f); - std::fill(m_upload_payload_rate_history, m_upload_payload_rate_history+history, 0.f); + std::memset(m_rate_history, 0, sizeof(m_rate_history)); } - void operator+=(const stat& s) + void operator+=(stat_channel const& s) { - INVARIANT_CHECK; - - m_downloaded_payload += s.m_downloaded_payload; - m_total_download_payload += s.m_downloaded_payload; - m_downloaded_protocol += s.m_downloaded_protocol; - m_total_download_protocol += s.m_downloaded_protocol; - - m_uploaded_payload += s.m_uploaded_payload; - m_total_upload_payload += s.m_uploaded_payload; - m_uploaded_protocol += s.m_uploaded_protocol; - m_total_upload_protocol += s.m_uploaded_protocol; + m_counter += s.m_counter; + m_total_counter += s.m_counter; } - void received_bytes(int bytes_payload, int bytes_protocol) + void add(int count) { - INVARIANT_CHECK; + TORRENT_ASSERT(count >= 0); - TORRENT_ASSERT(bytes_payload >= 0); - TORRENT_ASSERT(bytes_protocol >= 0); - - m_downloaded_payload += bytes_payload; - m_total_download_payload += bytes_payload; - m_downloaded_protocol += bytes_protocol; - m_total_download_protocol += bytes_protocol; - } - - void sent_bytes(int bytes_payload, int bytes_protocol) - { - INVARIANT_CHECK; - - TORRENT_ASSERT(bytes_payload >= 0); - TORRENT_ASSERT(bytes_protocol >= 0); - - m_uploaded_payload += bytes_payload; - m_total_upload_payload += bytes_payload; - m_uploaded_protocol += bytes_protocol; - m_total_upload_protocol += bytes_protocol; + m_counter += count; + m_total_counter += count; } // should be called once every second void second_tick(float tick_interval); + float rate() const { return m_rate_sum / float(history); } + size_type rate_sum() const { return m_rate_sum; } + size_type total() const { return m_total_counter; } - float upload_rate() const { return m_mean_upload_rate; } - float download_rate() const { return m_mean_download_rate; } + void offset(size_type counter) + { + TORRENT_ASSERT(counter >= 0); + m_total_counter += counter; + } - float upload_payload_rate() const { return m_mean_upload_payload_rate; } - float download_payload_rate() const { return m_mean_download_payload_rate; } + size_type counter() const { return m_counter; } - size_type total_payload_upload() const { return m_total_upload_payload; } - size_type total_payload_download() const { return m_total_download_payload; } + private: - size_type total_protocol_upload() const { return m_total_upload_protocol; } - size_type total_protocol_download() const { return m_total_download_protocol; } +#ifndef NDEBUG + void check_invariant() const + { + int sum = 0; + for (int i = 0; i < history; ++i) sum += m_rate_history[i]; + TORRENT_ASSERT(m_rate_sum == sum); + TORRENT_ASSERT(m_total_counter >= 0); + } +#endif + + // history of rates a few seconds back + int m_rate_history[history]; + + // the accumulator for this second. + int m_counter; + + // total counters + size_type m_total_counter; + + // sum of all elements in m_rate_history + size_type m_rate_sum; + }; + + class TORRENT_EXPORT stat + { + friend class invariant_access; + public: + void operator+=(const stat& s) + { + for (int i = 0; i < num_channels; ++i) + m_stat[i] += s.m_stat[i]; + } + + void received_bytes(int bytes_payload, int bytes_protocol) + { + TORRENT_ASSERT(bytes_payload >= 0); + TORRENT_ASSERT(bytes_protocol >= 0); + + m_stat[download_payload].add(bytes_payload); + m_stat[download_protocol].add(bytes_protocol); + } + + void sent_bytes(int bytes_payload, int bytes_protocol) + { + TORRENT_ASSERT(bytes_payload >= 0); + TORRENT_ASSERT(bytes_protocol >= 0); + + m_stat[upload_payload].add(bytes_payload); + m_stat[upload_protocol].add(bytes_protocol); + } + + // calculate ip protocol overhead + void calc_ip_overhead() + { + int uploaded = m_stat[upload_protocol].counter() + + m_stat[upload_payload].counter(); + int downloaded = m_stat[download_protocol].counter() + + m_stat[download_payload].counter(); + + // IP + TCP headers are 40 bytes per MTU (1460) + // bytes of payload, but at least 40 bytes + m_stat[upload_ip_protocol].add((std::max)(uploaded / 1460, uploaded>0?40:0)); + m_stat[download_ip_protocol].add((std::max)(downloaded / 1460, downloaded>0?40:0)); + + // also account for ACK traffic. That adds to the transfers + // in the opposite direction. Even on connections with symmetric + // transfer rates, it seems to add a penalty. + m_stat[upload_ip_protocol].add((std::max)(downloaded * 40 / 1460, downloaded>0?40:0)); + m_stat[download_ip_protocol].add((std::max)(uploaded * 40 / 1460, uploaded>0?40:0)); + } + + int upload_ip_overhead() const { return m_stat[upload_ip_protocol].counter(); } + int download_ip_overhead() const { return m_stat[download_ip_protocol].counter(); } + + // should be called once every second + void second_tick(float tick_interval) + { + for (int i = 0; i < num_channels; ++i) + m_stat[i].second_tick(tick_interval); + } + + float upload_rate() const + { + return (m_stat[upload_payload].rate_sum() + + m_stat[upload_protocol].rate_sum() + + m_stat[upload_ip_protocol].rate_sum()) + / float(stat_channel::history); + } + + float download_rate() const + { + return (m_stat[download_payload].rate_sum() + + m_stat[download_protocol].rate_sum() + + m_stat[download_ip_protocol].rate_sum()) + / float(stat_channel::history); + } + + float upload_payload_rate() const + { return m_stat[upload_payload].rate(); } + + float download_payload_rate() const + { return m_stat[download_payload].rate(); } + + size_type total_payload_upload() const + { return m_stat[upload_payload].total(); } + size_type total_payload_download() const + { return m_stat[download_payload].total(); } + + size_type total_protocol_upload() const + { return m_stat[upload_protocol].total(); } + size_type total_protocol_download() const + { return m_stat[download_protocol].total(); } // this is used to offset the statistics when a // peer_connection is opened and have some previous @@ -134,66 +209,33 @@ namespace libtorrent { TORRENT_ASSERT(downloaded >= 0); TORRENT_ASSERT(uploaded >= 0); - m_total_download_payload += downloaded; - m_total_upload_payload += uploaded; + m_stat[download_payload].offset(downloaded); + m_stat[upload_payload].offset(uploaded); } - size_type last_payload_downloaded() const { return m_downloaded_payload; } - size_type last_payload_uploaded() const { return m_uploaded_payload; } + size_type last_payload_downloaded() const + { return m_stat[download_payload].counter(); } + size_type last_payload_uploaded() const + { return m_stat[upload_payload].counter(); } private: -#ifndef NDEBUG - void check_invariant() const + // these are the channels we keep stats for + enum { - TORRENT_ASSERT(m_mean_upload_rate >= 0); - TORRENT_ASSERT(m_mean_download_rate >= 0); - TORRENT_ASSERT(m_mean_upload_payload_rate >= 0); - TORRENT_ASSERT(m_mean_download_payload_rate >= 0); - TORRENT_ASSERT(m_total_upload_payload >= 0); - TORRENT_ASSERT(m_total_download_payload >= 0); - TORRENT_ASSERT(m_total_upload_protocol >= 0); - TORRENT_ASSERT(m_total_download_protocol >= 0); - } -#endif + upload_payload, + upload_protocol, + upload_ip_protocol, + download_payload, + download_protocol, + download_ip_protocol, + num_channels + }; - // history of download/upload speeds a few seconds back - float m_download_rate_history[history]; - float m_upload_rate_history[history]; - - float m_download_payload_rate_history[history]; - float m_upload_payload_rate_history[history]; - - // the accumulators we are adding the downloads/uploads - // to this second. This only counts the actual payload - // and ignores the bytes sent as protocol chatter. - int m_downloaded_payload; - int m_uploaded_payload; - - // the accumulators we are adding the downloads/uploads - // to this second. This only counts the protocol - // chatter and ignores the actual payload - int m_downloaded_protocol; - int m_uploaded_protocol; - - // total download/upload counters - // only counting payload data - size_type m_total_download_payload; - size_type m_total_upload_payload; - - // total download/upload counters - // only counting protocol chatter - size_type m_total_download_protocol; - size_type m_total_upload_protocol; - - // current mean download/upload rates - float m_mean_download_rate; - float m_mean_upload_rate; - - float m_mean_download_payload_rate; - float m_mean_upload_payload_rate; + stat_channel m_stat[num_channels]; }; } #endif // TORRENT_STAT_HPP_INCLUDED + diff --git a/libtorrent/include/libtorrent/time.hpp b/libtorrent/include/libtorrent/time.hpp index 27e6e2561..f768c7fe2 100644 --- a/libtorrent/include/libtorrent/time.hpp +++ b/libtorrent/include/libtorrent/time.hpp @@ -86,7 +86,11 @@ namespace libtorrent #else +#if BOOST_VERSION < 103500 #include +#else +#include +#endif #include #include "libtorrent/assert.hpp" @@ -152,6 +156,9 @@ namespace libtorrent } // asio time_traits +#if BOOST_VERSION >= 103500 +namespace boost { +#endif namespace asio { template<> @@ -172,6 +179,9 @@ namespace asio { return boost::posix_time::microseconds(libtorrent::total_microseconds(d)); } }; } +#if BOOST_VERSION >= 103500 +} +#endif #if defined(__MACH__) diff --git a/libtorrent/include/libtorrent/torrent.hpp b/libtorrent/include/libtorrent/torrent.hpp index e6f3b685d..39aa2fe4b 100755 --- a/libtorrent/include/libtorrent/torrent.hpp +++ b/libtorrent/include/libtorrent/torrent.hpp @@ -151,8 +151,7 @@ namespace libtorrent void files_checked(); void start_checking(); - float seed_cycles(session_settings const& s) const; - int seed_cycles_int(session_settings const& s) const { return int(seed_cycles(s)); } + int seed_rank(session_settings const& s) const; storage_mode_t storage_mode() const { return m_storage_mode; } // this will flag the torrent as aborted. The main @@ -356,6 +355,7 @@ namespace libtorrent void force_tracker_request(); void force_tracker_request(ptime); void scrape_tracker(); + ptime const& last_scrape() const { return m_last_scrape; } // sets the username and password that will be sent to // the tracker @@ -453,6 +453,7 @@ namespace libtorrent void announce_piece(int index); void disconnect_all(); + int disconnect_peers(int num); // this is called wheh the torrent has completed // the download. It will post an event, disconnect @@ -461,17 +462,17 @@ namespace libtorrent // this is the asio callback that is called when a name // lookup for a PEER is completed. - void on_peer_name_lookup(asio::error_code const& e, tcp::resolver::iterator i + void on_peer_name_lookup(error_code const& e, tcp::resolver::iterator i , peer_id pid); // this is the asio callback that is called when a name // lookup for a WEB SEED is completed. - void on_name_lookup(asio::error_code const& e, tcp::resolver::iterator i + void on_name_lookup(error_code const& e, tcp::resolver::iterator i , std::string url, tcp::endpoint proxy); // this is the asio callback that is called when a name // lookup for a proxy for a web seed is completed. - void on_proxy_name_lookup(asio::error_code const& e, tcp::resolver::iterator i + void on_proxy_name_lookup(error_code const& e, tcp::resolver::iterator i , std::string url); // this is called when the torrent has finished. i.e. @@ -480,6 +481,11 @@ namespace libtorrent // completed() is called immediately after it. void finished(); + // This is the opposite of finished. It is called if we used + // to be finished but enabled some files for download so that + // we wasn't finished anymore. + void resume_download(); + void async_verify_piece(int piece_index, boost::function const&); // this is called from the peer_connection @@ -570,7 +576,7 @@ namespace libtorrent // to the checker thread for initial checking // of the storage. // a return value of false indicates an error - bool set_metadata(entry const& metadata, std::string& error); + bool set_metadata(lazy_entry const& metadata, std::string& error); int sequence_number() const { return m_sequence_number; } @@ -587,40 +593,43 @@ namespace libtorrent void try_next_tracker(); int prioritize_tracker(int tracker_index); - void on_country_lookup(asio::error_code const& error, tcp::resolver::iterator i + void on_country_lookup(error_code const& error, tcp::resolver::iterator i , boost::intrusive_ptr p) const; bool request_bandwidth_from_session(int channel) const; void update_peer_interest(bool was_finished); + policy m_policy; + + // total time we've been available on this torrent + // does not count when the torrent is stopped or paused + time_duration m_active_time; + + // total time we've been available as a seed on this torrent + // does not count when the torrent is stopped or paused + time_duration m_seeding_time; + + // all time totals of uploaded and downloaded payload + // stored in resume data + size_type m_total_uploaded; + size_type m_total_downloaded; + + // if this torrent is running, this was the time + // when it was started. This is used to have a + // bias towards keeping seeding torrents that + // recently was started, to avoid oscillation + ptime m_started; + + // the last time we initiated a scrape request to + // one of the trackers in this torrent + ptime m_last_scrape; + boost::intrusive_ptr m_torrent_file; - // is set to true when the torrent has - // been aborted. - bool m_abort; - - // is true if this torrent has been paused - bool m_paused; - // this is true from the time when the torrent was - // paused to the time should_request() is called - bool m_just_paused; - - // if this is true, libtorrent may pause and resume - // this torrent depending on queuing rules. Torrents - // started with auto_managed flag set may be added in - // a paused state in case there are no available - // slots. - bool m_auto_managed; - tracker_request::event_t m_event; void parse_response(const entry& e, std::vector& peer_list); - // the size of a request block - // each piece is divided into these - // blocks when requested - int m_block_size; - // if this pointer is 0, the torrent is in // a state where the metadata hasn't been // received yet. @@ -649,18 +658,6 @@ namespace libtorrent // the time of next tracker request ptime m_next_request; - // ----------------------------- - // DATA FROM TRACKER RESPONSE - - // the number number of seconds between requests - // from the tracker - int m_duration; - - // the scrape data from the tracker response, this - // is optional and may be -1. - int m_complete; - int m_incomplete; - #ifndef NDEBUG public: #endif @@ -681,28 +678,21 @@ namespace libtorrent // resolving the address for std::set m_resolving_web_seeds; +#ifndef TORRENT_DISABLE_EXTENSIONS + typedef std::list > extension_list_t; + extension_list_t m_extensions; +#endif + // used to resolve the names of web seeds mutable tcp::resolver m_host_resolver; -#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES - // this is true while there is a country - // resolution in progress. To avoid flodding - // the DNS request queue, only one ip is resolved - // at a time. - mutable bool m_resolving_country; - - // this is true if the user has enabled - // country resolution in this torrent - bool m_resolve_countries; -#endif - // this announce timer is used both // by Local service discovery and // by the DHT. deadline_timer m_announce_timer; static void on_announce_disp(boost::weak_ptr p - , asio::error_code const& e); + , error_code const& e); // this is called once per announce interval void on_announce(); @@ -737,41 +727,9 @@ namespace libtorrent std::vector m_trackers; // this is an index into m_trackers - int m_last_working_tracker; - int m_currently_trying_tracker; - // the number of connection attempts that has - // failed in a row, this is currently used to - // determine the timeout until next try. - int m_failed_trackers; - - // this is a counter that is decreased every - // second, and when it reaches 0, the policy::pulse() - // is called and the time scaler is reset to 10. - int m_time_scaler; - // the bitmask that says which pieces we have std::vector m_have_pieces; - // the number of pieces we have. The same as - // std::accumulate(m_have_pieces.begin(), - // m_have_pieces.end(), 0) - int m_num_pieces; - - // in case the piece picker hasn't been constructed - // when this settings is set, this variable will keep - // its value until the piece picker is created - bool m_sequential_download; - - // is false by default and set to - // true when the first tracker reponse - // is received - bool m_got_tracker_response; - - // the upload/download ratio that each peer - // tries to maintain. - // 0 is infinite - float m_ratio; - // the number of bytes that has been // downloaded that failed the hash-test size_type m_total_failed_bytes; @@ -791,25 +749,9 @@ namespace libtorrent // the state of this torrent (queued, checking, downloading) torrent_status::state_t m_state; - float m_progress; entry m_resume_data; - // defaults to 16 kiB, but can be set by the user - // when creating the torrent - const int m_default_block_size; - - // this is set to false as long as the connections - // of this torrent hasn't been initialized. If we - // have metadata from the start, connections are - // initialized immediately, if we didn't have metadata, - // they are initialized right after files_checked(). - // valid_resume_data() will return false as long as - // the connections aren't initialized, to avoid - // them from altering the piece-picker before it - // has been initialized with files_checked(). - bool m_connections_initialized; - // if the torrent is started without metadata, it may // still be given a name until the metadata is received // once the metadata is received this field will no @@ -820,6 +762,18 @@ namespace libtorrent storage_constructor_type m_storage_constructor; + float m_progress; + + // the number of pieces we have. The same as + // std::accumulate(m_have_pieces.begin(), + // m_have_pieces.end(), 0) + int m_num_pieces; + + // the upload/download ratio that each peer + // tries to maintain. + // 0 is infinite + float m_ratio; + // the maximum number of uploads for this torrent int m_max_uploads; @@ -829,14 +783,18 @@ namespace libtorrent // the maximum number of connections for this torrent int m_max_connections; -#ifndef NDEBUG - bool m_files_checked; -#endif - -#ifndef TORRENT_DISABLE_EXTENSIONS - typedef std::list > extension_list_t; - extension_list_t m_extensions; -#endif + // the size of a request block + // each piece is divided into these + // blocks when requested + int m_block_size; + + // ----------------------------- + // DATA FROM TRACKER RESPONSE + + // the scrape data from the tracker response, this + // is optional and may be -1. + int m_complete; + int m_incomplete; #ifndef NDEBUG // this is the amount downloaded when this torrent @@ -858,24 +816,84 @@ namespace libtorrent // torrent object, these points are called connect_points. int m_deficit_counter; - policy m_policy; + // the number number of seconds between requests + // from the tracker + boost::int16_t m_duration; // the sequence number for this torrent, this is a // monotonically increasing number for each added torrent - int m_sequence_number; + boost::int16_t m_sequence_number; - // total time we've been available on this torrent - // does not count when the torrent is stopped or paused - time_duration m_active_time; + // the index to the last tracker that worked + boost::int8_t m_last_working_tracker; - // total time we've been available as a seed on this torrent - // does not count when the torrent is stopped or paused - time_duration m_seeding_time; + // the tracker that is currently (or was last) + // tried + boost::int8_t m_currently_trying_tracker; - // all time totals of uploaded and downloaded payload - // stored in resume data - size_type m_total_uploaded; - size_type m_total_downloaded; + // the number of connection attempts that has + // failed in a row, this is currently used to + // determine the timeout until next try. + boost::int8_t m_failed_trackers; + + // this is a counter that is decreased every + // second, and when it reaches 0, the policy::pulse() + // is called and the time scaler is reset to 10. + boost::int8_t m_time_scaler; + + // is set to true when the torrent has + // been aborted. + bool m_abort:1; + + // is true if this torrent has been paused + bool m_paused:1; + // this is true from the time when the torrent was + // paused to the time should_request() is called + bool m_just_paused:1; + + // if this is true, libtorrent may pause and resume + // this torrent depending on queuing rules. Torrents + // started with auto_managed flag set may be added in + // a paused state in case there are no available + // slots. + bool m_auto_managed:1; + +#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES + // this is true while there is a country + // resolution in progress. To avoid flodding + // the DNS request queue, only one ip is resolved + // at a time. + mutable bool m_resolving_country:1; + + // this is true if the user has enabled + // country resolution in this torrent + bool m_resolve_countries:1; +#endif + + // in case the piece picker hasn't been constructed + // when this settings is set, this variable will keep + // its value until the piece picker is created + bool m_sequential_download:1; + + // is false by default and set to + // true when the first tracker reponse + // is received + bool m_got_tracker_response:1; + + // this is set to false as long as the connections + // of this torrent hasn't been initialized. If we + // have metadata from the start, connections are + // initialized immediately, if we didn't have metadata, + // they are initialized right after files_checked(). + // valid_resume_data() will return false as long as + // the connections aren't initialized, to avoid + // them from altering the piece-picker before it + // has been initialized with files_checked(). + bool m_connections_initialized:1; + +#ifndef NDEBUG + bool m_files_checked:1; +#endif }; inline ptime torrent::next_announce() const diff --git a/libtorrent/include/libtorrent/torrent_handle.hpp b/libtorrent/include/libtorrent/torrent_handle.hpp index d370770bc..e6e7e55f4 100755 --- a/libtorrent/include/libtorrent/torrent_handle.hpp +++ b/libtorrent/include/libtorrent/torrent_handle.hpp @@ -118,7 +118,8 @@ namespace libtorrent , all_time_download(0) , active_time(0) , seeding_time(0) - , seed_cycles(0.f) + , seed_rank(0) + , last_scrape(0) {} enum state_t @@ -257,7 +258,12 @@ namespace libtorrent int active_time; int seeding_time; - float seed_cycles; + // higher value means more important to seed + int seed_rank; + + // number of seconds since last scrape, or -1 if + // there hasn't been a scrape + int last_scrape; }; struct TORRENT_EXPORT block_info diff --git a/libtorrent/include/libtorrent/torrent_info.hpp b/libtorrent/include/libtorrent/torrent_info.hpp index 4a520300b..f6baa476c 100755 --- a/libtorrent/include/libtorrent/torrent_info.hpp +++ b/libtorrent/include/libtorrent/torrent_info.hpp @@ -45,12 +45,14 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #ifdef _MSC_VER #pragma warning(pop) #endif #include "libtorrent/entry.hpp" +#include "libtorrent/lazy_entry.hpp" #include "libtorrent/socket.hpp" #include "libtorrent/peer_id.hpp" #include "libtorrent/size_type.hpp" @@ -110,18 +112,12 @@ namespace libtorrent torrent_info(); torrent_info(sha1_hash const& info_hash); - torrent_info(entry const& torrent_file); + torrent_info(lazy_entry const& torrent_file); + torrent_info(char const* buffer, int size); + torrent_info(char const* filename); ~torrent_info(); - entry create_torrent() const; - entry create_info_metadata() const; - void set_comment(char const* str); - void set_creator(char const* str); - void set_piece_size(int size); - void set_hash(int index, sha1_hash const& h); void add_tracker(std::string const& url, int tier = 0); - void add_file(fs::path file, size_type size); - void add_url_seed(std::string const& url); bool remap_files(std::vector const& map); @@ -131,10 +127,9 @@ namespace libtorrent , bool storage = false) const; std::vector const& url_seeds() const - { - TORRENT_ASSERT(!m_half_metadata); - return m_url_seeds; - } + { return m_url_seeds; } + void add_url_seed(std::string const& url) + { m_url_seeds.push_back(url); } typedef std::vector::const_iterator file_iterator; typedef std::vector::const_reverse_iterator reverse_file_iterator; @@ -176,12 +171,12 @@ namespace libtorrent { TORRENT_ASSERT(m_piece_length > 0); if (!storage || m_remapped_files.empty()) - return (int)m_files.size(); + return int(m_files.size()); else - return (int)m_remapped_files.size(); + return int(m_remapped_files.size()); } - const file_entry& file_at(int index, bool storage = false) const + file_entry const& file_at(int index, bool storage = false) const { if (!storage || m_remapped_files.empty()) { @@ -195,7 +190,7 @@ namespace libtorrent } } - const std::vector& trackers() const { return m_urls; } + std::vector const& trackers() const { return m_urls; } size_type total_size() const { TORRENT_ASSERT(m_piece_length > 0); return m_total_size; } int piece_length() const { TORRENT_ASSERT(m_piece_length > 0); return m_piece_length; } @@ -204,25 +199,30 @@ namespace libtorrent const std::string& name() const { TORRENT_ASSERT(m_piece_length > 0); return m_name; } // ------- start deprecation ------- -// this functionaily will be removed in a future version +// these functions will be removed in a future version + torrent_info(entry const& torrent_file) TORRENT_DEPRECATED; void print(std::ostream& os) const TORRENT_DEPRECATED; // ------- end deprecation ------- bool is_valid() const { return m_piece_length > 0; } bool priv() const { return m_private; } - void set_priv(bool v) { m_private = v; } - - void convert_file_names(); int piece_size(int index) const; - const sha1_hash& hash_for_piece(int index) const + sha1_hash hash_for_piece(int index) const + { + return sha1_hash(hash_for_piece_ptr(index)); + } + + char const* hash_for_piece_ptr(int index) const { TORRENT_ASSERT(index >= 0); - TORRENT_ASSERT(index < (int)m_piece_hash.size()); - TORRENT_ASSERT(!m_half_metadata); - return m_piece_hash[index]; + TORRENT_ASSERT(index < m_num_pieces); + TORRENT_ASSERT(m_piece_hashes); + TORRENT_ASSERT(m_piece_hashes >= m_info_section.get()); + TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size); + return &m_piece_hashes[index*20]; } boost::optional creation_date() const; @@ -237,27 +237,30 @@ namespace libtorrent typedef std::vector > nodes_t; nodes_t const& nodes() const - { - TORRENT_ASSERT(!m_half_metadata); - return m_nodes; - } + { return m_nodes; } + void add_node(std::pair const& node) + { m_nodes.push_back(node); } - void add_node(std::pair const& node); + bool parse_info_section(lazy_entry const& e, std::string& error); - bool parse_info_section(entry const& e, std::string& error); - - entry const* extra(char const* key) const - { return m_extra_info.find_key(key); } - - // frees parts of the metadata that isn't - // used by seeds - void seed_free(); + lazy_entry const* info(char const* key) const + { + if (m_info_dict.type() == lazy_entry::none_t) + lazy_bdecode(m_info_section.get(), m_info_section.get() + + m_info_section_size, m_info_dict); + return m_info_dict.dict_find(key); + } void swap(torrent_info& ti); + boost::shared_array metadata() const + { return m_info_section; } + + int metadata_size() const { return m_info_section_size; } + private: - bool read_torrent_info(const entry& libtorrent, std::string& error); + bool parse_torrent_file(lazy_entry const& libtorrent, std::string& error); // the urls to the trackers std::vector m_urls; @@ -269,9 +272,6 @@ namespace libtorrent // in an uninitialized state int m_piece_length; - // the sha-1 hashes of each piece - std::vector m_piece_hash; - // the list of files that this torrent consists of std::vector m_files; @@ -293,7 +293,7 @@ namespace libtorrent // the hash that identifies this torrent // is mutable because it's calculated // lazily - mutable sha1_hash m_info_hash; + sha1_hash m_info_hash; std::string m_name; @@ -321,18 +321,19 @@ namespace libtorrent // be announced on the dht bool m_private; - // contains any non-parsed entries from the info-section - // these are kept in order to be able to accurately - // reproduce the info-section when sending the metadata - // to peers. - entry m_extra_info; + // this is a copy of the info section from the torrent. + // it use maintained in this flat format in order to + // make it available through the metadata extension + boost::shared_array m_info_section; + int m_info_section_size; -#ifndef NDEBUG - public: - // this is set to true when seed_free() is called - bool m_half_metadata; - private: -#endif + // this is a pointer into the m_info_section buffer + // pointing to the first byte of the first sha-1 hash + char const* m_piece_hashes; + + // the info section parsed. points into m_info_section + // parsed lazily + mutable lazy_entry m_info_dict; }; } diff --git a/libtorrent/include/libtorrent/tracker_manager.hpp b/libtorrent/include/libtorrent/tracker_manager.hpp index 2d8df1a36..c9d1f52c6 100755 --- a/libtorrent/include/libtorrent/tracker_manager.hpp +++ b/libtorrent/include/libtorrent/tracker_manager.hpp @@ -74,9 +74,6 @@ namespace libtorrent // returns -1 if gzip header is invalid or the header size in bytes TORRENT_EXPORT int gzip_header(const char* buf, int size); - TORRENT_EXPORT boost::tuple - parse_url_components(std::string url); - struct TORRENT_EXPORT tracker_request { tracker_request() @@ -160,7 +157,7 @@ namespace libtorrent private: - void timeout_callback(asio::error_code const&); + void timeout_callback(error_code const&); boost::intrusive_ptr self() { return boost::intrusive_ptr(this); } diff --git a/libtorrent/include/libtorrent/udp_socket.hpp b/libtorrent/include/libtorrent/udp_socket.hpp index 376e71ce1..77eae5050 100644 --- a/libtorrent/include/libtorrent/udp_socket.hpp +++ b/libtorrent/include/libtorrent/udp_socket.hpp @@ -46,16 +46,16 @@ namespace libtorrent class udp_socket { public: - typedef boost::function callback_t; - udp_socket(asio::io_service& ios, callback_t const& c, connection_queue& cc); + udp_socket(io_service& ios, callback_t const& c, connection_queue& cc); bool is_open() const { return m_ipv4_sock.is_open() || m_ipv6_sock.is_open(); } - asio::io_service& get_io_service() { return m_ipv4_sock.get_io_service(); } + io_service& get_io_service() { return m_ipv4_sock.get_io_service(); } - void send(udp::endpoint const& ep, char const* p, int len, asio::error_code& ec); - void bind(udp::endpoint const& ep, asio::error_code& ec); + void send(udp::endpoint const& ep, char const* p, int len, error_code& ec); + void bind(udp::endpoint const& ep, error_code& ec); void bind(int port); void close(); int local_port() const { return m_bind_port; } @@ -67,21 +67,21 @@ namespace libtorrent callback_t m_callback; - void on_read(udp::socket* sock, asio::error_code const& e, std::size_t bytes_transferred); - void on_name_lookup(asio::error_code const& e, tcp::resolver::iterator i); + void on_read(udp::socket* sock, error_code const& e, std::size_t bytes_transferred); + void on_name_lookup(error_code const& e, tcp::resolver::iterator i); void on_timeout(); void on_connect(int ticket); - void on_connected(asio::error_code const& ec); - void handshake1(asio::error_code const& e); - void handshake2(asio::error_code const& e); - void handshake3(asio::error_code const& e); - void handshake4(asio::error_code const& e); + void on_connected(error_code const& ec); + void handshake1(error_code const& e); + void handshake2(error_code const& e); + void handshake3(error_code const& e); + void handshake4(error_code const& e); void socks_forward_udp(); - void connect1(asio::error_code const& e); - void connect2(asio::error_code const& e); + void connect1(error_code const& e); + void connect2(error_code const& e); - void wrap(udp::endpoint const& ep, char const* p, int len, asio::error_code& ec); - void unwrap(asio::error_code const& e, char const* buf, int size); + void wrap(udp::endpoint const& ep, char const* p, int len, error_code& ec); + void unwrap(error_code const& e, char const* buf, int size); udp::socket m_ipv4_sock; udp::socket m_ipv6_sock; diff --git a/libtorrent/include/libtorrent/udp_tracker_connection.hpp b/libtorrent/include/libtorrent/udp_tracker_connection.hpp index b245f932d..dd0dea9fe 100755 --- a/libtorrent/include/libtorrent/udp_tracker_connection.hpp +++ b/libtorrent/include/libtorrent/udp_tracker_connection.hpp @@ -89,10 +89,10 @@ namespace libtorrent boost::intrusive_ptr self() { return boost::intrusive_ptr(this); } - void name_lookup(asio::error_code const& error, udp::resolver::iterator i); - void timeout(asio::error_code const& error); + void name_lookup(error_code const& error, udp::resolver::iterator i); + void timeout(error_code const& error); - void on_receive(asio::error_code const& e, udp::endpoint const& ep + void on_receive(error_code const& e, udp::endpoint const& ep , char const* buf, int size); void on_connect_response(char const* buf, int size); void on_announce_response(char const* buf, int size); diff --git a/libtorrent/include/libtorrent/upnp.hpp b/libtorrent/include/libtorrent/upnp.hpp index 7455fbf72..4b597071b 100644 --- a/libtorrent/include/libtorrent/upnp.hpp +++ b/libtorrent/include/libtorrent/upnp.hpp @@ -93,7 +93,7 @@ private: enum { default_lease_time = 3600 }; - void resend_request(asio::error_code const& e); + void resend_request(error_code const& e); void on_reply(udp::endpoint const& from, char* buffer , std::size_t bytes_transferred); @@ -102,15 +102,16 @@ private: void update_map(rootdevice& d, int i); - void on_upnp_xml(asio::error_code const& e - , libtorrent::http_parser const& p, rootdevice& d); - void on_upnp_map_response(asio::error_code const& e + void on_upnp_xml(error_code const& e , libtorrent::http_parser const& p, rootdevice& d - , int mapping); - void on_upnp_unmap_response(asio::error_code const& e + , http_connection& c); + void on_upnp_map_response(error_code const& e , libtorrent::http_parser const& p, rootdevice& d - , int mapping); - void on_expire(asio::error_code const& e); + , int mapping, http_connection& c); + void on_upnp_unmap_response(error_code const& e + , libtorrent::http_parser const& p, rootdevice& d + , int mapping, http_connection& c); + void on_expire(error_code const& e); void disable(char const* msg); void return_error(int mapping, int code); @@ -237,7 +238,7 @@ private: // current retry count int m_retry_count; - asio::io_service& m_io_service; + io_service& m_io_service; // the udp socket used to send and receive // multicast messages on the network @@ -252,7 +253,7 @@ private: bool m_disabled; bool m_closing; - bool m_ignore_outside_network; + bool m_ignore_non_routers; connection_queue& m_cc; diff --git a/libtorrent/include/libtorrent/variant_stream.hpp b/libtorrent/include/libtorrent/variant_stream.hpp index 30d972e31..3551f5c9e 100644 --- a/libtorrent/include/libtorrent/variant_stream.hpp +++ b/libtorrent/include/libtorrent/variant_stream.hpp @@ -21,7 +21,11 @@ # include # include +#if BOOST_VERSION < 103500 #include +#else +#include +#endif # define NETWORK_VARIANT_STREAM_LIMIT 5 @@ -48,7 +52,7 @@ namespace aux template struct io_control_visitor_ec: boost::static_visitor<> { - io_control_visitor_ec(IO_Control_Command& ioc, asio::error_code& ec_) + io_control_visitor_ec(IO_Control_Command& ioc, error_code& ec_) : ioc(ioc), ec(ec_) {} template @@ -61,7 +65,7 @@ namespace aux {} IO_Control_Command& ioc; - asio::error_code& ec; + error_code& ec; }; template @@ -112,7 +116,7 @@ namespace aux struct bind_visitor_ec : boost::static_visitor<> { - bind_visitor_ec(EndpointType const& ep, asio::error_code& ec_) + bind_visitor_ec(EndpointType const& ep, error_code& ec_) : endpoint(ep) , ec(ec_) {} @@ -124,7 +128,7 @@ namespace aux void operator()(boost::blank) const {} EndpointType const& endpoint; - asio::error_code& ec; + error_code& ec; }; template @@ -150,7 +154,7 @@ namespace aux struct open_visitor_ec : boost::static_visitor<> { - open_visitor_ec(Protocol const& p, asio::error_code& ec_) + open_visitor_ec(Protocol const& p, error_code& ec_) : proto(p) , ec(ec_) {} @@ -162,7 +166,7 @@ namespace aux void operator()(boost::blank) const {} Protocol const& proto; - asio::error_code& ec; + error_code& ec; }; template @@ -201,7 +205,7 @@ namespace aux struct close_visitor_ec : boost::static_visitor<> { - close_visitor_ec(asio::error_code& ec_) + close_visitor_ec(error_code& ec_) : ec(ec_) {} @@ -211,7 +215,7 @@ namespace aux void operator()(boost::blank) const {} - asio::error_code& ec; + error_code& ec; }; struct close_visitor @@ -230,18 +234,18 @@ namespace aux struct remote_endpoint_visitor_ec : boost::static_visitor { - remote_endpoint_visitor_ec(asio::error_code& ec) - : error_code(ec) + remote_endpoint_visitor_ec(error_code& ec_) + : ec(ec_) {} template EndpointType operator()(T const* p) const - { return p->remote_endpoint(error_code); } + { return p->remote_endpoint(ec); } EndpointType operator()(boost::blank) const { return EndpointType(); } - asio::error_code& error_code; + error_code& ec; }; template @@ -270,29 +274,29 @@ namespace aux void operator()(T* p) const { p->set_option(opt_); } - void operator()(boost::blank) const {} + void operator()(boost::blank) const {} SettableSocketOption const& opt_; }; template struct set_option_visitor_ec - : boost::static_visitor + : boost::static_visitor { - set_option_visitor_ec(SettableSocketOption const& opt, asio::error_code& ec) + set_option_visitor_ec(SettableSocketOption const& opt, error_code& ec) : opt_(opt) , ec_(ec) {} template - asio::error_code operator()(T* p) const + error_code operator()(T* p) const { return p->set_option(opt_, ec_); } - asio::error_code operator()(boost::blank) const + error_code operator()(boost::blank) const { return ec_; } SettableSocketOption const& opt_; - asio::error_code& ec_; + error_code& ec_; }; // -------------- local_endpoint ----------- @@ -301,14 +305,14 @@ namespace aux struct local_endpoint_visitor_ec : boost::static_visitor { - local_endpoint_visitor_ec(asio::error_code& ec) - : error_code(ec) + local_endpoint_visitor_ec(error_code& ec_) + : ec(ec_) {} template EndpointType operator()(T const* p) const { - return p->local_endpoint(error_code); + return p->local_endpoint(ec); } EndpointType operator()(boost::blank) const @@ -316,7 +320,7 @@ namespace aux return EndpointType(); } - asio::error_code& error_code; + error_code& ec; }; template @@ -372,7 +376,7 @@ namespace aux std::size_t operator()(T* p) const { return p->read_some(buffers); } - std::size_t operator()(boost::blank) const + std::size_t operator()(boost::blank) const { return 0; } Mutable_Buffers const& buffers; @@ -382,7 +386,7 @@ namespace aux struct read_some_visitor_ec : boost::static_visitor { - read_some_visitor_ec(Mutable_Buffers const& buffers, asio::error_code& ec_) + read_some_visitor_ec(Mutable_Buffers const& buffers, error_code& ec_) : buffers(buffers) , ec(ec_) {} @@ -391,11 +395,11 @@ namespace aux std::size_t operator()(T* p) const { return p->read_some(buffers, ec); } - std::size_t operator()(boost::blank) const + std::size_t operator()(boost::blank) const { return 0; } Mutable_Buffers const& buffers; - asio::error_code& ec; + error_code& ec; }; // -------------- async_write_some ----------- @@ -427,7 +431,7 @@ namespace aux struct in_avail_visitor_ec : boost::static_visitor { - in_avail_visitor_ec(asio::error_code& ec_) + in_avail_visitor_ec(error_code& ec_) : ec(ec_) {} @@ -442,7 +446,7 @@ namespace aux return 0; } - asio::error_code& ec; + error_code& ec; }; struct in_avail_visitor @@ -524,11 +528,11 @@ public: typedef typename S0::endpoint_type endpoint_type; typedef typename S0::protocol_type protocol_type; - explicit variant_stream(asio::io_service& ios) + explicit variant_stream(io_service& ios) : m_io_service(ios), m_variant(boost::blank()) {} template - void instantiate(asio::io_service& ios) + void instantiate(io_service& ios) { TORRENT_ASSERT(&ios == &m_io_service); std::auto_ptr owned(new S(ios)); @@ -540,7 +544,7 @@ public: template S& get() { - return *boost::get(m_variant); + return *boost::get(m_variant); } bool instantiated() const @@ -554,7 +558,7 @@ public: } template - std::size_t read_some(Mutable_Buffers const& buffers, asio::error_code& ec) + std::size_t read_some(Mutable_Buffers const& buffers, error_code& ec) { TORRENT_ASSERT(instantiated()); return boost::apply_visitor( @@ -612,7 +616,7 @@ public: } template - void io_control(IO_Control_Command& ioc, asio::error_code& ec) + void io_control(IO_Control_Command& ioc, error_code& ec) { TORRENT_ASSERT(instantiated()); boost::apply_visitor( @@ -627,7 +631,7 @@ public: boost::apply_visitor(aux::bind_visitor(endpoint), m_variant); } - void bind(endpoint_type const& endpoint, asio::error_code& ec) + void bind(endpoint_type const& endpoint, error_code& ec) { TORRENT_ASSERT(instantiated()); boost::apply_visitor( @@ -641,7 +645,7 @@ public: boost::apply_visitor(aux::open_visitor(p), m_variant); } - void open(protocol_type const& p, asio::error_code& ec) + void open(protocol_type const& p, error_code& ec) { TORRENT_ASSERT(instantiated()); boost::apply_visitor( @@ -660,7 +664,7 @@ public: boost::apply_visitor(aux::close_visitor(), m_variant); } - void close(asio::error_code& ec) + void close(error_code& ec) { if (!instantiated()) return; boost::apply_visitor( @@ -674,7 +678,7 @@ public: return boost::apply_visitor(aux::in_avail_visitor(), m_variant); } - std::size_t in_avail(asio::error_code& ec) const + std::size_t in_avail(error_code& ec) const { TORRENT_ASSERT(instantiated()); return boost::apply_visitor( @@ -688,7 +692,7 @@ public: return boost::apply_visitor(aux::remote_endpoint_visitor(), m_variant); } - endpoint_type remote_endpoint(asio::error_code& ec) const + endpoint_type remote_endpoint(error_code& ec) const { TORRENT_ASSERT(instantiated()); return boost::apply_visitor( @@ -705,20 +709,20 @@ public: } template - asio::error_code set_option(SettableSocketOption const& opt, asio::error_code& ec) + error_code set_option(SettableSocketOption const& opt, error_code& ec) { TORRENT_ASSERT(instantiated()); return boost::apply_visitor(aux::set_option_visitor_ec(opt, ec) , m_variant); } - + endpoint_type local_endpoint() const { TORRENT_ASSERT(instantiated()); return boost::apply_visitor(aux::local_endpoint_visitor(), m_variant); } - endpoint_type local_endpoint(asio::error_code& ec) const + endpoint_type local_endpoint(error_code& ec) const { TORRENT_ASSERT(instantiated()); return boost::apply_visitor( @@ -726,7 +730,7 @@ public: ); } - asio::io_service& get_io_service() + io_service& get_io_service() { return m_io_service; } @@ -740,7 +744,7 @@ public: } private: - asio::io_service& m_io_service; + io_service& m_io_service; variant_type m_variant; }; diff --git a/libtorrent/include/libtorrent/web_peer_connection.hpp b/libtorrent/include/libtorrent/web_peer_connection.hpp index f9d235bbc..c37608232 100755 --- a/libtorrent/include/libtorrent/web_peer_connection.hpp +++ b/libtorrent/include/libtorrent/web_peer_connection.hpp @@ -102,9 +102,9 @@ namespace libtorrent // called from the main loop when this connection has any // work to do. - void on_sent(asio::error_code const& error + void on_sent(error_code const& error , std::size_t bytes_transferred); - void on_receive(asio::error_code const& error + void on_receive(error_code const& error , std::size_t bytes_transferred); std::string const& url() const { return m_url; } diff --git a/libtorrent/src/GeoIP.c b/libtorrent/src/GeoIP.c index 2df4b5562..6ca0e51d8 100644 --- a/libtorrent/src/GeoIP.c +++ b/libtorrent/src/GeoIP.c @@ -18,7 +18,7 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "GeoIP.h" +#include "libtorrent/GeoIP.h" #ifndef WIN32 #include diff --git a/libtorrent/src/broadcast_socket.cpp b/libtorrent/src/broadcast_socket.cpp index 64f41b7e2..2a087ef79 100644 --- a/libtorrent/src/broadcast_socket.cpp +++ b/libtorrent/src/broadcast_socket.cpp @@ -30,8 +30,14 @@ POSSIBILITY OF SUCH DAMAGE. */ +#if BOOST_VERSION < 103500 #include #include +#else +#include +#include +#endif + #include #include "libtorrent/socket.hpp" @@ -75,10 +81,10 @@ namespace libtorrent return addr.to_v6() == address_v6::any(); } - address guess_local_address(asio::io_service& ios) + address guess_local_address(io_service& ios) { // make a best guess of the interface we're using and its IP - asio::error_code ec; + error_code ec; std::vector const& interfaces = enum_net_interfaces(ios, ec); address ret = address_v4::any(); for (std::vector::const_iterator i = interfaces.begin() @@ -137,7 +143,7 @@ namespace libtorrent - common_bits(b1.c_array(), b2.c_array(), b1.size()); } - broadcast_socket::broadcast_socket(asio::io_service& ios + broadcast_socket::broadcast_socket(io_service& ios , udp::endpoint const& multicast_endpoint , receive_handler_t const& handler , bool loopback) @@ -148,7 +154,7 @@ namespace libtorrent using namespace asio::ip::multicast; - asio::error_code ec; + error_code ec; std::vector interfaces = enum_net_interfaces(ios, ec); if (multicast_endpoint.address().is_v4()) @@ -179,7 +185,7 @@ namespace libtorrent { using namespace asio::ip::multicast; - asio::error_code ec; + error_code ec; boost::shared_ptr s(new datagram_socket(ios)); if (addr.is_v4()) s->open(udp::v4(), ec); @@ -205,7 +211,7 @@ namespace libtorrent void broadcast_socket::open_unicast_socket(io_service& ios, address const& addr) { using namespace asio::ip::multicast; - asio::error_code ec; + error_code ec; boost::shared_ptr s(new datagram_socket(ios)); s->open(addr.is_v4() ? udp::v4() : udp::v6(), ec); if (ec) return; @@ -220,13 +226,13 @@ namespace libtorrent , se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2)); } - void broadcast_socket::send(char const* buffer, int size, asio::error_code& ec) + void broadcast_socket::send(char const* buffer, int size, error_code& ec) { for (std::list::iterator i = m_unicast_sockets.begin() , end(m_unicast_sockets.end()); i != end; ++i) { if (!i->socket) continue; - asio::error_code e; + error_code e; i->socket->send_to(asio::buffer(buffer, size), m_multicast_endpoint, 0, e); #ifndef NDEBUG // std::cerr << " sending on " << i->socket->local_endpoint().address().to_string() << " to: " << m_multicast_endpoint << std::endl; @@ -239,7 +245,7 @@ namespace libtorrent } } - void broadcast_socket::on_receive(socket_entry* s, asio::error_code const& ec + void broadcast_socket::on_receive(socket_entry* s, error_code const& ec , std::size_t bytes_transferred) { if (ec || bytes_transferred == 0 || !m_on_receive) return; diff --git a/libtorrent/src/bt_peer_connection.cpp b/libtorrent/src/bt_peer_connection.cpp index b021e8cb1..80ee9fe1c 100755 --- a/libtorrent/src/bt_peer_connection.cpp +++ b/libtorrent/src/bt_peer_connection.cpp @@ -125,8 +125,9 @@ namespace libtorrent bt_peer_connection::bt_peer_connection( session_impl& ses , boost::shared_ptr s + , tcp::endpoint const& remote , policy::peer* peerinfo) - : peer_connection(ses, s, peerinfo) + : peer_connection(ses, s, remote, peerinfo) , m_state(read_protocol_identifier) #ifndef TORRENT_DISABLE_EXTENSIONS , m_supports_extensions(false) @@ -800,13 +801,14 @@ namespace libtorrent TORRENT_ASSERT(received > 0); if (packet_size() != 1) { - disconnect("'choke' message size != 1"); + disconnect("'choke' message size != 1", 2); return; } m_statistics.received_bytes(0, received); if (!packet_finished()) return; incoming_choke(); + if (is_disconnecting()) return; if (!m_supports_fast) { boost::shared_ptr t = associated_torrent().lock(); @@ -834,7 +836,7 @@ namespace libtorrent TORRENT_ASSERT(received > 0); if (packet_size() != 1) { - disconnect("'unchoke' message size != 1"); + disconnect("'unchoke' message size != 1", 2); return; } m_statistics.received_bytes(0, received); @@ -854,7 +856,7 @@ namespace libtorrent TORRENT_ASSERT(received > 0); if (packet_size() != 1) { - disconnect("'interested' message size != 1"); + disconnect("'interested' message size != 1", 2); return; } m_statistics.received_bytes(0, received); @@ -874,7 +876,7 @@ namespace libtorrent TORRENT_ASSERT(received > 0); if (packet_size() != 1) { - disconnect("'not interested' message size != 1"); + disconnect("'not interested' message size != 1", 2); return; } m_statistics.received_bytes(0, received); @@ -894,7 +896,7 @@ namespace libtorrent TORRENT_ASSERT(received > 0); if (packet_size() != 5) { - disconnect("'have' message size != 5"); + disconnect("'have' message size != 5", 2); return; } m_statistics.received_bytes(0, received); @@ -926,7 +928,7 @@ namespace libtorrent if (t->valid_metadata() && packet_size() - 1 != ((int)get_bitfield().size() + 7) / 8) { - disconnect("bitfield with invalid size"); + disconnect("bitfield with invalid size", 2); return; } @@ -963,7 +965,7 @@ namespace libtorrent TORRENT_ASSERT(received > 0); if (packet_size() != 13) { - disconnect("'request' message size != 13"); + disconnect("'request' message size != 13", 2); return; } m_statistics.received_bytes(0, received); @@ -1021,6 +1023,7 @@ namespace libtorrent } incoming_piece_fragment(); + if (is_disconnecting()) return; if (!packet_finished()) return; const char* ptr = recv_buffer.begin + 1; @@ -1044,7 +1047,7 @@ namespace libtorrent TORRENT_ASSERT(received > 0); if (packet_size() != 13) { - disconnect("'cancel' message size != 13"); + disconnect("'cancel' message size != 13", 2); return; } m_statistics.received_bytes(0, received); @@ -1071,14 +1074,14 @@ namespace libtorrent if (!m_supports_dht_port) { - disconnect("got 'dht_port' message from peer that doesn't support it"); + disconnect("got 'dht_port' message from peer that doesn't support it", 2); return; } TORRENT_ASSERT(received > 0); if (packet_size() != 3) { - disconnect("'dht_port' message size != 3"); + disconnect("'dht_port' message size != 3", 2); return; } m_statistics.received_bytes(0, received); @@ -1098,7 +1101,7 @@ namespace libtorrent if (!m_supports_fast) { - disconnect("got 'suggest_piece' without FAST excension support"); + disconnect("got 'suggest_piece' without FAST excension support", 2); return; } @@ -1118,7 +1121,7 @@ namespace libtorrent if (!m_supports_fast) { - disconnect("got 'have_all' without FAST extension support"); + disconnect("got 'have_all' without FAST extension support", 2); return; } m_statistics.received_bytes(0, received); @@ -1131,7 +1134,7 @@ namespace libtorrent if (!m_supports_fast) { - disconnect("got 'have_none' without FAST extension support"); + disconnect("got 'have_none' without FAST extension support", 2); return; } m_statistics.received_bytes(0, received); @@ -1144,7 +1147,7 @@ namespace libtorrent if (!m_supports_fast) { - disconnect("got 'reject_request' without FAST extension support"); + disconnect("got 'reject_request' without FAST extension support", 2); return; } @@ -1168,7 +1171,7 @@ namespace libtorrent if (!m_supports_fast) { - disconnect("got 'allowed_fast' without FAST extension support"); + disconnect("got 'allowed_fast' without FAST extension support", 2); return; } @@ -1193,13 +1196,13 @@ namespace libtorrent m_statistics.received_bytes(0, received); if (packet_size() < 2) { - disconnect("'extended' message smaller than 2 bytes"); + disconnect("'extended' message smaller than 2 bytes", 2); return; } if (associated_torrent().expired()) { - disconnect("'extended' message sent before proper handshake"); + disconnect("'extended' message sent before proper handshake", 2); return; } @@ -1229,7 +1232,7 @@ namespace libtorrent std::stringstream msg; msg << "unknown extended message id: " << extended_id; - disconnect(msg.str().c_str()); + disconnect(msg.str().c_str(), 2); return; } @@ -1298,6 +1301,12 @@ namespace libtorrent m_max_out_request_queue = 1; } + if (entry* upload_only = root.find_key("upload_only")) + { + if (upload_only->type() == entry::int_t && upload_only->integer() != 0) + set_upload_only(true); + } + if (entry* myip = root.find_key("yourip")) { // TODO: don't trust this blindly @@ -1318,6 +1327,11 @@ namespace libtorrent } } } + + // if we're finished and this peer is uploading only + // disconnect it + if (t->is_finished() && upload_only()) + disconnect("upload to upload connection, closing"); } bool bt_peer_connection::dispatch_message(int received) @@ -1350,7 +1364,7 @@ namespace libtorrent std::stringstream msg; msg << "unkown message id: " << packet_type << " size: " << packet_size(); - disconnect(msg.str().c_str()); + disconnect(msg.str().c_str(), 2); return packet_finished(); } @@ -1553,6 +1567,9 @@ namespace libtorrent detail::write_address(remote().address(), out); handshake["yourip"] = remote_address; handshake["reqq"] = m_ses.settings().max_allowed_in_request_queue; + boost::shared_ptr t = associated_torrent().lock(); + TORRENT_ASSERT(t); + if (t->is_finished()) handshake["upload_only"] = 1; tcp::endpoint ep = m_ses.get_ipv6_interface(); if (ep != tcp::endpoint()) @@ -1671,7 +1688,7 @@ namespace libtorrent detail::write_int32(r.start, ptr); send_buffer(msg, sizeof(msg)); - append_send_buffer(buffer.buffer(), r.length + append_send_buffer(buffer.get(), r.length , boost::bind(&session_impl::free_disk_buffer , boost::ref(m_ses), _1)); buffer.release(); @@ -1707,7 +1724,7 @@ namespace libtorrent // -------------------------- // throws exception when the client should be disconnected - void bt_peer_connection::on_receive(asio::error_code const& error + void bt_peer_connection::on_receive(error_code const& error , std::size_t bytes_transferred) { INVARIANT_CHECK; @@ -1802,7 +1819,7 @@ namespace libtorrent if (recv_buffer.left() < 20) { if (packet_finished()) - disconnect("sync hash not found"); + disconnect("sync hash not found", 2); return; } @@ -1828,7 +1845,7 @@ namespace libtorrent m_sync_bytes_read += bytes_processed; if (m_sync_bytes_read >= 512) { - disconnect("sync hash not found within 532 bytes"); + disconnect("sync hash not found within 532 bytes", 2); return; } @@ -1913,7 +1930,7 @@ namespace libtorrent if (!m_RC4_handler.get()) { - disconnect("invalid streamkey identifier (info hash) in encrypted handshake"); + disconnect("invalid streamkey identifier (info hash) in encrypted handshake", 2); return; } @@ -1925,7 +1942,7 @@ namespace libtorrent const char sh_vc[] = {0,0,0,0, 0,0,0,0}; if (!std::equal(sh_vc, sh_vc+8, recv_buffer.begin + 20)) { - disconnect("unable to verify constant"); + disconnect("unable to verify constant", 2); return; } @@ -1947,7 +1964,7 @@ namespace libtorrent if (recv_buffer.left() < 8) { if (packet_finished()) - disconnect("sync verification constant not found"); + disconnect("sync verification constant not found", 2); return; } @@ -1972,7 +1989,7 @@ namespace libtorrent m_sync_bytes_read += bytes_processed; if (m_sync_bytes_read >= 512) { - disconnect("sync verification constant not found within 520 bytes"); + disconnect("sync verification constant not found within 520 bytes", 2); return; } @@ -2035,7 +2052,7 @@ namespace libtorrent case pe_settings::plaintext: if (!(crypto_field & 0x01)) { - disconnect("plaintext not provided"); + disconnect("plaintext not provided", 1); return; } crypto_select = 0x01; @@ -2043,7 +2060,7 @@ namespace libtorrent case pe_settings::rc4: if (!(crypto_field & 0x02)) { - disconnect("rc4 not provided"); + disconnect("rc4 not provided", 1); return; } crypto_select = 0x02; @@ -2065,7 +2082,7 @@ namespace libtorrent } if (!crypto_select) { - disconnect("rc4/plaintext not provided"); + disconnect("rc4/plaintext not provided", 1); return; } break; @@ -2083,7 +2100,7 @@ namespace libtorrent { if (allowed_enc_level == pe_settings::plaintext) { - disconnect("rc4 selected by peer when not provided"); + disconnect("rc4 selected by peer when not provided", 2); return; } m_rc4_encrypted = true; @@ -2092,14 +2109,14 @@ namespace libtorrent { if (allowed_enc_level == pe_settings::rc4) { - disconnect("plaintext selected by peer when not provided"); + disconnect("plaintext selected by peer when not provided", 2); return; } m_rc4_encrypted = false; } else { - disconnect("unsupported crypto method selected by peer"); + disconnect("unsupported crypto method selected by peer", 2); return; } } @@ -2107,7 +2124,7 @@ namespace libtorrent int len_pad = detail::read_int16(recv_buffer.begin); if (len_pad < 0 || len_pad > 512) { - disconnect("invalid pad length"); + disconnect("invalid pad length", 2); return; } @@ -2145,7 +2162,7 @@ namespace libtorrent if (len_ia < 0) { - disconnect("invalid len_ia in handshake"); + disconnect("invalid len_ia in handshake", 2); return; } @@ -2277,7 +2294,7 @@ namespace libtorrent TORRENT_ASSERT((!is_local() && m_encrypted) || is_local()); #endif // #ifndef TORRENT_DISABLE_ENCRYPTION - disconnect("incorrect protocol identifier"); + disconnect("incorrect protocol identifier", 2); return; } @@ -2329,6 +2346,7 @@ namespace libtorrent #endif #ifndef DISABLE_EXTENSIONS + std::memcpy(m_reserved_bits, recv_buffer.begin, 20); if ((recv_buffer[5] & 0x10)) m_supports_extensions = true; #endif @@ -2360,7 +2378,7 @@ namespace libtorrent #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << " received invalid info_hash\n"; #endif - disconnect("invalid info-hash in handshake"); + disconnect("invalid info-hash in handshake", 2); return; } @@ -2449,8 +2467,7 @@ namespace libtorrent if (pid == m_ses.get_peer_id()) { - set_failed(); - disconnect("closing connection to ourself"); + disconnect("closing connection to ourself", 1); return; } @@ -2466,8 +2483,7 @@ namespace libtorrent // since it most likely is ourself then if (pid == m_ses.get_peer_id()) { - set_failed(); - disconnect("closing connection to ourself"); + disconnect("closing connection to ourself", 1); return; } @@ -2475,7 +2491,7 @@ namespace libtorrent for (extension_list_t::iterator i = m_extensions.begin() , end(m_extensions.end()); i != end;) { - if (!(*i)->on_handshake()) + if (!(*i)->on_handshake(m_reserved_bits)) { i = m_extensions.erase(i); } @@ -2484,6 +2500,7 @@ namespace libtorrent ++i; } } + if (is_disconnecting()) return; if (m_supports_extensions) write_extensions(); #endif @@ -2542,13 +2559,14 @@ namespace libtorrent // packet too large std::stringstream msg; msg << "packet > 1 MB (" << (unsigned int)packet_size << " bytes)"; - disconnect(msg.str().c_str()); + disconnect(msg.str().c_str(), 2); return; } if (packet_size == 0) { incoming_keepalive(); + if (is_disconnecting()) return; // keepalive message m_state = read_packet_size; cut_receive_buffer(4, 4); @@ -2586,8 +2604,7 @@ namespace libtorrent // SEND DATA // -------------------------- - // throws exception when the client should be disconnected - void bt_peer_connection::on_sent(asio::error_code const& error + void bt_peer_connection::on_sent(error_code const& error , std::size_t bytes_transferred) { INVARIANT_CHECK; diff --git a/libtorrent/src/connection_queue.cpp b/libtorrent/src/connection_queue.cpp index ded24dbda..548fe07e6 100644 --- a/libtorrent/src/connection_queue.cpp +++ b/libtorrent/src/connection_queue.cpp @@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include "libtorrent/invariant_check.hpp" #include "libtorrent/connection_queue.hpp" +#include "libtorrent/socket.hpp" namespace libtorrent { @@ -112,7 +113,7 @@ namespace libtorrent void connection_queue::close() { - asio::error_code ec; + error_code ec; m_timer.cancel(ec); } @@ -153,7 +154,7 @@ namespace libtorrent if (m_queue.empty()) { - asio::error_code ec; + error_code ec; m_timer.cancel(ec); return; } @@ -166,7 +167,7 @@ namespace libtorrent ptime expire = time_now() + i->timeout; if (m_num_connecting == 0) { - asio::error_code ec; + error_code ec; m_timer.expires_at(expire, ec); m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1)); } @@ -206,7 +207,7 @@ namespace libtorrent }; #endif - void connection_queue::on_timeout(asio::error_code const& e) + void connection_queue::on_timeout(error_code const& e) { mutex_t::scoped_lock l(m_mutex); @@ -251,7 +252,7 @@ namespace libtorrent if (next_expire < max_time()) { - asio::error_code ec; + error_code ec; m_timer.expires_at(next_expire, ec); m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1)); } diff --git a/libtorrent/src/disk_buffer_holder.cpp b/libtorrent/src/disk_buffer_holder.cpp index 01e0f21ce..1ee83e93e 100644 --- a/libtorrent/src/disk_buffer_holder.cpp +++ b/libtorrent/src/disk_buffer_holder.cpp @@ -49,6 +49,12 @@ namespace libtorrent TORRENT_ASSERT(buf == 0 || m_iothread.is_disk_buffer(buf)); } + void disk_buffer_holder::reset(char* buf) + { + if (m_buf) m_iothread.free_buffer(m_buf); + m_buf = buf; + } + char* disk_buffer_holder::release() { char* ret = m_buf; diff --git a/libtorrent/src/disk_io_thread.cpp b/libtorrent/src/disk_io_thread.cpp index ecb18b6de..ac76263ce 100644 --- a/libtorrent/src/disk_io_thread.cpp +++ b/libtorrent/src/disk_io_thread.cpp @@ -182,7 +182,6 @@ namespace libtorrent disk_io_thread::cache_t& cache , disk_io_job const& j, mutex_t::scoped_lock& l) { - TORRENT_ASSERT(l.locked()); for (cache_t::iterator i = cache.begin() , end(cache.end()); i != end; ++i) { @@ -196,7 +195,6 @@ namespace libtorrent { ptime now = time_now(); - TORRENT_ASSERT(l.locked()); INVARIANT_CHECK; for (;;) { @@ -213,7 +211,6 @@ namespace libtorrent void disk_io_thread::free_piece(cached_piece_entry& p, mutex_t::scoped_lock& l) { - TORRENT_ASSERT(l.locked()); int piece_size = p.storage->info()->piece_size(p.piece); int blocks_in_piece = (piece_size + m_block_size - 1) / m_block_size; @@ -251,7 +248,6 @@ namespace libtorrent void disk_io_thread::flush_oldest_piece(mutex_t::scoped_lock& l) { - TORRENT_ASSERT(l.locked()); INVARIANT_CHECK; // first look if there are any read cache entries that can // be cleared @@ -275,7 +271,6 @@ namespace libtorrent void disk_io_thread::flush(disk_io_thread::cache_t::iterator e , mutex_t::scoped_lock& l) { - TORRENT_ASSERT(l.locked()); INVARIANT_CHECK; cached_piece_entry& p = *e; int piece_size = p.storage->info()->piece_size(p.piece); @@ -340,7 +335,6 @@ namespace libtorrent void disk_io_thread::cache_block(disk_io_job& j, mutex_t::scoped_lock& l) { - TORRENT_ASSERT(l.locked()); INVARIANT_CHECK; TORRENT_ASSERT(find_cached_piece(m_pieces, j, l) == m_pieces.end()); cached_piece_entry p; @@ -365,8 +359,6 @@ namespace libtorrent // read or -1 if there was an error int disk_io_thread::read_into_piece(cached_piece_entry& p, int start_block, mutex_t::scoped_lock& l) { - TORRENT_ASSERT(l.locked()); - int piece_size = p.storage->info()->piece_size(p.piece); int blocks_in_piece = (piece_size + m_block_size - 1) / m_block_size; @@ -436,8 +428,6 @@ namespace libtorrent , cache_t::iterator ignore , mutex_t::scoped_lock& l) { - TORRENT_ASSERT(l.locked()); - if (m_cache_size - m_cache_stats.cache_size < num_blocks) { // there's not enough room in the cache, clear a piece @@ -452,8 +442,6 @@ namespace libtorrent // or the number of bytes read int disk_io_thread::cache_read_block(disk_io_job const& j, mutex_t::scoped_lock& l) { - TORRENT_ASSERT(l.locked()); - INVARIANT_CHECK; int piece_size = j.storage->info()->piece_size(j.piece); @@ -543,7 +531,6 @@ namespace libtorrent int disk_io_thread::try_read_from_cache(disk_io_job const& j, mutex_t::scoped_lock& l) { - TORRENT_ASSERT(l.locked()); TORRENT_ASSERT(j.buffer); if (!m_use_read_cache) return -2; @@ -707,7 +694,6 @@ namespace libtorrent char* disk_io_thread::allocate_buffer(mutex_t::scoped_lock& l) { - TORRENT_ASSERT(l.locked()); #ifdef TORRENT_STATS ++m_allocations; #endif @@ -720,7 +706,6 @@ namespace libtorrent void disk_io_thread::free_buffer(char* buf, mutex_t::scoped_lock& l) { - TORRENT_ASSERT(l.locked()); #ifdef TORRENT_STATS --m_allocations; #endif diff --git a/libtorrent/src/entry.cpp b/libtorrent/src/entry.cpp index 2b8410115..59e5b061d 100755 --- a/libtorrent/src/entry.cpp +++ b/libtorrent/src/entry.cpp @@ -35,8 +35,10 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include "libtorrent/entry.hpp" #include "libtorrent/config.hpp" +#include "libtorrent/escape_string.hpp" #if defined(_MSC_VER) namespace std @@ -54,19 +56,6 @@ namespace TORRENT_ASSERT(o); o->~T(); } - - struct compare_string - { - compare_string(char const* s): m_str(s) {} - - bool operator()( - std::pair const& e) const - { - return m_str && e.first == m_str; - } - char const* m_str; - }; } namespace libtorrent @@ -94,6 +83,16 @@ namespace libtorrent } entry& entry::operator[](char const* key) + { + dictionary_type::iterator i = dict().find(key); + if (i != dict().end()) return i->second; + dictionary_type::iterator ret = dict().insert( + dict().begin() + , std::make_pair(key, entry())); + return ret->second; + } + + entry& entry::operator[](std::string const& key) { dictionary_type::iterator i = dict().find(key); if (i != dict().end()) return i->second; @@ -103,21 +102,11 @@ namespace libtorrent return ret->second; } - - entry& entry::operator[](std::string const& key) - { - return (*this)[key.c_str()]; - } - entry* entry::find_key(char const* key) { - dictionary_type::iterator i = std::find_if( - dict().begin() - , dict().end() - , compare_string(key)); + dictionary_type::iterator i = dict().find(key); if (i == dict().end()) return 0; return &i->second; - } entry const* entry::find_key(char const* key) const @@ -127,6 +116,20 @@ namespace libtorrent return &i->second; } + entry* entry::find_key(std::string const& key) + { + dictionary_type::iterator i = dict().find(key); + if (i == dict().end()) return 0; + return &i->second; + } + + entry const* entry::find_key(std::string const& key) const + { + dictionary_type::const_iterator i = dict().find(key); + if (i == dict().end()) return 0; + return &i->second; + } + #ifndef BOOST_NO_EXCEPTIONS const entry& entry::operator[](char const* key) const { @@ -370,21 +373,8 @@ namespace libtorrent break; } } - if (binary_string) - { - os.unsetf(std::ios_base::dec); - os.setf(std::ios_base::hex); - for (std::string::const_iterator i = string().begin(); i != string().end(); ++i) - os << std::setfill('0') << std::setw(2) - << static_cast((unsigned char)*i); - os.unsetf(std::ios_base::hex); - os.setf(std::ios_base::dec); - os << "\n"; - } - else - { - os << string() << "\n"; - } + if (binary_string) os << to_hex(string()) << "\n"; + else os << string() << "\n"; } break; case list_t: { @@ -399,8 +389,21 @@ namespace libtorrent os << "dictionary\n"; for (dictionary_type::const_iterator i = dict().begin(); i != dict().end(); ++i) { + bool binary_string = false; + for (std::string::const_iterator k = i->first.begin(); k != i->first.end(); ++k) + { + if (!std::isprint(static_cast(*k))) + { + binary_string = true; + break; + } + } for (int j = 0; j < indent+1; ++j) os << " "; - os << "[" << i->first << "]"; + os << "["; + if (binary_string) os << to_hex(i->first); + else os << i->first; + os << "]"; + if (i->second.type() != entry::string_t && i->second.type() != entry::int_t) os << "\n"; diff --git a/libtorrent/src/enum_net.cpp b/libtorrent/src/enum_net.cpp index 4fad81cdd..eb5a9eeef 100644 --- a/libtorrent/src/enum_net.cpp +++ b/libtorrent/src/enum_net.cpp @@ -35,8 +35,11 @@ POSSIBILITY OF SUCH DAMAGE. #include #include "libtorrent/enum_net.hpp" #include "libtorrent/broadcast_socket.hpp" +#if BOOST_VERSION < 103500 #include - +#else +#include +#endif #if defined TORRENT_BSD #include @@ -225,7 +228,7 @@ namespace libtorrent == (iface.interface_address.to_v4().to_ulong() & iface.netmask.to_v4().to_ulong()); } - bool in_local_network(asio::io_service& ios, address const& addr, asio::error_code& ec) + bool in_local_network(io_service& ios, address const& addr, error_code& ec) { std::vector const& net = enum_net_interfaces(ios, ec); if (ec) return false; @@ -237,7 +240,7 @@ namespace libtorrent return false; } - std::vector enum_net_interfaces(asio::io_service& ios, asio::error_code& ec) + std::vector enum_net_interfaces(io_service& ios, error_code& ec) { std::vector ret; // covers linux, MacOS X and BSD distributions @@ -254,7 +257,7 @@ namespace libtorrent ifc.ifc_buf = buf; if (ioctl(s, SIOCGIFCONF, &ifc) < 0) { - ec = asio::error_code(errno, asio::error::system_category); + ec = error_code(errno, asio::error::system_category); close(s); return ret; } @@ -283,7 +286,7 @@ namespace libtorrent } else { - ec = asio::error_code(errno, asio::error::system_category); + ec = error_code(errno, asio::error::system_category); close(s); return ret; } @@ -310,7 +313,7 @@ namespace libtorrent SOCKET s = socket(AF_INET, SOCK_DGRAM, 0); if (s == SOCKET_ERROR) { - ec = asio::error_code(WSAGetLastError(), asio::error::system_category); + ec = error_code(WSAGetLastError(), asio::error::system_category); return ret; } @@ -320,7 +323,7 @@ namespace libtorrent if (WSAIoctl(s, SIO_GET_INTERFACE_LIST, 0, 0, buffer, sizeof(buffer), &size, 0, 0) != 0) { - ec = asio::error_code(WSAGetLastError(), asio::error::system_category); + ec = error_code(WSAGetLastError(), asio::error::system_category); closesocket(s); return ret; } @@ -356,16 +359,21 @@ namespace libtorrent return ret; } - address get_default_gateway(asio::io_service& ios, asio::error_code& ec) + address get_default_gateway(io_service& ios, error_code& ec) { std::vector ret = enum_routes(ios, ec); +#ifdef TORRENT_WINDOWS + std::vector::iterator i = std::find_if(ret.begin(), ret.end() + , boost::bind(&is_loopback, boost::bind(&ip_route::destination, _1))); +#else std::vector::iterator i = std::find_if(ret.begin(), ret.end() , boost::bind(&ip_route::destination, _1) == address()); +#endif if (i == ret.end()) return address(); return i->gateway; } - std::vector enum_routes(asio::io_service& ios, asio::error_code& ec) + std::vector enum_routes(io_service& ios, error_code& ec) { std::vector ret; @@ -390,14 +398,14 @@ namespace libtorrent int s = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC); if (s == -1) { - ec = asio::error_code(errno, asio::error::system_category); + ec = error_code(errno, asio::error::system_category); return std::vector(); } int n = write(s, &m, len); if (n == -1) { - ec = asio::error_code(errno, asio::error::system_category); + ec = error_code(errno, asio::error::system_category); close(s); return std::vector(); } @@ -412,7 +420,7 @@ namespace libtorrent n = read(s, &m, len); if (n == -1) { - ec = asio::error_code(errno, asio::error::system_category); + ec = error_code(errno, asio::error::system_category); close(s); return std::vector(); } @@ -423,7 +431,7 @@ namespace libtorrent std::cout << " rtm_type: " << ptr->rtm_type << std::endl; if (ptr->rtm_errno) { - ec = asio::error_code(ptr->rtm_errno, asio::error::system_category); + ec = error_code(ptr->rtm_errno, asio::error::system_category); return std::vector(); } if (m.m_rtm.rtm_flags & RTF_UP == 0 @@ -475,7 +483,7 @@ namespace libtorrent size_t needed = 0; if (sysctl(mib, 6, 0, &needed, 0, 0) < 0) { - ec = asio::error_code(errno, asio::error::system_category); + ec = error_code(errno, asio::error::system_category); return std::vector(); } @@ -493,7 +501,7 @@ namespace libtorrent if (sysctl(mib, 6, buf.get(), &needed, 0, 0) < 0) { - ec = asio::error_code(errno, asio::error::system_category); + ec = error_code(errno, asio::error::system_category); return std::vector(); } @@ -547,7 +555,6 @@ namespace libtorrent return std::vector(); } - address ret; if (GetAdaptersInfo(adapter_info, &out_buf_size) == NO_ERROR) { for (PIP_ADAPTER_INFO adapter = adapter_info; @@ -555,14 +562,14 @@ namespace libtorrent { ip_route r; - r.source = address::from_string(adapter->IpAddressList.IpAddress.String, ec); + r.destination = address::from_string(adapter->IpAddressList.IpAddress.String, ec); r.gateway = address::from_string(adapter->GatewayList.IpAddress.String, ec); r.netmask = address::from_string(adapter->IpAddressList.IpMask.String, ec); - strcpy(r.name, adapter->AdapterName); + strncpy(r.name, adapter->AdapterName, sizeof(r.name)); if (ec) { - ec = asio::error_code(); + ec = error_code(); continue; } ret.push_back(r); @@ -573,8 +580,6 @@ namespace libtorrent free(adapter_info); FreeLibrary(iphlp); - return ret; - #elif defined TORRENT_LINUX enum { BUFSIZE = 8192 }; @@ -582,7 +587,7 @@ namespace libtorrent int sock = socket(PF_ROUTE, SOCK_DGRAM, NETLINK_ROUTE); if (sock < 0) { - ec = asio::error_code(errno, asio::error::system_category); + ec = error_code(errno, asio::error::system_category); return std::vector(); } @@ -600,7 +605,7 @@ namespace libtorrent if (send(sock, nl_msg, nl_msg->nlmsg_len, 0) < 0) { - ec = asio::error_code(errno, asio::error::system_category); + ec = error_code(errno, asio::error::system_category); close(sock); return std::vector(); } @@ -608,7 +613,7 @@ namespace libtorrent int len = read_nl_sock(sock, msg, BUFSIZE, seq, getpid()); if (len < 0) { - ec = asio::error_code(errno, asio::error::system_category); + ec = error_code(errno, asio::error::system_category); close(sock); return std::vector(); } diff --git a/libtorrent/src/escape_string.cpp b/libtorrent/src/escape_string.cpp index 186b34f88..616570014 100755 --- a/libtorrent/src/escape_string.cpp +++ b/libtorrent/src/escape_string.cpp @@ -352,5 +352,17 @@ namespace libtorrent return url.substr(pos, url.find('&', pos) - pos); } + TORRENT_EXPORT std::string to_hex(std::string const& s) + { + std::string ret; + char* digits = "0123456789abcdef"; + for (std::string::const_iterator i = s.begin(); i != s.end(); ++i) + { + ret += digits[((unsigned char)*i) >> 4]; + ret += digits[((unsigned char)*i) & 0xf]; + } + return ret; + } + } diff --git a/libtorrent/src/http_connection.cpp b/libtorrent/src/http_connection.cpp index 0442d455c..0351925f6 100644 --- a/libtorrent/src/http_connection.cpp +++ b/libtorrent/src/http_connection.cpp @@ -34,12 +34,14 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/escape_string.hpp" #include "libtorrent/instantiate_connection.hpp" #include "libtorrent/gzip.hpp" -#include "libtorrent/tracker_manager.hpp" +#include "libtorrent/parse_url.hpp" +#include "libtorrent/socket.hpp" +#include "libtorrent/connection_queue.hpp" #include #include -#include #include +#include using boost::bind; @@ -56,8 +58,17 @@ void http_connection::get(std::string const& url, time_duration timeout, int pri std::string auth; std::string hostname; std::string path; + char const* error; int port; - boost::tie(protocol, auth, hostname, port, path) = parse_url_components(url); + + boost::tie(protocol, auth, hostname, port, path, error) + = parse_url_components(url); + + if (error) + { + callback(asio::error::socket_type_not_supported); + return; + } TORRENT_ASSERT(prio >= 0 && prio < 2); @@ -104,6 +115,7 @@ void http_connection::get(std::string const& url, time_duration timeout, int pri "\r\n"; sendbuffer = headers.str(); + m_url = url; start(hostname, boost::lexical_cast(port), timeout, prio , ps, ssl, handle_redirects, bind_addr); } @@ -118,7 +130,7 @@ void http_connection::start(std::string const& hostname, std::string const& port if (ps) m_proxy = *ps; m_timeout = timeout; - asio::error_code ec; + error_code ec; m_timer.expires_from_now(m_timeout, ec); m_timer.async_wait(bind(&http_connection::on_timeout , boost::weak_ptr(shared_from_this()), _1)); @@ -137,14 +149,14 @@ void http_connection::start(std::string const& hostname, std::string const& port if (m_sock.is_open() && m_hostname == hostname && m_port == port && m_ssl == ssl && m_bind_addr == bind_addr) { - asio::async_write(m_sock, asio::buffer(sendbuffer) + async_write(m_sock, asio::buffer(sendbuffer) , bind(&http_connection::on_write, shared_from_this(), _1)); } else { m_ssl = ssl; m_bind_addr = bind_addr; - asio::error_code ec; + error_code ec; m_sock.close(ec); #ifdef TORRENT_USE_OPENSSL @@ -168,7 +180,7 @@ void http_connection::start(std::string const& hostname, std::string const& port #endif if (m_bind_addr != address_v4::any()) { - asio::error_code ec; + error_code ec; m_sock.bind(tcp::endpoint(m_bind_addr, 0), ec); if (ec) { @@ -187,52 +199,65 @@ void http_connection::start(std::string const& hostname, std::string const& port void http_connection::on_connect_timeout() { + TORRENT_ASSERT(m_connection_ticket >= 0); if (m_connection_ticket > -1) m_cc.done(m_connection_ticket); m_connection_ticket = -1; - callback(asio::error::timed_out); - close(); + if (!m_endpoints.empty()) + { + m_sock.close(); + } + else + { + callback(asio::error::timed_out); + close(); + } } void http_connection::on_timeout(boost::weak_ptr p - , asio::error_code const& e) + , error_code const& e) { boost::shared_ptr c = p.lock(); if (!c) return; - if (c->m_connection_ticket > -1) c->m_cc.done(c->m_connection_ticket); - c->m_connection_ticket = -1; if (e == asio::error::operation_aborted) return; if (c->m_last_receive + c->m_timeout < time_now()) { - c->callback(asio::error::timed_out); - c->close(); + if (c->m_connection_ticket > -1 && !c->m_endpoints.empty()) + { + c->m_sock.close(); + error_code ec; + c->m_timer.expires_at(c->m_last_receive + c->m_timeout, ec); + c->m_timer.async_wait(bind(&http_connection::on_timeout, p, _1)); + } + else + { + c->callback(asio::error::timed_out); + c->close(); + } return; } if (!c->m_sock.is_open()) return; - asio::error_code ec; + error_code ec; c->m_timer.expires_at(c->m_last_receive + c->m_timeout, ec); c->m_timer.async_wait(bind(&http_connection::on_timeout, p, _1)); } void http_connection::close() { - asio::error_code ec; + error_code ec; m_timer.cancel(ec); m_limiter_timer.cancel(ec); m_sock.close(ec); m_hostname.clear(); m_port.clear(); - - if (m_connection_ticket > -1) m_cc.done(m_connection_ticket); - m_connection_ticket = -1; - m_handler.clear(); + m_abort = true; } -void http_connection::on_resolve(asio::error_code const& e +void http_connection::on_resolve(error_code const& e , tcp::resolver::iterator i) { if (e) @@ -243,21 +268,26 @@ void http_connection::on_resolve(asio::error_code const& e } TORRENT_ASSERT(i != tcp::resolver::iterator()); - // look for an address that has the same kind as the one - // we're binding to. To make sure a tracker get our - // correct listening address. - tcp::resolver::iterator target = i; - tcp::resolver::iterator end; - tcp::endpoint target_address = *i; - for (; target != end && target->endpoint().address().is_v4() - != m_bind_addr.is_v4(); ++target); + std::transform(i, tcp::resolver::iterator(), std::back_inserter(m_endpoints) + , boost::bind(&tcp::resolver::iterator::value_type::endpoint, _1)); - if (target != end) - { - target_address = *target; - } - - m_cc.enqueue(bind(&http_connection::connect, shared_from_this(), _1, target_address) + // sort the endpoints so that the ones with the same IP version as our + // bound listen socket are first. So that when contacting a tracker, + // we'll talk to it from the same IP that we're listening on + m_endpoints.sort( + (bind(&address::is_v4, bind(&tcp::endpoint::address, _1)) == m_bind_addr.is_v4()) + > (bind(&address::is_v4, bind(&tcp::endpoint::address, _2)) == m_bind_addr.is_v4())); + + queue_connect(); +} + +void http_connection::queue_connect() +{ + TORRENT_ASSERT(!m_endpoints.empty()); + tcp::endpoint target = m_endpoints.front(); + m_endpoints.pop_front(); + + m_cc.enqueue(bind(&http_connection::connect, shared_from_this(), _1, target) , bind(&http_connection::on_connect_timeout, shared_from_this()) , m_timeout, m_priority); } @@ -266,35 +296,35 @@ void http_connection::connect(int ticket, tcp::endpoint target_address) { m_connection_ticket = ticket; m_sock.async_connect(target_address, boost::bind(&http_connection::on_connect - , shared_from_this(), _1/*, ++i*/)); + , shared_from_this(), _1)); } -void http_connection::on_connect(asio::error_code const& e - /*, tcp::resolver::iterator i*/) +void http_connection::on_connect(error_code const& e) { + TORRENT_ASSERT(m_connection_ticket >= 0); + m_cc.done(m_connection_ticket); + + m_last_receive = time_now(); if (!e) { - m_last_receive = time_now(); if (m_connect_handler) m_connect_handler(*this); - asio::async_write(m_sock, asio::buffer(sendbuffer) + async_write(m_sock, asio::buffer(sendbuffer) , bind(&http_connection::on_write, shared_from_this(), _1)); } -/* else if (i != tcp::resolver::iterator()) + else if (!m_endpoints.empty() && !m_abort) { // The connection failed. Try the next endpoint in the list. m_sock.close(); - m_cc.enqueue(bind(&http_connection::connect, shared_from_this(), _1, *i) - , bind(&http_connection::on_connect_timeout, shared_from_this()) - , m_timeout, m_priority); + queue_connect(); } -*/ else + else { callback(e); close(); } } -void http_connection::callback(asio::error_code const& e, char const* data, int size) +void http_connection::callback(error_code const& e, char const* data, int size) { if (!m_bottled || !m_called) { @@ -307,7 +337,7 @@ void http_connection::callback(asio::error_code const& e, char const* data, int std::string error; if (inflate_gzip(data, size, buf, max_bottled_buffer, error)) { - callback(asio::error::fault, data, size); + if (m_handler) m_handler(asio::error::fault, m_parser, data, size, *this); close(); return; } @@ -317,11 +347,11 @@ void http_connection::callback(asio::error_code const& e, char const* data, int } m_called = true; m_timer.cancel(); - if (m_handler) m_handler(e, m_parser, data, size); + if (m_handler) m_handler(e, m_parser, data, size, *this); } } -void http_connection::on_write(asio::error_code const& e) +void http_connection::on_write(error_code const& e) { if (e) { @@ -340,7 +370,7 @@ void http_connection::on_write(asio::error_code const& e) if (m_download_quota == 0) { if (!m_limiter_timer_active) - on_assign_bandwidth(asio::error_code()); + on_assign_bandwidth(error_code()); return; } } @@ -350,7 +380,7 @@ void http_connection::on_write(asio::error_code const& e) , shared_from_this(), _1, _2)); } -void http_connection::on_read(asio::error_code const& e +void http_connection::on_read(error_code const& e , std::size_t bytes_transferred) { if (m_rate_limit) @@ -394,7 +424,7 @@ void http_connection::on_read(asio::error_code const& e if (error) { // HTTP parse error - asio::error_code ec = asio::error::fault; + error_code ec = asio::error::fault; callback(ec, 0, 0); return; } @@ -407,17 +437,44 @@ void http_connection::on_read(asio::error_code const& e if (code >= 300 && code < 400) { // attempt a redirect - std::string const& url = m_parser.header("location"); - if (url.empty()) + std::string const& location = m_parser.header("location"); + if (location.empty()) { // missing location header - callback(e); + callback(asio::error::fault); + close(); return; } - asio::error_code ec; + error_code ec; m_sock.close(ec); - get(url, m_timeout, m_priority, &m_proxy, m_redirects - 1); + using boost::tuples::ignore; + char const* error; + boost::tie(ignore, ignore, ignore, ignore, ignore, error) + = parse_url_components(location); + if (error == 0) + { + get(location, m_timeout, m_priority, &m_proxy, m_redirects - 1); + } + else + { + // some broken web servers send out relative paths + // in the location header. + std::string url = m_url; + // remove the leaf filename + std::size_t i = url.find_last_of('/'); + if (i == std::string::npos) + { + url += '/'; + } + else + { + url.resize(i + 1); + } + url += location; + + get(url, m_timeout, m_priority, &m_proxy, m_redirects - 1); + } return; } @@ -434,7 +491,7 @@ void http_connection::on_read(asio::error_code const& e } else if (m_bottled && m_parser.finished()) { - asio::error_code ec; + error_code ec; m_timer.cancel(ec); callback(e, m_parser.get_body().begin, m_parser.get_body().left()); } @@ -462,7 +519,7 @@ void http_connection::on_read(asio::error_code const& e if (m_download_quota == 0) { if (!m_limiter_timer_active) - on_assign_bandwidth(asio::error_code()); + on_assign_bandwidth(error_code()); return; } } @@ -472,7 +529,7 @@ void http_connection::on_read(asio::error_code const& e , shared_from_this(), _1, _2)); } -void http_connection::on_assign_bandwidth(asio::error_code const& e) +void http_connection::on_assign_bandwidth(error_code const& e) { if ((e == asio::error::operation_aborted && m_limiter_timer_active) @@ -499,7 +556,7 @@ void http_connection::on_assign_bandwidth(asio::error_code const& e) , bind(&http_connection::on_read , shared_from_this(), _1, _2)); - asio::error_code ec; + error_code ec; m_limiter_timer_active = true; m_limiter_timer.expires_from_now(milliseconds(250), ec); m_limiter_timer.async_wait(bind(&http_connection::on_assign_bandwidth @@ -512,7 +569,7 @@ void http_connection::rate_limit(int limit) if (!m_limiter_timer_active) { - asio::error_code ec; + error_code ec; m_limiter_timer_active = true; m_limiter_timer.expires_from_now(milliseconds(250), ec); m_limiter_timer.async_wait(bind(&http_connection::on_assign_bandwidth diff --git a/libtorrent/src/http_stream.cpp b/libtorrent/src/http_stream.cpp index 78603ca8b..eaa636bf1 100644 --- a/libtorrent/src/http_stream.cpp +++ b/libtorrent/src/http_stream.cpp @@ -38,13 +38,13 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { - void http_stream::name_lookup(asio::error_code const& e, tcp::resolver::iterator i + void http_stream::name_lookup(error_code const& e, tcp::resolver::iterator i , boost::shared_ptr h) { if (e || i == tcp::resolver::iterator()) { (*h)(e); - asio::error_code ec; + error_code ec; close(ec); return; } @@ -53,12 +53,12 @@ namespace libtorrent &http_stream::connected, this, _1, h)); } - void http_stream::connected(asio::error_code const& e, boost::shared_ptr h) + void http_stream::connected(error_code const& e, boost::shared_ptr h) { if (e) { (*h)(e); - asio::error_code ec; + error_code ec; close(ec); return; } @@ -82,32 +82,32 @@ namespace libtorrent m_user + ":" + m_password) + "\r\n", p); } write_string("\r\n", p); - asio::async_write(m_sock, asio::buffer(m_buffer) + async_write(m_sock, asio::buffer(m_buffer) , boost::bind(&http_stream::handshake1, this, _1, h)); } - void http_stream::handshake1(asio::error_code const& e, boost::shared_ptr h) + void http_stream::handshake1(error_code const& e, boost::shared_ptr h) { if (e) { (*h)(e); - asio::error_code ec; + error_code ec; close(ec); return; } // read one byte from the socket m_buffer.resize(1); - asio::async_read(m_sock, asio::buffer(m_buffer) + async_read(m_sock, asio::buffer(m_buffer) , boost::bind(&http_stream::handshake2, this, _1, h)); } - void http_stream::handshake2(asio::error_code const& e, boost::shared_ptr h) + void http_stream::handshake2(error_code const& e, boost::shared_ptr h) { if (e) { (*h)(e); - asio::error_code ec; + error_code ec; close(ec); return; } @@ -138,7 +138,7 @@ namespace libtorrent if (status == 0) { (*h)(asio::error::operation_not_supported); - asio::error_code ec; + error_code ec; close(ec); return; } @@ -148,7 +148,7 @@ namespace libtorrent if (code != 200) { (*h)(asio::error::operation_not_supported); - asio::error_code ec; + error_code ec; close(ec); return; } @@ -160,7 +160,7 @@ namespace libtorrent // read another byte from the socket m_buffer.resize(read_pos + 1); - asio::async_read(m_sock, asio::buffer(&m_buffer[0] + read_pos, 1) + async_read(m_sock, asio::buffer(&m_buffer[0] + read_pos, 1) , boost::bind(&http_stream::handshake2, this, _1, h)); } diff --git a/libtorrent/src/http_tracker_connection.cpp b/libtorrent/src/http_tracker_connection.cpp index ea4f0fda0..288ee7267 100755 --- a/libtorrent/src/http_tracker_connection.cpp +++ b/libtorrent/src/http_tracker_connection.cpp @@ -194,7 +194,7 @@ namespace libtorrent tracker_connection::close(); } - void http_tracker_connection::on_response(asio::error_code const& ec + void http_tracker_connection::on_response(error_code const& ec , http_parser const& parser, char const* data, int size) { // keep this alive @@ -313,9 +313,7 @@ namespace libtorrent if (tracker_req().kind == tracker_request::scrape_request) { - std::string ih; - std::copy(tracker_req().info_hash.begin(), tracker_req().info_hash.end() - , std::back_inserter(ih)); + std::string ih = tracker_req().info_hash.to_string(); entry const* files = e.find_key("files"); if (files == 0 || files->type() != entry::dictionary_t) @@ -324,7 +322,7 @@ namespace libtorrent return; } - entry const* scrape_data = e.find_key(ih.c_str()); + entry const* scrape_data = files->find_key(ih); if (scrape_data == 0 || scrape_data->type() != entry::dictionary_t) { fail(-1, "missing or invalid info-hash entry in scrape response"); diff --git a/libtorrent/src/instantiate_connection.cpp b/libtorrent/src/instantiate_connection.cpp index 23a202da4..776ab6a12 100644 --- a/libtorrent/src/instantiate_connection.cpp +++ b/libtorrent/src/instantiate_connection.cpp @@ -37,12 +37,11 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket_type.hpp" #include #include -#include namespace libtorrent { - bool instantiate_connection(asio::io_service& ios + bool instantiate_connection(io_service& ios , proxy_settings const& ps, socket_type& s) { if (ps.type == proxy_settings::none) diff --git a/libtorrent/src/kademlia/closest_nodes.cpp b/libtorrent/src/kademlia/closest_nodes.cpp index bd9957945..859170f7f 100644 --- a/libtorrent/src/kademlia/closest_nodes.cpp +++ b/libtorrent/src/kademlia/closest_nodes.cpp @@ -40,8 +40,6 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { namespace dht { -using asio::ip::udp; - closest_nodes_observer::~closest_nodes_observer() { if (m_algorithm) m_algorithm->failed(m_self, true); diff --git a/libtorrent/src/kademlia/dht_tracker.cpp b/libtorrent/src/kademlia/dht_tracker.cpp index bc638d045..461ea9da6 100644 --- a/libtorrent/src/kademlia/dht_tracker.cpp +++ b/libtorrent/src/kademlia/dht_tracker.cpp @@ -51,6 +51,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/bencode.hpp" #include "libtorrent/io.hpp" #include "libtorrent/version.hpp" +#include "libtorrent/escape_string.hpp" using boost::ref; using boost::lexical_cast; @@ -66,9 +67,6 @@ enum key_refresh = 5 // generate a new write token key every 5 minutes }; -using asio::ip::udp; -typedef asio::ip::address_v4 address; - namespace { const int tick_period = 1; // minutes @@ -228,7 +226,7 @@ namespace libtorrent { namespace dht s.dht_global_nodes = m_dht.num_global_nodes(); } - void dht_tracker::connection_timeout(asio::error_code const& e) + void dht_tracker::connection_timeout(error_code const& e) try { mutex_t::scoped_lock l(m_mutex); @@ -247,7 +245,7 @@ namespace libtorrent { namespace dht #endif }; - void dht_tracker::refresh_timeout(asio::error_code const& e) + void dht_tracker::refresh_timeout(error_code const& e) try { mutex_t::scoped_lock l(m_mutex); @@ -263,7 +261,7 @@ namespace libtorrent { namespace dht TORRENT_ASSERT(false); }; - void dht_tracker::tick(asio::error_code const& e) + void dht_tracker::tick(error_code const& e) try { mutex_t::scoped_lock l(m_mutex); @@ -375,6 +373,12 @@ namespace libtorrent { namespace dht m_dht.announce(ih, listen_port, f); } + + void dht_tracker::on_unreachable(udp::endpoint const& ep) + { + m_dht.unreachable(ep); + } + // translate bittorrent kademlia message into the generice kademlia message // used by the library void dht_tracker::on_receive(udp::endpoint const& ep, char const* buf, int bytes_transferred) @@ -404,8 +408,8 @@ namespace libtorrent { namespace dht if (match->count == 20) { TORRENT_LOG(dht_tracker) << time_now_string() << " BANNING PEER [ ip: " - << ep << " | time: " << total_milliseconds((now - match->limit) + seconds(5)) / 1000.f - << " | count: " << match->count << " ]"; + << ep << " time: " << total_milliseconds((now - match->limit) + seconds(5)) / 1000.f + << " count: " << match->count << " ]"; } #endif // we've received 20 messages in less than 5 seconds from @@ -442,8 +446,9 @@ namespace libtorrent { namespace dht entry e = bdecode(buf, buf + bytes_transferred); #ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(dht_tracker) << time_now_string() << " RECEIVED [" - << ep << "]:"; + std::stringstream log_line; + log_line << time_now_string() << " RECEIVED [" + " ip: " << ep; #endif libtorrent::dht::msg m; @@ -461,36 +466,36 @@ namespace libtorrent { namespace dht if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "UT")) { ++m_ut_message_input; - TORRENT_LOG(dht_tracker) << " client: uTorrent"; + log_line << " c: uTorrent"; } else if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "LT")) { ++m_lt_message_input; - TORRENT_LOG(dht_tracker) << " client: libtorrent"; + log_line << " c: libtorrent"; } else if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "MP")) { ++m_mp_message_input; - TORRENT_LOG(dht_tracker) << " client: MooPolice"; + log_line << " c: MooPolice"; } else if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "GR")) { ++m_gr_message_input; - TORRENT_LOG(dht_tracker) << " client: GetRight"; + log_line << " c: GetRight"; } else if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "MO")) { ++m_mo_message_input; - TORRENT_LOG(dht_tracker) << " client: Mono Torrent"; + log_line << " c: Mono Torrent"; } else { - TORRENT_LOG(dht_tracker) << " client: " << client; + log_line << " c: " << client; } } catch (std::exception&) { - TORRENT_LOG(dht_tracker) << " client: generic"; + log_line << " c: generic"; }; #endif @@ -499,8 +504,8 @@ namespace libtorrent { namespace dht if (msg_type == "r") { #ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(dht_tracker) << " reply: transaction: " - << m.transaction_id; + log_line << " r: " << messages::ids[m.message_id] + << " t: " << to_hex(m.transaction_id); #endif m.reply = true; @@ -528,7 +533,7 @@ namespace libtorrent { namespace dht read_endpoint_list(n, m.peers); } #ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(dht_tracker) << " peers: " << m.peers.size(); + log_line << " p: " << m.peers.size(); #endif } @@ -548,7 +553,7 @@ namespace libtorrent { namespace dht id, read_v4_endpoint(i))); } #ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(dht_tracker) << " nodes: " << m.nodes.size(); + log_line << " n: " << m.nodes.size(); #endif } @@ -573,7 +578,7 @@ namespace libtorrent { namespace dht id, read_v6_endpoint(in))); } #ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(dht_tracker) << " nodes2 + nodes: " << m.nodes.size(); + log_line << " n2: " << m.nodes.size(); #endif } @@ -590,7 +595,7 @@ namespace libtorrent { namespace dht std::string request_kind(e["q"].string()); #ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(dht_tracker) << " query: " << request_kind; + log_line << " q: " << request_kind; #endif if (request_kind == "ping") @@ -603,8 +608,7 @@ namespace libtorrent { namespace dht if (target.size() != 20) throw std::runtime_error("invalid size of target id"); std::copy(target.begin(), target.end(), m.info_hash.begin()); #ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(dht_tracker) << " target: " - << boost::lexical_cast(m.info_hash); + log_line << " t: " << boost::lexical_cast(m.info_hash); #endif m.message_id = libtorrent::dht::messages::find_node; @@ -616,8 +620,7 @@ namespace libtorrent { namespace dht std::copy(info_hash.begin(), info_hash.end(), m.info_hash.begin()); m.message_id = libtorrent::dht::messages::get_peers; #ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(dht_tracker) << " info_hash: " - << boost::lexical_cast(m.info_hash); + log_line << " ih: " << boost::lexical_cast(m.info_hash); #endif } else if (request_kind == "announce_peer") @@ -633,9 +636,8 @@ namespace libtorrent { namespace dht m.write_token = a["token"]; m.message_id = libtorrent::dht::messages::announce_peer; #ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(dht_tracker) << " info_hash: " - << boost::lexical_cast(m.info_hash); - TORRENT_LOG(dht_tracker) << " port: " << m.port; + log_line << " ih: " << boost::lexical_cast(m.info_hash); + log_line << " p: " << m.port; if (!m_dht.verify_token(m)) ++m_failed_announces; @@ -657,8 +659,8 @@ namespace libtorrent { namespace dht m.error_msg = list.back().string(); m.error_code = list.front().integer(); #ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(dht_tracker) << " incoming error: " << m.error_code << " " - << m.error_msg; + log_line << " incoming error: " << m.error_code + << " " << m.error_msg; #endif throw std::runtime_error("DHT error message"); } @@ -677,7 +679,7 @@ namespace libtorrent { namespace dht ++m_queries_received[m.message_id]; m_queries_bytes_received[m.message_id] += int(bytes_transferred); } - TORRENT_LOG(dht_tracker) << e; + TORRENT_LOG(dht_tracker) << log_line.str() << " ]"; #endif TORRENT_ASSERT(m.message_id != messages::error); m_dht.incoming(m); @@ -739,7 +741,7 @@ namespace libtorrent { namespace dht bind(&dht_tracker::on_name_lookup, self(), _1, _2)); } - void dht_tracker::on_name_lookup(asio::error_code const& e + void dht_tracker::on_name_lookup(error_code const& e , udp::resolver::iterator host) try { if (e || host == udp::resolver::iterator()) return; @@ -757,7 +759,7 @@ namespace libtorrent { namespace dht bind(&dht_tracker::on_router_name_lookup, self(), _1, _2)); } - void dht_tracker::on_router_name_lookup(asio::error_code const& e + void dht_tracker::on_router_name_lookup(error_code const& e , udp::resolver::iterator host) try { if (e || host == udp::resolver::iterator()) return; @@ -809,9 +811,6 @@ namespace libtorrent { namespace dht p.list().push_back(entry(endpoint)); } } -#ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(dht_tracker) << " nodes: " << m.nodes.size(); -#endif } } @@ -828,9 +827,10 @@ namespace libtorrent { namespace dht e["v"] = std::string(version_str, version_str + 4); #ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(dht_tracker) << time_now_string() - << " SENDING [" << m.addr << "]:"; - TORRENT_LOG(dht_tracker) << " transaction: " << m.transaction_id; + std::stringstream log_line; + log_line << time_now_string() + << " SENDING [ ip: " << m.addr + << " t: " << to_hex(m.transaction_id); #endif if (m.message_id == messages::error) @@ -843,8 +843,8 @@ namespace libtorrent { namespace dht error_list.list().push_back(entry(m.error_msg)); e["e"] = error_list; #ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(dht_tracker) << time_now_string() - << " outgoing error: " << m.error_code << " " << m.error_msg; + log_line << " err: " << m.error_code + << " msg: " << m.error_msg; #endif } else if (m.reply) @@ -855,8 +855,7 @@ namespace libtorrent { namespace dht r["id"] = std::string(m.id.begin(), m.id.end()); #ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(dht_tracker) << time_now_string() - << " reply: " << messages::ids[m.message_id]; + log_line << " r: " << messages::ids[m.message_id]; #endif if (m.write_token.type() != entry::undefined_t) @@ -892,7 +891,7 @@ namespace libtorrent { namespace dht p.list().push_back(entry(endpoint)); } #ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(dht_tracker) << " peers: " << m.peers.size(); + log_line << " p: " << m.peers.size(); #endif } break; @@ -916,8 +915,7 @@ namespace libtorrent { namespace dht e["q"] = messages::ids[m.message_id]; #ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(dht_tracker) << " query: " - << messages::ids[m.message_id]; + log_line << " q: " << messages::ids[m.message_id]; #endif switch (m.message_id) @@ -926,8 +924,7 @@ namespace libtorrent { namespace dht { a["target"] = std::string(m.info_hash.begin(), m.info_hash.end()); #ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(dht_tracker) << " target: " - << boost::lexical_cast(m.info_hash); + log_line << " target: " << boost::lexical_cast(m.info_hash); #endif break; } @@ -935,8 +932,7 @@ namespace libtorrent { namespace dht { a["info_hash"] = std::string(m.info_hash.begin(), m.info_hash.end()); #ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(dht_tracker) << " info_hash: " - << boost::lexical_cast(m.info_hash); + log_line << " ih: " << boost::lexical_cast(m.info_hash); #endif break; } @@ -945,9 +941,8 @@ namespace libtorrent { namespace dht a["info_hash"] = std::string(m.info_hash.begin(), m.info_hash.end()); a["token"] = m.write_token; #ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(dht_tracker) - << " port: " << m.port - << " info_hash: " << boost::lexical_cast(m.info_hash); + log_line << " p: " << m.port + << " ih: " << boost::lexical_cast(m.info_hash); #endif break; default: break; @@ -957,7 +952,7 @@ namespace libtorrent { namespace dht m_send_buf.clear(); bencode(std::back_inserter(m_send_buf), e); - asio::error_code ec; + error_code ec; m_sock.send(m.addr, &m_send_buf[0], (int)m_send_buf.size(), ec); #ifdef TORRENT_DHT_VERBOSE_LOGGING @@ -972,7 +967,7 @@ namespace libtorrent { namespace dht { m_queries_out_bytes += m_send_buf.size(); } - TORRENT_LOG(dht_tracker) << e; + TORRENT_LOG(dht_tracker) << log_line.str() << " ]"; #endif if (!m.piggy_backed_ping) return; diff --git a/libtorrent/src/kademlia/find_data.cpp b/libtorrent/src/kademlia/find_data.cpp index 9d11b5aeb..8da689d68 100644 --- a/libtorrent/src/kademlia/find_data.cpp +++ b/libtorrent/src/kademlia/find_data.cpp @@ -36,6 +36,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include namespace libtorrent { namespace dht { @@ -101,7 +102,7 @@ find_data::find_data( add_requests(); } -void find_data::invoke(node_id const& id, asio::ip::udp::endpoint addr) +void find_data::invoke(node_id const& id, udp::endpoint addr) { if (m_done) { diff --git a/libtorrent/src/kademlia/node.cpp b/libtorrent/src/kademlia/node.cpp index 8654b8978..904523753 100644 --- a/libtorrent/src/kademlia/node.cpp +++ b/libtorrent/src/kademlia/node.cpp @@ -65,8 +65,6 @@ namespace // TODO: configurable? enum { announce_interval = 30 }; -using asio::ip::udp; - #ifdef TORRENT_DHT_VERBOSE_LOGGING TORRENT_DEFINE_LOG(node) #endif @@ -245,6 +243,11 @@ void node_impl::refresh_bucket(int bucket) try } catch (std::exception&) {} +void node_impl::unreachable(udp::endpoint const& ep) +{ + m_rpc.unreachable(ep); +} + void node_impl::incoming(msg const& m) { if (m_rpc.incoming(m)) @@ -269,6 +272,9 @@ namespace for (std::vector::const_iterator i = v.begin() , end(v.end()); i != end; ++i) { +#ifdef TORRENT_DHT_VERBOSE_LOGGING + TORRENT_LOG(node) << " distance: " << (160 - distance_exp(ih, i->id)); +#endif observer_ptr o(new (rpc.allocator().malloc()) get_peers_observer(ih, listen_port, rpc, f)); #ifndef NDEBUG o->m_in_constructor = false; diff --git a/libtorrent/src/kademlia/refresh.cpp b/libtorrent/src/kademlia/refresh.cpp index 8edabb2c1..1c5978893 100644 --- a/libtorrent/src/kademlia/refresh.cpp +++ b/libtorrent/src/kademlia/refresh.cpp @@ -47,8 +47,6 @@ using boost::bind; namespace libtorrent { namespace dht { -using asio::ip::udp; - #ifdef TORRENT_DHT_VERBOSE_LOGGING TORRENT_DEFINE_LOG(refresh) #endif diff --git a/libtorrent/src/kademlia/routing_table.cpp b/libtorrent/src/kademlia/routing_table.cpp index 1deb00a71..6c4d93f2b 100644 --- a/libtorrent/src/kademlia/routing_table.cpp +++ b/libtorrent/src/kademlia/routing_table.cpp @@ -50,8 +50,9 @@ using boost::uint8_t; namespace libtorrent { namespace dht { -using asio::ip::udp; -typedef asio::ip::address_v4 address; +#ifdef TORRENT_DHT_VERBOSE_LOGGING +TORRENT_DEFINE_LOG(table) +#endif routing_table::routing_table(node_id const& id, int bucket_size , dht_settings const& settings) @@ -225,6 +226,15 @@ void routing_table::node_failed(node_id const& id) if (rb.empty()) { ++i->fail_count; + +#ifdef TORRENT_DHT_VERBOSE_LOGGING + TORRENT_LOG(table) << " NODE FAILED" + " id: " << id << + " ip: " << i->addr << + " fails: " << i->fail_count << + " up-time: " << total_seconds(time_now() - i->first_seen); +#endif + if (i->fail_count >= m_settings.max_fail_count) { b.erase(i); diff --git a/libtorrent/src/kademlia/rpc_manager.cpp b/libtorrent/src/kademlia/rpc_manager.cpp index 4319fc4b8..384be2eed 100644 --- a/libtorrent/src/kademlia/rpc_manager.cpp +++ b/libtorrent/src/kademlia/rpc_manager.cpp @@ -159,6 +159,39 @@ void rpc_manager::check_invariant() const } #endif +void rpc_manager::unreachable(udp::endpoint const& ep) +{ +#ifdef TORRENT_DHT_VERBOSE_LOGGING + TORRENT_LOG(rpc) << time_now_string() << " PORT_UNREACHABLE [ ip: " << ep << " ]"; +#endif + int num_active = m_oldest_transaction_id < m_next_transaction_id + ? m_next_transaction_id - m_oldest_transaction_id + : max_transactions - m_next_transaction_id + m_oldest_transaction_id; + TORRENT_ASSERT((m_oldest_transaction_id + num_active) % max_transactions + == m_next_transaction_id); + int tid = m_oldest_transaction_id; + for (int i = 0; i < num_active; ++i, ++tid) + { + if (tid >= max_transactions) tid = 0; + observer_ptr const& o = m_transactions[tid]; + if (!o) continue; + if (o->target_addr != ep) continue; + observer_ptr ptr = m_transactions[tid]; + m_transactions[tid] = 0; + if (tid == m_oldest_transaction_id) + { + ++m_oldest_transaction_id; + if (m_oldest_transaction_id >= max_transactions) + m_oldest_transaction_id = 0; + } +#ifdef TORRENT_DHT_VERBOSE_LOGGING + TORRENT_LOG(rpc) << " found transaction [ tid: " << tid << " ]"; +#endif + ptr->timeout(); + return; + } +} + bool rpc_manager::incoming(msg const& m) { INVARIANT_CHECK; diff --git a/libtorrent/src/kademlia/traversal_algorithm.cpp b/libtorrent/src/kademlia/traversal_algorithm.cpp index b1e803354..138d42905 100644 --- a/libtorrent/src/kademlia/traversal_algorithm.cpp +++ b/libtorrent/src/kademlia/traversal_algorithm.cpp @@ -39,7 +39,6 @@ POSSIBILITY OF SUCH DAMAGE. #include using boost::bind; -using asio::ip::udp; namespace libtorrent { namespace dht { @@ -89,7 +88,8 @@ boost::pool<>& traversal_algorithm::allocator() const void traversal_algorithm::traverse(node_id const& id, udp::endpoint addr) { #ifdef TORRENT_DHT_VERBOSE_LOGGING - TORRENT_LOG(traversal) << "node returned a list which included a node with id 0"; + if (id.is_all_zeros()) + TORRENT_LOG(traversal) << time_now_string() << " WARNING: node returned a list which included a node with id 0"; #endif add_entry(id, addr, 0); } diff --git a/libtorrent/src/lazy_bdecode.cpp b/libtorrent/src/lazy_bdecode.cpp index 4cb8b099e..bee91b49a 100644 --- a/libtorrent/src/lazy_bdecode.cpp +++ b/libtorrent/src/lazy_bdecode.cpp @@ -187,6 +187,7 @@ namespace libtorrent std::pair* tmp = new (std::nothrow) std::pair[capacity]; if (tmp == 0) return 0; std::memcpy(tmp, m_data.dict, sizeof(std::pair) * m_size); + for (int i = 0; i < m_size; ++i) m_data.dict[i].second.release(); delete[] m_data.dict; m_data.dict = tmp; m_capacity = capacity; @@ -299,6 +300,7 @@ namespace libtorrent lazy_entry* tmp = new (std::nothrow) lazy_entry[capacity]; if (tmp == 0) return 0; std::memcpy(tmp, m_data.list, sizeof(lazy_entry) * m_size); + for (int i = 0; i < m_size; ++i) m_data.list[i].release(); delete[] m_data.list; m_data.list = tmp; m_capacity = capacity; @@ -330,6 +332,7 @@ namespace libtorrent case dict_t: delete[] m_data.dict; break; default: break; } + m_data.start = 0; m_size = 0; m_capacity = 0; m_type = none_t; @@ -370,7 +373,8 @@ namespace libtorrent bool one_liner = (e.list_size() == 0 || e.list_at(0)->type() == lazy_entry::int_t || (e.list_at(0)->type() == lazy_entry::string_t - && e.list_at(0)->string_length() < 10)) + && (e.list_at(0)->string_length() < 10 + || e.list_size() < 2))) && e.list_size() < 5; if (!one_liner) os << "\n"; for (int i = 0; i < e.list_size(); ++i) @@ -388,7 +392,7 @@ namespace libtorrent bool one_liner = (e.dict_size() == 0 || e.dict_at(0).second->type() == lazy_entry::int_t || (e.dict_at(0).second->type() == lazy_entry::string_t - && e.dict_at(0).second->string_length() < 10) + && e.dict_at(0).second->string_length() < 30) || e.dict_at(0).first.size() < 10) && e.dict_size() < 5; diff --git a/libtorrent/src/lsd.cpp b/libtorrent/src/lsd.cpp index a0b6426a8..2d4e8b7da 100644 --- a/libtorrent/src/lsd.cpp +++ b/libtorrent/src/lsd.cpp @@ -40,8 +40,13 @@ POSSIBILITY OF SUCH DAMAGE. #include #include +#if BOOST_VERSION < 103500 #include #include +#else +#include +#include +#endif #include #include #include @@ -52,7 +57,7 @@ using namespace libtorrent; namespace libtorrent { // defined in broadcast_socket.cpp - address guess_local_address(asio::io_service&); + address guess_local_address(io_service&); } lsd::lsd(io_service& ios, address const& listen_interface @@ -84,7 +89,7 @@ void lsd::announce(sha1_hash const& ih, int listen_port) std::string const& msg = btsearch.str(); m_retry_count = 1; - asio::error_code ec; + error_code ec; m_socket.send(msg.c_str(), int(msg.size()), ec); if (ec) { @@ -101,11 +106,11 @@ void lsd::announce(sha1_hash const& ih, int listen_port) m_broadcast_timer.async_wait(bind(&lsd::resend_announce, self(), _1, msg)); } -void lsd::resend_announce(asio::error_code const& e, std::string msg) +void lsd::resend_announce(error_code const& e, std::string msg) { if (e) return; - asio::error_code ec; + error_code ec; m_socket.send(msg.c_str(), int(msg.size()), ec); ++m_retry_count; @@ -192,7 +197,7 @@ void lsd::on_announce(udp::endpoint const& from, char* buffer void lsd::close() { m_socket.close(); - asio::error_code ec; + error_code ec; m_broadcast_timer.cancel(ec); m_disabled = true; m_callback.clear(); diff --git a/libtorrent/src/mapped_storage.cpp b/libtorrent/src/mapped_storage.cpp index bb1380d88..f0c4d1b8b 100644 --- a/libtorrent/src/mapped_storage.cpp +++ b/libtorrent/src/mapped_storage.cpp @@ -47,6 +47,11 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#if BOOST_VERSION >= 103500 +#include +#endif + +#include #ifdef _MSC_VER #pragma warning(pop) @@ -57,8 +62,10 @@ using boost::iostreams::mapped_file_params; namespace libtorrent { - namespace fs = boost::filesystem; +#if BOOST_VERSION >= 103500 + using boost::system::error_code; +#endif struct mapped_file_pool { @@ -78,7 +85,7 @@ namespace libtorrent #ifndef NDEBUG if (file_size > 0) { - fs::system_error_type ec; + error_code ec; fs::file_status st = fs::status(path, ec); TORRENT_ASSERT(!fs::exists(st)); } @@ -197,7 +204,11 @@ namespace libtorrent size_type start = (offset / view_size) * view_size; TORRENT_ASSERT(start + view_size >= offset + length); +#if BOOST_VERSION < 103500 fs::system_error_type ec; +#else + error_code ec; +#endif fs::file_status st = fs::status(p, ec); m_files.push_back(file_entry()); diff --git a/libtorrent/src/metadata_transfer.cpp b/libtorrent/src/metadata_transfer.cpp index f5dcab181..8938cfb7b 100644 --- a/libtorrent/src/metadata_transfer.cpp +++ b/libtorrent/src/metadata_transfer.cpp @@ -55,6 +55,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/extensions.hpp" #include "libtorrent/extensions/metadata_transfer.hpp" #include "libtorrent/alert_types.hpp" +#include "libtorrent/buffer.hpp" namespace libtorrent { namespace { @@ -107,40 +108,37 @@ namespace libtorrent { namespace virtual void on_files_checked() { - // if the torrent is a seed, copy the metadata from - // the torrent before it is deallocated - if (m_torrent.is_seed()) - metadata(); + // if the torrent is a seed, make a reference to + // the metadata from the torrent before it is deallocated + if (m_torrent.is_seed()) metadata(); } virtual boost::shared_ptr new_connection( peer_connection* pc); - std::vector const& metadata() const + buffer::const_interval metadata() const { - if (m_metadata.empty()) + if (!m_metadata) { - bencode(std::back_inserter(m_metadata) - , m_torrent.torrent_file().create_info_metadata()); - - TORRENT_ASSERT(hasher(&m_metadata[0], m_metadata.size()).final() + m_metadata = m_torrent.torrent_file().metadata(); + m_metadata_size = m_torrent.torrent_file().metadata_size(); + TORRENT_ASSERT(hasher(m_metadata.get(), m_metadata_size).final() == m_torrent.torrent_file().info_hash()); } - TORRENT_ASSERT(!m_metadata.empty()); - return m_metadata; + return buffer::const_interval(m_metadata.get(), m_metadata.get() + + m_metadata_size); } bool received_metadata(char const* buf, int size, int offset, int total_size) { if (m_torrent.valid_metadata()) return false; - if ((int)m_metadata.size() < total_size) - m_metadata.resize(total_size); - - std::copy( - buf - , buf + size - , &m_metadata[offset]); + if (!m_metadata || m_metadata_size < total_size) + { + m_metadata.reset(new char[total_size]); + m_metadata_size = total_size; + } + std::copy(buf, buf + size, &m_metadata[offset]); if (m_have_metadata.empty()) m_have_metadata.resize(256, false); @@ -163,7 +161,7 @@ namespace libtorrent { namespace if (!have_all) return false; hasher h; - h.update(&m_metadata[0], (int)m_metadata.size()); + h.update(&m_metadata[0], m_metadata_size); sha1_hash info_hash = h.final(); if (info_hash != m_torrent.torrent_file().info_hash()) @@ -184,9 +182,10 @@ namespace libtorrent { namespace return false; } - entry metadata = bdecode(m_metadata.begin(), m_metadata.end()); + lazy_entry e; + lazy_bdecode(m_metadata.get(), m_metadata.get() + m_metadata_size, e); std::string error; - if (!m_torrent.set_metadata(metadata, error)) + if (!m_torrent.set_metadata(e, error)) { // this means the metadata is correct, since we // verified it against the info-hash, but we @@ -240,10 +239,10 @@ namespace libtorrent { namespace // the metadata file while downloading it from // peers, and while sending it. // it is mutable because it's generated lazily - mutable std::vector m_metadata; + mutable boost::shared_array m_metadata; int m_metadata_progress; - int m_metadata_size; + mutable int m_metadata_size; // this is a bitfield of size 256, each bit represents // a piece of the metadata. It is set to one if we @@ -333,7 +332,7 @@ namespace libtorrent { namespace if (m_torrent.valid_metadata() && !m_torrent.torrent_file().priv()) { std::pair offset - = req_to_offset(req, (int)m_tp.metadata().size()); + = req_to_offset(req, (int)m_tp.metadata().left()); buffer::interval i = m_pc.allocate_send_buffer(15 + offset.second); @@ -343,11 +342,11 @@ namespace libtorrent { namespace detail::write_uint8(m_message_index, i.begin); // means 'data packet' detail::write_uint8(1, i.begin); - detail::write_uint32((int)m_tp.metadata().size(), i.begin); + detail::write_uint32((int)m_tp.metadata().left(), i.begin); detail::write_uint32(offset.first, i.begin); - std::vector const& metadata = m_tp.metadata(); - std::copy(metadata.begin() + offset.first - , metadata.begin() + offset.first + offset.second, i.begin); + char const* metadata = m_tp.metadata().begin; + std::copy(metadata + offset.first + , metadata + offset.first + offset.second, i.begin); i.begin += offset.second; TORRENT_ASSERT(i.begin == i.end); } diff --git a/libtorrent/src/natpmp.cpp b/libtorrent/src/natpmp.cpp index 234ceb6c7..56f109761 100644 --- a/libtorrent/src/natpmp.cpp +++ b/libtorrent/src/natpmp.cpp @@ -33,7 +33,11 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/pch.hpp" #include +#if BOOST_VERSION < 103500 #include +#else +#include +#endif #include "libtorrent/natpmp.hpp" #include "libtorrent/io.hpp" @@ -63,7 +67,7 @@ void natpmp::rebind(address const& listen_interface) { mutex_t::scoped_lock l(m_mutex); - asio::error_code ec; + error_code ec; address gateway = get_default_gateway(m_socket.get_io_service(), ec); if (ec) { @@ -198,7 +202,7 @@ void natpmp::try_next_mapping(int i) { if (m_abort) { - asio::error_code ec; + error_code ec; m_send_timer.cancel(ec); m_socket.close(ec); } @@ -264,7 +268,7 @@ void natpmp::send_map_request(int i) << " ttl: " << ttl << " ]" << std::endl; #endif - asio::error_code ec; + error_code ec; m_socket.send_to(asio::buffer(buf, 12), m_nat_endpoint, 0, ec); // linear back-off instead of exponential ++m_retry_count; @@ -272,7 +276,7 @@ void natpmp::send_map_request(int i) m_send_timer.async_wait(bind(&natpmp::resend_request, self(), i, _1)); } -void natpmp::resend_request(int i, asio::error_code const& e) +void natpmp::resend_request(int i, error_code const& e) { if (e) return; @@ -290,7 +294,7 @@ void natpmp::resend_request(int i, asio::error_code const& e) send_map_request(i); } -void natpmp::on_reply(asio::error_code const& e +void natpmp::on_reply(error_code const& e , std::size_t bytes_transferred) { using namespace libtorrent::detail; @@ -305,7 +309,7 @@ void natpmp::on_reply(asio::error_code const& e mutex_t::scoped_lock l(m_mutex); - asio::error_code ec; + error_code ec; m_send_timer.cancel(ec); TORRENT_ASSERT(m_currently_mapping >= 0); @@ -439,7 +443,7 @@ void natpmp::update_expiration_timer() << " ttl: " << total_seconds(min_expire - time_now()) << " ]" << std::endl; #endif - asio::error_code ec; + error_code ec; if (m_next_refresh >= 0) m_refresh_timer.cancel(ec); m_refresh_timer.expires_from_now(min_expire - now, ec); m_refresh_timer.async_wait(bind(&natpmp::mapping_expired, self(), _1, min_index)); @@ -447,7 +451,7 @@ void natpmp::update_expiration_timer() } } -void natpmp::mapping_expired(asio::error_code const& e, int i) +void natpmp::mapping_expired(error_code const& e, int i) { if (e) return; mutex_t::scoped_lock l(m_mutex); @@ -463,7 +467,7 @@ void natpmp::close() { mutex_t::scoped_lock l(m_mutex); m_abort = true; - asio::error_code ec; + error_code ec; #if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) m_log << time_now_string() << " close" << std::endl; #endif diff --git a/libtorrent/src/peer_connection.cpp b/libtorrent/src/peer_connection.cpp index 51aba79d9..29c7689fd 100755 --- a/libtorrent/src/peer_connection.cpp +++ b/libtorrent/src/peer_connection.cpp @@ -64,7 +64,7 @@ namespace libtorrent session_impl& ses , boost::weak_ptr tor , shared_ptr s - , tcp::endpoint const& remote + , tcp::endpoint const& endp , policy::peer* peerinfo) : #ifndef NDEBUG @@ -73,41 +73,28 @@ namespace libtorrent #endif m_ses(ses) , m_max_out_request_queue(m_ses.settings().max_out_request_queue) - , 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_last_receive(time_now()) + , m_last_sent(time_now()) + , m_remote_dl_update(time_now()) + , m_became_uninterested(time_now()) + , m_became_uninteresting(time_now()) + , m_free_upload(0) + , m_downloaded_at_last_unchoke(0) + , m_disk_recv_buffer(ses, 0) + , m_socket(s) + , m_remote(endp) + , m_torrent(tor) + , m_num_pieces(0) + , m_timeout(m_ses.settings().peer_timeout) , m_packet_size(0) , m_recv_pos(0) , m_disk_recv_buffer_size(0) - , m_disk_recv_buffer(0) , m_reading_bytes(0) - , m_last_receive(time_now()) - , m_last_sent(time_now()) - , m_socket(s) - , m_remote(remote) - , m_torrent(tor) - , m_active(true) - , m_peer_interested(false) - , m_peer_choked(true) - , m_interesting(false) - , 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) - , m_assume_fifo(false) , m_num_invalid_requests(0) - , m_disconnecting(false) - , m_became_uninterested(time_now()) - , m_became_uninteresting(time_now()) - , m_connecting(true) - , m_queued(true) - , m_prefer_whole_pieces(false) - , m_request_large_blocks(false) , m_priority(1) , m_upload_limit(bandwidth_limit::inf) , m_download_limit(bandwidth_limit::inf) @@ -116,13 +103,27 @@ namespace libtorrent , m_connection_ticket(-1) , m_remote_bytes_dled(0) , m_remote_dl_rate(0) - , m_remote_dl_update(time_now()) , m_outstanding_writing_bytes(0) - , m_fast_reconnect(false) - , m_rtt(0) - , m_downloaded_at_last_unchoke(0) , m_download_rate_peak(0) , m_upload_rate_peak(0) + , m_rtt(0) + , m_prefer_whole_pieces(0) + , m_desired_queue_size(2) + , m_fast_reconnect(false) + , m_active(true) + , m_peer_interested(false) + , m_peer_choked(true) + , m_interesting(false) + , m_choked(true) + , m_failed(false) + , m_ignore_bandwidth_limits(false) + , m_have_all(false) + , m_assume_fifo(false) + , m_disconnecting(false) + , m_connecting(true) + , m_queued(true) + , m_request_large_blocks(false) + , m_upload_only(false) #ifndef NDEBUG , m_in_constructor(true) #endif @@ -164,6 +165,7 @@ namespace libtorrent peer_connection::peer_connection( session_impl& ses , boost::shared_ptr s + , tcp::endpoint const& endp , policy::peer* peerinfo) : #ifndef NDEBUG @@ -172,39 +174,27 @@ namespace libtorrent #endif m_ses(ses) , m_max_out_request_queue(m_ses.settings().max_out_request_queue) - , 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_last_receive(time_now()) + , m_last_sent(time_now()) + , m_remote_dl_update(time_now()) + , m_became_uninterested(time_now()) + , m_became_uninteresting(time_now()) + , m_free_upload(0) + , m_downloaded_at_last_unchoke(0) + , m_disk_recv_buffer(ses, 0) + , m_socket(s) + , m_remote(endp) + , m_num_pieces(0) + , m_timeout(m_ses.settings().peer_timeout) , m_packet_size(0) , m_recv_pos(0) , m_disk_recv_buffer_size(0) - , m_disk_recv_buffer(0) , m_reading_bytes(0) - , m_last_receive(time_now()) - , m_last_sent(time_now()) - , m_socket(s) - , m_active(false) - , m_peer_interested(false) - , m_peer_choked(true) - , m_interesting(false) - , 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) - , m_assume_fifo(false) , m_num_invalid_requests(0) - , m_disconnecting(false) - , m_became_uninterested(time_now()) - , m_became_uninteresting(time_now()) - , m_connecting(false) - , m_queued(false) - , m_prefer_whole_pieces(false) - , m_request_large_blocks(false) , m_priority(1) , m_upload_limit(bandwidth_limit::inf) , m_download_limit(bandwidth_limit::inf) @@ -213,13 +203,27 @@ namespace libtorrent , m_connection_ticket(-1) , m_remote_bytes_dled(0) , m_remote_dl_rate(0) - , m_remote_dl_update(time_now()) , m_outstanding_writing_bytes(0) - , m_fast_reconnect(false) - , m_rtt(0) - , m_downloaded_at_last_unchoke(0) , m_download_rate_peak(0) , m_upload_rate_peak(0) + , m_rtt(0) + , m_prefer_whole_pieces(0) + , m_desired_queue_size(2) + , m_fast_reconnect(false) + , m_active(false) + , m_peer_interested(false) + , m_peer_choked(true) + , m_interesting(false) + , m_choked(true) + , m_failed(false) + , m_ignore_bandwidth_limits(false) + , m_have_all(false) + , m_assume_fifo(false) + , m_disconnecting(false) + , m_connecting(false) + , m_queued(false) + , m_request_large_blocks(false) + , m_upload_only(false) #ifndef NDEBUG , m_in_constructor(true) #endif @@ -243,8 +247,8 @@ namespace libtorrent #endif #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING - asio::error_code ec; - TORRENT_ASSERT(m_socket->remote_endpoint() == remote() || ec); + error_code ec; + TORRENT_ASSERT(m_socket->remote_endpoint(ec) == m_remote || ec); m_logger = m_ses.create_log(remote().address().to_string(ec) + "_" + boost::lexical_cast(remote().port()), m_ses.listen_port()); (*m_logger) << "*** INCOMING CONNECTION\n"; @@ -286,12 +290,13 @@ namespace libtorrent void peer_connection::start() { + TORRENT_ASSERT(m_peer_info == 0 || m_peer_info->connection == this); boost::shared_ptr t = m_torrent.lock(); if (!t) { tcp::socket::non_blocking_io ioc(true); - asio::error_code ec; + error_code ec; m_socket->io_control(ioc, ec); if (ec) { @@ -439,7 +444,7 @@ namespace libtorrent // if this is a web seed. we don't have a peer_info struct if (m_peer_info) m_peer_info->seed = true; // if we're a seed too, disconnect - if (t->is_finished()) + if (t->is_finished() && m_ses.settings().close_redundant_connections) { disconnect("seed to seed connection redundant"); return; @@ -476,12 +481,7 @@ namespace libtorrent TORRENT_ASSERT(!m_in_constructor); TORRENT_ASSERT(m_disconnecting); - if (m_disk_recv_buffer) - { - m_ses.free_disk_buffer(m_disk_recv_buffer); - m_disk_recv_buffer = 0; - m_disk_recv_buffer_size = 0; - } + m_disk_recv_buffer_size = 0; #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING if (m_logger) @@ -616,6 +616,7 @@ namespace libtorrent #endif } #endif + if (is_disconnecting()) return; if (peer_info_struct()) { @@ -701,7 +702,7 @@ namespace libtorrent (*m_logger) << " " << i->second->torrent_file().info_hash() << "\n"; } #endif - disconnect("got invalid info-hash"); + disconnect("got invalid info-hash", 2); return; } @@ -785,6 +786,7 @@ namespace libtorrent if ((*i)->on_choke()) return; } #endif + if (is_disconnecting()) return; #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << time_now_string() << " <== CHOKE\n"; @@ -838,6 +840,8 @@ namespace libtorrent } #endif + if (is_disconnecting()) return; + 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())); @@ -921,6 +925,7 @@ namespace libtorrent } #endif + if (is_disconnecting()) return; if (t->have_piece(index)) return; if (m_suggested_pieces.size() > 9) @@ -956,6 +961,8 @@ namespace libtorrent (*m_logger) << time_now_string() << " <== UNCHOKE\n"; #endif m_peer_choked = false; + if (is_disconnecting()) return; + t->get_policy().unchoked(*this); } @@ -982,6 +989,7 @@ namespace libtorrent (*m_logger) << time_now_string() << " <== INTERESTED\n"; #endif m_peer_interested = true; + if (is_disconnecting()) return; t->get_policy().interested(*this); } @@ -1006,11 +1014,12 @@ namespace libtorrent #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << time_now_string() << " <== NOT_INTERESTED\n"; #endif + m_peer_interested = false; + if (is_disconnecting()) return; boost::shared_ptr t = m_torrent.lock(); TORRENT_ASSERT(t); - m_peer_interested = false; t->get_policy().not_interested(*this); } @@ -1033,6 +1042,8 @@ namespace libtorrent } #endif + if (is_disconnecting()) return; + #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << time_now_string() << " <== HAVE [ piece: " << index << "]\n"; @@ -1059,7 +1070,7 @@ namespace libtorrent // if we got an invalid message, abort if (index >= int(m_have_piece.size()) || index < 0) { - disconnect("got 'have'-message with higher index than the number of pieces"); + disconnect("got 'have'-message with higher index than the number of pieces", 2); return; } @@ -1099,11 +1110,11 @@ namespace libtorrent } } - if (is_seed()) + if (upload_only()) { TORRENT_ASSERT(m_peer_info); - m_peer_info->seed = true; - if (t->is_finished()) + if (is_seed()) m_peer_info->seed = true; + if (t->is_finished() && m_ses.settings().close_redundant_connections) { disconnect("seed to seed connection redundant"); return; @@ -1131,6 +1142,8 @@ namespace libtorrent } #endif + if (is_disconnecting()) return; + #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << time_now_string() << " <== BITFIELD "; @@ -1151,7 +1164,7 @@ namespace libtorrent msg << "got bitfield with invalid size: " << (bitfield.size() / 8) << "bytes. expected: " << (m_have_piece.size() / 8) << " bytes"; - disconnect(msg.str().c_str()); + disconnect(msg.str().c_str(), 2); return; } @@ -1178,7 +1191,7 @@ namespace libtorrent // if this is a web seed. we don't have a peer_info struct if (m_peer_info) m_peer_info->seed = true; // if we're a seed too, disconnect - if (t->is_finished()) + if (t->is_finished() && m_ses.settings().close_redundant_connections) { disconnect("seed to seed connection redundant, disconnecting"); return; @@ -1220,6 +1233,7 @@ namespace libtorrent m_num_pieces = num_pieces; if (interesting) t->get_policy().peer_is_interesting(*this); + else if (upload_only()) disconnect("upload to upload connections"); } // ----------------------------- @@ -1240,6 +1254,7 @@ namespace libtorrent if ((*i)->on_request(r)) return; } #endif + if (is_disconnecting()) return; if (!t->valid_metadata()) { @@ -1426,7 +1441,7 @@ namespace libtorrent boost::shared_ptr t = m_torrent.lock(); TORRENT_ASSERT(t); - TORRENT_ASSERT(m_disk_recv_buffer == 0); + TORRENT_ASSERT(!m_disk_recv_buffer); TORRENT_ASSERT(m_disk_recv_buffer_size == 0); #ifndef TORRENT_DISABLE_EXTENSIONS @@ -1436,6 +1451,7 @@ namespace libtorrent if ((*i)->on_piece(p, data)) return; } #endif + if (is_disconnecting()) return; #ifndef NDEBUG check_postcondition post_checker_(t); @@ -1461,7 +1477,7 @@ namespace libtorrent "start: " << p.start << " | " "length: " << p.length << " ]\n"; #endif - disconnect("got invalid piece packet"); + disconnect("got invalid piece packet", 2); return; } @@ -1648,6 +1664,7 @@ namespace libtorrent if ((*i)->on_cancel(r)) return; } #endif + if (is_disconnecting()) return; #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << time_now_string() @@ -1717,6 +1734,7 @@ namespace libtorrent if ((*i)->on_have_all()) return; } #endif + if (is_disconnecting()) return; m_have_all = true; @@ -1739,7 +1757,7 @@ namespace libtorrent #endif // if we're a seed too, disconnect - if (t->is_finished()) + if (t->is_finished() && m_ses.settings().close_redundant_connections) { disconnect("seed to seed connection redundant, disconnecting"); return; @@ -1762,13 +1780,13 @@ namespace libtorrent { INVARIANT_CHECK; - boost::shared_ptr t = m_torrent.lock(); - TORRENT_ASSERT(t); - #ifdef TORRENT_VERBOSE_LOGGING (*m_logger) << time_now_string() << " <== HAVE_NONE\n"; #endif + boost::shared_ptr t = m_torrent.lock(); + TORRENT_ASSERT(t); + #ifndef TORRENT_DISABLE_EXTENSIONS for (extension_list_t::iterator i = m_extensions.begin() , end(m_extensions.end()); i != end; ++i) @@ -1776,8 +1794,9 @@ namespace libtorrent if ((*i)->on_have_none()) return; } #endif - + if (is_disconnecting()) return; if (m_peer_info) m_peer_info->seed = false; + TORRENT_ASSERT(!m_have_piece.empty() || !t->ready_for_connections()); } @@ -1803,6 +1822,7 @@ namespace libtorrent if ((*i)->on_allowed_fast(index)) return; } #endif + if (is_disconnecting()) return; if (index < 0 || index >= int(m_have_piece.size())) { @@ -2109,6 +2129,7 @@ namespace libtorrent { if (handled = (*i)->write_request(r)) break; } + if (is_disconnecting()) return; if (!handled) { write_request(r); @@ -2141,24 +2162,38 @@ namespace libtorrent (*m_ses.m_logger) << time_now_string() << " CONNECTION TIMED OUT: " << m_remote.address().to_string() << "\n"; #endif - set_failed(); - disconnect("timed out"); + disconnect("timed out: connect", 1); } - void peer_connection::disconnect(char const* message) + // the error argument defaults to 0, which means deliberate disconnect + // 1 means unexpected disconnect/error + // 2 protocol error (client sent something invalid) + void peer_connection::disconnect(char const* message, int error) { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING - (*m_logger) << "*** CONNECTION FAILED " << message << "\n"; + switch (error) + { + case 0: + (*m_logger) << "*** CONNECTION CLOSED " << message << "\n"; + break; + case 1: + (*m_logger) << "*** CONNECTION FAILED " << message << "\n"; + break; + case 2: + (*m_logger) << "*** PEER ERROR " << message << "\n"; + break; + } #endif // we cannot do this in a constructor TORRENT_ASSERT(m_in_constructor == false); + if (error > 0) m_failed = true; + if (m_disconnecting) return; boost::intrusive_ptr me(this); INVARIANT_CHECK; - if (m_disconnecting) return; if (m_connecting && m_connection_ticket >= 0) { m_ses.m_half_open.done(m_connection_ticket); @@ -2167,13 +2202,18 @@ namespace libtorrent boost::shared_ptr t = m_torrent.lock(); - if (message && m_ses.m_alerts.should_post(alert::debug)) + if (message) { - m_ses.m_alerts.post_alert( - peer_error_alert( - remote() - , pid() - , message)); + if (error > 1 && m_ses.m_alerts.should_post(alert::info)) + { + m_ses.m_alerts.post_alert( + peer_error_alert(remote(), pid(), message)); + } + else if (error <= 1 && m_ses.m_alerts.should_post(alert::debug)) + { + m_ses.m_alerts.post_alert( + peer_disconnected_alert(remote(), pid(), message)); + } } if (t) @@ -2207,7 +2247,7 @@ namespace libtorrent #endif m_disconnecting = true; - asio::error_code ec; + error_code ec; m_socket->close(ec); m_ses.close_connection(this, message); } @@ -2372,17 +2412,17 @@ namespace libtorrent TORRENT_ASSERT(m_packet_size > 0); TORRENT_ASSERT(m_recv_pos <= m_packet_size - disk_buffer_size); - TORRENT_ASSERT(m_disk_recv_buffer == 0); + TORRENT_ASSERT(!m_disk_recv_buffer); TORRENT_ASSERT(disk_buffer_size <= 16 * 1024); if (disk_buffer_size > 16 * 1024) { - disconnect("invalid piece size"); + disconnect("invalid piece size", 2); return false; } - m_disk_recv_buffer = m_ses.allocate_disk_buffer(); - if (m_disk_recv_buffer == 0) + m_disk_recv_buffer.reset(m_ses.allocate_disk_buffer()); + if (!m_disk_recv_buffer) { disconnect("out of memory"); return false; @@ -2393,10 +2433,8 @@ namespace libtorrent char* peer_connection::release_disk_receive_buffer() { - char* ret = m_disk_recv_buffer; - m_disk_recv_buffer = 0; m_disk_recv_buffer_size = 0; - return ret; + return m_disk_recv_buffer.release(); } void peer_connection::cut_receive_buffer(int size, int packet_size) @@ -2420,11 +2458,17 @@ namespace libtorrent m_packet_size = packet_size; } + void peer_connection::calc_ip_overhead() + { + m_statistics.calc_ip_overhead(); + } + void peer_connection::second_tick(float tick_interval) { INVARIANT_CHECK; ptime now(time_now()); + boost::intrusive_ptr me(self()); boost::shared_ptr t = m_torrent.lock(); if (!t || m_disconnecting) @@ -2466,6 +2510,7 @@ namespace libtorrent } #endif } + if (is_disconnecting()) return; if (!t->valid_metadata()) return; @@ -2829,7 +2874,7 @@ namespace libtorrent if (int(m_recv_buffer.size()) < regular_buffer_size) m_recv_buffer.resize(regular_buffer_size); - if (m_disk_recv_buffer == 0 || regular_buffer_size >= m_recv_pos + max_receive) + if (!m_disk_recv_buffer || regular_buffer_size >= m_recv_pos + max_receive) { // only receive into regular buffer TORRENT_ASSERT(m_recv_pos + max_receive <= int(m_recv_buffer.size())); @@ -2841,7 +2886,7 @@ namespace libtorrent // only receive into disk buffer TORRENT_ASSERT(m_recv_pos - regular_buffer_size >= 0); TORRENT_ASSERT(m_recv_pos - regular_buffer_size + max_receive <= m_disk_recv_buffer_size); - m_socket->async_read_some(asio::buffer(m_disk_recv_buffer + m_recv_pos - regular_buffer_size + m_socket->async_read_some(asio::buffer(m_disk_recv_buffer.get() + m_recv_pos - regular_buffer_size , max_receive) , bind(&peer_connection::on_receive_data, self(), _1, _2)); } @@ -2856,7 +2901,7 @@ namespace libtorrent boost::array vec; vec[0] = asio::buffer(&m_recv_buffer[m_recv_pos] , regular_buffer_size - m_recv_pos); - vec[1] = asio::buffer(m_disk_recv_buffer + vec[1] = asio::buffer(m_disk_recv_buffer.get() , max_receive - regular_buffer_size + m_recv_pos); m_socket->async_read_some(vec, bind(&peer_connection::on_receive_data , self(), _1, _2)); @@ -2874,7 +2919,7 @@ namespace libtorrent std::pair vec; int regular_buffer_size = m_packet_size - m_disk_recv_buffer_size; TORRENT_ASSERT(regular_buffer_size >= 0); - if (m_disk_recv_buffer == 0 || regular_buffer_size >= m_recv_pos) + if (!m_disk_recv_buffer || regular_buffer_size >= m_recv_pos) { vec.first = buffer::interval(&m_recv_buffer[0] + m_recv_pos - bytes, &m_recv_buffer[0] + m_recv_pos); @@ -2882,8 +2927,8 @@ namespace libtorrent } else if (m_recv_pos - bytes >= regular_buffer_size) { - vec.first = buffer::interval(m_disk_recv_buffer + m_recv_pos - - regular_buffer_size - bytes, m_disk_recv_buffer + m_recv_pos + vec.first = buffer::interval(m_disk_recv_buffer.get() + m_recv_pos + - regular_buffer_size - bytes, m_disk_recv_buffer.get() + m_recv_pos - regular_buffer_size); vec.second = buffer::interval(0,0); } @@ -2893,8 +2938,8 @@ namespace libtorrent TORRENT_ASSERT(m_recv_pos > regular_buffer_size); vec.first = buffer::interval(&m_recv_buffer[0] + m_recv_pos - bytes , &m_recv_buffer[0] + regular_buffer_size); - vec.second = buffer::interval(m_disk_recv_buffer - , m_disk_recv_buffer + m_recv_pos - regular_buffer_size); + vec.second = buffer::interval(m_disk_recv_buffer.get() + , m_disk_recv_buffer.get() + m_recv_pos - regular_buffer_size); } TORRENT_ASSERT(vec.first.left() + vec.second.left() == bytes); return vec; @@ -2998,7 +3043,7 @@ namespace libtorrent // -------------------------- // throws exception when the client should be disconnected - void peer_connection::on_receive_data(const asio::error_code& error + void peer_connection::on_receive_data(const error_code& error , std::size_t bytes_transferred) { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); @@ -3014,7 +3059,6 @@ namespace libtorrent (*m_logger) << time_now_string() << " **ERROR**: " << error.message() << "[in peer_connection::on_receive_data]\n"; #endif - set_failed(); on_receive(error, bytes_transferred); disconnect(error.message().c_str()); return; @@ -3063,8 +3107,8 @@ namespace libtorrent if (int(m_recv_buffer.size()) < regular_buffer_size) m_recv_buffer.resize(regular_buffer_size); - asio::error_code ec; - if (m_disk_recv_buffer == 0 || regular_buffer_size >= m_recv_pos + max_receive) + error_code ec; + if (!m_disk_recv_buffer || regular_buffer_size >= m_recv_pos + max_receive) { // only receive into regular buffer TORRENT_ASSERT(m_recv_pos + max_receive <= int(m_recv_buffer.size())); @@ -3076,7 +3120,7 @@ namespace libtorrent // only receive into disk buffer TORRENT_ASSERT(m_recv_pos - regular_buffer_size >= 0); TORRENT_ASSERT(m_recv_pos - regular_buffer_size + max_receive <= m_disk_recv_buffer_size); - bytes_transferred = m_socket->read_some(asio::buffer(m_disk_recv_buffer + bytes_transferred = m_socket->read_some(asio::buffer(m_disk_recv_buffer.get() + m_recv_pos - regular_buffer_size, (std::min)(m_packet_size - m_recv_pos, max_receive)), ec); } @@ -3091,7 +3135,7 @@ namespace libtorrent boost::array vec; vec[0] = asio::buffer(&m_recv_buffer[m_recv_pos] , regular_buffer_size - m_recv_pos); - vec[1] = asio::buffer(m_disk_recv_buffer + vec[1] = asio::buffer(m_disk_recv_buffer.get() , (std::min)(m_disk_recv_buffer_size , max_receive - regular_buffer_size + m_recv_pos)); bytes_transferred = m_socket->read_some(vec, ec); @@ -3107,27 +3151,6 @@ namespace libtorrent setup_receive(); } - /* - catch (file_error& e) - { - session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); - - boost::shared_ptr t = m_torrent.lock(); - if (!t) - { - disconnect(e.what()); - return; - } - - if (t->alerts().should_post(alert::fatal)) - { - t->alerts().post_alert( - file_error_alert(t->get_handle() - , std::string("torrent paused: ") + e.what())); - } - t->pause(); - } -*/ bool peer_connection::can_write() const { @@ -3158,7 +3181,7 @@ namespace libtorrent { INVARIANT_CHECK; - asio::error_code ec; + error_code ec; #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING (*m_ses.m_logger) << time_now_string() << " CONNECTING: " << m_remote.address().to_string(ec) << ":" << m_remote.port() << "\n"; @@ -3209,7 +3232,7 @@ namespace libtorrent } } - void peer_connection::on_connection_complete(asio::error_code const& e) + void peer_connection::on_connection_complete(error_code const& e) { ptime completed = time_now(); @@ -3230,8 +3253,7 @@ namespace libtorrent (*m_ses.m_logger) << time_now_string() << " CONNECTION FAILED: " << m_remote.address().to_string() << ": " << e.message() << "\n"; #endif - set_failed(); - disconnect(e.message().c_str()); + disconnect(e.message().c_str(), 1); return; } @@ -3247,7 +3269,7 @@ namespace libtorrent if (m_remote.address().is_v4()) { - asio::error_code ec; + error_code ec; m_socket->set_option(type_of_service(m_ses.settings().peer_tos), ec); } @@ -3261,7 +3283,7 @@ namespace libtorrent // -------------------------- // throws exception when the client should be disconnected - void peer_connection::on_send_data(asio::error_code const& error + void peer_connection::on_send_data(error_code const& error , std::size_t bytes_transferred) { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); @@ -3286,7 +3308,6 @@ namespace libtorrent #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING (*m_logger) << "**ERROR**: " << error.message() << " [in peer_connection::on_send_data]\n"; #endif - set_failed(); disconnect(error.message().c_str()); return; } @@ -3306,7 +3327,7 @@ namespace libtorrent #ifndef NDEBUG void peer_connection::check_invariant() const { - TORRENT_ASSERT((m_disk_recv_buffer != 0) == (m_disk_recv_buffer_size > 0)); + TORRENT_ASSERT(bool(m_disk_recv_buffer) == (m_disk_recv_buffer_size > 0)); boost::shared_ptr t = m_torrent.lock(); if (m_disconnecting) diff --git a/libtorrent/src/piece_picker.cpp b/libtorrent/src/piece_picker.cpp index cdad7425e..bbacb9889 100755 --- a/libtorrent/src/piece_picker.cpp +++ b/libtorrent/src/piece_picker.cpp @@ -133,22 +133,8 @@ namespace libtorrent { int index = static_cast(i - pieces.begin()); piece_pos& p = m_piece_map[index]; - if (*i) - { - if (m_sequential_download == index) ++m_sequential_download; - ++m_num_have; - p.set_have(); - if (p.filtered()) - { - ++m_num_have_filtered; - TORRENT_ASSERT(m_num_filtered > 0); - --m_num_filtered; - } - } - else - { - p.index = 0; - } + if (*i) we_have(index); + else TORRENT_ASSERT(p.index == 0); } } diff --git a/libtorrent/src/policy.cpp b/libtorrent/src/policy.cpp index 7c74a845f..c87eb4056 100755 --- a/libtorrent/src/policy.cpp +++ b/libtorrent/src/policy.cpp @@ -225,7 +225,7 @@ namespace libtorrent // blocks be from whole pieces, possibly by returning more blocks // than we requested. #ifndef NDEBUG - asio::error_code ec; + error_code ec; TORRENT_ASSERT(c.remote() == c.get_socket()->remote_endpoint(ec) || ec); #endif @@ -348,6 +348,7 @@ namespace libtorrent , m_torrent(t) , m_available_free_upload(0) , m_num_connect_candidates(0) + , m_num_seeds(0) { TORRENT_ASSERT(t); } // disconnects and removes all peers that are now filtered @@ -420,49 +421,6 @@ namespace libtorrent return true; } - policy::iterator policy::find_disconnect_candidate() - { - INVARIANT_CHECK; - - iterator disconnect_peer = m_peers.end(); - double slowest_transfer_rate = (std::numeric_limits::max)(); - - ptime now = time_now(); - - for (iterator i = m_peers.begin(); - i != m_peers.end(); ++i) - { - peer_connection* c = i->second.connection; - if (c == 0) continue; - if (c->is_disconnecting()) continue; - - // never disconnect an interesting peer if we have a candidate that - // isn't interesting - if (disconnect_peer != m_peers.end() - && c->is_interesting() - && !disconnect_peer->second.connection->is_interesting()) - continue; - - double transferred_amount - = (double)c->statistics().total_payload_download(); - - time_duration connected_time = now - i->second.connected; - - double connected_time_in_seconds = total_seconds(connected_time); - - double transfer_rate - = transferred_amount / (connected_time_in_seconds + 1); - - // prefer to disconnect uninteresting peers, and secondly slow peers - if (transfer_rate <= slowest_transfer_rate) - { - slowest_transfer_rate = transfer_rate; - disconnect_peer = i; - } - } - return disconnect_peer; - } - policy::iterator policy::find_connect_candidate() { // too expensive @@ -625,7 +583,7 @@ namespace libtorrent // TODO: only allow _one_ connection to use this // override at a time - asio::error_code ec; + error_code ec; TORRENT_ASSERT(c.remote() == c.get_socket()->remote_endpoint(ec) || ec); aux::session_impl& ses = m_torrent->session(); @@ -697,7 +655,7 @@ namespace libtorrent { // we don't have any info about this peer. // add a new entry - asio::error_code ec; + error_code ec; TORRENT_ASSERT(c.remote() == c.get_socket()->remote_endpoint(ec) || ec); peer p(c.remote(), peer::not_connectable, 0); @@ -1073,19 +1031,6 @@ namespace libtorrent return true; } - bool policy::disconnect_one_peer() - { - iterator p = find_disconnect_candidate(); - if (p == m_peers.end()) - return false; -#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING - (*p->second.connection->m_logger) << "*** CLOSING CONNECTION 'too many connections'\n"; -#endif - - p->second.connection->disconnect("too many connections, closing"); - return true; - } - // this is called whenever a peer connection is closed void policy::connection_closed(const peer_connection& c) { @@ -1156,7 +1101,7 @@ namespace libtorrent // INVARIANT_CHECK; TORRENT_ASSERT(c); - asio::error_code ec; + error_code ec; TORRENT_ASSERT(c->remote() == c->get_socket()->remote_endpoint(ec) || ec); return std::find_if( diff --git a/libtorrent/src/session.cpp b/libtorrent/src/session.cpp index f6ee4a2bb..bfceb7024 100755 --- a/libtorrent/src/session.cpp +++ b/libtorrent/src/session.cpp @@ -253,7 +253,6 @@ namespace libtorrent , bool paused , storage_constructor_type sc) { - TORRENT_ASSERT(!ti.m_half_metadata); boost::intrusive_ptr tip(new torrent_info(ti)); add_torrent_params p(sc); p.ti = tip; @@ -273,7 +272,6 @@ namespace libtorrent , storage_constructor_type sc , void* userdata) { - TORRENT_ASSERT(!ti->m_half_metadata); add_torrent_params p(sc); p.ti = ti; p.save_path = save_path; diff --git a/libtorrent/src/session_impl.cpp b/libtorrent/src/session_impl.cpp index 0a68547ea..5e70cb6e7 100755 --- a/libtorrent/src/session_impl.cpp +++ b/libtorrent/src/session_impl.cpp @@ -76,6 +76,10 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/enum_net.hpp" #include "libtorrent/config.hpp" +#ifndef TORRENT_WINDOWS +#include +#endif + #ifndef TORRENT_DISABLE_ENCRYPTION #include @@ -162,6 +166,7 @@ namespace aux { , m_auto_manage_time_scaler(0) , m_optimistic_unchoke_time_scaler(0) , m_disconnect_time_scaler(90) + , m_auto_scrape_time_scaler(180) , m_incoming_connection(false) , m_last_tick(time_now()) , m_torrent_sequence(0) @@ -207,6 +212,11 @@ namespace aux { #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING m_logger = create_log("main_session", listen_port(), false); (*m_logger) << time_now_string() << "\n"; + + (*m_logger) << "sizeof(torrent): " << sizeof(torrent) << "\n"; + (*m_logger) << "sizeof(peer_connection): " << sizeof(peer_connection) << "\n"; + (*m_logger) << "sizeof(bt_peer_connection): " << sizeof(bt_peer_connection) << "\n"; + (*m_logger) << "sizeof(policy::peer): " << sizeof(policy::peer) << "\n"; #endif #ifdef TORRENT_STATS @@ -250,7 +260,7 @@ namespace aux { *i = printable[rand() % (sizeof(printable)-1)]; } - asio::error_code ec; + error_code ec; m_timer.expires_from_now(seconds(1), ec); m_timer.async_wait( bind(&session_impl::second_tick, this, _1)); @@ -396,7 +406,7 @@ namespace aux { if (m_dht) m_dht->stop(); m_dht_socket.close(); #endif - asio::error_code ec; + error_code ec; m_timer.cancel(ec); // close the listen sockets @@ -535,7 +545,7 @@ namespace aux { session_impl::listen_socket_t session_impl::setup_listener(tcp::endpoint ep , int retries, bool v6_only) { - asio::error_code ec; + error_code ec; listen_socket_t s; s.sock.reset(new socket_acceptor(m_io_service)); s.sock->open(ep.protocol(), ec); @@ -544,7 +554,7 @@ namespace aux { s.sock->bind(ep, ec); while (ec && retries > 0) { - ec = asio::error_code(); + ec = error_code(); TORRENT_ASSERT(!ec); --retries; ep.port(ep.port() + 1); @@ -555,7 +565,7 @@ namespace aux { // instead of giving up, try // let the OS pick a port ep.port(0); - ec = asio::error_code(); + ec = error_code(); s.sock->bind(ep, ec); } if (ec) @@ -661,7 +671,7 @@ namespace aux { for (std::list::const_iterator i = m_listen_sockets.begin() , end(m_listen_sockets.end()); i != end; ++i) { - asio::error_code ec; + error_code ec; tcp::endpoint ep = i->sock->local_endpoint(ec); if (ec || ep.address().is_v4()) continue; @@ -691,7 +701,7 @@ namespace aux { if (!m_listen_sockets.empty()) { - asio::error_code ec; + error_code ec; tcp::endpoint local = m_listen_sockets.front().sock->local_endpoint(ec); if (!ec) { @@ -713,11 +723,16 @@ namespace aux { #ifndef TORRENT_DISABLE_DHT - void session_impl::on_receive_udp(asio::error_code const& e + void session_impl::on_receive_udp(error_code const& e , udp::endpoint const& ep, char const* buf, int len) { if (e) { + if (e == asio::error::connection_refused + || e == asio::error::connection_reset + || e == asio::error::connection_aborted) + m_dht->on_unreachable(ep); + if (m_alerts.should_post(alert::info)) { std::string msg = "UDP socket error from '" @@ -746,7 +761,7 @@ namespace aux { } void session_impl::on_incoming_connection(shared_ptr const& s - , weak_ptr listen_socket, asio::error_code const& e) + , weak_ptr listen_socket, error_code const& e) { boost::shared_ptr listener = listen_socket.lock(); if (!listener) return; @@ -756,7 +771,7 @@ namespace aux { mutex_t::scoped_lock l(m_mutex); if (m_abort) return; - asio::error_code ec; + error_code ec; if (e) { tcp::endpoint ep = listener->local_endpoint(ec); @@ -842,7 +857,13 @@ namespace aux { // check if we have any active torrents // if we don't reject the connection - if (m_torrents.empty()) return; + if (m_torrents.empty()) + { +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + (*m_logger) << " There are no torrents, disconnect\n"; +#endif + return; + } bool has_active_torrent = false; for (torrent_map::iterator i = m_torrents.begin() @@ -854,10 +875,16 @@ namespace aux { break; } } - if (!has_active_torrent) return; + if (!has_active_torrent) + { +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + (*m_logger) << " There are no _active_ torrents, disconnect\n"; +#endif + return; + } boost::intrusive_ptr c( - new bt_peer_connection(*this, s, 0)); + new bt_peer_connection(*this, s, endp, 0)); #ifndef NDEBUG c->m_in_constructor = false; #endif @@ -926,7 +953,7 @@ namespace aux { return port; } - void session_impl::second_tick(asio::error_code const& e) + void session_impl::second_tick(error_code const& e) { session_impl::mutex_t::scoped_lock l(m_mutex); @@ -947,7 +974,7 @@ namespace aux { float tick_interval = total_microseconds(time_now() - m_last_tick) / 1000000.f; m_last_tick = time_now(); - asio::error_code ec; + error_code ec; m_timer.expires_from_now(seconds(1), ec); m_timer.async_wait( bind(&session_impl::second_tick, this, _1)); @@ -986,7 +1013,6 @@ namespace aux { << m_disk_thread.disk_allocations() << "\t" << std::endl; #endif - // -------------------------------------------------------------- // second_tick every torrent // -------------------------------------------------------------- @@ -1002,6 +1028,9 @@ namespace aux { // count the number of peers of downloading torrents int num_downloads_peers = 0; + torrent_map::iterator least_recently_scraped = m_torrents.begin(); + int num_paused_auto_managed = 0; + // check each torrent for tracker updates // TODO: do this in a timer-event in each torrent instead for (torrent_map::iterator i = m_torrents.begin(); @@ -1014,6 +1043,17 @@ namespace aux { else ++uncongested_torrents; + if (t.is_auto_managed() && t.is_paused()) + { + ++num_paused_auto_managed; + if (!least_recently_scraped->second->is_auto_managed() + || !least_recently_scraped->second->is_paused() + || least_recently_scraped->second->last_scrape() > t.last_scrape()) + { + least_recently_scraped = i; + } + } + if (t.is_finished()) { ++num_seeds; @@ -1046,9 +1086,29 @@ namespace aux { ++i; } + // drain the IP overhead from the bandwidth limiters + m_download_channel.drain(m_stat.download_ip_overhead()); + m_upload_channel.drain(m_stat.upload_ip_overhead()); + m_stat.second_tick(tick_interval); - + // -------------------------------------------------------------- + // scrape paused torrents that are auto managed + // -------------------------------------------------------------- + --m_auto_scrape_time_scaler; + if (m_auto_scrape_time_scaler <= 0) + { + m_auto_scrape_time_scaler = m_settings.auto_scrape_interval + / (std::max)(1, num_paused_auto_managed); + if (m_auto_scrape_time_scaler < m_settings.auto_scrape_min_interval) + m_auto_scrape_time_scaler = m_settings.auto_scrape_min_interval; + + if (least_recently_scraped != m_torrents.end()) + { + least_recently_scraped->second->scrape_tracker(); + } + } + // -------------------------------------------------------------- // connect new peers // -------------------------------------------------------------- @@ -1156,20 +1216,10 @@ namespace aux { peer_connection& c = *j->get(); if (c.has_timed_out()) { - if (m_alerts.should_post(alert::debug)) - { - m_alerts.post_alert( - peer_error_alert( - c.remote() - , c.pid() - , "connection timed out")); - } #if defined(TORRENT_VERBOSE_LOGGING) (*c.m_logger) << "*** CONNECTION TIMED OUT\n"; #endif - - c.set_failed(); - c.disconnect("timed out"); + c.disconnect("timed out: inactive", 1); continue; } @@ -1205,17 +1255,37 @@ namespace aux { { m_disconnect_time_scaler = 90; - // every 90 seconds, disconnect the worst peer + // every 90 seconds, disconnect the worst peers // if we have reached the connection limit - if (num_connections() >= max_connections() && !m_torrents.empty()) + if (num_connections() >= max_connections() * m_settings.peer_turnover_cutoff + && !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))); TORRENT_ASSERT(i != m_torrents.end()); - // TODO: make the number of peers a percentage of the number of connected peers - i->second->get_policy().disconnect_one_peer(); + int peers_to_disconnect = (std::min)((std::max)(int(i->second->num_peers() + * m_settings.peer_turnover), 1) + , i->second->get_policy().num_connect_candidates()); + i->second->disconnect_peers(peers_to_disconnect); + } + else + { + // if we haven't reached the global max. see if any torrent + // has reached its local limit + for (torrent_map::iterator i = m_torrents.begin() + , end(m_torrents.end()); i != end; ++i) + { + boost::shared_ptr t = i->second; + if (t->num_peers() < t->max_connections() * m_settings.peer_turnover_cutoff) + continue; + + int peers_to_disconnect = (std::min)((std::max)(int(i->second->num_peers() + * m_settings.peer_turnover), 1) + , i->second->get_policy().num_connect_candidates()); + t->disconnect_peers(peers_to_disconnect); + } } } } @@ -1276,8 +1346,8 @@ namespace aux { , bind(&torrent::sequence_number, _1) < bind(&torrent::sequence_number, _2)); std::sort(seeds.begin(), seeds.end() - , bind(&torrent::seed_cycles_int, _1, boost::ref(m_settings)) - < bind(&torrent::seed_cycles_int, _2, boost::ref(m_settings))); + , bind(&torrent::seed_rank, _1, boost::ref(m_settings)) + > bind(&torrent::seed_rank, _2, boost::ref(m_settings))); } for (std::vector::iterator i = downloaders.begin() @@ -2111,7 +2181,19 @@ namespace aux { INVARIANT_CHECK; - if (limit <= 0) limit = (std::numeric_limits::max)(); + if (limit <= 0) + { + limit = (std::numeric_limits::max)(); +#ifndef TORRENT_WINDOWS + rlimit l; + if (getrlimit(RLIMIT_NOFILE, &l) == 0 + && l.rlim_cur != RLIM_INFINITY) + { + limit = l.rlim_cur - m_settings.file_pool_size; + if (limit < 5) limit = 5; + } +#endif + } m_max_connections = limit; } diff --git a/libtorrent/src/socks4_stream.cpp b/libtorrent/src/socks4_stream.cpp index c96dde85b..e4add5d4f 100644 --- a/libtorrent/src/socks4_stream.cpp +++ b/libtorrent/src/socks4_stream.cpp @@ -37,13 +37,13 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { - void socks4_stream::name_lookup(asio::error_code const& e, tcp::resolver::iterator i + void socks4_stream::name_lookup(error_code const& e, tcp::resolver::iterator i , boost::shared_ptr h) { if (e) { (*h)(e); - asio::error_code ec; + error_code ec; close(ec); return; } @@ -54,7 +54,7 @@ namespace libtorrent if (i == tcp::resolver::iterator()) { - asio::error_code ec = asio::error::operation_not_supported; + error_code ec = asio::error::operation_not_supported; (*h)(ec); close(ec); return; @@ -64,12 +64,12 @@ namespace libtorrent &socks4_stream::connected, this, _1, h)); } - void socks4_stream::connected(asio::error_code const& e, boost::shared_ptr h) + void socks4_stream::connected(error_code const& e, boost::shared_ptr h) { if (e) { (*h)(e); - asio::error_code ec; + error_code ec; close(ec); return; } @@ -86,31 +86,31 @@ namespace libtorrent p += m_user.size(); write_uint8(0, p); // NULL terminator - asio::async_write(m_sock, asio::buffer(m_buffer) + async_write(m_sock, asio::buffer(m_buffer) , boost::bind(&socks4_stream::handshake1, this, _1, h)); } - void socks4_stream::handshake1(asio::error_code const& e, boost::shared_ptr h) + void socks4_stream::handshake1(error_code const& e, boost::shared_ptr h) { if (e) { (*h)(e); - asio::error_code ec; + error_code ec; close(ec); return; } m_buffer.resize(8); - asio::async_read(m_sock, asio::buffer(m_buffer) + async_read(m_sock, asio::buffer(m_buffer) , boost::bind(&socks4_stream::handshake2, this, _1, h)); } - void socks4_stream::handshake2(asio::error_code const& e, boost::shared_ptr h) + void socks4_stream::handshake2(error_code const& e, boost::shared_ptr h) { if (e) { (*h)(e); - asio::error_code ec; + error_code ec; close(ec); return; } @@ -123,7 +123,7 @@ namespace libtorrent if (reply_version != 0) { - asio::error_code ec = asio::error::operation_not_supported; + error_code ec = asio::error::operation_not_supported; (*h)(ec); close(ec); return; @@ -137,7 +137,7 @@ namespace libtorrent return; } - asio::error_code ec = asio::error::fault; + error_code ec = asio::error::fault; switch (status_code) { case 91: ec = asio::error::connection_refused; break; diff --git a/libtorrent/src/socks5_stream.cpp b/libtorrent/src/socks5_stream.cpp index 62d1faf22..3fb9ec666 100644 --- a/libtorrent/src/socks5_stream.cpp +++ b/libtorrent/src/socks5_stream.cpp @@ -38,13 +38,13 @@ POSSIBILITY OF SUCH DAMAGE. namespace libtorrent { - void socks5_stream::name_lookup(asio::error_code const& e, tcp::resolver::iterator i + void socks5_stream::name_lookup(error_code const& e, tcp::resolver::iterator i , boost::shared_ptr h) { if (e || i == tcp::resolver::iterator()) { (*h)(e); - asio::error_code ec; + error_code ec; close(ec); return; } @@ -53,12 +53,12 @@ namespace libtorrent &socks5_stream::connected, this, _1, h)); } - void socks5_stream::connected(asio::error_code const& e, boost::shared_ptr h) + void socks5_stream::connected(error_code const& e, boost::shared_ptr h) { if (e) { (*h)(e); - asio::error_code ec; + error_code ec; close(ec); return; } @@ -79,31 +79,31 @@ namespace libtorrent write_uint8(0, p); // no authentication write_uint8(2, p); // username/password } - asio::async_write(m_sock, asio::buffer(m_buffer) + async_write(m_sock, asio::buffer(m_buffer) , boost::bind(&socks5_stream::handshake1, this, _1, h)); } - void socks5_stream::handshake1(asio::error_code const& e, boost::shared_ptr h) + void socks5_stream::handshake1(error_code const& e, boost::shared_ptr h) { if (e) { (*h)(e); - asio::error_code ec; + error_code ec; close(ec); return; } m_buffer.resize(2); - asio::async_read(m_sock, asio::buffer(m_buffer) + async_read(m_sock, asio::buffer(m_buffer) , boost::bind(&socks5_stream::handshake2, this, _1, h)); } - void socks5_stream::handshake2(asio::error_code const& e, boost::shared_ptr h) + void socks5_stream::handshake2(error_code const& e, boost::shared_ptr h) { if (e) { (*h)(e); - asio::error_code ec; + error_code ec; close(ec); return; } @@ -117,7 +117,7 @@ namespace libtorrent if (version < 5) { (*h)(asio::error::operation_not_supported); - asio::error_code ec; + error_code ec; close(ec); return; } @@ -131,7 +131,7 @@ namespace libtorrent if (m_user.empty()) { (*h)(asio::error::operation_not_supported); - asio::error_code ec; + error_code ec; close(ec); return; } @@ -144,41 +144,41 @@ namespace libtorrent write_string(m_user, p); write_uint8(m_password.size(), p); write_string(m_password, p); - asio::async_write(m_sock, asio::buffer(m_buffer) + async_write(m_sock, asio::buffer(m_buffer) , boost::bind(&socks5_stream::handshake3, this, _1, h)); } else { (*h)(asio::error::operation_not_supported); - asio::error_code ec; + error_code ec; close(ec); return; } } - void socks5_stream::handshake3(asio::error_code const& e + void socks5_stream::handshake3(error_code const& e , boost::shared_ptr h) { if (e) { (*h)(e); - asio::error_code ec; + error_code ec; close(ec); return; } m_buffer.resize(2); - asio::async_read(m_sock, asio::buffer(m_buffer) + async_read(m_sock, asio::buffer(m_buffer) , boost::bind(&socks5_stream::handshake4, this, _1, h)); } - void socks5_stream::handshake4(asio::error_code const& e + void socks5_stream::handshake4(error_code const& e , boost::shared_ptr h) { if (e) { (*h)(e); - asio::error_code ec; + error_code ec; close(ec); return; } @@ -192,7 +192,7 @@ namespace libtorrent if (version != 1) { (*h)(asio::error::operation_not_supported); - asio::error_code ec; + error_code ec; close(ec); return; } @@ -200,7 +200,7 @@ namespace libtorrent if (status != 0) { (*h)(asio::error::operation_not_supported); - asio::error_code ec; + error_code ec; close(ec); return; } @@ -223,31 +223,31 @@ namespace libtorrent write_endpoint(m_remote_endpoint, p); TORRENT_ASSERT(p - &m_buffer[0] == int(m_buffer.size())); - asio::async_write(m_sock, asio::buffer(m_buffer) + async_write(m_sock, asio::buffer(m_buffer) , boost::bind(&socks5_stream::connect1, this, _1, h)); } - void socks5_stream::connect1(asio::error_code const& e, boost::shared_ptr h) + void socks5_stream::connect1(error_code const& e, boost::shared_ptr h) { if (e) { (*h)(e); - asio::error_code ec; + error_code ec; close(ec); return; } m_buffer.resize(6 + 4); // assume an IPv4 address - asio::async_read(m_sock, asio::buffer(m_buffer) + async_read(m_sock, asio::buffer(m_buffer) , boost::bind(&socks5_stream::connect2, this, _1, h)); } - void socks5_stream::connect2(asio::error_code const& e, boost::shared_ptr h) + void socks5_stream::connect2(error_code const& e, boost::shared_ptr h) { if (e) { (*h)(e); - asio::error_code ec; + error_code ec; close(ec); return; } @@ -260,14 +260,14 @@ namespace libtorrent if (version < 5) { (*h)(asio::error::operation_not_supported); - asio::error_code ec; + error_code ec; close(ec); return; } int response = read_uint8(p); if (response != 0) { - asio::error_code e = asio::error::fault; + error_code e = asio::error::fault; switch (response) { case 1: e = asio::error::fault; break; @@ -280,7 +280,7 @@ namespace libtorrent case 8: e = asio::error::address_family_not_supported; break; } (*h)(e); - asio::error_code ec; + error_code ec; close(ec); return; } @@ -305,22 +305,22 @@ namespace libtorrent else { (*h)(asio::error::operation_not_supported); - asio::error_code ec; + error_code ec; close(ec); return; } m_buffer.resize(skip_bytes); - asio::async_read(m_sock, asio::buffer(m_buffer) + async_read(m_sock, asio::buffer(m_buffer) , boost::bind(&socks5_stream::connect3, this, _1, h)); } - void socks5_stream::connect3(asio::error_code const& e, boost::shared_ptr h) + void socks5_stream::connect3(error_code const& e, boost::shared_ptr h) { if (e) { (*h)(e); - asio::error_code ec; + error_code ec; close(ec); return; } diff --git a/libtorrent/src/stat.cpp b/libtorrent/src/stat.cpp index d695edc42..18a3285f8 100755 --- a/libtorrent/src/stat.cpp +++ b/libtorrent/src/stat.cpp @@ -47,47 +47,23 @@ POSSIBILITY OF SUCH DAMAGE. #define for if (false) {} else for #endif -using namespace libtorrent; +namespace libtorrent +{ -void libtorrent::stat::second_tick(float tick_interval) +void stat_channel::second_tick(float tick_interval) { INVARIANT_CHECK; + m_rate_sum -= m_rate_history[history-1]; + for (int i = history - 2; i >= 0; --i) - { - m_download_rate_history[i + 1] = m_download_rate_history[i]; - m_upload_rate_history[i + 1] = m_upload_rate_history[i]; - m_download_payload_rate_history[i + 1] = m_download_payload_rate_history[i]; - m_upload_payload_rate_history[i + 1] = m_upload_payload_rate_history[i]; - } + m_rate_history[i + 1] = m_rate_history[i]; - m_download_rate_history[0] = (m_downloaded_payload + m_downloaded_protocol) - / tick_interval; - m_upload_rate_history[0] = (m_uploaded_payload + m_uploaded_protocol) - / tick_interval; - m_download_payload_rate_history[0] = m_downloaded_payload / tick_interval; - m_upload_payload_rate_history[0] = m_uploaded_payload / tick_interval; - - m_downloaded_payload = 0; - m_uploaded_payload = 0; - m_downloaded_protocol = 0; - m_uploaded_protocol = 0; - - m_mean_download_rate = 0; - m_mean_upload_rate = 0; - m_mean_download_payload_rate = 0; - m_mean_upload_payload_rate = 0; - - for (int i = 0; i < history; ++i) - { - m_mean_download_rate += m_download_rate_history[i]; - m_mean_upload_rate += m_upload_rate_history[i]; - m_mean_download_payload_rate += m_download_payload_rate_history[i]; - m_mean_upload_payload_rate += m_upload_payload_rate_history[i]; - } - - m_mean_download_rate /= history; - m_mean_upload_rate /= history; - m_mean_download_payload_rate /= history; - m_mean_upload_payload_rate /= history; + m_rate_history[0] = m_counter / tick_interval; + m_rate_sum += m_rate_history[0]; + m_counter = 0; } + + +} + diff --git a/libtorrent/src/storage.cpp b/libtorrent/src/storage.cpp index 51fab7e12..e86d3d58d 100755 --- a/libtorrent/src/storage.cpp +++ b/libtorrent/src/storage.cpp @@ -527,12 +527,23 @@ namespace libtorrent std::pair ret = directories.insert((m_save_path / bp).string()); bp = bp.branch_path(); } +#if defined(_WIN32) && defined(UNICODE) + try + { fs::remove(safe_convert(p)); } + catch (std::exception& e) + { + error = e.what(); + error_file = p; + result = 1; + } +#else if (std::remove(p.c_str()) != 0 && errno != ENOENT) { error = std::strerror(errno); error_file = p; result = errno; } +#endif } // remove the directories. Reverse order to delete @@ -541,12 +552,23 @@ namespace libtorrent for (std::set::reverse_iterator i = directories.rbegin() , end(directories.rend()); i != end; ++i) { +#if defined(_WIN32) && defined(UNICODE) + try + { fs::remove(safe_convert(*i)); } + catch (std::exception& e) + { + error = e.what(); + error_file = *i; + result = 1; + } +#else if (std::remove(i->c_str()) != 0 && errno != ENOENT) { error = std::strerror(errno); error_file = *i; result = errno; } +#endif } if (!error.empty()) @@ -1230,7 +1252,7 @@ namespace libtorrent { TORRENT_ASSERT(r.length <= 16 * 1024); // the buffer needs to be allocated through the io_thread - TORRENT_ASSERT(m_io_thread.is_disk_buffer(buffer.buffer())); + TORRENT_ASSERT(m_io_thread.is_disk_buffer(buffer.get())); disk_io_job j; j.storage = this; @@ -1238,7 +1260,7 @@ namespace libtorrent j.piece = r.piece; j.offset = r.start; j.buffer_size = r.length; - j.buffer = buffer.buffer(); + j.buffer = buffer.get(); m_io_thread.add_job(j, handler); buffer.release(); } @@ -2465,7 +2487,8 @@ namespace libtorrent && m_free_slots.empty() && m_state == state_finished) { - TORRENT_ASSERT(m_storage_mode != storage_mode_compact); + TORRENT_ASSERT(m_storage_mode != storage_mode_compact + || m_info->num_pieces() == 0); } if (m_storage_mode != storage_mode_compact) diff --git a/libtorrent/src/torrent.cpp b/libtorrent/src/torrent.cpp index 51f416add..25cb02558 100755 --- a/libtorrent/src/torrent.cpp +++ b/libtorrent/src/torrent.cpp @@ -59,6 +59,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/session.hpp" #include "libtorrent/torrent_info.hpp" #include "libtorrent/tracker_manager.hpp" +#include "libtorrent/parse_url.hpp" #include "libtorrent/bencode.hpp" #include "libtorrent/hasher.hpp" #include "libtorrent/entry.hpp" @@ -95,20 +96,6 @@ namespace , tracker_failed_max = 5 }; - int calculate_block_size(const torrent_info& i, int default_block_size) - { - if (default_block_size < 1024) default_block_size = 1024; - - // if pieces are too small, adjust the block size - if (i.piece_length() < default_block_size) - { - return i.piece_length(); - } - - // otherwise, go with the default - return default_block_size; - } - struct find_peer_by_ip { find_peer_by_ip(tcp::endpoint const& a, const torrent* t) @@ -160,23 +147,18 @@ namespace libtorrent , entry const* resume_data , int seq , bool auto_managed) - : m_torrent_file(tf) - , m_abort(false) - , m_paused(paused) - , m_just_paused(false) - , m_auto_managed(auto_managed) + : m_policy(this) + , m_active_time(seconds(0)) + , m_seeding_time(seconds(0)) + , m_total_uploaded(0) + , m_total_downloaded(0) + , m_started(time_now()) + , m_last_scrape(min_time()) + , m_torrent_file(tf) , m_event(tracker_request::started) - , m_block_size(0) , m_storage(0) , m_next_request(time_now()) - , m_duration(1800) - , m_complete(-1) - , m_incomplete(-1) , m_host_resolver(ses.m_io_service) -#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES - , m_resolving_country(false) - , m_resolve_countries(false) -#endif , m_announce_timer(ses.m_io_service) #ifndef TORRENT_DISABLE_DHT , m_last_dht_announce(time_now() - minutes(15)) @@ -184,35 +166,41 @@ namespace libtorrent , m_ses(ses) , m_picker(0) , m_trackers(m_torrent_file->trackers()) - , m_last_working_tracker(-1) - , m_currently_trying_tracker(0) - , m_failed_trackers(0) - , m_time_scaler(0) - , m_num_pieces(0) - , m_sequential_download(false) - , m_got_tracker_response(false) - , m_ratio(0.f) , m_total_failed_bytes(0) , m_total_redundant_bytes(0) , m_net_interface(net_interface.address(), 0) , m_save_path(complete(save_path)) , m_storage_mode(storage_mode) , m_state(torrent_status::queued_for_checking) - , m_progress(0.f) - , m_default_block_size(block_size) - , m_connections_initialized(true) , m_settings(ses.settings()) , m_storage_constructor(sc) + , m_progress(0.f) + , m_num_pieces(0) + , m_ratio(0.f) , m_max_uploads((std::numeric_limits::max)()) , m_num_uploads(0) , m_max_connections((std::numeric_limits::max)()) + , m_block_size(block_size) + , m_complete(-1) + , m_incomplete(-1) , m_deficit_counter(0) - , m_policy(this) + , m_duration(1800) , m_sequence_number(seq) - , m_active_time(seconds(0)) - , m_seeding_time(seconds(0)) - , m_total_uploaded(0) - , m_total_downloaded(0) + , m_last_working_tracker(-1) + , m_currently_trying_tracker(0) + , m_failed_trackers(0) + , m_time_scaler(0) + , m_abort(false) + , m_paused(paused) + , m_just_paused(false) + , m_auto_managed(auto_managed) +#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES + , m_resolving_country(false) + , m_resolve_countries(false) +#endif + , m_sequential_download(false) + , m_got_tracker_response(false) + , m_connections_initialized(true) { if (resume_data) m_resume_data = *resume_data; #ifndef NDEBUG @@ -234,58 +222,59 @@ namespace libtorrent , entry const* resume_data , int seq , bool auto_managed) - : m_torrent_file(new torrent_info(info_hash)) - , m_abort(false) - , m_paused(paused) - , m_just_paused(false) - , m_auto_managed(auto_managed) + : m_policy(this) + , m_active_time(seconds(0)) + , m_seeding_time(seconds(0)) + , m_total_uploaded(0) + , m_total_downloaded(0) + , m_started(time_now()) + , m_last_scrape(min_time()) + , m_torrent_file(new torrent_info(info_hash)) , m_event(tracker_request::started) - , m_block_size(0) , m_storage(0) , m_next_request(time_now()) - , m_duration(1800) - , m_complete(-1) - , m_incomplete(-1) , m_host_resolver(ses.m_io_service) -#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES - , m_resolving_country(false) - , m_resolve_countries(false) -#endif , m_announce_timer(ses.m_io_service) #ifndef TORRENT_DISABLE_DHT , m_last_dht_announce(time_now() - minutes(15)) #endif , m_ses(ses) , m_picker(0) - , m_last_working_tracker(-1) - , m_currently_trying_tracker(0) - , m_failed_trackers(0) - , m_time_scaler(0) - , m_num_pieces(0) - , m_sequential_download(false) - , m_got_tracker_response(false) - , m_ratio(0.f) , m_total_failed_bytes(0) , m_total_redundant_bytes(0) , m_net_interface(net_interface.address(), 0) , m_save_path(complete(save_path)) , m_storage_mode(storage_mode) , m_state(torrent_status::queued_for_checking) - , m_progress(0.f) - , m_default_block_size(block_size) - , m_connections_initialized(false) , m_settings(ses.settings()) , m_storage_constructor(sc) + , m_progress(0.f) + , m_num_pieces(0) + , m_ratio(0.f) , m_max_uploads((std::numeric_limits::max)()) , m_num_uploads(0) , m_max_connections((std::numeric_limits::max)()) + , m_block_size(block_size) + , m_complete(-1) + , m_incomplete(-1) , m_deficit_counter(0) - , m_policy(this) + , m_duration(1800) , m_sequence_number(seq) - , m_active_time(seconds(0)) - , m_seeding_time(seconds(0)) - , m_total_uploaded(0) - , m_total_downloaded(0) + , m_last_working_tracker(-1) + , m_currently_trying_tracker(0) + , m_failed_trackers(0) + , m_time_scaler(0) + , m_abort(false) + , m_paused(paused) + , m_just_paused(false) + , m_auto_managed(auto_managed) +#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES + , m_resolving_country(false) + , m_resolve_countries(false) +#endif + , m_sequential_download(false) + , m_got_tracker_response(false) + , m_connections_initialized(false) { if (resume_data) m_resume_data = *resume_data; #ifndef NDEBUG @@ -307,7 +296,7 @@ namespace libtorrent boost::weak_ptr self(shared_from_this()); if (m_torrent_file->is_valid()) init(); if (m_abort) return; - asio::error_code ec; + error_code ec; m_announce_timer.expires_from_now(seconds(1), ec); m_announce_timer.async_wait( bind(&torrent::on_announce_disp, self, _1)); @@ -425,7 +414,6 @@ namespace libtorrent , m_save_path, m_ses.m_files, m_ses.m_disk_thread, m_storage_constructor , m_storage_mode); m_storage = m_owning_storage.get(); - m_block_size = calculate_block_size(*m_torrent_file, m_default_block_size); m_picker.reset(new piece_picker( m_torrent_file->piece_length() / m_block_size , int((m_torrent_file->total_size()+m_block_size-1)/m_block_size))); @@ -603,6 +591,13 @@ namespace libtorrent } } } + + int index = 0; + for (std::vector::iterator i = m_have_pieces.begin() + , end(m_have_pieces.end()); i != end; ++i, ++index) + { + if (*i) m_picker->we_have(index); + } } files_checked(); @@ -654,6 +649,8 @@ namespace libtorrent { m_have_pieces[j.offset] = true; ++m_num_pieces; + TORRENT_ASSERT(m_picker); + m_picker->we_have(j.offset); } // we're not done checking yet @@ -673,7 +670,7 @@ namespace libtorrent } void torrent::on_announce_disp(boost::weak_ptr p - , asio::error_code const& e) + , error_code const& e) { if (e) return; boost::shared_ptr t = p.lock(); @@ -687,7 +684,7 @@ namespace libtorrent boost::weak_ptr self(shared_from_this()); - asio::error_code ec; + error_code ec; if (!m_torrent_file->priv()) { // announce on local network every 5 minutes @@ -759,6 +756,8 @@ namespace libtorrent req.url = m_trackers[m_currently_trying_tracker].url; m_ses.m_tracker_manager.queue_request(m_ses.m_io_service, m_ses.m_half_open, req , tracker_login(), m_ses.m_listen_interface.address(), shared_from_this()); + + m_last_scrape = time_now(); } // returns true if it is time for this torrent to make another @@ -837,6 +836,8 @@ namespace libtorrent if (complete >= 0) m_complete = complete; if (incomplete >= 0) m_incomplete = incomplete; + if (complete >= 0 && incomplete >= 0) + m_last_scrape = time_now(); // connect to random peers from the list std::random_shuffle(peer_list.begin(), peer_list.end()); @@ -865,7 +866,7 @@ namespace libtorrent if (i->pid == m_ses.get_peer_id()) continue; - asio::error_code ec; + error_code ec; tcp::endpoint a(address::from_string(i->ip, ec), i->port); if (ec) @@ -875,7 +876,7 @@ namespace libtorrent tcp::resolver::query q(i->ip, boost::lexical_cast(i->port)); m_host_resolver.async_resolve(q, - bind(&torrent::on_peer_name_lookup, shared_from_this(), _1, _2, i->pid)); + bind(&torrent::on_peer_name_lookup, shared_from_this(), _1, _2, i->pid)); } else { @@ -905,7 +906,7 @@ namespace libtorrent m_got_tracker_response = true; } - void torrent::on_peer_name_lookup(asio::error_code const& e, tcp::resolver::iterator host + void torrent::on_peer_name_lookup(error_code const& e, tcp::resolver::iterator host , peer_id pid) { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); @@ -1369,7 +1370,7 @@ namespace libtorrent bind(&torrent::on_files_released, shared_from_this(), _1, _2)); m_owning_storage = 0; - asio::error_code ec; + error_code ec; m_announce_timer.cancel(ec); m_host_resolver.cancel(); } @@ -1487,9 +1488,8 @@ namespace libtorrent #endif if (is_seed()) { + m_state = torrent_status::seeding; m_picker.reset(); - if (m_ses.settings().free_torrent_hashes) - m_torrent_file->seed_free(); } } @@ -1653,6 +1653,8 @@ namespace libtorrent // the torrent just became finished if (is_finished() && !was_finished) finished(); + else if (!is_finished() && was_finished) + resume_download(); } void torrent::filter_piece(int index, bool filter) @@ -1912,9 +1914,20 @@ namespace libtorrent std::string hostname; int port; std::string path; - boost::tie(protocol, auth, hostname, port, path) + char const* error; + boost::tie(protocol, auth, hostname, port, path, error) = parse_url_components(url); + if (error) + { +#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING + (*m_ses.m_logger) << time_now_string() << " failed to parse web seed url: " << error << "\n"; +#endif + // never try it again + remove_url_seed(url); + return; + } + #ifdef TORRENT_USE_OPENSSL if (protocol != "http" && protocol != "https") #else @@ -1968,6 +1981,18 @@ namespace libtorrent } else { + if (m_ses.m_port_filter.access(port) & port_filter::blocked) + { + if (m_ses.m_alerts.should_post(alert::warning)) + { + m_ses.m_alerts.post_alert( + url_seed_alert(get_handle(), url, "port blocked by port-filter")); + } + // never try it again + remove_url_seed(url); + return; + } + tcp::resolver::query q(hostname, boost::lexical_cast(port)); m_host_resolver.async_resolve(q, bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url @@ -1976,7 +2001,7 @@ namespace libtorrent } - void torrent::on_proxy_name_lookup(asio::error_code const& e, tcp::resolver::iterator host + void torrent::on_proxy_name_lookup(error_code const& e, tcp::resolver::iterator host , std::string url) { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); @@ -1991,10 +2016,8 @@ namespace libtorrent { if (m_ses.m_alerts.should_post(alert::warning)) { - std::stringstream msg; - msg << "HTTP seed proxy hostname lookup failed: " << e.message(); m_ses.m_alerts.post_alert( - url_seed_alert(get_handle(), url, msg.str())); + url_seed_alert(get_handle(), url, e.message())); } // the name lookup failed for the http host. Don't try @@ -2010,9 +2033,21 @@ namespace libtorrent using boost::tuples::ignore; std::string hostname; int port; - boost::tie(ignore, ignore, hostname, port, ignore) + char const* error; + boost::tie(ignore, ignore, hostname, port, ignore, error) = parse_url_components(url); + if (error) + { + if (m_ses.m_alerts.should_post(alert::warning)) + { + m_ses.m_alerts.post_alert( + url_seed_alert(get_handle(), url, error)); + } + remove_url_seed(url); + return; + } + if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked) { if (m_ses.m_alerts.should_post(alert::info)) @@ -2028,7 +2063,7 @@ namespace libtorrent bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url, a)); } - void torrent::on_name_lookup(asio::error_code const& e, tcp::resolver::iterator host + void torrent::on_name_lookup(error_code const& e, tcp::resolver::iterator host , std::string url, tcp::endpoint proxy) { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); @@ -2090,7 +2125,7 @@ namespace libtorrent } std::pair const& out_ports = m_settings.outgoing_ports; - asio::error_code ec; + error_code ec; if (out_ports.first > 0 && out_ports.second >= out_ports.first) s->bind(tcp::endpoint(address(), m_ses.next_port()), ec); @@ -2135,9 +2170,7 @@ namespace libtorrent #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING (*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << e.what() << "\n"; #endif - - // TODO: post an error alert! - c->disconnect(e.what()); + c->disconnect(e.what(), 1); } #endif } @@ -2176,7 +2209,7 @@ namespace libtorrent }; } - void torrent::on_country_lookup(asio::error_code const& error, tcp::resolver::iterator i + void torrent::on_country_lookup(error_code const& error, tcp::resolver::iterator i , intrusive_ptr p) const { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); @@ -2287,6 +2320,19 @@ namespace libtorrent m_active_time = seconds((e != 0 && e->type() == entry::int_t)?e->integer():0); e = rd.find_key("seeding_time"); m_seeding_time = seconds((e != 0 && e->type() == entry::int_t)?e->integer():0); + + e = rd.find_key("num_seeds"); + m_complete = (e != 0 && e->type() == entry::int_t)?e->integer():-1; + e = rd.find_key("num_downloaders"); + m_incomplete = (e != 0 && e->type() == entry::int_t)?e->integer():-1; + /* + m_total_uploaded = rd.find_int_value("total_uploaded"); + m_total_downloaded = rd.find_inte_value("total_downloaded"); + m_active_time = rd.find_int_value("active_time"); + m_seeding_time = rd.find_int_value("seeding_time"); + m_complete = rd.find_int_value("num_seeds", -1); + m_incomplete = rd.find_int_value("num_downloaders", -1); + */ } void torrent::write_resume_data(entry& ret) const @@ -2299,6 +2345,16 @@ namespace libtorrent ret["active_time"] = total_seconds(m_active_time); ret["seeding_time"] = total_seconds(m_seeding_time); + + int seeds = 0; + int downloaders = 0; + if (m_complete >= 0) seeds = m_complete; + else seeds = m_policy.num_seeds(); + if (m_incomplete >= 0) downloaders = m_incomplete; + else downloaders = m_policy.num_peers() - m_policy.num_seeds(); + + ret["num_seeds"] = seeds; + ret["num_downloaders"] = downloaders; ret["allocation"] = m_storage_mode == storage_mode_sparse?"sparse" :m_storage_mode == storage_mode_allocate?"full":"compact"; @@ -2369,7 +2425,7 @@ namespace libtorrent for (policy::const_iterator i = m_policy.begin_peer() , end(m_policy.end_peer()); i != end; ++i) { - asio::error_code ec; + error_code ec; if (i->second.banned) { tcp::endpoint ip = i->second.ip; @@ -2538,7 +2594,7 @@ namespace libtorrent bool ret = instantiate_connection(m_ses.m_io_service, m_ses.peer_proxy(), *s); TORRENT_ASSERT(ret); std::pair const& out_ports = m_ses.settings().outgoing_ports; - asio::error_code ec; + error_code ec; if (out_ports.first > 0 && out_ports.second >= out_ports.first) s->bind(tcp::endpoint(address(), m_ses.next_port()), ec); @@ -2571,6 +2627,7 @@ namespace libtorrent // add the newly connected peer to this torrent's peer list m_connections.insert(boost::get_pointer(c)); m_ses.m_connections.insert(c); + peerinfo->connection = c.get(); c->start(); int timeout = settings().peer_connect_timeout; @@ -2595,11 +2652,10 @@ namespace libtorrent return false; } #endif - peerinfo->connection = c.get(); return true; } - bool torrent::set_metadata(entry const& metadata, std::string& error) + bool torrent::set_metadata(lazy_entry const& metadata, std::string& error) { INVARIANT_CHECK; @@ -2683,7 +2739,7 @@ namespace libtorrent TORRENT_ASSERT(m_connections.find(p) == m_connections.end()); peer_iterator ci = m_connections.insert(p).first; #ifndef NDEBUG - asio::error_code ec; + error_code ec; TORRENT_ASSERT(p->remote() == p->get_socket()->remote_endpoint(ec) || ec); #endif @@ -2698,7 +2754,8 @@ namespace libtorrent return int(m_connections.size()) < m_max_connections && !m_paused && m_state != torrent_status::checking_files - && m_state != torrent_status::queued_for_checking + && (m_state != torrent_status::queued_for_checking + || !valid_metadata()) && m_policy.num_connect_candidates() > 0; } @@ -2730,6 +2787,71 @@ namespace libtorrent } } + namespace + { + // this returns true if lhs is a better disconnect candidate than rhs + bool compare_disconnect_peer(peer_connection const* lhs, peer_connection const* rhs) + { + // prefer to disconnect peers we're not interested in + if (lhs->is_interesting() != rhs->is_interesting()) + return rhs->is_interesting(); + + // prefer to disconnect peers that are not seeds + if (lhs->is_seed() != rhs->is_seed()) + return rhs->is_seed(); + + // prefer to disconnect peers that are on parole + if (lhs->on_parole() != rhs->on_parole()) + return lhs->on_parole(); + + // prefer to disconnect peers that send data at a lower rate + size_type lhs_transferred = lhs->statistics().total_payload_download(); + size_type rhs_transferred = rhs->statistics().total_payload_download(); + + if (lhs_transferred != rhs_transferred + && lhs_transferred > 0 + && rhs_transferred > 0) + { + ptime now = time_now(); + size_type lhs_time_connected = total_seconds(now - lhs->connected_time()); + size_type rhs_time_connected = total_seconds(now - rhs->connected_time()); + + double lhs_rate = double(lhs_transferred) / (lhs_time_connected + 1); + double rhs_rate = double(rhs_transferred) / (rhs_time_connected + 1); + + return lhs_rate < rhs_rate; + } + + // prefer to disconnect peers that chokes us + if (lhs->is_choked() != rhs->is_choked()) + return lhs->is_choked(); + + return lhs->last_received() < rhs->last_received(); + } + } + + int torrent::disconnect_peers(int num) + { + int ret = 0; + // buils a list of all connected peers and sort it by 'disconnectability'. + std::vector peers(m_connections.size()); + std::copy(m_connections.begin(), m_connections.end(), peers.begin()); + std::sort(peers.begin(), peers.end(), boost::bind(&compare_disconnect_peer, _1, _2)); + + // never disconnect peers that connected less than 90 seconds ago + ptime cut_off = time_now() - seconds(90); + + for (std::vector::iterator i = peers.begin() + , end(peers.end()); i != end && ret < num; ++i) + { + peer_connection* p = *i; + if (p->connected_time() > cut_off) continue; + ++ret; + p->disconnect("optimistic disconnect"); + } + return ret; + } + int torrent::bandwidth_throttle(int channel) const { return m_bandwidth_limit[channel].throttle(); @@ -2844,7 +2966,7 @@ namespace libtorrent { peer_connection* p = *i; TORRENT_ASSERT(p->associated_torrent().lock().get() == this); - if (p->is_seed()) + if (p->upload_only()) { #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING (*p->m_logger) << "*** SEED, CLOSING CONNECTION\n"; @@ -2853,14 +2975,23 @@ namespace libtorrent } } std::for_each(seeds.begin(), seeds.end() - , bind(&peer_connection::disconnect, _1, "torrent finished, disconnecting seed")); + , bind(&peer_connection::disconnect, _1, "torrent finished, disconnecting seed", 0)); TORRENT_ASSERT(m_storage); // we need to keep the object alive during this operation m_storage->async_release_files( bind(&torrent::on_files_released, shared_from_this(), _1, _2)); } + + // this is called when we were finished, but some files were + // marked for downloading, and we are no longer finished + void torrent::resume_download() + { + INVARIANT_CHECK; + m_state = torrent_status::downloading; + } + // called when torrent is complete (all pieces downloaded) void torrent::completed() { @@ -2900,7 +3031,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)(int(m_failed_trackers), int(tracker_failed_max)) * (tracker_retry_delay_max - tracker_retry_delay_min) / tracker_failed_max; @@ -2968,8 +3099,6 @@ namespace libtorrent { m_state = torrent_status::seeding; m_picker.reset(); - if (m_ses.settings().free_torrent_hashes) - m_torrent_file->seed_free(); } if (!m_connections_initialized) @@ -3285,27 +3414,59 @@ namespace libtorrent m_ses.m_auto_manage_time_scaler = 0; } - float torrent::seed_cycles(session_settings const& s) const + // the higher seed rank, the more important to seed + int torrent::seed_rank(session_settings const& s) const { - if (!is_seed()) return 0.f; + enum flags + { + seed_ratio_not_met = 0x400000, + recently_started = 0x200000, + no_seeds = 0x100000, + prio_mask = 0xfffff + }; - int seeding = total_seconds(m_seeding_time); - int downloading = total_seconds(m_active_time) - seeding; + if (!is_seed()) return 0; - // if the seed time limit is set to less than 60 minutes - // use 60 minutes, to avoid oscillation - float ret = seeding / float((std::max)(s.seed_time_limit, 60 * 60)); + int ret = 0; - // if it took less than 30 minutes to download, disregard the - // seed_time_ratio_limit, since it would make it oscillate too frequent - if (downloading > 30 * 60 && s.seed_time_ratio_limit >= 1.f) - ret = (std::max)(ret, (seeding / downloading - / s.seed_time_ratio_limit)); + ptime now(time_now()); + int seed_time = total_seconds(m_seeding_time); + int download_time = total_seconds(m_active_time) - seed_time; + + // if we haven't yet met the seed limits, set the seed_ratio_not_met + // flag. That will make this seed prioritized size_type downloaded = (std::max)(m_total_downloaded, m_torrent_file->total_size()); - if (downloaded > 0 && s.share_ratio_limit >= 1.f) - ret = (std::max)(ret, float(m_total_uploaded) / downloaded - / s.share_ratio_limit); + if (seed_time < s.seed_time_limit + && (seed_time > 1 && download_time / float(seed_time) < s.seed_time_ratio_limit) + && m_total_uploaded / downloaded < s.share_ratio_limit) + ret |= seed_ratio_not_met; + + // if this torrent is running, and it was started less + // than 30 minutes ago, give it priority, to avoid oscillation + if (!is_paused() && now - m_started < minutes(30)) + ret |= recently_started; + + // if we have any scrape data, use it to calculate + // seed rank + int seeds = 0; + int downloaders = 0; + + if (m_complete >= 0) seeds = m_complete; + else seeds = m_policy.num_seeds(); + + if (m_incomplete >= 0) downloaders = m_incomplete; + else downloaders = m_policy.num_peers() - m_policy.num_seeds(); + + if (seeds == 0) + { + ret |= no_seeds; + ret |= downloaders & prio_mask; + } + else + { + ret |= (downloaders * 100 / seeds) & prio_mask; + } return ret; } @@ -3402,6 +3563,7 @@ namespace libtorrent #endif m_paused = false; + m_started = time_now(); // tell the tracker that we're back m_event = tracker_request::started; @@ -3489,6 +3651,7 @@ namespace libtorrent { peer_connection* p = *i; ++i; + p->calc_ip_overhead(); m_stat += p->statistics(); // updates the peer connection's ul/dl bandwidth // resource requests @@ -3504,8 +3667,7 @@ namespace libtorrent #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING (*p->m_logger) << "**ERROR**: " << e.what() << "\n"; #endif - p->set_failed(); - p->disconnect(e.what()); + p->disconnect(e.what(), 1); } #endif } @@ -3643,8 +3805,18 @@ namespace libtorrent , m_have_pieces.end() , 0) == m_num_pieces); + ptime now = time_now(); + torrent_status st; + if (m_last_scrape == min_time()) + { + st.last_scrape = -1; + } + else + { + st.last_scrape = total_seconds(now - m_last_scrape); + } st.up_bandwidth_queue = (int)m_bandwidth_queue[peer_connection::upload_channel].size(); st.down_bandwidth_queue = (int)m_bandwidth_queue[peer_connection::download_channel].size(); @@ -3654,7 +3826,7 @@ namespace libtorrent st.list_peers = m_policy.num_peers(); st.list_seeds = m_policy.num_seeds(); st.connect_candidates = m_policy.num_connect_candidates(); - st.seed_cycles = seed_cycles(m_ses.m_settings); + st.seed_rank = seed_rank(m_ses.m_settings); st.all_time_upload = m_total_uploaded; st.all_time_download = m_total_downloaded; @@ -3668,6 +3840,7 @@ namespace libtorrent st.num_incomplete = m_incomplete; st.paused = m_paused; boost::tie(st.total_done, st.total_wanted_done) = bytes_done(); + TORRENT_ASSERT(st.total_wanted_done >= 0); TORRENT_ASSERT(st.total_done >= st.total_wanted_done); // payload transfer @@ -3691,7 +3864,7 @@ namespace libtorrent st.upload_payload_rate = m_stat.upload_payload_rate(); st.next_announce = boost::posix_time::seconds( - total_seconds(next_announce() - time_now())); + total_seconds(next_announce() - now)); if (st.next_announce.is_negative()) st.next_announce = boost::posix_time::seconds(0); @@ -3713,7 +3886,7 @@ namespace libtorrent if (!valid_metadata()) { - if (m_got_tracker_response == false) + if (m_got_tracker_response == false && m_connections.empty()) st.state = torrent_status::connecting_to_tracker; else st.state = torrent_status::downloading_metadata; @@ -3728,6 +3901,7 @@ namespace libtorrent // fill in status that depends on metadata st.total_wanted = m_torrent_file->total_size(); + TORRENT_ASSERT(st.total_wanted >= 0); if (m_picker.get() && (m_picker->num_filtered() > 0 || m_picker->num_have_filtered() > 0)) diff --git a/libtorrent/src/torrent_info.cpp b/libtorrent/src/torrent_info.cpp index f1d3e50b2..5a59cffc7 100755 --- a/libtorrent/src/torrent_info.cpp +++ b/libtorrent/src/torrent_info.cpp @@ -1,6 +1,6 @@ /* -Copyright (c) 2003, Arvid Norberg +Copyright (c) 2008, Arvid Norberg All rights reserved. Redistribution and use in source and binary forms, with or without @@ -46,6 +46,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include #include @@ -159,13 +160,13 @@ namespace } } - bool extract_single_file(entry const& dict, file_entry& target + bool extract_single_file(lazy_entry const& dict, file_entry& target , std::string const& root_dir) { - entry const* length = dict.find_key("length"); - if (length == 0 || length->type() != entry::int_t) + lazy_entry const* length = dict.dict_find("length"); + if (length == 0 || length->type() != lazy_entry::int_t) return false; - target.size = length->integer(); + target.size = length->int_value(); target.path = root_dir; target.file_base = 0; @@ -173,27 +174,19 @@ namespace // because if it exists, it is more // likely to be correctly encoded - const entry::list_type* list = 0; - entry const* p8 = dict.find_key("path.utf-8"); - if (p8 != 0 && p8->type() == entry::list_t) - { - list = &p8->list(); - } - else - { - entry const* p = dict.find_key("path"); - if (p == 0 || p->type() != entry::list_t) - return false; - list = &p->list(); - } + lazy_entry const* p = dict.dict_find("path.utf-8"); + if (p == 0 || p->type() != lazy_entry::list_t) + p = dict.dict_find("path"); + if (p == 0 || p->type() != lazy_entry::list_t) + return false; - for (entry::list_type::const_iterator i = list->begin(); - i != list->end(); ++i) + for (int i = 0, end(p->list_size()); i < end; ++i) { - if (i->type() != entry::string_t) + if (p->list_at(i)->type() != lazy_entry::string_t) return false; - if (i->string() != "..") - target.path /= i->string(); + std::string path_element = p->list_at(i)->string_value(); + if (path_element != "..") + target.path /= path_element; } verify_encoding(target); if (target.path.is_complete()) @@ -201,14 +194,15 @@ namespace return true; } - bool extract_files(const entry::list_type& list, std::vector& target + bool extract_files(lazy_entry const& list, std::vector& target , std::string const& root_dir) { size_type offset = 0; - for (entry::list_type::const_iterator i = list.begin(); i != list.end(); ++i) + if (list.type() != lazy_entry::list_t) return false; + for (int i = 0, end(list.list_size()); i < end; ++i) { target.push_back(file_entry()); - if (!extract_single_file(*i, target.back(), root_dir)) + if (!extract_single_file(*list.list_at(i), target.back(), root_dir)) return false; target.back().offset = offset; offset += target.back().size; @@ -231,25 +225,65 @@ namespace libtorrent { // standard constructor that parses a torrent file - torrent_info::torrent_info(const entry& torrent_file) + torrent_info::torrent_info(entry const& torrent_file) : m_num_pieces(0) , m_creation_date(pt::ptime(pt::not_a_date_time)) , m_multifile(false) , m_private(false) - , m_extra_info(entry::dictionary_t) -#ifndef NDEBUG - , m_half_metadata(false) + , m_info_section_size(0) + , m_piece_hashes(0) + { + std::vector tmp; + std::back_insert_iterator > out(tmp); + bencode(out, torrent_file); + + lazy_entry e; + lazy_bdecode(&tmp[0], &tmp[0] + tmp.size(), e); + std::string error; +#ifndef BOOST_NO_EXCEPTIONS + if (!parse_torrent_file(e, error)) + throw invalid_torrent_file(); +#else + read_torrent_info(e, error); #endif + } + + torrent_info::torrent_info(lazy_entry const& torrent_file) + : m_num_pieces(0) + , m_creation_date(pt::ptime(pt::not_a_date_time)) + , m_multifile(false) + , m_private(false) + , m_info_section_size(0) + , m_piece_hashes(0) { std::string error; #ifndef BOOST_NO_EXCEPTIONS - if (!read_torrent_info(torrent_file, error)) + if (!parse_torrent_file(torrent_file, error)) throw invalid_torrent_file(); #else read_torrent_info(torrent_file, error); #endif } + torrent_info::torrent_info(char const* buffer, int size) + : m_num_pieces(0) + , m_creation_date(pt::ptime(pt::not_a_date_time)) + , m_multifile(false) + , m_private(false) + , m_info_section_size(0) + , m_piece_hashes(0) + { + std::string error; + lazy_entry e; + lazy_bdecode(buffer, buffer + size, e); +#ifndef BOOST_NO_EXCEPTIONS + if (!parse_torrent_file(e, error)) + throw invalid_torrent_file(); +#else + read_torrent_info(e, error); +#endif + } + // constructor used for creating new torrents // will not contain any hashes, comments, creation date // just the necessary to use it with piece manager @@ -263,10 +297,8 @@ namespace libtorrent , m_creation_date(pt::second_clock::universal_time()) , m_multifile(false) , m_private(false) - , m_extra_info(entry::dictionary_t) -#ifndef NDEBUG - , m_half_metadata(false) -#endif + , m_info_section_size(0) + , m_piece_hashes(0) { } @@ -279,13 +311,35 @@ namespace libtorrent , m_creation_date(pt::second_clock::universal_time()) , m_multifile(false) , m_private(false) - , m_extra_info(entry::dictionary_t) -#ifndef NDEBUG - , m_half_metadata(false) -#endif + , m_info_section_size(0) + , m_piece_hashes(0) { } + torrent_info::torrent_info(char const* filename) + : m_num_pieces(0) + , m_creation_date(pt::ptime(pt::not_a_date_time)) + , m_multifile(false) + , m_private(false) + { + size_type s = fs::file_size(fs::path(filename)); + // don't load torrent files larger than 2 MB + if (s > 2000000) return; + std::vector buf(s); + std::ifstream f(filename); + f.read(&buf[0], s); + + std::string error; + lazy_entry e; + lazy_bdecode(&buf[0], &buf[0] + buf.size(), e); +#ifndef BOOST_NO_EXCEPTIONS + if (!parse_torrent_file(e, error)) + throw invalid_torrent_file(); +#else + read_torrent_info(e, error); +#endif + } + torrent_info::~torrent_info() {} @@ -294,9 +348,8 @@ namespace libtorrent using std::swap; m_urls.swap(ti.m_urls); m_url_seeds.swap(ti.m_url_seeds); - swap(m_piece_length, ti.m_piece_length); - m_piece_hash.swap(ti.m_piece_hash); m_files.swap(ti.m_files); + m_files.swap(ti.m_remapped_files); m_nodes.swap(ti.m_nodes); swap(m_num_pieces, ti.m_num_pieces); swap(m_info_hash, ti.m_info_hash); @@ -306,83 +359,51 @@ namespace libtorrent m_created_by.swap(ti.m_created_by); swap(m_multifile, ti.m_multifile); swap(m_private, ti.m_private); - m_extra_info.swap(ti.m_extra_info); -#ifndef NDEBUG - swap(m_half_metadata, ti.m_half_metadata); -#endif + swap(m_info_section, ti.m_info_section); + swap(m_info_section_size, ti.m_info_section_size); + swap(m_piece_hashes, ti.m_piece_hashes); + swap(m_info_dict, ti.m_info_dict); } - void torrent_info::set_piece_size(int size) + bool torrent_info::parse_info_section(lazy_entry const& info, std::string& error) { - // make sure the size is an even power of 2 -#ifndef NDEBUG - for (int i = 0; i < 32; ++i) - { - if (size & (1 << i)) - { - TORRENT_ASSERT((size & ~(1 << i)) == 0); - break; - } - } -#endif - TORRENT_ASSERT(!m_half_metadata); - m_piece_length = size; - - m_num_pieces = static_cast( - (m_total_size + m_piece_length - 1) / m_piece_length); - int old_num_pieces = static_cast(m_piece_hash.size()); - - m_piece_hash.resize(m_num_pieces); - for (int i = old_num_pieces; i < m_num_pieces; ++i) - { - m_piece_hash[i].clear(); - } - } - - bool torrent_info::parse_info_section(entry const& info, std::string& error) - { - if (info.type() != entry::dictionary_t) + if (info.type() != lazy_entry::dict_t) { error = "'info' entry is not a dictionary"; return false; } - // encode the info-field in order to calculate it's sha1-hash - std::vector buf; - bencode(std::back_inserter(buf), info); + // hash the info-field to calculate info-hash hasher h; - h.update(&buf[0], (int)buf.size()); + std::pair section = info.data_section(); + h.update(section.first, section.second); m_info_hash = h.final(); + // copy the info section + m_info_section_size = section.second; + m_info_section.reset(new char[m_info_section_size]); + memcpy(m_info_section.get(), section.first, m_info_section_size); + TORRENT_ASSERT(section.first[0] == 'd'); + TORRENT_ASSERT(section.first[m_info_section_size-1] == 'e'); + // extract piece length - entry const* piece_length = info.find_key("piece length"); - if (piece_length == 0 || piece_length->type() != entry::int_t) + m_piece_length = info.dict_find_int_value("piece length", -1); + if (m_piece_length <= 0) { error = "invalid or missing 'piece length' entry in torrent file"; return false; } - m_piece_length = int(piece_length->integer()); - if (m_piece_length <= 0) + + // extract file name (or the directory name if it's a multifile libtorrent) + m_name = info.dict_find_string_value("name.utf-8"); + if (m_name.empty()) m_name = info.dict_find_string_value("name"); + + if (m_name.empty()) { - error = "invalid torrent. piece length <= 0"; + error = "invalid name in torrent file"; return false; } - // extract file name (or the directory name if it's a multifile libtorrent) - entry const* e = info.find_key("name.utf-8"); - if (e && e->type() == entry::string_t) - { m_name = e->string(); } - else - { - entry const* e = info.find_key("name"); - if (e == 0 || e->type() != entry::string_t) - { - error = "invalid name in torrent file"; - return false; - } - m_name = e->string(); - } - fs::path tmp = m_name; if (tmp.is_complete()) { @@ -401,32 +422,31 @@ namespace libtorrent } if (m_name == ".." || m_name == ".") { - error = "invalid 'name' of torrent (possible exploit attempt)"; return false; } // extract file list - entry const* i = info.find_key("files"); + lazy_entry const* i = info.dict_find_list("files"); if (i == 0) { - entry const* length = info.find_key("length"); - if (length == 0 || length->type() != entry::int_t) - { - error = "invalid length of torrent"; - return false; - } // if there's no list of files, there has to be a length // field. file_entry e; e.path = m_name; e.offset = 0; - e.size = length->integer(); + e.size = info.dict_find_int_value("length", -1); + if (e.size < 0) + { + error = "invalid length of torrent"; + return false; + } m_files.push_back(e); + m_multifile = false; } else { - if (!extract_files(i->list(), m_files, m_name)) + if (!extract_files(*i, m_files, m_name)) { error = "failed to parse files from torrent file"; return false; @@ -443,84 +463,51 @@ namespace libtorrent // we want this division to round upwards, that's why we have the // extra addition - entry const* pieces_ent = info.find_key("pieces"); - if (pieces_ent == 0 || pieces_ent->type() != entry::string_t) + m_num_pieces = static_cast((m_total_size + m_piece_length - 1) / m_piece_length); + + lazy_entry const* pieces = info.dict_find("pieces"); + if (pieces == 0 || pieces->type() != lazy_entry::string_t) { error = "invalid or missing 'pieces' entry in torrent file"; return false; } - m_num_pieces = static_cast((m_total_size + m_piece_length - 1) / m_piece_length); - m_piece_hash.resize(m_num_pieces); - const std::string& hash_string = pieces_ent->string(); - - if ((int)hash_string.length() != m_num_pieces * 20) + if (pieces->string_length() != m_num_pieces * 20) { error = "incorrect number of piece hashes in torrent file"; return false; } - for (int i = 0; i < m_num_pieces; ++i) - std::copy( - hash_string.begin() + i*20 - , hash_string.begin() + (i+1)*20 - , m_piece_hash[i].begin()); + m_piece_hashes = m_info_section.get() + (pieces->string_ptr() - section.first); + TORRENT_ASSERT(m_piece_hashes >= m_info_section.get()); + TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size); - for (entry::dictionary_type::const_iterator i = info.dict().begin() - , end(info.dict().end()); i != end; ++i) - { - if (i->first == "pieces" - || i->first == "piece length" - || i->first == "length") - continue; - m_extra_info[i->first] = i->second; - } - - if (entry const* priv = info.find_key("private")) - { - if (priv->type() != entry::int_t - || priv->integer() != 0) - { - // this key exists and it's not 0. - // consider the torrent private - m_private = true; - } - } - -#ifndef NDEBUG - std::vector info_section_buf; - entry gen_info_section = create_info_metadata(); - bencode(std::back_inserter(info_section_buf), gen_info_section); - TORRENT_ASSERT(hasher(&info_section_buf[0], info_section_buf.size()).final() - == m_info_hash); -#endif + m_private = info.dict_find_int_value("private", 0); return true; } - // extracts information from a libtorrent file and fills in the structures in - // the torrent object - bool torrent_info::read_torrent_info(const entry& torrent_file, std::string& error) + bool torrent_info::parse_torrent_file(lazy_entry const& torrent_file, std::string& error) { - if (torrent_file.type() != entry::dictionary_t) + if (torrent_file.type() != lazy_entry::dict_t) { error = "torrent file is not a dictionary"; return false; } // extract the url of the tracker - entry const* i = torrent_file.find_key("announce-list"); - if (i && i->type() == entry::list_t) + lazy_entry const* i = torrent_file.dict_find_list("announce-list"); + if (i) { - const entry::list_type& l = i->list(); - for (entry::list_type::const_iterator j = l.begin(); j != l.end(); ++j) + m_urls.reserve(i->list_size()); + for (int j = 0, end(i->list_size()); j < end; ++j) { - if (j->type() != entry::list_t) break; - const entry::list_type& ll = j->list(); - for (entry::list_type::const_iterator k = ll.begin(); k != ll.end(); ++k) + lazy_entry const* tier = i->list_at(j); + if (tier->type() != lazy_entry::list_t) continue; + for (int k = 0, end(tier->list_size()); k < end; ++k) { - if (k->type() != entry::string_t) break; - announce_entry e(k->string()); - e.tier = (int)std::distance(l.begin(), j); + announce_entry e(tier->list_string_value_at(k)); + if (e.url.empty()) continue; + e.tier = j; m_urls.push_back(e); } } @@ -541,71 +528,62 @@ namespace libtorrent std::random_shuffle(start, stop); } - entry const* announce = torrent_file.find_key("announce"); - if (m_urls.empty() && announce && announce->type() == entry::string_t) + + if (m_urls.empty()) { - m_urls.push_back(announce_entry(announce->string())); + announce_entry e(torrent_file.dict_find_string_value("announce")); + if (!e.url.empty()) m_urls.push_back(e); } - entry const* nodes = torrent_file.find_key("nodes"); - if (nodes && nodes->type() == entry::list_t) + lazy_entry const* nodes = torrent_file.dict_find_list("nodes"); + if (nodes) { - entry::list_type const& list = nodes->list(); - for (entry::list_type::const_iterator i(list.begin()) - , end(list.end()); i != end; ++i) + for (int i = 0, end(nodes->list_size()); i < end; ++i) { - if (i->type() != entry::list_t) continue; - entry::list_type const& l = i->list(); - entry::list_type::const_iterator iter = l.begin(); - if (l.size() < 1) continue; - if (iter->type() != entry::string_t) continue; - std::string const& hostname = iter->string(); - ++iter; - int port = 6881; - if (iter->type() != entry::int_t) continue; - if (l.end() != iter) port = int(iter->integer()); - m_nodes.push_back(std::make_pair(hostname, port)); + lazy_entry const* n = nodes->list_at(i); + if (n->type() != lazy_entry::list_t + || n->list_size() < 2 + || n->list_at(0)->type() != lazy_entry::string_t + || n->list_at(1)->type() != lazy_entry::int_t) + continue; + m_nodes.push_back(std::make_pair( + n->list_at(0)->string_value() + , int(n->list_at(1)->int_value()))); } } // extract creation date - entry const* creation_date = torrent_file.find_key("creation date"); - if (creation_date && creation_date->type() == entry::int_t) + size_type cd = torrent_file.dict_find_int_value("creation date", -1); + if (cd >= 0) { m_creation_date = pt::ptime(gr::date(1970, gr::Jan, 1)) - + pt::seconds(long(creation_date->integer())); + + pt::seconds(long(cd)); } // if there are any url-seeds, extract them - entry const* url_seeds = torrent_file.find_key("url-list"); - if (url_seeds && url_seeds->type() == entry::string_t) + lazy_entry const* url_seeds = torrent_file.dict_find("url-list"); + if (url_seeds && url_seeds->type() == lazy_entry::string_t) { - m_url_seeds.push_back(url_seeds->string()); + m_url_seeds.push_back(url_seeds->string_value()); } - else if (url_seeds && url_seeds->type() == entry::list_t) + else if (url_seeds && url_seeds->type() == lazy_entry::list_t) { - entry::list_type const& l = url_seeds->list(); - for (entry::list_type::const_iterator i = l.begin(); - i != l.end(); ++i) + for (int i = 0, end(url_seeds->list_size()); i < end; ++i) { - if (i->type() != entry::string_t) continue; - m_url_seeds.push_back(i->string()); + lazy_entry const* url = url_seeds->list_at(i); + if (url->type() != lazy_entry::string_t) continue; + m_url_seeds.push_back(url->string_value()); } } - // extract comment - if (entry const* e = torrent_file.find_key("comment.utf-8")) - { m_comment = e->string(); } - else if (entry const* e = torrent_file.find_key("comment")) - { m_comment = e->string(); } + m_comment = torrent_file.dict_find_string_value("comment.utf-8"); + if (m_comment.empty()) m_comment = torrent_file.dict_find_string_value("comment"); - if (entry const* e = torrent_file.find_key("created by.utf-8")) - { m_created_by = e->string(); } - else if (entry const* e = torrent_file.find_key("created by")) - { m_created_by = e->string(); } + m_created_by = torrent_file.dict_find_string_value("created by.utf-8"); + if (m_created_by.empty()) m_created_by = torrent_file.dict_find_string_value("created by"); - entry const* info = torrent_file.find_key("info"); - if (info == 0 || info->type() != entry::dictionary_t) + lazy_entry const* info = torrent_file.dict_find_dict("info"); + if (info == 0) { error = "missing or invalid 'info' section in torrent file"; return false; @@ -634,234 +612,6 @@ namespace libtorrent , bind(&announce_entry::tier, _1), bind(&announce_entry::tier, _2))); } - void torrent_info::add_file(fs::path file, size_type size) - { -// TORRENT_ASSERT(file.begin() != file.end()); - - if (!file.has_branch_path()) - { - // you have already added at least one file with a - // path to the file (branch_path), which means that - // all the other files need to be in the same top - // directory as the first file. - TORRENT_ASSERT(m_files.empty()); - TORRENT_ASSERT(!m_multifile); - m_name = file.string(); - } - else - { -#ifndef NDEBUG - if (!m_files.empty()) - TORRENT_ASSERT(m_name == *file.begin()); -#endif - m_multifile = true; - m_name = *file.begin(); - } - - file_entry e; - e.path = file; - e.size = size; - e.offset = m_files.empty() ? 0 : m_files.back().offset - + m_files.back().size; - m_files.push_back(e); - - m_total_size += size; - - if (m_piece_length == 0) - m_piece_length = 256 * 1024; - - m_num_pieces = static_cast( - (m_total_size + m_piece_length - 1) / m_piece_length); - int old_num_pieces = static_cast(m_piece_hash.size()); - - m_piece_hash.resize(m_num_pieces); - if (m_num_pieces > old_num_pieces) - std::for_each(m_piece_hash.begin() + old_num_pieces - , m_piece_hash.end(), boost::bind(&sha1_hash::clear, _1)); - } - - void torrent_info::add_url_seed(std::string const& url) - { - m_url_seeds.push_back(url); - } - - void torrent_info::set_comment(char const* str) - { - m_comment = str; - } - - void torrent_info::set_creator(char const* str) - { - m_created_by = str; - } - - entry torrent_info::create_info_metadata() const - { - // you have to add files to the torrent first - TORRENT_ASSERT(!m_files.empty()); - - entry info(m_extra_info); - - if (!info.find_key("name")) - info["name"] = m_name; - - if (m_private) info["private"] = 1; - - if (!m_multifile) - { - info["length"] = m_files.front().size; - } - else - { - if (!info.find_key("files")) - { - entry& files = info["files"]; - - for (std::vector::const_iterator i = m_files.begin(); - i != m_files.end(); ++i) - { - files.list().push_back(entry()); - entry& file_e = files.list().back(); - file_e["length"] = i->size; - entry& path_e = file_e["path"]; - - fs::path const* file_path; - if (i->orig_path) file_path = &(*i->orig_path); - else file_path = &i->path; - TORRENT_ASSERT(file_path->has_branch_path()); - TORRENT_ASSERT(*file_path->begin() == m_name); - - for (fs::path::iterator j = boost::next(file_path->begin()); - j != file_path->end(); ++j) - { - path_e.list().push_back(entry(*j)); - } - } - } - } - - info["piece length"] = piece_length(); - entry& pieces = info["pieces"]; - - std::string& p = pieces.string(); - - for (std::vector::const_iterator i = m_piece_hash.begin(); - i != m_piece_hash.end(); ++i) - { - p.append((char*)i->begin(), (char*)i->end()); - } - - return info; - } - - entry torrent_info::create_torrent() const - { - TORRENT_ASSERT(m_piece_length > 0); - - if (m_files.empty()) - { - // TODO: throw something here - // throw - return entry(); - } - - entry dict; - - if (!m_urls.empty()) - dict["announce"] = m_urls.front().url; - - if (!m_nodes.empty()) - { - entry& nodes = dict["nodes"]; - entry::list_type& nodes_list = nodes.list(); - for (nodes_t::const_iterator i = m_nodes.begin() - , end(m_nodes.end()); i != end; ++i) - { - entry::list_type node; - node.push_back(entry(i->first)); - node.push_back(entry(i->second)); - nodes_list.push_back(entry(node)); - } - } - - if (m_urls.size() > 1) - { - entry trackers(entry::list_t); - entry tier(entry::list_t); - int current_tier = m_urls.front().tier; - for (std::vector::const_iterator i = m_urls.begin(); - i != m_urls.end(); ++i) - { - if (i->tier != current_tier) - { - current_tier = i->tier; - trackers.list().push_back(tier); - tier.list().clear(); - } - tier.list().push_back(entry(i->url)); - } - trackers.list().push_back(tier); - dict["announce-list"] = trackers; - } - - if (!m_comment.empty()) - dict["comment"] = m_comment; - - dict["creation date"] = - (m_creation_date - pt::ptime(gr::date(1970, gr::Jan, 1))).total_seconds(); - - if (!m_created_by.empty()) - dict["created by"] = m_created_by; - - if (!m_url_seeds.empty()) - { - if (m_url_seeds.size() == 1) - { - dict["url-list"] = m_url_seeds.front(); - } - else - { - entry& list = dict["url-list"]; - for (std::vector::const_iterator i - = m_url_seeds.begin(); i != m_url_seeds.end(); ++i) - { - list.list().push_back(entry(*i)); - } - } - } - - dict["info"] = create_info_metadata(); - - entry const& info_section = dict["info"]; - std::vector buf; - bencode(std::back_inserter(buf), info_section); - m_info_hash = hasher(&buf[0], buf.size()).final(); - - return dict; - } - - void torrent_info::set_hash(int index, const sha1_hash& h) - { - TORRENT_ASSERT(index >= 0); - TORRENT_ASSERT(index < (int)m_piece_hash.size()); - m_piece_hash[index] = h; - } - - void torrent_info::convert_file_names() - { - TORRENT_ASSERT(false); - } - - void torrent_info::seed_free() - { - std::vector().swap(m_url_seeds); - nodes_t().swap(m_nodes); - std::vector().swap(m_piece_hash); -#ifndef NDEBUG - m_half_metadata = true; -#endif - } - // ------- start deprecation ------- void torrent_info::print(std::ostream& os) const @@ -901,11 +651,6 @@ namespace libtorrent return piece_length(); } - void torrent_info::add_node(std::pair const& node) - { - m_nodes.push_back(node); - } - bool torrent_info::remap_files(std::vector const& map) { size_type offset = 0; diff --git a/libtorrent/src/tracker_manager.cpp b/libtorrent/src/tracker_manager.cpp index 9dda723bb..6a0b28d60 100755 --- a/libtorrent/src/tracker_manager.cpp +++ b/libtorrent/src/tracker_manager.cpp @@ -84,7 +84,7 @@ namespace libtorrent int timeout = (std::min)( m_read_timeout, (std::min)(m_completion_timeout, m_read_timeout)); - asio::error_code ec; + error_code ec; m_timeout.expires_at(m_read_time + seconds(timeout), ec); m_timeout.async_wait(bind( &timeout_handler::timeout_callback, self(), _1)); @@ -99,11 +99,11 @@ namespace libtorrent { m_abort = true; m_completion_timeout = 0; - asio::error_code ec; + error_code ec; m_timeout.cancel(ec); } - void timeout_handler::timeout_callback(asio::error_code const& error) + void timeout_handler::timeout_callback(error_code const& error) { if (error) return; if (m_completion_timeout == 0) return; @@ -125,7 +125,7 @@ namespace libtorrent int timeout = (std::min)( m_read_timeout, (std::min)(m_completion_timeout, m_read_timeout)); - asio::error_code ec; + error_code ec; m_timeout.expires_at(m_read_time + seconds(timeout), ec); m_timeout.async_wait( bind(&timeout_handler::timeout_callback, self(), _1)); @@ -180,83 +180,6 @@ namespace libtorrent m_connections.erase(i); } - // returns protocol, auth, hostname, port, path - tuple - parse_url_components(std::string url) - { - std::string hostname; // hostname only - std::string auth; // user:pass - std::string protocol; // http or https for instance - int port = 80; - - std::string::iterator at; - std::string::iterator colon; - std::string::iterator port_pos; - - // PARSE URL - std::string::iterator start = url.begin(); - // remove white spaces in front of the url - while (start != url.end() && (*start == ' ' || *start == '\t')) - ++start; - std::string::iterator end - = std::find(url.begin(), url.end(), ':'); - protocol.assign(start, end); - - if (protocol == "https") port = 443; - - if (end == url.end()) goto exit; - ++end; - if (end == url.end()) goto exit; - if (*end != '/') goto exit; - ++end; - if (end == url.end()) goto exit; - if (*end != '/') goto exit; - ++end; - start = end; - - at = std::find(start, url.end(), '@'); - colon = std::find(start, url.end(), ':'); - end = std::find(start, url.end(), '/'); - - if (at != url.end() - && colon != url.end() - && colon < at - && at < end) - { - auth.assign(start, at); - start = at; - ++start; - } - - // this is for IPv6 addresses - if (start != url.end() && *start == '[') - { - port_pos = std::find(start, url.end(), ']'); - if (port_pos == url.end()) goto exit; - port_pos = std::find(port_pos, url.end(), ':'); - } - else - { - port_pos = std::find(start, url.end(), ':'); - } - - if (port_pos < end) - { - hostname.assign(start, port_pos); - ++port_pos; - port = atoi(std::string(port_pos, end).c_str()); - } - else - { - hostname.assign(start, end); - } - - start = end; -exit: - return make_tuple(protocol, auth, hostname, port - , std::string(start, url.end())); - } - void tracker_manager::queue_request( io_service& ios , connection_queue& cc diff --git a/libtorrent/src/udp_socket.cpp b/libtorrent/src/udp_socket.cpp index ccbb3992b..78091116a 100644 --- a/libtorrent/src/udp_socket.cpp +++ b/libtorrent/src/udp_socket.cpp @@ -4,7 +4,11 @@ #include #include #include +#if BOOST_VERSION < 103500 #include +#else +#include +#endif using namespace libtorrent; @@ -22,7 +26,7 @@ udp_socket::udp_socket(asio::io_service& ios, udp_socket::callback_t const& c { } -void udp_socket::send(udp::endpoint const& ep, char const* p, int len, asio::error_code& ec) +void udp_socket::send(udp::endpoint const& ep, char const* p, int len, error_code& ec) { if (ec == asio::error::operation_aborted) return; @@ -39,7 +43,7 @@ void udp_socket::send(udp::endpoint const& ep, char const* p, int len, asio::err m_ipv6_sock.send_to(asio::buffer(p, len), ep, 0, ec); } -void udp_socket::on_read(udp::socket* s, asio::error_code const& e, std::size_t bytes_transferred) +void udp_socket::on_read(udp::socket* s, error_code const& e, std::size_t bytes_transferred) { if (e == asio::error::operation_aborted) return; @@ -113,7 +117,7 @@ void udp_socket::on_read(udp::socket* s, asio::error_code const& e, std::size_t } } -void udp_socket::wrap(udp::endpoint const& ep, char const* p, int len, asio::error_code& ec) +void udp_socket::wrap(udp::endpoint const& ep, char const* p, int len, error_code& ec) { using namespace libtorrent::detail; @@ -137,7 +141,7 @@ void udp_socket::wrap(udp::endpoint const& ep, char const* p, int len, asio::err } // unwrap the UDP packet from the SOCKS5 header -void udp_socket::unwrap(asio::error_code const& e, char const* buf, int size) +void udp_socket::unwrap(error_code const& e, char const* buf, int size) { using namespace libtorrent::detail; @@ -174,7 +178,7 @@ void udp_socket::unwrap(asio::error_code const& e, char const* buf, int size) void udp_socket::close() { - asio::error_code ec; + error_code ec; m_ipv4_sock.close(ec); m_ipv6_sock.close(ec); m_socks5_sock.close(ec); @@ -186,7 +190,7 @@ void udp_socket::close() } } -void udp_socket::bind(udp::endpoint const& ep, asio::error_code& ec) +void udp_socket::bind(udp::endpoint const& ep, error_code& ec) { if (m_ipv4_sock.is_open()) m_ipv4_sock.close(ec); if (m_ipv6_sock.is_open()) m_ipv6_sock.close(ec); @@ -214,7 +218,7 @@ void udp_socket::bind(udp::endpoint const& ep, asio::error_code& ec) void udp_socket::bind(int port) { - asio::error_code ec; + error_code ec; if (m_ipv4_sock.is_open()) m_ipv4_sock.close(ec); if (m_ipv6_sock.is_open()) m_ipv6_sock.close(ec); @@ -239,7 +243,7 @@ void udp_socket::bind(int port) void udp_socket::set_proxy_settings(proxy_settings const& ps) { - asio::error_code ec; + error_code ec; m_socks5_sock.close(ec); m_tunnel_packets = false; @@ -256,7 +260,7 @@ void udp_socket::set_proxy_settings(proxy_settings const& ps) } } -void udp_socket::on_name_lookup(asio::error_code const& e, tcp::resolver::iterator i) +void udp_socket::on_name_lookup(error_code const& e, tcp::resolver::iterator i) { if (e) return; m_proxy_addr.address(i->endpoint().address()); @@ -267,7 +271,7 @@ void udp_socket::on_name_lookup(asio::error_code const& e, tcp::resolver::iterat void udp_socket::on_timeout() { - asio::error_code ec; + error_code ec; m_socks5_sock.close(ec); m_connection_ticket = -1; } @@ -275,13 +279,13 @@ void udp_socket::on_timeout() void udp_socket::on_connect(int ticket) { m_connection_ticket = ticket; - asio::error_code ec; + error_code ec; m_socks5_sock.open(m_proxy_addr.address().is_v4()?tcp::v4():tcp::v6(), ec); m_socks5_sock.async_connect(tcp::endpoint(m_proxy_addr.address(), m_proxy_addr.port()) , boost::bind(&udp_socket::on_connected, this, _1)); } -void udp_socket::on_connected(asio::error_code const& e) +void udp_socket::on_connected(error_code const& e) { m_cc.done(m_connection_ticket); m_connection_ticket = -1; @@ -308,7 +312,7 @@ void udp_socket::on_connected(asio::error_code const& e) , boost::bind(&udp_socket::handshake1, this, _1)); } -void udp_socket::handshake1(asio::error_code const& e) +void udp_socket::handshake1(error_code const& e) { if (e) return; @@ -316,7 +320,7 @@ void udp_socket::handshake1(asio::error_code const& e) , boost::bind(&udp_socket::handshake2, this, _1)); } -void udp_socket::handshake2(asio::error_code const& e) +void udp_socket::handshake2(error_code const& e) { if (e) return; @@ -336,7 +340,7 @@ void udp_socket::handshake2(asio::error_code const& e) { if (m_proxy_settings.username.empty()) { - asio::error_code ec; + error_code ec; m_socks5_sock.close(ec); return; } @@ -353,13 +357,13 @@ void udp_socket::handshake2(asio::error_code const& e) } else { - asio::error_code ec; + error_code ec; m_socks5_sock.close(ec); return; } } -void udp_socket::handshake3(asio::error_code const& e) +void udp_socket::handshake3(error_code const& e) { if (e) return; @@ -367,7 +371,7 @@ void udp_socket::handshake3(asio::error_code const& e) , boost::bind(&udp_socket::handshake4, this, _1)); } -void udp_socket::handshake4(asio::error_code const& e) +void udp_socket::handshake4(error_code const& e) { if (e) return; @@ -400,7 +404,7 @@ void udp_socket::socks_forward_udp() , boost::bind(&udp_socket::connect1, this, _1)); } -void udp_socket::connect1(asio::error_code const& e) +void udp_socket::connect1(error_code const& e) { if (e) return; @@ -408,7 +412,7 @@ void udp_socket::connect1(asio::error_code const& e) , boost::bind(&udp_socket::connect2, this, _1)); } -void udp_socket::connect2(asio::error_code const& e) +void udp_socket::connect2(error_code const& e) { if (e) return; diff --git a/libtorrent/src/udp_tracker_connection.cpp b/libtorrent/src/udp_tracker_connection.cpp index 1eda73841..e19d5696d 100755 --- a/libtorrent/src/udp_tracker_connection.cpp +++ b/libtorrent/src/udp_tracker_connection.cpp @@ -52,6 +52,7 @@ POSSIBILITY OF SUCH DAMAGE. #endif #include "libtorrent/tracker_manager.hpp" +#include "libtorrent/parse_url.hpp" #include "libtorrent/udp_tracker_connection.hpp" #include "libtorrent/io.hpp" @@ -95,10 +96,18 @@ namespace libtorrent std::string hostname; int port; + char const* error; using boost::tuples::ignore; - boost::tie(ignore, ignore, hostname, port, ignore) = parse_url_components(req.url); + boost::tie(ignore, ignore, hostname, port, ignore, error) + = parse_url_components(req.url); + if (error) + { + fail(-1, error); + return; + } + udp::resolver::query q(hostname, boost::lexical_cast(port)); m_name_lookup.async_resolve(q , boost::bind( @@ -113,7 +122,7 @@ namespace libtorrent #endif } - void udp_tracker_connection::name_lookup(asio::error_code const& error + void udp_tracker_connection::name_lookup(error_code const& error , udp::resolver::iterator i) { if (error == asio::error::operation_aborted) return; @@ -156,7 +165,7 @@ namespace libtorrent if (cb) cb->m_tracker_address = tcp::endpoint(target_address.address(), target_address.port()); m_target = target_address; - asio::error_code ec; + error_code ec; m_socket.bind(udp::endpoint(bind_interface(), 0), ec); if (ec) { @@ -179,13 +188,13 @@ namespace libtorrent void udp_tracker_connection::close() { - asio::error_code ec; + error_code ec; m_socket.close(); m_name_lookup.cancel(); tracker_connection::close(); } - void udp_tracker_connection::on_receive(asio::error_code const& e + void udp_tracker_connection::on_receive(error_code const& e , udp::endpoint const& ep, char const* buf, int size) { // ignore resposes before we've sent any requests @@ -305,7 +314,7 @@ namespace libtorrent detail::write_int32(m_transaction_id, ptr); // transaction_id TORRENT_ASSERT(ptr - buf == sizeof(buf)); - asio::error_code ec; + error_code ec; m_socket.send(m_target, buf, 16, ec); m_state = action_connect; ++m_attempts; @@ -334,7 +343,7 @@ namespace libtorrent out += 20; TORRENT_ASSERT(out - buf == sizeof(buf)); - asio::error_code ec; + error_code ec; m_socket.send(m_target, buf, sizeof(buf), ec); m_state = action_scrape; ++m_attempts; @@ -494,7 +503,7 @@ namespace libtorrent } #endif - asio::error_code ec; + error_code ec; m_socket.send(m_target, buf, sizeof(buf), ec); m_state = action_announce; ++m_attempts; diff --git a/libtorrent/src/upnp.cpp b/libtorrent/src/upnp.cpp index 34092a60d..b7e05963b 100644 --- a/libtorrent/src/upnp.cpp +++ b/libtorrent/src/upnp.cpp @@ -35,15 +35,20 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/socket.hpp" #include "libtorrent/upnp.hpp" #include "libtorrent/io.hpp" -#include "libtorrent/http_tracker_connection.hpp" +#include "libtorrent/parse_url.hpp" #include "libtorrent/xml_parse.hpp" #include "libtorrent/connection_queue.hpp" #include "libtorrent/enum_net.hpp" #include #include +#if BOOST_VERSION < 103500 #include #include +#else +#include +#include +#endif #include #include @@ -54,12 +59,6 @@ POSSIBILITY OF SUCH DAMAGE. using boost::bind; using namespace libtorrent; -namespace libtorrent -{ - bool is_local(address const& a); - address guess_local_address(asio::io_service&); -} - upnp::upnp(io_service& ios, connection_queue& cc , address const& listen_interface, std::string const& user_agent , portmap_callback_t const& cb, bool ignore_nonrouters) @@ -73,7 +72,7 @@ upnp::upnp(io_service& ios, connection_queue& cc , m_refresh_timer(ios) , m_disabled(false) , m_closing(false) - , m_ignore_outside_network(ignore_nonrouters) + , m_ignore_non_routers(ignore_nonrouters) , m_cc(cc) { #ifdef TORRENT_UPNP_LOGGING @@ -103,7 +102,7 @@ void upnp::discover_device_impl() "MX:3\r\n" "\r\n\r\n"; - asio::error_code ec; + error_code ec; #ifdef TORRENT_DEBUG_UPNP // simulate packet loss if (m_retry_count & 1) @@ -215,7 +214,7 @@ void upnp::delete_mapping(int mapping) } } -void upnp::resend_request(asio::error_code const& e) +void upnp::resend_request(error_code const& e) { if (e) return; @@ -254,9 +253,10 @@ void upnp::resend_request(asio::error_code const& e) m_log << time_now_string() << " ==> connecting to " << d.url << std::endl; #endif + if (d.upnp_connection) d.upnp_connection->close(); d.upnp_connection.reset(new http_connection(m_io_service , m_cc, bind(&upnp::on_upnp_xml, self(), _1, _2 - , boost::ref(d)))); + , boost::ref(d), _5))); d.upnp_connection->get(d.url, seconds(30), 1); } catch (std::exception& e) @@ -306,8 +306,34 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer Server:Microsoft-Windows-NT/5.1 UPnP/1.0 UPnP-Device-Host/1.0 */ - asio::error_code ec; - if (m_ignore_outside_network && !in_local_network(m_io_service, from.address(), ec)) + error_code ec; + if (!in_local_network(m_io_service, from.address(), ec)) + { +#ifdef TORRENT_UPNP_LOGGING + if (ec) + { + m_log << time_now_string() << " <== (" << from << ") error: " + << ec.message() << std::endl; + } + else + { + m_log << time_now_string() << " <== (" << from << ") UPnP device " + "ignored because it's not on our local network "; + std::vector const& net = enum_net_interfaces(m_io_service, ec); + for (std::vector::const_iterator i = net.begin() + , end(net.end()); i != end; ++i) + { + m_log << "(" << i->interface_address << ", " << i->netmask << ") "; + } + m_log << std::endl; + } +#endif + return; + } + + std::vector routes = enum_routes(m_io_service, ec); + if (m_ignore_non_routers && std::find_if(routes.begin(), routes.end() + , bind(&ip_route::gateway, _1) == from.address()) == routes.end()) { // this upnp device is filtered because it's not in the // list of configured routers @@ -319,13 +345,12 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer } else { - std::vector const& net = enum_net_interfaces(m_io_service, ec); m_log << time_now_string() << " <== (" << from << ") UPnP device " - "ignored because it's not on our network "; - for (std::vector::const_iterator i = net.begin() - , end(net.end()); i != end; ++i) + "ignored because it's not a router on our network "; + for (std::vector::const_iterator i = routes.begin() + , end(routes.end()); i != end; ++i) { - m_log << "(" << i->interface_address << ", " << i->netmask << ") "; + m_log << "(" << i->gateway << ", " << i->netmask << ") "; } m_log << std::endl; } @@ -392,10 +417,21 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer std::string protocol; std::string auth; + char const* error; // we don't have this device in our list. Add it - boost::tie(protocol, auth, d.hostname, d.port, d.path) + boost::tie(protocol, auth, d.hostname, d.port, d.path, error) = parse_url_components(d.url); + if (error) + { +#ifdef TORRENT_UPNP_LOGGING + m_log << time_now_string() + << " <== (" << from << ") Rootdevice advertized an invalid url: '" << d.url + << "'. " << error << ". Ignoring device" << std::endl; +#endif + return; + } + // ignore the auth here. It will be re-parsed // by the http connection later @@ -453,7 +489,7 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer // just to make sure we find all devices if (m_retry_count >= 4 && !m_devices.empty()) { - asio::error_code ec; + error_code ec; m_broadcast_timer.cancel(ec); for (std::set::iterator i = m_devices.begin() @@ -473,9 +509,10 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer m_log << time_now_string() << " ==> connecting to " << d.url << std::endl; #endif + if (d.upnp_connection) d.upnp_connection->close(); d.upnp_connection.reset(new http_connection(m_io_service , m_cc, bind(&upnp::on_upnp_xml, self(), _1, _2 - , boost::ref(d)))); + , boost::ref(d), _5))); d.upnp_connection->get(d.url, seconds(30), 1); #ifndef BOOST_NO_EXCEPTIONS } @@ -543,7 +580,7 @@ void upnp::create_port_mapping(http_connection& c, rootdevice& d, int i) "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">" ""; - asio::error_code ec; + error_code ec; soap << "" "" << d.mapping[i].external_port << "" "" << (d.mapping[i].protocol == udp ? "UDP" : "TCP") << "" @@ -612,9 +649,10 @@ void upnp::update_map(rootdevice& d, int i) return; } + if (d.upnp_connection) d.upnp_connection->close(); d.upnp_connection.reset(new http_connection(m_io_service , m_cc, bind(&upnp::on_upnp_map_response, self(), _1, _2 - , boost::ref(d), i), true + , boost::ref(d), i, _5), true , bind(&upnp::create_port_mapping, self(), _1, boost::ref(d), i))); d.upnp_connection->start(d.hostname, boost::lexical_cast(d.port) @@ -622,9 +660,10 @@ void upnp::update_map(rootdevice& d, int i) } else if (m.action == mapping_t::action_delete) { + if (d.upnp_connection) d.upnp_connection->close(); d.upnp_connection.reset(new http_connection(m_io_service , m_cc, bind(&upnp::on_upnp_unmap_response, self(), _1, _2 - , boost::ref(d), i), true + , boost::ref(d), i, _5), true , bind(&upnp::delete_port_mapping, self(), boost::ref(d), i))); d.upnp_connection->start(d.hostname, boost::lexical_cast(d.port) , seconds(10), 1); @@ -732,13 +771,14 @@ namespace } -void upnp::on_upnp_xml(asio::error_code const& e - , libtorrent::http_parser const& p, rootdevice& d) +void upnp::on_upnp_xml(error_code const& e + , libtorrent::http_parser const& p, rootdevice& d + , http_connection& c) { mutex_t::scoped_lock l(m_mutex); TORRENT_ASSERT(d.magic == 1337); - if (d.upnp_connection) + if (d.upnp_connection && d.upnp_connection.get() == &c) { d.upnp_connection->close(); d.upnp_connection.reset(); @@ -816,7 +856,7 @@ void upnp::on_upnp_xml(asio::error_code const& e d.control_url = s.control_url; - update_map(d, 0); + if (num_mappings() > 0) update_map(d, 0); } void upnp::disable(char const* msg) @@ -833,7 +873,7 @@ void upnp::disable(char const* msg) } m_devices.clear(); - asio::error_code ec; + error_code ec; m_broadcast_timer.cancel(ec); m_refresh_timer.cancel(ec); m_socket.close(); @@ -891,13 +931,14 @@ namespace } -void upnp::on_upnp_map_response(asio::error_code const& e - , libtorrent::http_parser const& p, rootdevice& d, int mapping) +void upnp::on_upnp_map_response(error_code const& e + , libtorrent::http_parser const& p, rootdevice& d, int mapping + , http_connection& c) { mutex_t::scoped_lock l(m_mutex); TORRENT_ASSERT(d.magic == 1337); - if (d.upnp_connection) + if (d.upnp_connection && d.upnp_connection.get() == &c) { d.upnp_connection->close(); d.upnp_connection.reset(); @@ -1014,7 +1055,7 @@ void upnp::on_upnp_map_response(asio::error_code const& e if (next_expire < time_now() || next_expire > m.expires) { - asio::error_code ec; + error_code ec; m_refresh_timer.expires_at(m.expires, ec); m_refresh_timer.async_wait(bind(&upnp::on_expire, self(), _1)); } @@ -1046,13 +1087,14 @@ void upnp::return_error(int mapping, int code) m_callback(mapping, 0, error_string); } -void upnp::on_upnp_unmap_response(asio::error_code const& e - , libtorrent::http_parser const& p, rootdevice& d, int mapping) +void upnp::on_upnp_unmap_response(error_code const& e + , libtorrent::http_parser const& p, rootdevice& d, int mapping + , http_connection& c) { mutex_t::scoped_lock l(m_mutex); TORRENT_ASSERT(d.magic == 1337); - if (d.upnp_connection) + if (d.upnp_connection && d.upnp_connection.get() == &c) { d.upnp_connection->close(); d.upnp_connection.reset(); @@ -1093,7 +1135,7 @@ void upnp::on_upnp_unmap_response(asio::error_code const& e next(d, mapping); } -void upnp::on_expire(asio::error_code const& e) +void upnp::on_expire(error_code const& e) { if (e) return; @@ -1125,7 +1167,7 @@ void upnp::on_expire(asio::error_code const& e) } if (next_expire != max_time()) { - asio::error_code ec; + error_code ec; m_refresh_timer.expires_at(next_expire, ec); m_refresh_timer.async_wait(bind(&upnp::on_expire, self(), _1)); } @@ -1135,7 +1177,7 @@ void upnp::close() { mutex_t::scoped_lock l(m_mutex); - asio::error_code ec; + error_code ec; m_refresh_timer.cancel(ec); m_broadcast_timer.cancel(ec); m_closing = true; @@ -1159,7 +1201,7 @@ void upnp::close() j->action = mapping_t::action_delete; m_mappings[j - d.mapping.begin()].protocol = none; } - update_map(d, 0); + if (num_mappings() > 0) update_map(d, 0); } } diff --git a/libtorrent/src/ut_metadata.cpp b/libtorrent/src/ut_metadata.cpp index 4cefcdc7c..f92fa88d4 100644 --- a/libtorrent/src/ut_metadata.cpp +++ b/libtorrent/src/ut_metadata.cpp @@ -54,7 +54,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/bencode.hpp" #include "libtorrent/torrent.hpp" #include "libtorrent/extensions.hpp" -#include "libtorrent/extensions/metadata_transfer.hpp" +#include "libtorrent/extensions/ut_metadata.hpp" #include "libtorrent/alert_types.hpp" #ifdef TORRENT_STATS #include "libtorrent/aux_/session_impl.hpp" @@ -89,39 +89,38 @@ namespace libtorrent { namespace virtual boost::shared_ptr new_connection( peer_connection* pc); - std::vector const& metadata() const + buffer::const_interval metadata() const { TORRENT_ASSERT(m_torrent.valid_metadata()); - - if (m_metadata.empty()) + if (!m_metadata) { - bencode(std::back_inserter(m_metadata) - , m_torrent.torrent_file().create_info_metadata()); - - TORRENT_ASSERT(hasher(&m_metadata[0], m_metadata.size()).final() + m_metadata = m_torrent.torrent_file().metadata(); + m_metadata_size = m_torrent.torrent_file().metadata_size(); + TORRENT_ASSERT(hasher(m_metadata.get(), m_metadata_size).final() == m_torrent.torrent_file().info_hash()); } - TORRENT_ASSERT(!m_metadata.empty()); - return m_metadata; + return buffer::const_interval(m_metadata.get(), m_metadata.get() + + m_metadata_size); } bool received_metadata(char const* buf, int size, int piece, int total_size) { if (m_torrent.valid_metadata()) return false; - if (m_metadata.empty()) + if (!m_metadata) { // verify the total_size if (total_size <= 0 || total_size > 500 * 1024) return false; - m_metadata.resize(total_size); + m_metadata.reset(new char[total_size]); m_requested_metadata.resize(div_round_up(total_size, 16 * 1024), 0); + m_metadata_size = total_size; } if (piece < 0 || piece >= int(m_requested_metadata.size())) return false; - TORRENT_ASSERT(piece * 16 * 1024 + size <= int(m_metadata.size())); + TORRENT_ASSERT(piece * 16 * 1024 + size <= m_metadata_size); std::memcpy(&m_metadata[piece * 16 * 1024], buf, size); // mark this piece has 'have' m_requested_metadata[piece] = (std::numeric_limits::max)(); @@ -133,7 +132,7 @@ namespace libtorrent { namespace if (!have_all) return false; hasher h; - h.update(&m_metadata[0], (int)m_metadata.size()); + h.update(&m_metadata[0], m_metadata_size); sha1_hash info_hash = h.final(); if (info_hash != m_torrent.torrent_file().info_hash()) @@ -149,7 +148,8 @@ namespace libtorrent { namespace return false; } - entry metadata = bdecode(m_metadata.begin(), m_metadata.end()); + lazy_entry metadata; + int ret = lazy_bdecode(m_metadata.get(), m_metadata.get() + m_metadata_size, metadata); std::string error; if (!m_torrent.set_metadata(metadata, error)) { @@ -191,7 +191,7 @@ namespace libtorrent { namespace { if (m_metadata_size > 0 || size <= 0 || size > 500 * 1024) return; m_metadata_size = size; - m_metadata.resize(size); + m_metadata.reset(new char[size]); m_requested_metadata.resize(div_round_up(size, 16 * 1024), 0); } @@ -202,10 +202,10 @@ namespace libtorrent { namespace // the metadata file while downloading it from // peers, and while sending it. // it is mutable because it's generated lazily - mutable std::vector m_metadata; + mutable boost::shared_array m_metadata; int m_metadata_progress; - int m_metadata_size; + mutable int m_metadata_size; // this vector keeps track of how many times each meatdata // block has been requested @@ -231,7 +231,7 @@ namespace libtorrent { namespace entry& messages = h["m"]; messages["ut_metadata"] = 15; if (m_torrent.valid_metadata()) - h["metadata_size"] = m_tp.metadata().size(); + h["metadata_size"] = m_tp.metadata().left(); } // called when the extension handshake from the other end is received @@ -273,14 +273,14 @@ namespace libtorrent { namespace if (type == 1) { TORRENT_ASSERT(m_pc.associated_torrent().lock()->valid_metadata()); - e["total_size"] = m_tp.metadata().size(); + e["total_size"] = m_tp.metadata().left(); int offset = piece * 16 * 1024; - metadata = &m_tp.metadata()[0] + offset; + metadata = m_tp.metadata().begin + offset; metadata_piece_size = (std::min)( - int(m_tp.metadata().size() - offset), 16 * 1024); + int(m_tp.metadata().left() - offset), 16 * 1024); TORRENT_ASSERT(metadata_piece_size > 0); TORRENT_ASSERT(offset >= 0); - TORRENT_ASSERT(offset + metadata_piece_size <= int(m_tp.metadata().size())); + TORRENT_ASSERT(offset + metadata_piece_size <= int(m_tp.metadata().left())); } char msg[200]; diff --git a/libtorrent/src/ut_pex.cpp b/libtorrent/src/ut_pex.cpp index d27186a1b..a98fc9508 100644 --- a/libtorrent/src/ut_pex.cpp +++ b/libtorrent/src/ut_pex.cpp @@ -113,7 +113,7 @@ namespace libtorrent { namespace for (torrent::peer_iterator i = m_torrent.begin() , end(m_torrent.end()); i != end; ++i) { - peer_connection* peer = *i; + peer_connection* peer = *i; if (!send_peer(*peer)) continue; tcp::endpoint const& remote = peer->remote(); diff --git a/libtorrent/src/web_peer_connection.cpp b/libtorrent/src/web_peer_connection.cpp index 04ee0a410..6d7db636e 100755 --- a/libtorrent/src/web_peer_connection.cpp +++ b/libtorrent/src/web_peer_connection.cpp @@ -49,6 +49,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/io.hpp" #include "libtorrent/version.hpp" #include "libtorrent/aux_/session_impl.hpp" +#include "libtorrent/parse_url.hpp" using boost::bind; using boost::shared_ptr; @@ -72,6 +73,8 @@ namespace libtorrent // we want large blocks as well, so // we can request more bytes at once request_large_blocks(true); + set_upload_only(true); + // we only want left-over bandwidth set_priority(0); shared_ptr tor = t.lock(); @@ -95,8 +98,10 @@ namespace libtorrent #endif std::string protocol; - boost::tie(protocol, m_auth, m_host, m_port, m_path) + char const* error; + boost::tie(protocol, m_auth, m_host, m_port, m_path, error) = parse_url_components(url); + TORRENT_ASSERT(error == 0); if (!m_auth.empty()) m_auth = base64encode(m_auth); @@ -315,7 +320,7 @@ namespace libtorrent } } - void web_peer_connection::on_receive(asio::error_code const& error + void web_peer_connection::on_receive(error_code const& error , std::size_t bytes_transferred) { INVARIANT_CHECK; @@ -349,7 +354,7 @@ namespace libtorrent if (error) { - disconnect("failed to parse HTTP response"); + disconnect("failed to parse HTTP response", 2); return; } @@ -380,7 +385,7 @@ namespace libtorrent m_ses.m_alerts.post_alert(url_seed_alert(t->get_handle(), url() , error_msg)); } - disconnect(error_msg.c_str()); + disconnect(error_msg.c_str(), 1); return; } if (!m_parser.header_finished()) break; @@ -406,7 +411,7 @@ namespace libtorrent { // we should not try this server again. t->remove_url_seed(m_url); - disconnect("got HTTP redirection status without location header"); + disconnect("got HTTP redirection status without location header", 2); return; } @@ -430,7 +435,7 @@ namespace libtorrent std::stringstream msg; msg << "got invalid HTTP redirection location (\"" << location << "\") " "expected it to end with: " << path; - disconnect(msg.str().c_str()); + disconnect(msg.str().c_str(), 2); return; } location.resize(i); @@ -475,7 +480,7 @@ namespace libtorrent t->remove_url_seed(m_url); std::stringstream msg; msg << "invalid range in HTTP response: " << range_str.str(); - disconnect(msg.str().c_str()); + disconnect(msg.str().c_str(), 2); return; } // the http range is inclusive @@ -489,7 +494,7 @@ namespace libtorrent { // we should not try this server again. t->remove_url_seed(m_url); - disconnect("no content-length in HTTP response"); + disconnect("no content-length in HTTP response", 2); return; } } @@ -501,7 +506,7 @@ namespace libtorrent if (m_requests.empty() || m_file_requests.empty()) { - disconnect("unexpected HTTP response"); + disconnect("unexpected HTTP response", 2); return; } @@ -534,7 +539,7 @@ namespace libtorrent { // this means the end of the incoming request ends _before_ the // first expected byte (fs + m_piece.size()) - disconnect("invalid range in HTTP response"); + disconnect("invalid range in HTTP response", 2); return; } @@ -662,7 +667,7 @@ namespace libtorrent } // throws exception when the client should be disconnected - void web_peer_connection::on_sent(asio::error_code const& error + void web_peer_connection::on_sent(error_code const& error , std::size_t bytes_transferred) { INVARIANT_CHECK; diff --git a/setup.py b/setup.py index ae21bb8b6..906e4f626 100644 --- a/setup.py +++ b/setup.py @@ -85,15 +85,10 @@ if not os.environ.has_key("CPP"): # The libtorrent extension _extra_compile_args = [ - "-DHAVE_INCLUDE_LIBTORRENT_ASIO____ASIO_HPP=1", - "-DHAVE_INCLUDE_LIBTORRENT_ASIO_SSL_STREAM_HPP=1", - "-DHAVE_INCLUDE_LIBTORRENT_ASIO_IP_TCP_HPP=1", - "-DHAVE_PTHREAD=1", "-DTORRENT_USE_OPENSSL=1", - "-DHAVE_SSL=1", "-O2", "-D_FILE_OFFSET_BITS=64", - "-DNDEBUG" + "-DNDEBUG", ] if windows_check():