diff --git a/libtorrent/include/libtorrent/alert_types.hpp b/libtorrent/include/libtorrent/alert_types.hpp index 6f41758fa..a1dcf4364 100755 --- a/libtorrent/include/libtorrent/alert_types.hpp +++ b/libtorrent/include/libtorrent/alert_types.hpp @@ -82,6 +82,35 @@ namespace libtorrent { return std::auto_ptr(new tracker_warning_alert(*this)); } }; + struct TORRENT_EXPORT scrape_reply_alert: torrent_alert + { + scrape_reply_alert(torrent_handle const& h + , int incomplete_ + , int complete_ + , std::string const& msg) + : torrent_alert(h, alert::info, msg) + , incomplete(incomplete_) + , complete(complete_) + {} + + int incomplete; + int complete; + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new scrape_reply_alert(*this)); } + }; + + struct TORRENT_EXPORT scrape_failed_alert: torrent_alert + { + scrape_failed_alert(torrent_handle const& h + , std::string const& msg) + : torrent_alert(h, alert::warning, msg) + {} + + virtual std::auto_ptr clone() const + { return std::auto_ptr(new scrape_failed_alert(*this)); } + }; + struct TORRENT_EXPORT tracker_reply_alert: torrent_alert { tracker_reply_alert(torrent_handle const& h diff --git a/libtorrent/include/libtorrent/aux_/session_impl.hpp b/libtorrent/include/libtorrent/aux_/session_impl.hpp index df39fabb0..95089b649 100644 --- a/libtorrent/include/libtorrent/aux_/session_impl.hpp +++ b/libtorrent/include/libtorrent/aux_/session_impl.hpp @@ -184,7 +184,11 @@ namespace libtorrent session_impl( std::pair listen_port_range , fingerprint const& cl_fprint - , char const* listen_interface = "0.0.0.0"); + , char const* listen_interface +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + , fs::path const& logpath +#endif + ); ~session_impl(); #ifndef TORRENT_DISABLE_EXTENSIONS @@ -469,7 +473,7 @@ namespace libtorrent // we might need more than one listen socket std::list m_listen_sockets; - listen_socket_t setup_listener(tcp::endpoint ep, int retries); + listen_socket_t setup_listener(tcp::endpoint ep, int retries, bool v6_only = false); // the settings for the client session_settings m_settings; @@ -575,6 +579,7 @@ namespace libtorrent // whe shutting down process std::list > m_tracker_loggers; + fs::path m_logpath; public: boost::shared_ptr m_logger; private: diff --git a/libtorrent/include/libtorrent/debug.hpp b/libtorrent/include/libtorrent/debug.hpp index 0d3158417..96c2c9dc7 100755 --- a/libtorrent/include/libtorrent/debug.hpp +++ b/libtorrent/include/libtorrent/debug.hpp @@ -58,11 +58,11 @@ namespace libtorrent struct logger { - logger(fs::path const& filename, int instance, bool append = true) + logger(fs::path const& logpath, fs::path const& filename, int instance, bool append = true) { try { - fs::path dir(fs::complete("libtorrent_logs" + boost::lexical_cast(instance))); + fs::path dir(fs::complete(logpath / ("libtorrent_logs" + boost::lexical_cast(instance)))); if (!fs::exists(dir)) fs::create_directories(dir); m_file.open((dir / filename).string().c_str(), std::ios_base::out | (append ? std::ios_base::app : std::ios_base::out)); *this << "\n\n\n*** starting log ***\n"; diff --git a/libtorrent/include/libtorrent/http_connection.hpp b/libtorrent/include/libtorrent/http_connection.hpp index 4a70a902c..9d32af2e9 100644 --- a/libtorrent/include/libtorrent/http_connection.hpp +++ b/libtorrent/include/libtorrent/http_connection.hpp @@ -115,6 +115,8 @@ private: , asio::error_code const& e); void on_assign_bandwidth(asio::error_code const& e); + void callback(asio::error_code const& e, char const* data = 0, int size = 0); + std::vector m_recvbuffer; tcp::socket m_sock; int m_read_pos; diff --git a/libtorrent/include/libtorrent/http_tracker_connection.hpp b/libtorrent/include/libtorrent/http_tracker_connection.hpp index c0057dfa1..41df4c953 100755 --- a/libtorrent/include/libtorrent/http_tracker_connection.hpp +++ b/libtorrent/include/libtorrent/http_tracker_connection.hpp @@ -91,6 +91,9 @@ namespace libtorrent int content_length() const { return m_content_length; } void reset(); + + std::map const& headers() const { return m_header; } + private: int m_recv_pos; int m_status_code; diff --git a/libtorrent/include/libtorrent/peer_id.hpp b/libtorrent/include/libtorrent/peer_id.hpp index 13d857f99..a546c6e08 100755 --- a/libtorrent/include/libtorrent/peer_id.hpp +++ b/libtorrent/include/libtorrent/peer_id.hpp @@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE. #include #include #include +#include #include "libtorrent/config.hpp" #include "libtorrent/assert.hpp" diff --git a/libtorrent/include/libtorrent/proxy_base.hpp b/libtorrent/include/libtorrent/proxy_base.hpp index f2a955958..037a1c2d4 100644 --- a/libtorrent/include/libtorrent/proxy_base.hpp +++ b/libtorrent/include/libtorrent/proxy_base.hpp @@ -123,11 +123,13 @@ public: { m_remote_endpoint = endpoint_type(); m_sock.close(); + m_resolver.cancel(); } void close(asio::error_code& ec) { m_sock.close(ec); + m_resolver.cancel(); } endpoint_type remote_endpoint() diff --git a/libtorrent/include/libtorrent/session.hpp b/libtorrent/include/libtorrent/session.hpp index 5093e2336..1d29e03b3 100755 --- a/libtorrent/include/libtorrent/session.hpp +++ b/libtorrent/include/libtorrent/session.hpp @@ -121,11 +121,19 @@ namespace libtorrent public: session(fingerprint const& print = fingerprint("LT" - , LIBTORRENT_VERSION_MAJOR, LIBTORRENT_VERSION_MINOR, 0, 0)); + , LIBTORRENT_VERSION_MAJOR, LIBTORRENT_VERSION_MINOR, 0, 0) +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + , fs::path logpath = "." +#endif + ); session( fingerprint const& print , std::pair listen_port_range - , char const* listen_interface = "0.0.0.0"); + , char const* listen_interface = "0.0.0.0" +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + , fs::path logpath = "." +#endif + ); ~session(); diff --git a/libtorrent/include/libtorrent/session_settings.hpp b/libtorrent/include/libtorrent/session_settings.hpp index 7b08ec11e..f1f9d190c 100644 --- a/libtorrent/include/libtorrent/session_settings.hpp +++ b/libtorrent/include/libtorrent/session_settings.hpp @@ -115,6 +115,7 @@ namespace libtorrent #ifndef TORRENT_DISABLE_DHT , use_dht_as_fallback(true) #endif + , free_torrent_hashes(true) {} // this is the user agent that will be sent to the tracker @@ -281,6 +282,12 @@ namespace libtorrent // tracker is online bool use_dht_as_fallback; #endif + + // if this is true, the piece hashes will be freed, in order + // to save memory, once the torrent is seeding. This will + // make the get_torrent_info() function to return an incomplete + // torrent object that cannot be passed back to add_torrent() + bool free_torrent_hashes; }; #ifndef TORRENT_DISABLE_DHT diff --git a/libtorrent/include/libtorrent/socket.hpp b/libtorrent/include/libtorrent/socket.hpp index 514be256c..499842dd7 100755 --- a/libtorrent/include/libtorrent/socket.hpp +++ b/libtorrent/include/libtorrent/socket.hpp @@ -171,6 +171,21 @@ namespace libtorrent return Endpoint(addr, port); } } + + struct v6only + { + v6only(bool enable): m_value(enable) {} + template + int level(Protocol const&) const { return IPPROTO_IPV6; } + template + int name(Protocol const&) const { return IPV6_V6ONLY; } + template + int const* data(Protocol const&) const { return &m_value; } + template + size_t size(Protocol const&) const { return sizeof(m_value); } + int m_value; + }; + } #endif // TORRENT_SOCKET_HPP_INCLUDED diff --git a/libtorrent/include/libtorrent/torrent.hpp b/libtorrent/include/libtorrent/torrent.hpp index 5ee5ddb03..7aa779081 100755 --- a/libtorrent/include/libtorrent/torrent.hpp +++ b/libtorrent/include/libtorrent/torrent.hpp @@ -309,6 +309,8 @@ namespace libtorrent virtual void tracker_request_error(tracker_request const& r , int response_code, const std::string& str); virtual void tracker_warning(std::string const& msg); + virtual void tracker_scrape_response(tracker_request const& req + , int complete, int incomplete, int downloaded); // generates a request string for sending // to the tracker @@ -332,6 +334,7 @@ namespace libtorrent // forcefully sets next_announce to the current time void force_tracker_request(); void force_tracker_request(ptime); + void scrape_tracker(); // sets the username and password that will be sent to // the tracker diff --git a/libtorrent/include/libtorrent/torrent_handle.hpp b/libtorrent/include/libtorrent/torrent_handle.hpp index 7ddb218a6..48a17e2ec 100755 --- a/libtorrent/include/libtorrent/torrent_handle.hpp +++ b/libtorrent/include/libtorrent/torrent_handle.hpp @@ -94,15 +94,17 @@ namespace libtorrent , upload_rate(0) , download_payload_rate(0) , upload_payload_rate(0) + , num_seeds(0) , num_peers(0) , num_complete(-1) , num_incomplete(-1) + , list_seeds(0) + , list_peers(0) , pieces(0) , num_pieces(0) , total_done(0) , total_wanted_done(0) , total_wanted(0) - , num_seeds(0) , distributed_copies(0.f) , block_size(0) , num_uploads(0) @@ -159,8 +161,12 @@ namespace libtorrent float download_payload_rate; float upload_payload_rate; + // the number of peers this torrent is connected to + // that are seeding. + int num_seeds; + // the number of peers this torrent - // is connected to. + // is connected to (including seeds). int num_peers; // if the tracker sends scrape info in its @@ -171,6 +177,15 @@ namespace libtorrent int num_complete; int num_incomplete; + // this is the number of seeds whose IP we know + // but are not necessarily connected to + int list_seeds; + + // this is the number of peers whose IP we know + // (including seeds), but are not necessarily + // connected to + int list_peers; + const std::vector* pieces; // this is the number of pieces the client has @@ -193,10 +208,6 @@ namespace libtorrent // in case any pieces are filtered as not wanted size_type total_wanted; - // the number of peers this torrent is connected to - // that are seeding. - int num_seeds; - // the number of distributed copies of the file. // note that one copy may be spread out among many peers. // @@ -345,6 +356,9 @@ namespace libtorrent // timed out. void force_reannounce(boost::posix_time::time_duration) const; + // performs a scrape request + void scrape_tracker() const; + // returns the name of this torrent, in case it doesn't // have metadata it returns the name assigned to it // when it was added. diff --git a/libtorrent/include/libtorrent/tracker_manager.hpp b/libtorrent/include/libtorrent/tracker_manager.hpp index fdc3f6bbf..8fec9563c 100755 --- a/libtorrent/include/libtorrent/tracker_manager.hpp +++ b/libtorrent/include/libtorrent/tracker_manager.hpp @@ -122,6 +122,8 @@ namespace libtorrent request_callback(): m_manager(0) {} virtual ~request_callback() {} virtual void tracker_warning(std::string const& msg) = 0; + virtual void tracker_scrape_response(tracker_request const& req + , int complete, int incomplete, int downloads) {} virtual void tracker_response( tracker_request const& , std::vector& peers @@ -191,7 +193,7 @@ namespace libtorrent : timeout_handler { tracker_connection(tracker_manager& man - , tracker_request req + , tracker_request const& req , asio::strand& str , address bind_interface , boost::weak_ptr r); diff --git a/libtorrent/src/broadcast_socket.cpp b/libtorrent/src/broadcast_socket.cpp index a9d27eff4..e03ad2274 100644 --- a/libtorrent/src/broadcast_socket.cpp +++ b/libtorrent/src/broadcast_socket.cpp @@ -182,7 +182,7 @@ namespace libtorrent void broadcast_socket::on_receive(socket_entry* s, asio::error_code const& ec , std::size_t bytes_transferred) { - if (ec || bytes_transferred == 0) return; + if (ec || bytes_transferred == 0 || !m_on_receive) return; m_on_receive(s->remote, s->buffer, bytes_transferred); s->socket->async_receive_from(asio::buffer(s->buffer, sizeof(s->buffer)) , s->remote, bind(&broadcast_socket::on_receive, this, s, _1, _2)); diff --git a/libtorrent/src/bt_peer_connection.cpp b/libtorrent/src/bt_peer_connection.cpp index d7b3226ec..384bc2375 100755 --- a/libtorrent/src/bt_peer_connection.cpp +++ b/libtorrent/src/bt_peer_connection.cpp @@ -1272,7 +1272,13 @@ namespace libtorrent { INVARIANT_CHECK; - TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield); + // Don't require the bitfield to have been sent at this point + // the case where m_sent_bitfield may not be true is if the + // torrent doesn't have any metadata, and a peer is timimg out. + // then the keep-alive message will be sent before the bitfield + // this is a violation to the original protocol, but necessary + // for the metadata extension. + TORRENT_ASSERT(m_sent_handshake); char msg[] = {0,0,0,0}; send_buffer(msg, sizeof(msg)); @@ -2477,6 +2483,11 @@ namespace libtorrent TORRENT_ASSERT(!m_rc4_encrypted || m_RC4_handler.get()); #endif + if (!in_handshake()) + { + TORRENT_ASSERT(m_sent_handshake); + } + if (!m_in_constructor) peer_connection::check_invariant(); diff --git a/libtorrent/src/entry.cpp b/libtorrent/src/entry.cpp index 88800713c..8219ecc06 100755 --- a/libtorrent/src/entry.cpp +++ b/libtorrent/src/entry.cpp @@ -33,6 +33,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/pch.hpp" #include +#include #include #include "libtorrent/entry.hpp" #include "libtorrent/config.hpp" diff --git a/libtorrent/src/file.cpp b/libtorrent/src/file.cpp index 67024cf81..5e01e1ae5 100755 --- a/libtorrent/src/file.cpp +++ b/libtorrent/src/file.cpp @@ -68,6 +68,7 @@ BOOST_STATIC_ASSERT(sizeof(lseek(0, 0, 0)) >= 8); #include #include "libtorrent/file.hpp" #include +#include #ifndef O_BINARY #define O_BINARY 0 @@ -184,7 +185,7 @@ namespace libtorrent { std::stringstream msg; msg << "open failed: '" << path.native_file_string() << "'. " - << strerror(errno); + << std::strerror(errno); throw file_error(msg.str()); } m_open_mode = mode; @@ -216,7 +217,7 @@ namespace libtorrent if (ret == -1) { std::stringstream msg; - msg << "read failed: " << strerror(errno); + msg << "read failed: " << std::strerror(errno); throw file_error(msg.str()); } return ret; @@ -240,7 +241,7 @@ namespace libtorrent if (ret == -1) { std::stringstream msg; - msg << "write failed: " << strerror(errno); + msg << "write failed: " << std::strerror(errno); throw file_error(msg.str()); } return ret; @@ -254,7 +255,7 @@ namespace libtorrent if (ftruncate(m_fd, s) < 0) { std::stringstream msg; - msg << "ftruncate failed: '" << strerror(errno); + msg << "ftruncate failed: '" << std::strerror(errno); throw file_error(msg.str()); } #endif @@ -278,7 +279,7 @@ namespace libtorrent if (ret == -1) { std::stringstream msg; - msg << "seek failed: '" << strerror(errno) + msg << "seek failed: '" << std::strerror(errno) << "' fd: " << m_fd << " offset: " << offset << " seekdir: " << seekdir; diff --git a/libtorrent/src/http_connection.cpp b/libtorrent/src/http_connection.cpp index 08be387cc..a0d8e3fa3 100644 --- a/libtorrent/src/http_connection.cpp +++ b/libtorrent/src/http_connection.cpp @@ -96,9 +96,7 @@ void http_connection::on_connect_timeout() if (m_connection_ticket > -1) m_cc.done(m_connection_ticket); m_connection_ticket = -1; - if (m_bottled && m_called) return; - m_called = true; - m_handler(asio::error::timed_out, m_parser, 0, 0); + callback(asio::error::timed_out); close(); } @@ -112,15 +110,15 @@ void http_connection::on_timeout(boost::weak_ptr p if (e == asio::error::operation_aborted) return; - if (c->m_bottled && c->m_called) return; - if (c->m_last_receive + c->m_timeout < time_now()) { - c->m_called = true; - c->m_handler(asio::error::timed_out, c->m_parser, 0, 0); + c->callback(asio::error::timed_out); + c->close(); return; } + if (!c->m_sock.is_open()) return; + c->m_timer.expires_at(c->m_last_receive + c->m_timeout); c->m_timer.async_wait(bind(&http_connection::on_timeout, p, _1)); } @@ -135,6 +133,8 @@ void http_connection::close() if (m_connection_ticket > -1) m_cc.done(m_connection_ticket); m_connection_ticket = -1; + + m_handler.clear(); } void http_connection::on_resolve(asio::error_code const& e @@ -142,10 +142,8 @@ void http_connection::on_resolve(asio::error_code const& e { if (e) { + callback(e); close(); - if (m_bottled && m_called) return; - m_called = true; - m_handler(e, m_parser, 0, 0); return; } TORRENT_ASSERT(i != tcp::resolver::iterator()); @@ -181,10 +179,17 @@ void http_connection::on_connect(asio::error_code const& e } */ else { + callback(e); close(); - if (m_bottled && m_called) return; + } +} + +void http_connection::callback(asio::error_code const& e, char const* data, int size) +{ + if (!m_bottled || !m_called) + { m_called = true; - m_handler(e, m_parser, 0, 0); + if (m_handler) m_handler(e, m_parser, data, size); } } @@ -192,10 +197,8 @@ void http_connection::on_write(asio::error_code const& e) { if (e) { + callback(e); close(); - if (m_bottled && m_called) return; - m_called = true; - m_handler(e, m_parser, 0, 0); return; } @@ -230,9 +233,6 @@ void http_connection::on_read(asio::error_code const& e if (e == asio::error::eof) { - close(); - if (m_bottled && m_called) return; - m_called = true; char const* data = 0; std::size_t size = 0; if (m_bottled && m_parser.header_finished()) @@ -240,16 +240,15 @@ void http_connection::on_read(asio::error_code const& e data = m_parser.get_body().begin; size = m_parser.get_body().left(); } - m_handler(e, m_parser, data, size); + callback(e, data, size); + close(); return; } if (e) { + callback(e); close(); - if (m_bottled && m_called) return; - m_called = true; - m_handler(e, m_parser, 0, 0); return; } @@ -267,9 +266,7 @@ void http_connection::on_read(asio::error_code const& e if (url.empty()) { // missing location header - if (m_bottled && m_called) return; - m_called = true; - m_handler(e, m_parser, 0, 0); + callback(e); return; } @@ -291,7 +288,7 @@ void http_connection::on_read(asio::error_code const& e if (!m_bottled && m_parser.header_finished()) { if (m_read_pos > m_parser.body_start()) - m_handler(e, m_parser, &m_recvbuffer[0] + m_parser.body_start() + callback(e, &m_recvbuffer[0] + m_parser.body_start() , m_read_pos - m_parser.body_start()); m_read_pos = 0; m_last_receive = time_now(); @@ -299,15 +296,13 @@ void http_connection::on_read(asio::error_code const& e else if (m_bottled && m_parser.finished()) { m_timer.cancel(); - if (m_bottled && m_called) return; - m_called = true; - m_handler(e, m_parser, m_parser.get_body().begin, m_parser.get_body().left()); + callback(e, m_parser.get_body().begin, m_parser.get_body().left()); } } else { TORRENT_ASSERT(!m_bottled); - m_handler(e, m_parser, &m_recvbuffer[0], m_read_pos); + callback(e, &m_recvbuffer[0], m_read_pos); m_read_pos = 0; m_last_receive = time_now(); } @@ -316,10 +311,8 @@ void http_connection::on_read(asio::error_code const& e m_recvbuffer.resize((std::min)(m_read_pos + 2048, int(max_bottled_buffer))); if (m_read_pos == max_bottled_buffer) { + callback(asio::error::eof); close(); - if (m_bottled && m_called) return; - m_called = true; - m_handler(asio::error::eof, m_parser, 0, 0); return; } int amount_to_read = m_recvbuffer.size() - m_read_pos; @@ -345,8 +338,7 @@ void http_connection::on_assign_bandwidth(asio::error_code const& e) && m_limiter_timer_active) || !m_sock.is_open()) { - if (!m_bottled || !m_called) - m_handler(e, m_parser, 0, 0); + callback(asio::error::eof); return; } m_limiter_timer_active = false; @@ -360,6 +352,8 @@ void http_connection::on_assign_bandwidth(asio::error_code const& e) if (amount_to_read > m_download_quota) amount_to_read = m_download_quota; + if (!m_sock.is_open()) return; + m_sock.async_read_some(asio::buffer(&m_recvbuffer[0] + m_read_pos , amount_to_read) , bind(&http_connection::on_read @@ -373,6 +367,8 @@ void http_connection::on_assign_bandwidth(asio::error_code const& e) void http_connection::rate_limit(int limit) { + if (!m_sock.is_open()) return; + if (!m_limiter_timer_active) { m_limiter_timer_active = true; diff --git a/libtorrent/src/http_tracker_connection.cpp b/libtorrent/src/http_tracker_connection.cpp index ed9823b83..86d21e494 100755 --- a/libtorrent/src/http_tracker_connection.cpp +++ b/libtorrent/src/http_tracker_connection.cpp @@ -797,7 +797,7 @@ namespace libtorrent return; } m_buffer.erase(m_buffer.begin(), m_buffer.begin() + m_parser.body_start()); - if (inflate_gzip(m_buffer, tracker_request(), cb.get(), + if (inflate_gzip(m_buffer, tracker_req(), cb.get(), m_settings.tracker_maximum_response_length)) { close(); @@ -897,21 +897,35 @@ namespace libtorrent } catch(type_error const&) {} - std::vector peer_list; - 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)); entry scrape_data = e["files"][ih]; - int complete = scrape_data["complete"].integer(); - int incomplete = scrape_data["incomplete"].integer(); - cb->tracker_response(tracker_request(), peer_list, 0, complete - , incomplete); + + int complete = -1; + int incomplete = -1; + int downloaded = -1; + + entry const* complete_ent = scrape_data.find_key("complete"); + if (complete_ent && complete_ent->type() == entry::int_t) + complete = complete_ent->integer(); + + entry const* incomplete_ent = scrape_data.find_key("incomplete"); + if (incomplete_ent && incomplete_ent->type() == entry::int_t) + incomplete = incomplete_ent->integer(); + + entry const* downloaded_ent = scrape_data.find_key("downloaded"); + if (downloaded_ent && downloaded_ent->type() == entry::int_t) + downloaded = downloaded_ent->integer(); + + cb->tracker_scrape_response(tracker_req(), complete + , incomplete, downloaded); return; } + std::vector peer_list; int interval = (int)e["interval"].integer(); if (e["peers"].type() == entry::string_t) @@ -965,16 +979,16 @@ namespace libtorrent try { incomplete = e["incomplete"].integer(); } catch(type_error&) {} - cb->tracker_response(tracker_request(), peer_list, interval, complete + cb->tracker_response(tracker_req(), peer_list, interval, complete , incomplete); } catch(type_error& e) { - cb->tracker_request_error(tracker_request(), m_parser.status_code(), e.what()); + cb->tracker_request_error(tracker_req(), m_parser.status_code(), e.what()); } catch(std::runtime_error& e) { - cb->tracker_request_error(tracker_request(), m_parser.status_code(), e.what()); + cb->tracker_request_error(tracker_req(), m_parser.status_code(), e.what()); } } diff --git a/libtorrent/src/identify_client.cpp b/libtorrent/src/identify_client.cpp index 4888f4a95..73221de66 100755 --- a/libtorrent/src/identify_client.cpp +++ b/libtorrent/src/identify_client.cpp @@ -174,6 +174,7 @@ namespace , {"ML", "MLDonkey"} , {"MO", "Mono Torrent"} , {"MP", "MooPolice"} + , {"MR", "Miro"} , {"MT", "Moonlight Torrent"} , {"O", "Osprey Permaseed"} , {"PD", "Pando"} diff --git a/libtorrent/src/kademlia/dht_tracker.cpp b/libtorrent/src/kademlia/dht_tracker.cpp index b2981f7cd..f32db06d4 100644 --- a/libtorrent/src/kademlia/dht_tracker.cpp +++ b/libtorrent/src/kademlia/dht_tracker.cpp @@ -224,6 +224,7 @@ namespace libtorrent { namespace dht m_connection_timer.cancel(); m_refresh_timer.cancel(); m_socket.close(); + m_host_resolver.cancel(); } void dht_tracker::dht_status(session_status& s) diff --git a/libtorrent/src/kademlia/node_id.cpp b/libtorrent/src/kademlia/node_id.cpp index 52a5c766a..99f3df219 100644 --- a/libtorrent/src/kademlia/node_id.cpp +++ b/libtorrent/src/kademlia/node_id.cpp @@ -87,7 +87,7 @@ int distance_exp(node_id const& n1, node_id const& n2) // return the bit-number of the first bit // that differs int bit = byte * 8; - for (int b = 7; b > 0; --b) + for (int b = 7; b >= 0; --b) if (t >= (1 << b)) return bit + b; return bit; } diff --git a/libtorrent/src/lsd.cpp b/libtorrent/src/lsd.cpp index 6e1dcb7b3..06e570f3c 100644 --- a/libtorrent/src/lsd.cpp +++ b/libtorrent/src/lsd.cpp @@ -185,5 +185,7 @@ void lsd::close() { m_socket.close(); m_broadcast_timer.cancel(); + m_disabled = true; + m_callback.clear(); } diff --git a/libtorrent/src/session.cpp b/libtorrent/src/session.cpp index 5bdb6b07e..0b8aecff7 100755 --- a/libtorrent/src/session.cpp +++ b/libtorrent/src/session.cpp @@ -106,8 +106,16 @@ namespace libtorrent session::session( fingerprint const& id , std::pair listen_port_range - , char const* listen_interface) - : m_impl(new session_impl(listen_port_range, id, listen_interface)) + , char const* listen_interface +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + , fs::path logpath +#endif + ) + : m_impl(new session_impl(listen_port_range, id, listen_interface +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + , logpath +#endif + )) { // turn off the filename checking in boost.filesystem TORRENT_ASSERT(listen_port_range.first > 0); @@ -121,8 +129,16 @@ namespace libtorrent #endif } - session::session(fingerprint const& id) - : m_impl(new session_impl(std::make_pair(0, 0), id)) + session::session(fingerprint const& id +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + , fs::path logpath +#endif + ) +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + : m_impl(new session_impl(std::make_pair(0, 0), id, "0.0.0.0", logpath)) +#else + : m_impl(new session_impl(std::make_pair(0, 0), id, "0.0.0.0")) +#endif { #ifndef NDEBUG boost::function0 test = boost::ref(*m_impl); diff --git a/libtorrent/src/session_impl.cpp b/libtorrent/src/session_impl.cpp index b3eba0bf7..69f2c1bc1 100755 --- a/libtorrent/src/session_impl.cpp +++ b/libtorrent/src/session_impl.cpp @@ -545,7 +545,11 @@ namespace detail session_impl::session_impl( std::pair listen_port_range , fingerprint const& cl_fprint - , char const* listen_interface) + , char const* listen_interface +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + , fs::path const& logpath +#endif + ) : m_send_buffers(send_buffer_size) , m_files(40) , m_strand(m_io_service) @@ -570,6 +574,9 @@ namespace detail #endif , m_timer(m_io_service) , m_next_connect_torrent(0) +#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) + , m_logpath(logpath) +#endif , m_checker_impl(*this) { #ifdef WIN32 @@ -807,13 +814,15 @@ namespace detail return m_ipv6_interface; } - session_impl::listen_socket_t session_impl::setup_listener(tcp::endpoint ep, int retries) + session_impl::listen_socket_t session_impl::setup_listener(tcp::endpoint ep + , int retries, bool v6_only) { asio::error_code ec; listen_socket_t s; s.sock.reset(new socket_acceptor(m_io_service)); s.sock->open(ep.protocol(), ec); s.sock->set_option(socket_acceptor::reuse_address(true), ec); + if (ep.protocol() == tcp::v6()) s.sock->set_option(v6only(v6_only), ec); s.sock->bind(ep, ec); while (ec && retries > 0) { @@ -906,7 +915,7 @@ namespace detail s = setup_listener( tcp::endpoint(address_v6::any(), m_listen_interface.port()) - , m_listen_port_retries); + , m_listen_port_retries, true); if (s.sock) { @@ -1021,7 +1030,6 @@ namespace detail async_accept(listener); // we got a connection request! - m_incoming_connection = true; tcp::endpoint endp = s->remote_endpoint(ec); if (ec) @@ -1036,6 +1044,14 @@ namespace detail #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) (*m_logger) << endp << " <== INCOMING CONNECTION\n"; #endif + + // local addresses do not count, since it's likely + // coming from our own client through local service discovery + // and it does not reflect whether or not a router is open + // for incoming connections or not. + if (!is_local(endp.address())) + m_incoming_connection = true; + if (m_ip_filter.access(endp.address()) & ip_filter::blocked) { #if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) @@ -1602,7 +1618,7 @@ namespace detail , int instance, bool append) { // current options are file_logger, cout_logger and null_logger - return boost::shared_ptr(new logger(name + ".log", instance, append)); + return boost::shared_ptr(new logger(m_logpath, name + ".log", instance, append)); } #endif @@ -2265,6 +2281,8 @@ namespace detail INVARIANT_CHECK; + if (m_lsd) return; + m_lsd = new lsd(m_io_service , m_listen_interface.address() , bind(&session_impl::on_lsd_peer, this, _1, _2)); @@ -2276,6 +2294,8 @@ namespace detail INVARIANT_CHECK; + if (m_natpmp) return; + m_natpmp = new natpmp(m_io_service , m_listen_interface.address() , bind(&session_impl::on_port_mapping @@ -2294,6 +2314,8 @@ namespace detail INVARIANT_CHECK; + if (m_upnp) return; + m_upnp = new upnp(m_io_service, m_half_open , m_listen_interface.address() , m_settings.user_agent @@ -2310,6 +2332,8 @@ namespace detail void session_impl::stop_lsd() { mutex_t::scoped_lock l(m_mutex); + if (m_lsd.get()) + m_lsd->close(); m_lsd = 0; } diff --git a/libtorrent/src/storage.cpp b/libtorrent/src/storage.cpp index 0468684f3..cf0781e6a 100755 --- a/libtorrent/src/storage.cpp +++ b/libtorrent/src/storage.cpp @@ -478,6 +478,8 @@ namespace libtorrent m_files.release(this); buffer().swap(m_scratch_buffer); + std::string error; + // delete the files from disk std::set directories; typedef std::set::iterator iter_t; @@ -493,13 +495,21 @@ namespace libtorrent std::pair ret = directories.insert((m_save_path / bp).string()); bp = bp.branch_path(); } - std::remove(p.c_str()); + if (std::remove(p.c_str()) != 0 && errno != ENOENT) + error = std::strerror(errno); } // remove the directories. Reverse order to delete // subdirectories first - std::for_each(directories.rbegin(), directories.rend() - , bind((int(*)(char const*))&std::remove, bind(&std::string::c_str, _1))); + + for (std::set::reverse_iterator i = directories.rbegin() + , end(directories.rend()); i != end; ++i) + { + if (std::remove(i->c_str()) != 0 && errno != ENOENT) + error = std::strerror(errno); + } + + if (!error.empty()) throw std::runtime_error(error); } void storage::write_resume_data(entry& rd) const diff --git a/libtorrent/src/torrent.cpp b/libtorrent/src/torrent.cpp index 84f30aa2d..33a73d1f3 100755 --- a/libtorrent/src/torrent.cpp +++ b/libtorrent/src/torrent.cpp @@ -278,6 +278,7 @@ namespace libtorrent { boost::weak_ptr self(shared_from_this()); if (m_torrent_file->is_valid()) init(); + if (m_abort) return; m_announce_timer.expires_from_now(seconds(1)); m_announce_timer.async_wait(m_ses.m_strand.wrap( bind(&torrent::on_announce_disp, self, _1))); @@ -421,6 +422,8 @@ namespace libtorrent try #endif { + if (m_abort) return; + boost::weak_ptr self(shared_from_this()); if (!m_torrent_file->priv()) @@ -489,13 +492,28 @@ namespace libtorrent #endif + void torrent::scrape_tracker() + { + if (m_trackers.empty()) return; + + TORRENT_ASSERT(m_currently_trying_tracker >= 0); + TORRENT_ASSERT(m_currently_trying_tracker < int(m_trackers.size())); + + tracker_request req; + req.info_hash = m_torrent_file->info_hash(); + req.kind = tracker_request::scrape_request; + req.url = m_trackers[m_currently_trying_tracker].url; + m_ses.m_tracker_manager.queue_request(m_ses.m_strand, m_ses.m_half_open, req + , tracker_login(), m_ses.m_listen_interface.address(), shared_from_this()); + } + // returns true if it is time for this torrent to make another // tracker request bool torrent::should_request() { INVARIANT_CHECK; - if (m_torrent_file->trackers().empty()) return false; + if (m_trackers.empty()) return false; if (m_just_paused) { @@ -517,8 +535,28 @@ namespace libtorrent } } + void torrent::tracker_scrape_response(tracker_request const& req + , int complete, int incomplete, int downloaded) + { + session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); + + INVARIANT_CHECK; + TORRENT_ASSERT(req.kind == tracker_request::scrape_request); + + if (complete >= 0) m_complete = complete; + if (incomplete >= 0) m_incomplete = incomplete; + + if (m_ses.m_alerts.should_post(alert::info)) + { + std::stringstream s; + s << "Got scrape response from tracker: " << req.url; + m_ses.m_alerts.post_alert(scrape_reply_alert( + get_handle(), m_incomplete, m_complete, s.str())); + } + } + void torrent::tracker_response( - tracker_request const& + tracker_request const& r , std::vector& peer_list , int interval , int complete @@ -527,6 +565,7 @@ namespace libtorrent session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); INVARIANT_CHECK; + TORRENT_ASSERT(r.kind == tracker_request::announce_request); m_failed_trackers = 0; // announce intervals less than 5 minutes @@ -603,8 +642,7 @@ namespace libtorrent if (m_ses.m_alerts.should_post(alert::info)) { std::stringstream s; - s << "Got response from tracker: " - << m_trackers[m_last_working_tracker].url; + s << "Got response from tracker: " << r.url; m_ses.m_alerts.post_alert(tracker_reply_alert( get_handle(), peer_list.size(), s.str())); } @@ -1060,6 +1098,7 @@ namespace libtorrent m_owning_storage = 0; m_announce_timer.cancel(); + m_host_resolver.cancel(); } void torrent::on_files_deleted(int ret, disk_io_job const& j) @@ -1068,7 +1107,14 @@ namespace libtorrent if (alerts().should_post(alert::warning)) { - alerts().post_alert(torrent_deleted_alert(get_handle(), "files deleted")); + if (ret != 0) + { + alerts().post_alert(torrent_deleted_alert(get_handle(), "delete files failed: " + j.str)); + } + else + { + alerts().post_alert(torrent_deleted_alert(get_handle(), "files deleted")); + } } } @@ -1142,7 +1188,8 @@ namespace libtorrent if (is_seed()) { m_picker.reset(); - m_torrent_file->seed_free(); + if (m_ses.settings().free_torrent_hashes) + m_torrent_file->seed_free(); } } @@ -1402,7 +1449,6 @@ namespace libtorrent void torrent::replace_trackers(std::vector const& urls) { - TORRENT_ASSERT(!urls.empty()); m_trackers = urls; if (m_currently_trying_tracker >= (int)m_trackers.size()) m_currently_trying_tracker = (int)m_trackers.size()-1; @@ -2206,6 +2252,7 @@ namespace libtorrent // only start the announce if we want to announce with the dht if (should_announce_dht()) { + if (m_abort) return; // force the DHT to reannounce m_last_dht_announce = time_now() - minutes(15); boost::weak_ptr self(shared_from_this()); @@ -2336,7 +2383,8 @@ namespace libtorrent if (is_seed()) { m_picker.reset(); - m_torrent_file->seed_free(); + if (m_ses.settings().free_torrent_hashes) + m_torrent_file->seed_free(); } if (!m_connections_initialized) @@ -2847,8 +2895,12 @@ namespace libtorrent torrent_status st; - st.num_peers = (int)std::count_if(m_connections.begin(), m_connections.end(), - !boost::bind(&peer_connection::is_connecting, _1)); + st.num_peers = (int)std::count_if(m_connections.begin(), m_connections.end() + , !boost::bind(&peer_connection::is_connecting, _1)); + + st.list_peers = std::distance(m_policy.begin_peer(), m_policy.end_peer()); + st.list_seeds = (int)std::count_if(m_policy.begin_peer(), m_policy.end_peer() + , boost::bind(&policy::peer::seed, bind(&policy::iterator::value_type::second, _1))); st.storage_mode = m_storage_mode; @@ -2979,7 +3031,7 @@ namespace libtorrent } void torrent::tracker_request_timed_out( - tracker_request const&) + tracker_request const& r) { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); @@ -2992,19 +3044,26 @@ namespace libtorrent if (m_ses.m_alerts.should_post(alert::warning)) { std::stringstream s; - s << "tracker: \"" - << m_trackers[m_currently_trying_tracker].url - << "\" timed out"; - m_ses.m_alerts.post_alert(tracker_alert(get_handle() - , m_failed_trackers + 1, 0, s.str())); + s << "tracker: \"" << r.url << "\" timed out"; + if (r.kind == tracker_request::announce_request) + { + m_ses.m_alerts.post_alert(tracker_alert(get_handle() + , m_failed_trackers + 1, 0, s.str())); + } + else if (r.kind == tracker_request::scrape_request) + { + m_ses.m_alerts.post_alert(scrape_failed_alert(get_handle(), s.str())); + } } - try_next_tracker(); + + if (r.kind == tracker_request::announce_request) + try_next_tracker(); } // TODO: with some response codes, we should just consider // the tracker as a failure and not retry // it anymore - void torrent::tracker_request_error(tracker_request const& + void torrent::tracker_request_error(tracker_request const& r , int response_code, const std::string& str) { session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); @@ -3017,14 +3076,20 @@ namespace libtorrent if (m_ses.m_alerts.should_post(alert::warning)) { std::stringstream s; - s << "tracker: \"" - << m_trackers[m_currently_trying_tracker].url - << "\" " << str; - m_ses.m_alerts.post_alert(tracker_alert(get_handle() - , m_failed_trackers + 1, response_code, s.str())); + s << "tracker: \"" << r.url << "\" " << str; + if (r.kind == tracker_request::announce_request) + { + m_ses.m_alerts.post_alert(tracker_alert(get_handle() + , m_failed_trackers + 1, response_code, s.str())); + } + else if (r.kind == tracker_request::scrape_request) + { + m_ses.m_alerts.post_alert(scrape_failed_alert(get_handle(), s.str())); + } } - try_next_tracker(); + if (r.kind == tracker_request::announce_request) + try_next_tracker(); } diff --git a/libtorrent/src/torrent_handle.cpp b/libtorrent/src/torrent_handle.cpp index b19e05bb4..aa517ac76 100755 --- a/libtorrent/src/torrent_handle.cpp +++ b/libtorrent/src/torrent_handle.cpp @@ -863,6 +863,20 @@ namespace libtorrent t->force_tracker_request(); } + void torrent_handle::scrape_tracker() const + { + INVARIANT_CHECK; + + if (m_ses == 0) throw_invalid_handle(); + TORRENT_ASSERT(m_chk); + + session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); + boost::shared_ptr t = m_ses->find_torrent(m_info_hash).lock(); + if (!t) throw_invalid_handle(); + + t->scrape_tracker(); + } + void torrent_handle::set_ratio(float ratio) const { INVARIANT_CHECK; diff --git a/libtorrent/src/tracker_manager.cpp b/libtorrent/src/tracker_manager.cpp index 82c5cc948..19da33d4b 100755 --- a/libtorrent/src/tracker_manager.cpp +++ b/libtorrent/src/tracker_manager.cpp @@ -359,7 +359,7 @@ namespace libtorrent tracker_connection::tracker_connection( tracker_manager& man - , tracker_request req + , tracker_request const& req , asio::strand& str , address bind_interface_ , boost::weak_ptr r) diff --git a/libtorrent/src/udp_tracker_connection.cpp b/libtorrent/src/udp_tracker_connection.cpp index 6d76988d3..eb138e67a 100755 --- a/libtorrent/src/udp_tracker_connection.cpp +++ b/libtorrent/src/udp_tracker_connection.cpp @@ -548,7 +548,7 @@ namespace libtorrent } int complete = detail::read_int32(buf); - /*int downloaded = */detail::read_int32(buf); + int downloaded = detail::read_int32(buf); int incomplete = detail::read_int32(buf); boost::shared_ptr cb = requester(); @@ -559,9 +559,8 @@ namespace libtorrent return; } - std::vector peer_list; - cb->tracker_response(tracker_req(), peer_list, 0 - , complete, incomplete); + cb->tracker_scrape_response(tracker_req() + , complete, incomplete, downloaded); m_man.remove_request(this); close();