libtorrent sync 2347

This commit is contained in:
Andrew Resch 2008-05-20 06:23:48 +00:00
parent 576cae3b26
commit b15608252c
98 changed files with 2453 additions and 2129 deletions

View File

@ -134,7 +134,7 @@ class Torrent:
def set_private_flag(self, private): def set_private_flag(self, private):
self.private = 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): def set_prioritize_first_last(self, prioritize):
self.prioritize_first_last = prioritize self.prioritize_first_last = prioritize

View File

@ -28,17 +28,17 @@ namespace
this->peer_plugin::add_handshake(e); this->peer_plugin::add_handshake(e);
} }
bool on_handshake() bool on_handshake(char const* reserved_bits)
{ {
if (override f = this->get_override("on_handshake")) if (override f = this->get_override("on_handshake"))
return f(); return f();
else 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) bool on_extension_handshake(entry const& e)

View File

@ -74,13 +74,7 @@ void bind_torrent_info()
.def(init<entry const&>()) .def(init<entry const&>())
.def(init<sha1_hash const&>()) .def(init<sha1_hash const&>())
.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_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("add_url_seed", &torrent_info::add_url_seed)
.def("name", &torrent_info::name, copy) .def("name", &torrent_info::name, copy)
@ -91,7 +85,7 @@ void bind_torrent_info()
.def("num_pieces", &torrent_info::num_pieces) .def("num_pieces", &torrent_info::num_pieces)
.def("info_hash", &torrent_info::info_hash, copy) .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("piece_size", &torrent_info::piece_size)
.def("num_files", &torrent_info::num_files, (arg("storage")=false)) .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("files", &files, (arg("storage")=false))
.def("priv", &torrent_info::priv) .def("priv", &torrent_info::priv)
.def("set_priv", &torrent_info::set_priv)
.def("trackers", range(begin_trackers, end_trackers)) .def("trackers", range(begin_trackers, end_trackers))
.def("creation_date", &torrent_info::creation_date) .def("creation_date", &torrent_info::creation_date)

View File

@ -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 */ /* 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); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -188,7 +188,7 @@ namespace libtorrent
struct TORRENT_EXPORT peer_error_alert: alert struct TORRENT_EXPORT peer_error_alert: alert
{ {
peer_error_alert(tcp::endpoint const& pip, peer_id const& pid_, std::string const& msg) 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) , ip(pip)
, pid(pid_) , pid(pid_)
{} {}
@ -200,6 +200,21 @@ namespace libtorrent
peer_id pid; 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<alert> clone() const
{ return std::auto_ptr<alert>(new peer_disconnected_alert(*this)); }
tcp::endpoint ip;
peer_id pid;
};
struct TORRENT_EXPORT invalid_request_alert: torrent_alert struct TORRENT_EXPORT invalid_request_alert: torrent_alert
{ {
invalid_request_alert( invalid_request_alert(

View File

@ -151,7 +151,7 @@ namespace libtorrent
void async_accept(boost::shared_ptr<socket_acceptor> const& listener); void async_accept(boost::shared_ptr<socket_acceptor> const& listener);
void on_incoming_connection(boost::shared_ptr<socket_type> const& s void on_incoming_connection(boost::shared_ptr<socket_type> const& s
, boost::weak_ptr<socket_acceptor> listener, asio::error_code const& e); , boost::weak_ptr<socket_acceptor> listener, error_code const& e);
// must be locked to access the data // must be locked to access the data
// in this struct // in this struct
@ -489,6 +489,11 @@ namespace libtorrent
// from the torrent with the most peers // from the torrent with the most peers
int m_disconnect_time_scaler; 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. // statistics gathered from all torrents.
stat m_stat; stat m_stat;
@ -498,7 +503,7 @@ namespace libtorrent
// NAT or not. // NAT or not.
bool m_incoming_connection; 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_auto_managed_torrents();
void recalculate_unchoke_slots(int congested_torrents void recalculate_unchoke_slots(int congested_torrents
, int uncongested_torrents); , int uncongested_torrents);
@ -528,7 +533,7 @@ namespace libtorrent
udp_socket m_dht_socket; 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); , udp::endpoint const& ep, char const* buf, int len);
#endif #endif

View File

@ -76,6 +76,8 @@ struct history_entry
history_entry(intrusive_ptr<PeerConnection> p, weak_ptr<Torrent> t history_entry(intrusive_ptr<PeerConnection> p, weak_ptr<Torrent> t
, int a, ptime exp) , int a, ptime exp)
: expires_at(exp), amount(a), peer(p), tor(t) {} : 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; ptime expires_at;
int amount; int amount;
intrusive_ptr<PeerConnection> peer; intrusive_ptr<PeerConnection> peer;
@ -111,6 +113,7 @@ struct bandwidth_manager
: m_ios(ios) : m_ios(ios)
, m_history_timer(m_ios) , m_history_timer(m_ios)
, m_limit(bandwidth_limit::inf) , m_limit(bandwidth_limit::inf)
, m_drain_quota(0)
, m_current_quota(0) , m_current_quota(0)
, m_channel(channel) , m_channel(channel)
, m_in_hand_out_bandwidth(false) , m_in_hand_out_bandwidth(false)
@ -123,6 +126,14 @@ struct bandwidth_manager
#endif #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) void throttle(int limit)
{ {
mutex_t::scoped_lock l(m_mutex); 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 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() for (typename queue_t::const_iterator i = m_queue.begin()
, end(m_queue.end()); i != end; ++i) , 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 bool is_in_history(PeerConnection const* peer, boost::mutex::scoped_lock& l) const
{ {
TORRENT_ASSERT(l.locked());
for (typename history_t::const_iterator i for (typename history_t::const_iterator i
= m_history.begin(), end(m_history.end()); i != end; ++i) = m_history.begin(), end(m_history.end()); i != end; ++i)
{ {
@ -258,12 +267,12 @@ private:
if (m_abort) return; if (m_abort) return;
asio::error_code ec; error_code ec;
m_history_timer.expires_at(e.expires_at, ec); m_history_timer.expires_at(e.expires_at, ec);
m_history_timer.async_wait(bind(&bandwidth_manager::on_history_expire, this, _1)); 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; if (e) return;
@ -290,6 +299,7 @@ private:
<< std::endl; << std::endl;
#endif #endif
intrusive_ptr<PeerConnection> c = e.peer; intrusive_ptr<PeerConnection> c = e.peer;
if (!c) continue;
shared_ptr<Torrent> t = e.tor.lock(); shared_ptr<Torrent> t = e.tor.lock();
l.unlock(); l.unlock();
if (!c->is_disconnecting()) c->expire_bandwidth(m_channel, e.amount); if (!c->is_disconnecting()) c->expire_bandwidth(m_channel, e.amount);
@ -300,7 +310,7 @@ private:
// now, wait for the next chunk to expire // now, wait for the next chunk to expire
if (!m_history.empty() && !m_abort) 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.expires_at(m_history.back().expires_at, ec);
m_history_timer.async_wait(bind(&bandwidth_manager::on_history_expire, this, _1)); 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) void hand_out_bandwidth(boost::mutex::scoped_lock& l)
{ {
TORRENT_ASSERT(l.locked());
// if we're already handing out bandwidth, just return back // if we're already handing out bandwidth, just return back
// to the loop further down on the callstack // to the loop further down on the callstack
if (m_in_hand_out_bandwidth) return; if (m_in_hand_out_bandwidth) return;
@ -332,6 +341,15 @@ private:
if (amount <= 0) return; 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<PeerConnection, Torrent>(
drain_amount, now + bw_window_size));
}
queue_t tmp; queue_t tmp;
while (!m_queue.empty() && amount > 0) while (!m_queue.empty() && amount > 0)
{ {
@ -436,6 +454,10 @@ private:
// the rate limit (bytes per second) // the rate limit (bytes per second)
int m_limit; 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 // the sum of all recently handed out bandwidth blocks
int m_current_quota; int m_current_quota;

View File

@ -51,7 +51,7 @@ namespace libtorrent
int common_bits(unsigned char const* b1 int common_bits(unsigned char const* b1
, unsigned char const* b2, int n); , 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<void(udp::endpoint const& from typedef boost::function<void(udp::endpoint const& from
, char* buffer, int size)> receive_handler_t; , char* buffer, int size)> receive_handler_t;
@ -59,11 +59,11 @@ namespace libtorrent
class TORRENT_EXPORT broadcast_socket class TORRENT_EXPORT broadcast_socket
{ {
public: 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); , receive_handler_t const& handler, bool loopback = true);
~broadcast_socket() { close(); } ~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(); void close();
private: private:
@ -77,12 +77,12 @@ namespace libtorrent
void close() void close()
{ {
if (!socket) return; if (!socket) return;
asio::error_code ec; error_code ec;
socket->close(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); , std::size_t bytes_transferred);
void open_unicast_socket(io_service& ios, address const& addr); void open_unicast_socket(io_service& ios, address const& addr);
void open_multicast_socket(io_service& ios, address const& addr void open_multicast_socket(io_service& ios, address const& addr

View File

@ -100,6 +100,7 @@ namespace libtorrent
bt_peer_connection( bt_peer_connection(
aux::session_impl& ses aux::session_impl& ses
, boost::shared_ptr<socket_type> s , boost::shared_ptr<socket_type> s
, tcp::endpoint const& remote
, policy::peer* peerinfo); , policy::peer* peerinfo);
void start(); void start();
@ -141,9 +142,9 @@ namespace libtorrent
// called from the main loop when this connection has any // called from the main loop when this connection has any
// work to do. // work to do.
void on_sent(asio::error_code const& error void on_sent(error_code const& error
, std::size_t bytes_transferred); , 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::size_t bytes_transferred);
virtual void get_specific_peer_info(peer_info& p) const; virtual void get_specific_peer_info(peer_info& p) const;
@ -363,6 +364,7 @@ private:
// the peer indicated that it supports the // the peer indicated that it supports the
// extension protocol // extension protocol
bool m_supports_extensions; bool m_supports_extensions;
char m_reserved_bits[20];
#endif #endif
bool m_supports_dht_port; bool m_supports_dht_port;
bool m_supports_fast; bool m_supports_fast;

View File

@ -34,12 +34,19 @@ POSSIBILITY OF SUCH DAMAGE.
#define TORRENT_CHAINED_BUFFER_HPP_INCLUDED #define TORRENT_CHAINED_BUFFER_HPP_INCLUDED
#include <boost/function.hpp> #include <boost/function.hpp>
#if BOOST_VERSION < 103500
#include <asio/buffer.hpp> #include <asio/buffer.hpp>
#else
#include <boost/asio/buffer.hpp>
#endif
#include <list> #include <list>
#include <cstring> #include <cstring>
namespace libtorrent namespace libtorrent
{ {
#if BOOST_VERSION >= 103500
namespace asio = boost::asio;
#endif
struct chained_buffer struct chained_buffer
{ {
chained_buffer(): m_bytes(0), m_capacity(0) {} chained_buffer(): m_bytes(0), m_capacity(0) {}

View File

@ -71,7 +71,7 @@ public:
private: private:
void try_connect(); void try_connect();
void on_timeout(asio::error_code const& e); void on_timeout(error_code const& e);
struct entry struct entry
{ {

View File

@ -47,7 +47,13 @@ namespace libtorrent
disk_buffer_holder(disk_io_thread& iothread, char* buf); disk_buffer_holder(disk_io_thread& iothread, char* buf);
~disk_buffer_holder(); ~disk_buffer_holder();
char* release(); 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: private:
disk_io_thread& m_iothread; disk_io_thread& m_iothread;
char* m_buf; char* m_buf;

View File

@ -149,7 +149,7 @@ namespace libtorrent
// of disk io jobs // of disk io jobs
struct disk_io_thread : boost::noncopyable 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(); ~disk_io_thread();
#ifdef TORRENT_STATS #ifdef TORRENT_STATS
@ -292,7 +292,7 @@ namespace libtorrent
size_type m_writes; size_type m_writes;
size_type m_blocks_written; size_type m_blocks_written;
asio::io_service& m_ios; io_service& m_ios;
// thread for performing blocking disk io operations // thread for performing blocking disk io operations
boost::thread m_disk_io_thread; boost::thread m_disk_io_thread;

View File

@ -167,6 +167,8 @@ namespace libtorrent
#endif #endif
entry* find_key(char const* key); entry* find_key(char const* key);
entry const* find_key(char const* key) const; 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; void print(std::ostream& os, int indent = 0) const;

View File

@ -43,7 +43,7 @@ namespace libtorrent
{ {
address interface_address; address interface_address;
address netmask; address netmask;
char name[32]; char name[64];
}; };
struct ip_route struct ip_route
@ -51,15 +51,15 @@ namespace libtorrent
address destination; address destination;
address netmask; address netmask;
address gateway; address gateway;
char name[32]; char name[64];
}; };
// returns a list of the configured IP interfaces // returns a list of the configured IP interfaces
// on the machine // on the machine
TORRENT_EXPORT std::vector<ip_interface> enum_net_interfaces(asio::io_service& ios TORRENT_EXPORT std::vector<ip_interface> enum_net_interfaces(io_service& ios
, asio::error_code& ec); , error_code& ec);
TORRENT_EXPORT std::vector<ip_route> enum_routes(asio::io_service& ios, asio::error_code& ec); TORRENT_EXPORT std::vector<ip_route> enum_routes(io_service& ios, error_code& ec);
// returns true if the specified address is on the same // returns true if the specified address is on the same
// local network as the specified interface // local network as the specified interface
@ -67,11 +67,11 @@ namespace libtorrent
// returns true if the specified address is on the same // returns true if the specified address is on the same
// local network as us // local network as us
TORRENT_EXPORT bool in_local_network(asio::io_service& ios, address const& addr TORRENT_EXPORT bool in_local_network(io_service& ios, address const& addr
, asio::error_code& ec); , error_code& ec);
TORRENT_EXPORT address get_default_gateway(asio::io_service& ios TORRENT_EXPORT address get_default_gateway(io_service& ios
, asio::error_code& ec); , error_code& ec);
} }
#endif #endif

View File

@ -51,6 +51,8 @@ namespace libtorrent
TORRENT_EXPORT boost::optional<std::string> url_has_argument( TORRENT_EXPORT boost::optional<std::string> url_has_argument(
std::string const& url, std::string argument); std::string const& url, std::string argument);
TORRENT_EXPORT std::string to_hex(std::string const& s);
} }
#endif // TORRENT_ESCAPE_STRING_HPP_INCLUDED #endif // TORRENT_ESCAPE_STRING_HPP_INCLUDED

View File

@ -99,7 +99,7 @@ namespace libtorrent
// means that the other end doesn't support this extension and will remove // means that the other end doesn't support this extension and will remove
// it from the list of plugins. // it from the list of plugins.
// this is not called for web seeds // 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 // called when the extension handshake from the other end is received
// if this returns false, it means that this extension isn't // if this returns false, it means that this extension isn't

View File

@ -39,6 +39,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/enable_shared_from_this.hpp> #include <boost/enable_shared_from_this.hpp>
#include <boost/noncopyable.hpp> #include <boost/noncopyable.hpp>
#include <vector> #include <vector>
#include <list>
#include <string> #include <string>
#include "libtorrent/socket.hpp" #include "libtorrent/socket.hpp"
@ -59,8 +60,8 @@ namespace libtorrent
struct http_connection; struct http_connection;
class connection_queue; class connection_queue;
typedef boost::function<void(asio::error_code const& typedef boost::function<void(error_code const&
, http_parser const&, char const* data, int size)> http_handler; , http_parser const&, char const* data, int size, http_connection&)> http_handler;
typedef boost::function<void(http_connection&)> http_connect_handler; typedef boost::function<void(http_connection&)> http_connect_handler;
@ -70,7 +71,7 @@ typedef boost::function<void(http_connection&)> http_connect_handler;
// will always be 0 // will always be 0
struct http_connection : boost::enable_shared_from_this<http_connection>, boost::noncopyable struct http_connection : boost::enable_shared_from_this<http_connection>, 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_handler const& handler, bool bottled = true
, http_connect_handler const& ch = http_connect_handler()) , http_connect_handler const& ch = http_connect_handler())
: m_sock(ios) : m_sock(ios)
@ -91,6 +92,7 @@ struct http_connection : boost::enable_shared_from_this<http_connection>, boost:
, m_cc(cc) , m_cc(cc)
, m_ssl(false) , m_ssl(false)
, m_priority(0) , m_priority(0)
, m_abort(false)
{ {
TORRENT_ASSERT(!m_handler.empty()); TORRENT_ASSERT(!m_handler.empty());
} }
@ -121,19 +123,19 @@ struct http_connection : boost::enable_shared_from_this<http_connection>, boost:
private: private:
void on_resolve(asio::error_code const& e void on_resolve(error_code const& e
, tcp::resolver::iterator i); , tcp::resolver::iterator i);
void queue_connect();
void connect(int ticket, tcp::endpoint target_address); void connect(int ticket, tcp::endpoint target_address);
void on_connect_timeout(); void on_connect_timeout();
void on_connect(asio::error_code const& e void on_connect(error_code const& e);
/* , tcp::resolver::iterator i*/); void on_write(error_code const& e);
void on_write(asio::error_code const& e); void on_read(error_code const& e, std::size_t bytes_transferred);
void on_read(asio::error_code const& e, std::size_t bytes_transferred);
static void on_timeout(boost::weak_ptr<http_connection> p static void on_timeout(boost::weak_ptr<http_connection> p
, asio::error_code const& e); , error_code const& e);
void on_assign_bandwidth(asio::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<char> m_recvbuffer; std::vector<char> m_recvbuffer;
#ifdef TORRENT_USE_OPENSSL #ifdef TORRENT_USE_OPENSSL
@ -158,6 +160,9 @@ private:
bool m_called; bool m_called;
std::string m_hostname; std::string m_hostname;
std::string m_port; std::string m_port;
std::string m_url;
std::list<tcp::endpoint> m_endpoints;
// the current download limit, in bytes per second // the current download limit, in bytes per second
// 0 is unlimited. // 0 is unlimited.
@ -195,6 +200,8 @@ private:
// the priority we have in the connection queue. // the priority we have in the connection queue.
// 0 is normal, 1 is high // 0 is normal, 1 is high
int m_priority; int m_priority;
bool m_abort;
}; };
} }

View File

@ -41,7 +41,7 @@ class http_stream : public proxy_base
{ {
public: public:
explicit http_stream(asio::io_service& io_service) explicit http_stream(io_service& io_service)
: proxy_base(io_service) : proxy_base(io_service)
, m_no_connect(false) , m_no_connect(false)
{} {}
@ -55,7 +55,7 @@ public:
m_password = password; m_password = password;
} }
typedef boost::function<void(asio::error_code const&)> handler_type; typedef boost::function<void(error_code const&)> handler_type;
template <class Handler> template <class Handler>
void async_connect(endpoint_type const& endpoint, Handler const& handler) void async_connect(endpoint_type const& endpoint, Handler const& handler)
@ -80,11 +80,11 @@ public:
private: 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<handler_type> h); , boost::shared_ptr<handler_type> h);
void connected(asio::error_code const& e, boost::shared_ptr<handler_type> h); void connected(error_code const& e, boost::shared_ptr<handler_type> h);
void handshake1(asio::error_code const& e, boost::shared_ptr<handler_type> h); void handshake1(error_code const& e, boost::shared_ptr<handler_type> h);
void handshake2(asio::error_code const& e, boost::shared_ptr<handler_type> h); void handshake2(error_code const& e, boost::shared_ptr<handler_type> h);
// send and receive buffer // send and receive buffer
std::vector<char> m_buffer; std::vector<char> m_buffer;

View File

@ -82,7 +82,7 @@ namespace libtorrent
boost::intrusive_ptr<http_tracker_connection> self() boost::intrusive_ptr<http_tracker_connection> self()
{ return boost::intrusive_ptr<http_tracker_connection>(this); } { return boost::intrusive_ptr<http_tracker_connection>(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); , char const* data, int size);
virtual void on_timeout() {} virtual void on_timeout() {}

View File

@ -34,14 +34,13 @@ POSSIBILITY OF SUCH DAMAGE.
#define TORRENT_INSTANTIATE_CONNECTION #define TORRENT_INSTANTIATE_CONNECTION
#include "libtorrent/socket_type.hpp" #include "libtorrent/socket_type.hpp"
#include <asio/io_service.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
namespace libtorrent namespace libtorrent
{ {
struct proxy_settings; struct proxy_settings;
bool instantiate_connection(asio::io_service& ios bool instantiate_connection(io_service& ios
, proxy_settings const& ps, socket_type& s); , proxy_settings const& ps, socket_type& s);
} }

View File

@ -68,7 +68,7 @@ public:
private: private:
void done(); void done();
void invoke(node_id const& id, asio::ip::udp::endpoint addr); void invoke(node_id const& id, udp::endpoint addr);
closest_nodes( closest_nodes(
node_id target node_id target

View File

@ -53,6 +53,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/session_settings.hpp" #include "libtorrent/session_settings.hpp"
#include "libtorrent/session_status.hpp" #include "libtorrent/session_status.hpp"
#include "libtorrent/udp_socket.hpp" #include "libtorrent/udp_socket.hpp"
#include "libtorrent/socket.hpp"
namespace libtorrent { namespace dht namespace libtorrent { namespace dht
{ {
@ -89,19 +90,20 @@ namespace libtorrent { namespace dht
// translate bittorrent kademlia message into the generic kademlia message // translate bittorrent kademlia message into the generic kademlia message
// used by the library // used by the library
void on_receive(udp::endpoint const& ep, char const* pkt, int size); void on_receive(udp::endpoint const& ep, char const* pkt, int size);
void on_unreachable(udp::endpoint const& ep);
private: private:
boost::intrusive_ptr<dht_tracker> self() boost::intrusive_ptr<dht_tracker> self()
{ return boost::intrusive_ptr<dht_tracker>(this); } { return boost::intrusive_ptr<dht_tracker>(this); }
void on_name_lookup(asio::error_code const& e void on_name_lookup(error_code const& e
, udp::resolver::iterator host); , 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); , udp::resolver::iterator host);
void connection_timeout(asio::error_code const& e); void connection_timeout(error_code const& e);
void refresh_timeout(asio::error_code const& e); void refresh_timeout(error_code const& e);
void tick(asio::error_code const& e); void tick(error_code const& e);
void on_bootstrap(); void on_bootstrap();
void send_packet(msg const& m); void send_packet(msg const& m);

View File

@ -48,8 +48,6 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent { namespace dht namespace libtorrent { namespace dht
{ {
using asio::ip::udp;
typedef std::vector<char> packet_t; typedef std::vector<char> packet_t;
class rpc_manager; class rpc_manager;

View File

@ -36,15 +36,17 @@ POSSIBILITY OF SUCH DAMAGE.
#include <string> #include <string>
#include <libtorrent/kademlia/node_id.hpp> #include <libtorrent/kademlia/node_id.hpp>
#include "libtorrent/entry.hpp" #include "libtorrent/entry.hpp"
#if BOOST_VERSION < 103500
#include <asio/ip/udp.hpp> #include <asio/ip/udp.hpp>
#else
#include <boost/asio/ip/udp.hpp>
#endif
namespace libtorrent { namespace libtorrent {
namespace dht { namespace dht {
typedef std::vector<char> packet_t; typedef std::vector<char> packet_t;
using asio::ip::udp;
namespace messages namespace messages
{ {
enum { ping = 0, find_node = 1, get_peers = 2, announce_peer = 3, error = 4 }; enum { ping = 0, find_node = 1, get_peers = 2, announce_peer = 3, error = 4 };

View File

@ -56,8 +56,6 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent { namespace dht namespace libtorrent { namespace dht
{ {
using asio::ip::udp;
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_DECLARE_LOG(node); TORRENT_DECLARE_LOG(node);
#endif #endif
@ -174,6 +172,7 @@ public:
void(std::vector<node_entry> const&)> f); void(std::vector<node_entry> const&)> f);
void add_router_node(udp::endpoint router); void add_router_node(udp::endpoint router);
void unreachable(udp::endpoint const& ep);
void incoming(msg const& m); void incoming(msg const& m);
void refresh(); void refresh();

View File

@ -41,20 +41,33 @@ namespace libtorrent { namespace dht
struct node_entry 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_) : id(id_)
, addr(addr_) , addr(addr_)
, fail_count(0) {} , fail_count(0)
node_entry(asio::ip::udp::endpoint addr_) {
#ifdef TORRENT_DHT_VERBOSE_LOGGING
first_seen = time_now();
#endif
}
node_entry(udp::endpoint addr_)
: id(0) : id(0)
, addr(addr_) , addr(addr_)
, fail_count(0) {} , fail_count(0)
{
#ifdef TORRENT_DHT_VERBOSE_LOGGING
first_seen = time_now();
#endif
}
node_id id; node_id id;
udp::endpoint addr; udp::endpoint addr;
// the number of times this node has failed to // the number of times this node has failed to
// respond in a row // respond in a row
int fail_count; int fail_count;
#ifdef TORRENT_DHT_VERBOSE_LOGGING
ptime first_seen;
#endif
}; };
} } // namespace libtorrent::dht } } // namespace libtorrent::dht

View File

@ -55,9 +55,10 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent { namespace dht 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<node_entry> bucket_t; typedef std::vector<node_entry> bucket_t;

View File

@ -56,7 +56,6 @@ namespace libtorrent { namespace dht
struct observer; struct observer;
using asio::ip::udp;
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_DECLARE_LOG(rpc); TORRENT_DECLARE_LOG(rpc);
#endif #endif
@ -82,6 +81,8 @@ public:
, routing_table& table, send_fun const& sf); , routing_table& table, send_fun const& sf);
~rpc_manager(); ~rpc_manager();
void unreachable(udp::endpoint const& ep);
// returns true if the node needs a refresh // returns true if the node needs a refresh
bool incoming(msg const&); bool incoming(msg const&);
time_duration tick(); time_duration tick();

View File

@ -179,6 +179,15 @@ namespace libtorrent
void clear(); 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() ~lazy_entry()
{ clear(); } { clear(); }
@ -186,6 +195,17 @@ namespace libtorrent
// this entry has its bencoded data // this entry has its bencoded data
std::pair<char const*, int> data_section() const; std::pair<char const*, int> 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: private:
entry_type_t m_type; entry_type_t m_type;

View File

@ -67,7 +67,7 @@ public:
private: 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 void on_announce(udp::endpoint const& from, char* buffer
, std::size_t bytes_transferred); , std::size_t bytes_transferred);
// void setup_receive(); // void setup_receive();

View File

@ -70,12 +70,12 @@ private:
void update_mapping(int i); void update_mapping(int i);
void send_map_request(int i); void send_map_request(int i);
void resend_request(int i, asio::error_code const& e); void resend_request(int i, error_code const& e);
void on_reply(asio::error_code const& e void on_reply(error_code const& e
, std::size_t bytes_transferred); , std::size_t bytes_transferred);
void try_next_mapping(int i); void try_next_mapping(int i);
void update_expiration_timer(); 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); void disable(char const* message);

View File

@ -121,6 +121,7 @@ namespace libtorrent
peer_connection( peer_connection(
aux::session_impl& ses aux::session_impl& ses
, boost::shared_ptr<socket_type> s , boost::shared_ptr<socket_type> s
, tcp::endpoint const& remote
, policy::peer* peerinfo); , policy::peer* peerinfo);
// this function is called after it has been constructed and properly // this function is called after it has been constructed and properly
@ -197,6 +198,9 @@ namespace libtorrent
bool is_seed() const; 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; bool has_timed_out() const;
// will send a keep-alive message to the peer // will send a keep-alive message to the peer
@ -230,6 +234,8 @@ namespace libtorrent
const stat& statistics() const { return m_statistics; } const stat& statistics() const { return m_statistics; }
void add_stat(size_type downloaded, size_type uploaded); void add_stat(size_type downloaded, size_type uploaded);
void calc_ip_overhead();
// is called once every second by the main loop // is called once every second by the main loop
void second_tick(float tick_interval); void second_tick(float tick_interval);
@ -240,15 +246,18 @@ namespace libtorrent
std::vector<int> const& allowed_fast(); std::vector<int> const& allowed_fast();
std::vector<int> const& suggested_pieces() const { return m_suggested_pieces; } std::vector<int> 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(); void timed_out();
// this will cause this peer_connection to be disconnected. // 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; } bool is_disconnecting() const { return m_disconnecting; }
// this is called when the connection attempt has succeeded // this is called when the connection attempt has succeeded
// and the peer_connection is supposed to set m_connecting // and the peer_connection is supposed to set m_connecting
// to false, and stop monitor writability // 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 // returns true if this connection is still waiting to
// finish the connection attempt // finish the connection attempt
@ -288,7 +297,6 @@ namespace libtorrent
bool ignore_bandwidth_limits() const bool ignore_bandwidth_limits() const
{ return m_ignore_bandwidth_limits; } { return m_ignore_bandwidth_limits; }
void set_failed() { m_failed = true; }
bool failed() const { return m_failed; } bool failed() const { return m_failed; }
int desired_queue_size() const { return m_desired_queue_size; } int desired_queue_size() const { return m_desired_queue_size; }
@ -449,15 +457,15 @@ namespace libtorrent
virtual void on_connected() = 0; virtual void on_connected() = 0;
virtual void on_tick() {} 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; , 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; , std::size_t bytes_transferred) = 0;
#ifndef TORRENT_DISABLE_ENCRYPTION #ifndef TORRENT_DISABLE_ENCRYPTION
buffer::interval wr_recv_buffer() 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); TORRENT_ASSERT(m_disk_recv_buffer_size == 0);
if (m_recv_buffer.empty()) return buffer::interval(0,0); if (m_recv_buffer.empty()) return buffer::interval(0,0);
return buffer::interval(&m_recv_buffer[0] return buffer::interval(&m_recv_buffer[0]
@ -501,9 +509,9 @@ namespace libtorrent
// called from the main loop when this connection has any // called from the main loop when this connection has any
// work to do. // 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); , 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); , std::size_t bytes_transferred);
// this is the limit on the number of outstanding requests // 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 void on_disk_write_complete(int ret, disk_io_job const& j
, peer_request r, boost::shared_ptr<torrent> t); , peer_request r, boost::shared_ptr<torrent> t);
// the timeout in seconds
int m_timeout;
// the time when we last got a part of a // the time when we last got a part of a
// piece packet from this peer // piece packet from this peer
ptime m_last_piece; ptime m_last_piece;
@ -559,28 +564,54 @@ namespace libtorrent
// the time when we unchoked this peer // the time when we unchoked this peer
ptime m_last_unchoke; ptime m_last_unchoke;
int m_packet_size; // timeouts
int m_recv_pos; 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; buffer m_recv_buffer;
// if this peer is receiving a piece, this // if this peer is receiving a piece, this
// points to a disk buffer that the data is // points to a disk buffer that the data is
// read into. This eliminates a memcopy from // read into. This eliminates a memcopy from
// the receive buffer into the disk buffer // the receive buffer into the disk buffer
int m_disk_recv_buffer_size; disk_buffer_holder m_disk_recv_buffer;
char* m_disk_recv_buffer;
chained_buffer m_send_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<socket_type> m_socket; boost::shared_ptr<socket_type> m_socket;
// this is the peer we're actually talking to // this is the peer we're actually talking to
// it may not necessarily be the peer we're // it may not necessarily be the peer we're
@ -593,51 +624,12 @@ namespace libtorrent
// until the info_hash is received. Then it's // until the info_hash is received. Then it's
// set to the torrent it belongs to. // set to the torrent it belongs to.
boost::weak_ptr<torrent> m_torrent; boost::weak_ptr<torrent> 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 // remote peer's id
peer_id m_peer_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 // the pieces the other end have
std::vector<bool> m_have_piece; std::vector<bool> 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 // the queue of requests we have got
// from this peer // from this peer
@ -651,25 +643,42 @@ namespace libtorrent
// from this peer // from this peer
std::deque<piece_block> m_download_queue; std::deque<piece_block> m_download_queue;
// the number of request we should queue up // the pieces we will send to the peer
// at the remote end. // if requested (regardless of choke state)
int m_desired_queue_size; std::set<int> m_accept_fast;
// the amount of data this peer has been given // the pieces the peer will send us if
// as free upload. This is distributed from // requested (regardless of choke state)
// peers from which we get free download std::vector<int> m_allowed_fast;
// 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;
// if this is true, this peer is assumed to handle all piece // pieces that has been suggested to be
// requests in fifo order. All skipped blocks are re-requested // downloaded from this peer
// immediately instead of having a looser requirement std::vector<int> m_suggested_pieces;
// where blocks can be sent out of order. The default is to
// allow non-fifo order.
bool m_assume_fifo;
// 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 // the number of invalid piece-requests
// we have got from this peer. If the request // we have got from this peer. If the request
// queue gets empty, and there have been // queue gets empty, and there have been
@ -679,49 +688,6 @@ namespace libtorrent
// by sending choke, unchoke. // by sending choke, unchoke.
int m_num_invalid_requests; 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 // this is the priority with which this peer gets
// download bandwidth quota assigned to it. // download bandwidth quota assigned to it.
int m_priority; int m_priority;
@ -753,60 +719,114 @@ namespace libtorrent
// approximate peer download rate // approximate peer download rate
int m_remote_dl_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<int> m_accept_fast;
// the pieces the peer will send us if
// requested (regardless of choke state)
std::vector<int> m_allowed_fast;
// pieces that has been suggested to be
// downloaded from this peer
std::vector<int> m_suggested_pieces;
// the number of bytes send to the disk-io // the number of bytes send to the disk-io
// thread that hasn't yet been completely written. // thread that hasn't yet been completely written.
int m_outstanding_writing_bytes; 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 // if this is true, the disconnection
// timestamp is not updated when the connection // timestamp is not updated when the connection
// is closed. This means the time until we can // is closed. This means the time until we can
// reconnect to this peer is shorter, and likely // reconnect to this peer is shorter, and likely
// immediate. // immediate.
bool m_fast_reconnect; bool m_fast_reconnect:1;
// the time when async_connect was called // is true if it was we that connected to the peer
ptime m_connect; // 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 // other side says that it's interested in downloading
// based on the time from when async_connect // from us.
// was called to when on_connection_complete bool m_peer_interested:1;
// was called. The rtt is specified in milliseconds
int m_rtt;
// the total payload download bytes // the other side has told us that it won't send anymore
// at the last unchoke cycle. This is used to // data to us for a while
// measure the number of bytes transferred during bool m_peer_choked:1;
// an unchoke cycle, to unchoke peers the more bytes
// they sent us
size_type m_downloaded_at_last_unchoke;
#ifndef TORRENT_DISABLE_GEO_IP // the peer has pieces we are interested in
std::string m_inet_as_name; bool m_interesting:1;
#endif
// max transfer rates seen on this peer // we have choked the upload to the peer
int m_download_rate_peak; bool m_choked:1;
int m_upload_rate_peak;
// 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 #ifndef NDEBUG
public: public:
bool m_in_constructor; bool m_in_constructor:1;
#endif #endif
}; };
} }

View File

@ -142,6 +142,9 @@ namespace libtorrent
iterator begin() { return m_number; } iterator begin() { return m_number; }
iterator end() { return m_number+number_size; } iterator end() { return m_number+number_size; }
std::string to_string() const
{ return std::string((char const*)&m_number[0], number_size); }
private: private:
unsigned char m_number[number_size]; unsigned char m_number[number_size];

View File

@ -248,7 +248,6 @@ namespace libtorrent
const_iterator end_peer() const { return m_peers.end(); } const_iterator end_peer() const { return m_peers.end(); }
bool connect_one_peer(); bool connect_one_peer();
bool disconnect_one_peer();
bool has_peer(policy::peer const* p) const; 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 bool compare_peer(policy::peer const& lhs, policy::peer const& rhs
, address const& external_ip) const; , address const& external_ip) const;
iterator find_disconnect_candidate();
iterator find_connect_candidate(); iterator find_connect_candidate();
bool is_connect_candidate(peer const& p, bool finished); bool is_connect_candidate(peer const& p, bool finished);

View File

@ -38,9 +38,13 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/function.hpp> #include <boost/function.hpp>
#if BOOST_VERSION < 103500
#include <asio/read.hpp> #include <asio/read.hpp>
#include <asio/write.hpp> #include <asio/write.hpp>
#else
#include <boost/asio/read.hpp>
#include <boost/asio/write.hpp>
#endif
namespace libtorrent { namespace libtorrent {
@ -52,7 +56,7 @@ public:
typedef stream_socket::endpoint_type endpoint_type; typedef stream_socket::endpoint_type endpoint_type;
typedef stream_socket::protocol_type protocol_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_sock(io_service)
, m_resolver(io_service) , m_resolver(io_service)
{} {}
@ -70,7 +74,7 @@ public:
} }
template <class Mutable_Buffers> template <class Mutable_Buffers>
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); return m_sock.read_some(buffers, ec);
} }
@ -90,7 +94,7 @@ public:
#endif #endif
template <class IO_Control_Command> template <class IO_Control_Command>
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); m_sock.io_control(ioc, ec);
} }
@ -110,7 +114,7 @@ public:
#endif #endif
template <class SettableSocketOption> template <class SettableSocketOption>
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); return m_sock.set_option(opt, ec);
} }
@ -122,7 +126,7 @@ public:
} }
#endif #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); m_sock.bind(endpoint, ec);
} }
@ -134,7 +138,7 @@ public:
} }
#endif #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); m_sock.open(p, ec);
} }
@ -148,7 +152,7 @@ public:
} }
#endif #endif
void close(asio::error_code& ec) void close(error_code& ec)
{ {
m_sock.close(ec); m_sock.close(ec);
m_resolver.cancel(); m_resolver.cancel();
@ -161,7 +165,7 @@ public:
} }
#endif #endif
endpoint_type remote_endpoint(asio::error_code& ec) const endpoint_type remote_endpoint(error_code& ec) const
{ {
return m_remote_endpoint; return m_remote_endpoint;
} }
@ -173,14 +177,14 @@ public:
} }
#endif #endif
endpoint_type local_endpoint(asio::error_code& ec) const endpoint_type local_endpoint(error_code& ec) const
{ {
return m_sock.local_endpoint(ec); 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() lowest_layer_type& lowest_layer()

View File

@ -129,7 +129,7 @@ namespace libtorrent
, resume_data(0) , resume_data(0)
, storage_mode(storage_mode_sparse) , storage_mode(storage_mode_sparse)
, paused(true) , paused(true)
, auto_managed(false) , auto_managed(true)
, duplicate_is_error(false) , duplicate_is_error(false)
, storage(sc) , storage(sc)
, userdata(0) , userdata(0)

View File

@ -102,11 +102,7 @@ namespace libtorrent
, min_reconnect_time(60) , min_reconnect_time(60)
, peer_connect_timeout(7) , peer_connect_timeout(7)
, ignore_limits_on_local_network(true) , ignore_limits_on_local_network(true)
#if !defined NDEBUG && !defined TORRENT_DISABLE_INVARIANT_CHECKS
, connection_speed(2)
#else
, connection_speed(20) , connection_speed(20)
#endif
, send_redundant_have(false) , send_redundant_have(false)
, lazy_bitfields(true) , lazy_bitfields(true)
, inactivity_timeout(600) , inactivity_timeout(600)
@ -134,6 +130,11 @@ namespace libtorrent
, share_ratio_limit(2.f) , share_ratio_limit(2.f)
, seed_time_ratio_limit(7.f) , seed_time_ratio_limit(7.f)
, seed_time_limit(24 * 60 * 60) // 24 hours , 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 // this is the user agent that will be sent to the tracker
@ -376,6 +377,31 @@ namespace libtorrent
float share_ratio_limit; float share_ratio_limit;
float seed_time_ratio_limit; float seed_time_ratio_limit;
int seed_time_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 #ifndef TORRENT_DISABLE_DHT

View File

@ -45,13 +45,25 @@ POSSIBILITY OF SUCH DAMAGE.
#define Protocol Protocol_ #define Protocol Protocol_
#endif #endif
#if BOOST_VERSION < 103500
#include <asio/ip/tcp.hpp> #include <asio/ip/tcp.hpp>
#include <asio/ip/udp.hpp> #include <asio/ip/udp.hpp>
#include <asio/io_service.hpp> #include <asio/io_service.hpp>
#include <asio/deadline_timer.hpp> #include <asio/deadline_timer.hpp>
#include <asio/write.hpp> #include <asio/write.hpp>
#include <asio/read.hpp>
#include <asio/time_traits.hpp> #include <asio/time_traits.hpp>
#include <asio/basic_deadline_timer.hpp> #include <asio/basic_deadline_timer.hpp>
#else
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/ip/udp.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/deadline_timer.hpp>
#include <boost/asio/write.hpp>
#include <boost/asio/read.hpp>
#include <boost/asio/time_traits.hpp>
#include <boost/asio/basic_deadline_timer.hpp>
#endif
#ifdef __OBJC__ #ifdef __OBJC__
#undef Protocol #undef Protocol
@ -67,24 +79,12 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent namespace libtorrent
{ {
/* #if BOOST_VERSION < 103500
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;
using asio::ip::tcp; using asio::ip::tcp;
using asio::ip::udp; using asio::ip::udp;
using asio::async_write;
using asio::async_read;
typedef asio::ip::tcp::socket stream_socket; typedef asio::ip::tcp::socket stream_socket;
typedef asio::ip::address address; typedef asio::ip::address address;
typedef asio::ip::address_v4 address_v4; typedef asio::ip::address_v4 address_v4;
@ -92,14 +92,32 @@ namespace libtorrent
typedef asio::ip::udp::socket datagram_socket; typedef asio::ip::udp::socket datagram_socket;
typedef asio::ip::tcp::acceptor socket_acceptor; typedef asio::ip::tcp::acceptor socket_acceptor;
typedef asio::io_service io_service; typedef asio::io_service io_service;
typedef asio::error_code error_code;
using asio::async_write; namespace asio = ::asio;
typedef asio::basic_deadline_timer<libtorrent::ptime> deadline_timer; typedef asio::basic_deadline_timer<libtorrent::ptime> 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<libtorrent::ptime> deadline_timer;
#endif
inline std::ostream& print_address(std::ostream& os, address const& addr) 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); std::string a = addr.to_string(ec);
if (ec) return os; if (ec) return os;
os << a; os << a;
@ -109,7 +127,7 @@ namespace libtorrent
inline std::ostream& print_endpoint(std::ostream& os, tcp::endpoint const& ep) inline std::ostream& print_endpoint(std::ostream& os, tcp::endpoint const& ep)
{ {
address const& addr = ep.address(); address const& addr = ep.address();
asio::error_code ec; error_code ec;
std::string a = addr.to_string(ec); std::string a = addr.to_string(ec);
if (ec) return os; if (ec) return os;
@ -132,7 +150,7 @@ namespace libtorrent
} }
else if (a.is_v6()) else if (a.is_v6())
{ {
asio::ip::address_v6::bytes_type bytes address_v6::bytes_type bytes
= a.to_v6().to_bytes(); = a.to_v6().to_bytes();
std::copy(bytes.begin(), bytes.end(), out); std::copy(bytes.begin(), bytes.end(), out);
} }
@ -142,18 +160,18 @@ namespace libtorrent
address read_v4_address(InIt& in) address read_v4_address(InIt& in)
{ {
unsigned long ip = read_uint32(in); unsigned long ip = read_uint32(in);
return asio::ip::address_v4(ip); return address_v4(ip);
} }
template<class InIt> template<class InIt>
address read_v6_address(InIt& in) 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; bytes_t bytes;
for (bytes_t::iterator i = bytes.begin() for (bytes_t::iterator i = bytes.begin()
, end(bytes.end()); i != end; ++i) , end(bytes.end()); i != end; ++i)
*i = read_uint8(in); *i = read_uint8(in);
return asio::ip::address_v6(bytes); return address_v6(bytes);
} }
template<class Endpoint, class OutIt> template<class Endpoint, class OutIt>

View File

@ -41,8 +41,8 @@ class socks4_stream : public proxy_base
{ {
public: public:
explicit socks4_stream(asio::io_service& io_service) explicit socks4_stream(io_service& io_service_)
: proxy_base(io_service) : proxy_base(io_service_)
{} {}
void set_username(std::string const& user) void set_username(std::string const& user)
@ -50,7 +50,7 @@ public:
m_user = user; m_user = user;
} }
typedef boost::function<void(asio::error_code const&)> handler_type; typedef boost::function<void(error_code const&)> handler_type;
template <class Handler> template <class Handler>
void async_connect(endpoint_type const& endpoint, Handler const& handler) void async_connect(endpoint_type const& endpoint, Handler const& handler)
@ -74,11 +74,11 @@ public:
private: 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<handler_type> h); , boost::shared_ptr<handler_type> h);
void connected(asio::error_code const& e, boost::shared_ptr<handler_type> h); void connected(error_code const& e, boost::shared_ptr<handler_type> h);
void handshake1(asio::error_code const& e, boost::shared_ptr<handler_type> h); void handshake1(error_code const& e, boost::shared_ptr<handler_type> h);
void handshake2(asio::error_code const& e, boost::shared_ptr<handler_type> h); void handshake2(error_code const& e, boost::shared_ptr<handler_type> h);
// send and receive buffer // send and receive buffer
std::vector<char> m_buffer; std::vector<char> m_buffer;

View File

@ -41,7 +41,7 @@ class socks5_stream : public proxy_base
{ {
public: public:
explicit socks5_stream(asio::io_service& io_service) explicit socks5_stream(io_service& io_service)
: proxy_base(io_service) : proxy_base(io_service)
{} {}
@ -52,7 +52,7 @@ public:
m_password = password; m_password = password;
} }
typedef boost::function<void(asio::error_code const&)> handler_type; typedef boost::function<void(error_code const&)> handler_type;
template <class Handler> template <class Handler>
void async_connect(endpoint_type const& endpoint, Handler const& handler) void async_connect(endpoint_type const& endpoint, Handler const& handler)
@ -79,17 +79,17 @@ public:
private: 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<handler_type> h); , boost::shared_ptr<handler_type> h);
void connected(asio::error_code const& e, boost::shared_ptr<handler_type> h); void connected(error_code const& e, boost::shared_ptr<handler_type> h);
void handshake1(asio::error_code const& e, boost::shared_ptr<handler_type> h); void handshake1(error_code const& e, boost::shared_ptr<handler_type> h);
void handshake2(asio::error_code const& e, boost::shared_ptr<handler_type> h); void handshake2(error_code const& e, boost::shared_ptr<handler_type> h);
void handshake3(asio::error_code const& e, boost::shared_ptr<handler_type> h); void handshake3(error_code const& e, boost::shared_ptr<handler_type> h);
void handshake4(asio::error_code const& e, boost::shared_ptr<handler_type> h); void handshake4(error_code const& e, boost::shared_ptr<handler_type> h);
void socks_connect(boost::shared_ptr<handler_type> h); void socks_connect(boost::shared_ptr<handler_type> h);
void connect1(asio::error_code const& e, boost::shared_ptr<handler_type> h); void connect1(error_code const& e, boost::shared_ptr<handler_type> h);
void connect2(asio::error_code const& e, boost::shared_ptr<handler_type> h); void connect2(error_code const& e, boost::shared_ptr<handler_type> h);
void connect3(asio::error_code const& e, boost::shared_ptr<handler_type> h); void connect3(error_code const& e, boost::shared_ptr<handler_type> h);
// send and receive buffer // send and receive buffer
std::vector<char> m_buffer; std::vector<char> m_buffer;

View File

@ -34,8 +34,11 @@ POSSIBILITY OF SUCH DAMAGE.
#define TORRENT_SSL_STREAM_HPP_INCLUDED #define TORRENT_SSL_STREAM_HPP_INCLUDED
#include "libtorrent/socket.hpp" #include "libtorrent/socket.hpp"
#if BOOST_VERSION < 103500
#include <asio/ssl.hpp> #include <asio/ssl.hpp>
#else
#include <boost/asio/ssl.hpp>
#endif
// openssl seems to believe it owns // openssl seems to believe it owns
// this name in every single scope // this name in every single scope
#undef set_key #undef set_key
@ -47,7 +50,7 @@ class ssl_stream
{ {
public: 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_context(io_service, asio::ssl::context::sslv23_client)
, m_sock(io_service, m_context) , m_sock(io_service, m_context)
{ {
@ -60,7 +63,7 @@ public:
typedef typename Stream::protocol_type protocol_type; typedef typename Stream::protocol_type protocol_type;
typedef typename asio::ssl::stream<Stream> sock_type; typedef typename asio::ssl::stream<Stream> sock_type;
typedef boost::function<void(asio::error_code const&)> handler_type; typedef boost::function<void(error_code const&)> handler_type;
template <class Handler> template <class Handler>
void async_connect(endpoint_type const& endpoint, Handler const& handler) void async_connect(endpoint_type const& endpoint, Handler const& handler)
@ -70,7 +73,7 @@ public:
// 2. perform SSL client handshake // 2. perform SSL client handshake
// to avoid unnecessary copying of the handler, // to avoid unnecessary copying of the handler,
// store it in a shaed_ptr // store it in a shared_ptr
boost::shared_ptr<handler_type> h(new handler_type(handler)); boost::shared_ptr<handler_type> h(new handler_type(handler));
m_sock.next_layer().async_connect(endpoint m_sock.next_layer().async_connect(endpoint
@ -84,7 +87,7 @@ public:
} }
template <class Mutable_Buffers> template <class Mutable_Buffers>
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); return m_sock.read_some(buffers, ec);
} }
@ -104,7 +107,7 @@ public:
#endif #endif
template <class IO_Control_Command> template <class IO_Control_Command>
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); m_sock.next_layer().io_control(ioc, ec);
} }
@ -122,7 +125,7 @@ public:
} }
#endif #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); m_sock.next_layer().bind(endpoint, ec);
} }
@ -134,7 +137,7 @@ public:
} }
#endif #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); m_sock.next_layer().open(p, ec);
} }
@ -151,7 +154,7 @@ public:
} }
#endif #endif
void close(asio::error_code& ec) void close(error_code& ec)
{ {
m_sock.next_layer().close(ec); m_sock.next_layer().close(ec);
} }
@ -163,7 +166,7 @@ public:
} }
#endif #endif
endpoint_type remote_endpoint(asio::error_code& ec) const endpoint_type remote_endpoint(error_code& ec) const
{ {
return const_cast<sock_type&>(m_sock).next_layer().remote_endpoint(ec); return const_cast<sock_type&>(m_sock).next_layer().remote_endpoint(ec);
} }
@ -175,14 +178,14 @@ public:
} }
#endif #endif
endpoint_type local_endpoint(asio::error_code& ec) const endpoint_type local_endpoint(error_code& ec) const
{ {
return const_cast<sock_type&>(m_sock).next_layer().local_endpoint(ec); return const_cast<sock_type&>(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() lowest_layer_type& lowest_layer()
@ -197,7 +200,7 @@ public:
private: private:
void connected(asio::error_code const& e, boost::shared_ptr<handler_type> h) void connected(error_code const& e, boost::shared_ptr<handler_type> h)
{ {
if (e) if (e)
{ {
@ -209,7 +212,7 @@ private:
, boost::bind(&ssl_stream::handshake, this, _1, h)); , boost::bind(&ssl_stream::handshake, this, _1, h));
} }
void handshake(asio::error_code const& e, boost::shared_ptr<handler_type> h) void handshake(error_code const& e, boost::shared_ptr<handler_type> h)
{ {
(*h)(e); (*h)(e);
} }

View File

@ -36,6 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <algorithm> #include <algorithm>
#include <vector> #include <vector>
#include <assert.h> #include <assert.h>
#include <cstring>
#include "libtorrent/size_type.hpp" #include "libtorrent/size_type.hpp"
#include "libtorrent/invariant_check.hpp" #include "libtorrent/invariant_check.hpp"
@ -44,88 +45,162 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent namespace libtorrent
{ {
class TORRENT_EXPORT stat_channel
class TORRENT_EXPORT stat
{ {
friend class invariant_access; friend class invariant_access;
public: public:
enum { history = 10 }; enum { history = 10 };
stat() stat_channel()
: m_downloaded_payload(0) : m_counter(0)
, m_uploaded_payload(0) , m_total_counter(0)
, m_downloaded_protocol(0) , m_rate_sum(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)
{ {
std::fill(m_download_rate_history, m_download_rate_history+history, 0.f); std::memset(m_rate_history, 0, sizeof(m_rate_history));
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);
} }
void operator+=(const stat& s) void operator+=(stat_channel const& s)
{ {
INVARIANT_CHECK; m_counter += s.m_counter;
m_total_counter += s.m_counter;
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;
} }
void received_bytes(int bytes_payload, int bytes_protocol) void add(int count)
{ {
INVARIANT_CHECK; TORRENT_ASSERT(count >= 0);
TORRENT_ASSERT(bytes_payload >= 0); m_counter += count;
TORRENT_ASSERT(bytes_protocol >= 0); m_total_counter += count;
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;
} }
// should be called once every second // should be called once every second
void second_tick(float tick_interval); 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; } void offset(size_type counter)
float download_rate() const { return m_mean_download_rate; } {
TORRENT_ASSERT(counter >= 0);
m_total_counter += counter;
}
float upload_payload_rate() const { return m_mean_upload_payload_rate; } size_type counter() const { return m_counter; }
float download_payload_rate() const { return m_mean_download_payload_rate; }
size_type total_payload_upload() const { return m_total_upload_payload; } private:
size_type total_payload_download() const { return m_total_download_payload; }
size_type total_protocol_upload() const { return m_total_upload_protocol; } #ifndef NDEBUG
size_type total_protocol_download() const { return m_total_download_protocol; } 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 // this is used to offset the statistics when a
// peer_connection is opened and have some previous // peer_connection is opened and have some previous
@ -134,66 +209,33 @@ namespace libtorrent
{ {
TORRENT_ASSERT(downloaded >= 0); TORRENT_ASSERT(downloaded >= 0);
TORRENT_ASSERT(uploaded >= 0); TORRENT_ASSERT(uploaded >= 0);
m_total_download_payload += downloaded; m_stat[download_payload].offset(downloaded);
m_total_upload_payload += uploaded; m_stat[upload_payload].offset(uploaded);
} }
size_type last_payload_downloaded() const { return m_downloaded_payload; } size_type last_payload_downloaded() const
size_type last_payload_uploaded() const { return m_uploaded_payload; } { return m_stat[download_payload].counter(); }
size_type last_payload_uploaded() const
{ return m_stat[upload_payload].counter(); }
private: private:
#ifndef NDEBUG // these are the channels we keep stats for
void check_invariant() const enum
{ {
TORRENT_ASSERT(m_mean_upload_rate >= 0); upload_payload,
TORRENT_ASSERT(m_mean_download_rate >= 0); upload_protocol,
TORRENT_ASSERT(m_mean_upload_payload_rate >= 0); upload_ip_protocol,
TORRENT_ASSERT(m_mean_download_payload_rate >= 0); download_payload,
TORRENT_ASSERT(m_total_upload_payload >= 0); download_protocol,
TORRENT_ASSERT(m_total_download_payload >= 0); download_ip_protocol,
TORRENT_ASSERT(m_total_upload_protocol >= 0); num_channels
TORRENT_ASSERT(m_total_download_protocol >= 0); };
}
#endif
// history of download/upload speeds a few seconds back stat_channel m_stat[num_channels];
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;
}; };
} }
#endif // TORRENT_STAT_HPP_INCLUDED #endif // TORRENT_STAT_HPP_INCLUDED

View File

@ -86,7 +86,11 @@ namespace libtorrent
#else #else
#if BOOST_VERSION < 103500
#include <asio/time_traits.hpp> #include <asio/time_traits.hpp>
#else
#include <boost/asio/time_traits.hpp>
#endif
#include <boost/cstdint.hpp> #include <boost/cstdint.hpp>
#include "libtorrent/assert.hpp" #include "libtorrent/assert.hpp"
@ -152,6 +156,9 @@ namespace libtorrent
} }
// asio time_traits // asio time_traits
#if BOOST_VERSION >= 103500
namespace boost {
#endif
namespace asio namespace asio
{ {
template<> template<>
@ -172,6 +179,9 @@ namespace asio
{ return boost::posix_time::microseconds(libtorrent::total_microseconds(d)); } { return boost::posix_time::microseconds(libtorrent::total_microseconds(d)); }
}; };
} }
#if BOOST_VERSION >= 103500
}
#endif
#if defined(__MACH__) #if defined(__MACH__)

View File

@ -151,8 +151,7 @@ namespace libtorrent
void files_checked(); void files_checked();
void start_checking(); void start_checking();
float seed_cycles(session_settings const& s) const; int seed_rank(session_settings const& s) const;
int seed_cycles_int(session_settings const& s) const { return int(seed_cycles(s)); }
storage_mode_t storage_mode() const { return m_storage_mode; } storage_mode_t storage_mode() const { return m_storage_mode; }
// this will flag the torrent as aborted. The main // this will flag the torrent as aborted. The main
@ -356,6 +355,7 @@ namespace libtorrent
void force_tracker_request(); void force_tracker_request();
void force_tracker_request(ptime); void force_tracker_request(ptime);
void scrape_tracker(); void scrape_tracker();
ptime const& last_scrape() const { return m_last_scrape; }
// sets the username and password that will be sent to // sets the username and password that will be sent to
// the tracker // the tracker
@ -453,6 +453,7 @@ namespace libtorrent
void announce_piece(int index); void announce_piece(int index);
void disconnect_all(); void disconnect_all();
int disconnect_peers(int num);
// this is called wheh the torrent has completed // this is called wheh the torrent has completed
// the download. It will post an event, disconnect // 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 // this is the asio callback that is called when a name
// lookup for a PEER is completed. // 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); , peer_id pid);
// this is the asio callback that is called when a name // this is the asio callback that is called when a name
// lookup for a WEB SEED is completed. // 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); , std::string url, tcp::endpoint proxy);
// this is the asio callback that is called when a name // this is the asio callback that is called when a name
// lookup for a proxy for a web seed is completed. // 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); , std::string url);
// this is called when the torrent has finished. i.e. // this is called when the torrent has finished. i.e.
@ -480,6 +481,11 @@ namespace libtorrent
// completed() is called immediately after it. // completed() is called immediately after it.
void finished(); 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<void(int)> const&); void async_verify_piece(int piece_index, boost::function<void(int)> const&);
// this is called from the peer_connection // this is called from the peer_connection
@ -570,7 +576,7 @@ namespace libtorrent
// to the checker thread for initial checking // to the checker thread for initial checking
// of the storage. // of the storage.
// a return value of false indicates an error // 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; } int sequence_number() const { return m_sequence_number; }
@ -587,40 +593,43 @@ namespace libtorrent
void try_next_tracker(); void try_next_tracker();
int prioritize_tracker(int tracker_index); 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<peer_connection> p) const; , boost::intrusive_ptr<peer_connection> p) const;
bool request_bandwidth_from_session(int channel) const; bool request_bandwidth_from_session(int channel) const;
void update_peer_interest(bool was_finished); 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<torrent_info> m_torrent_file; boost::intrusive_ptr<torrent_info> 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; tracker_request::event_t m_event;
void parse_response(const entry& e, std::vector<peer_entry>& peer_list); void parse_response(const entry& e, std::vector<peer_entry>& 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 // if this pointer is 0, the torrent is in
// a state where the metadata hasn't been // a state where the metadata hasn't been
// received yet. // received yet.
@ -649,18 +658,6 @@ namespace libtorrent
// the time of next tracker request // the time of next tracker request
ptime m_next_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 #ifndef NDEBUG
public: public:
#endif #endif
@ -681,28 +678,21 @@ namespace libtorrent
// resolving the address for // resolving the address for
std::set<std::string> m_resolving_web_seeds; std::set<std::string> m_resolving_web_seeds;
#ifndef TORRENT_DISABLE_EXTENSIONS
typedef std::list<boost::shared_ptr<torrent_plugin> > extension_list_t;
extension_list_t m_extensions;
#endif
// used to resolve the names of web seeds // used to resolve the names of web seeds
mutable tcp::resolver m_host_resolver; 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 // this announce timer is used both
// by Local service discovery and // by Local service discovery and
// by the DHT. // by the DHT.
deadline_timer m_announce_timer; deadline_timer m_announce_timer;
static void on_announce_disp(boost::weak_ptr<torrent> p static void on_announce_disp(boost::weak_ptr<torrent> p
, asio::error_code const& e); , error_code const& e);
// this is called once per announce interval // this is called once per announce interval
void on_announce(); void on_announce();
@ -737,41 +727,9 @@ namespace libtorrent
std::vector<announce_entry> m_trackers; std::vector<announce_entry> m_trackers;
// this is an index into 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 // the bitmask that says which pieces we have
std::vector<bool> m_have_pieces; std::vector<bool> 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 // the number of bytes that has been
// downloaded that failed the hash-test // downloaded that failed the hash-test
size_type m_total_failed_bytes; size_type m_total_failed_bytes;
@ -791,25 +749,9 @@ namespace libtorrent
// the state of this torrent (queued, checking, downloading) // the state of this torrent (queued, checking, downloading)
torrent_status::state_t m_state; torrent_status::state_t m_state;
float m_progress;
entry m_resume_data; 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 // if the torrent is started without metadata, it may
// still be given a name until the metadata is received // still be given a name until the metadata is received
// once the metadata is received this field will no // once the metadata is received this field will no
@ -820,6 +762,18 @@ namespace libtorrent
storage_constructor_type m_storage_constructor; 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 // the maximum number of uploads for this torrent
int m_max_uploads; int m_max_uploads;
@ -829,14 +783,18 @@ namespace libtorrent
// the maximum number of connections for this torrent // the maximum number of connections for this torrent
int m_max_connections; int m_max_connections;
#ifndef NDEBUG // the size of a request block
bool m_files_checked; // each piece is divided into these
#endif // blocks when requested
int m_block_size;
#ifndef TORRENT_DISABLE_EXTENSIONS
typedef std::list<boost::shared_ptr<torrent_plugin> > extension_list_t; // -----------------------------
extension_list_t m_extensions; // DATA FROM TRACKER RESPONSE
#endif
// the scrape data from the tracker response, this
// is optional and may be -1.
int m_complete;
int m_incomplete;
#ifndef NDEBUG #ifndef NDEBUG
// this is the amount downloaded when this torrent // this is the amount downloaded when this torrent
@ -858,24 +816,84 @@ namespace libtorrent
// torrent object, these points are called connect_points. // torrent object, these points are called connect_points.
int m_deficit_counter; 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 // the sequence number for this torrent, this is a
// monotonically increasing number for each added torrent // 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 // the index to the last tracker that worked
// does not count when the torrent is stopped or paused boost::int8_t m_last_working_tracker;
time_duration m_active_time;
// total time we've been available as a seed on this torrent // the tracker that is currently (or was last)
// does not count when the torrent is stopped or paused // tried
time_duration m_seeding_time; boost::int8_t m_currently_trying_tracker;
// all time totals of uploaded and downloaded payload // the number of connection attempts that has
// stored in resume data // failed in a row, this is currently used to
size_type m_total_uploaded; // determine the timeout until next try.
size_type m_total_downloaded; 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 inline ptime torrent::next_announce() const

View File

@ -118,7 +118,8 @@ namespace libtorrent
, all_time_download(0) , all_time_download(0)
, active_time(0) , active_time(0)
, seeding_time(0) , seeding_time(0)
, seed_cycles(0.f) , seed_rank(0)
, last_scrape(0)
{} {}
enum state_t enum state_t
@ -257,7 +258,12 @@ namespace libtorrent
int active_time; int active_time;
int seeding_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 struct TORRENT_EXPORT block_info

View File

@ -45,12 +45,14 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/optional.hpp> #include <boost/optional.hpp>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <boost/shared_array.hpp>
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
#endif #endif
#include "libtorrent/entry.hpp" #include "libtorrent/entry.hpp"
#include "libtorrent/lazy_entry.hpp"
#include "libtorrent/socket.hpp" #include "libtorrent/socket.hpp"
#include "libtorrent/peer_id.hpp" #include "libtorrent/peer_id.hpp"
#include "libtorrent/size_type.hpp" #include "libtorrent/size_type.hpp"
@ -110,18 +112,12 @@ namespace libtorrent
torrent_info(); torrent_info();
torrent_info(sha1_hash const& info_hash); 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(); ~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_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<file_entry> const& map); bool remap_files(std::vector<file_entry> const& map);
@ -131,10 +127,9 @@ namespace libtorrent
, bool storage = false) const; , bool storage = false) const;
std::vector<std::string> const& url_seeds() const std::vector<std::string> const& url_seeds() const
{ { return m_url_seeds; }
TORRENT_ASSERT(!m_half_metadata); void add_url_seed(std::string const& url)
return m_url_seeds; { m_url_seeds.push_back(url); }
}
typedef std::vector<file_entry>::const_iterator file_iterator; typedef std::vector<file_entry>::const_iterator file_iterator;
typedef std::vector<file_entry>::const_reverse_iterator reverse_file_iterator; typedef std::vector<file_entry>::const_reverse_iterator reverse_file_iterator;
@ -176,12 +171,12 @@ namespace libtorrent
{ {
TORRENT_ASSERT(m_piece_length > 0); TORRENT_ASSERT(m_piece_length > 0);
if (!storage || m_remapped_files.empty()) if (!storage || m_remapped_files.empty())
return (int)m_files.size(); return int(m_files.size());
else 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()) if (!storage || m_remapped_files.empty())
{ {
@ -195,7 +190,7 @@ namespace libtorrent
} }
} }
const std::vector<announce_entry>& trackers() const { return m_urls; } std::vector<announce_entry> const& trackers() const { return m_urls; }
size_type total_size() const { TORRENT_ASSERT(m_piece_length > 0); return m_total_size; } 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; } 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; } const std::string& name() const { TORRENT_ASSERT(m_piece_length > 0); return m_name; }
// ------- start deprecation ------- // ------- 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; void print(std::ostream& os) const TORRENT_DEPRECATED;
// ------- end deprecation ------- // ------- end deprecation -------
bool is_valid() const { return m_piece_length > 0; } bool is_valid() const { return m_piece_length > 0; }
bool priv() const { return m_private; } bool priv() const { return m_private; }
void set_priv(bool v) { m_private = v; }
void convert_file_names();
int piece_size(int index) const; 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 >= 0);
TORRENT_ASSERT(index < (int)m_piece_hash.size()); TORRENT_ASSERT(index < m_num_pieces);
TORRENT_ASSERT(!m_half_metadata); TORRENT_ASSERT(m_piece_hashes);
return m_piece_hash[index]; 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<pt::ptime> creation_date() const; boost::optional<pt::ptime> creation_date() const;
@ -237,27 +237,30 @@ namespace libtorrent
typedef std::vector<std::pair<std::string, int> > nodes_t; typedef std::vector<std::pair<std::string, int> > nodes_t;
nodes_t const& nodes() const nodes_t const& nodes() const
{ { return m_nodes; }
TORRENT_ASSERT(!m_half_metadata); void add_node(std::pair<std::string, int> const& node)
return m_nodes; { m_nodes.push_back(node); }
}
void add_node(std::pair<std::string, int> const& node); bool parse_info_section(lazy_entry const& e, std::string& error);
bool parse_info_section(entry const& e, std::string& error); lazy_entry const* info(char const* key) const
{
entry const* extra(char const* key) const if (m_info_dict.type() == lazy_entry::none_t)
{ return m_extra_info.find_key(key); } lazy_bdecode(m_info_section.get(), m_info_section.get()
+ m_info_section_size, m_info_dict);
// frees parts of the metadata that isn't return m_info_dict.dict_find(key);
// used by seeds }
void seed_free();
void swap(torrent_info& ti); void swap(torrent_info& ti);
boost::shared_array<char> metadata() const
{ return m_info_section; }
int metadata_size() const { return m_info_section_size; }
private: 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 // the urls to the trackers
std::vector<announce_entry> m_urls; std::vector<announce_entry> m_urls;
@ -269,9 +272,6 @@ namespace libtorrent
// in an uninitialized state // in an uninitialized state
int m_piece_length; int m_piece_length;
// the sha-1 hashes of each piece
std::vector<sha1_hash> m_piece_hash;
// the list of files that this torrent consists of // the list of files that this torrent consists of
std::vector<file_entry> m_files; std::vector<file_entry> m_files;
@ -293,7 +293,7 @@ namespace libtorrent
// the hash that identifies this torrent // the hash that identifies this torrent
// is mutable because it's calculated // is mutable because it's calculated
// lazily // lazily
mutable sha1_hash m_info_hash; sha1_hash m_info_hash;
std::string m_name; std::string m_name;
@ -321,18 +321,19 @@ namespace libtorrent
// be announced on the dht // be announced on the dht
bool m_private; bool m_private;
// contains any non-parsed entries from the info-section // this is a copy of the info section from the torrent.
// these are kept in order to be able to accurately // it use maintained in this flat format in order to
// reproduce the info-section when sending the metadata // make it available through the metadata extension
// to peers. boost::shared_array<char> m_info_section;
entry m_extra_info; int m_info_section_size;
#ifndef NDEBUG // this is a pointer into the m_info_section buffer
public: // pointing to the first byte of the first sha-1 hash
// this is set to true when seed_free() is called char const* m_piece_hashes;
bool m_half_metadata;
private: // the info section parsed. points into m_info_section
#endif // parsed lazily
mutable lazy_entry m_info_dict;
}; };
} }

View File

@ -74,9 +74,6 @@ namespace libtorrent
// returns -1 if gzip header is invalid or the header size in bytes // 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 int gzip_header(const char* buf, int size);
TORRENT_EXPORT boost::tuple<std::string, std::string, std::string, int, std::string>
parse_url_components(std::string url);
struct TORRENT_EXPORT tracker_request struct TORRENT_EXPORT tracker_request
{ {
tracker_request() tracker_request()
@ -160,7 +157,7 @@ namespace libtorrent
private: private:
void timeout_callback(asio::error_code const&); void timeout_callback(error_code const&);
boost::intrusive_ptr<timeout_handler> self() boost::intrusive_ptr<timeout_handler> self()
{ return boost::intrusive_ptr<timeout_handler>(this); } { return boost::intrusive_ptr<timeout_handler>(this); }

View File

@ -46,16 +46,16 @@ namespace libtorrent
class udp_socket class udp_socket
{ {
public: public:
typedef boost::function<void(asio::error_code const& ec typedef boost::function<void(error_code const& ec
, udp::endpoint const&, char const* buf, int size)> callback_t; , udp::endpoint const&, char const* buf, int size)> 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(); } 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 send(udp::endpoint const& ep, char const* p, int len, error_code& ec);
void bind(udp::endpoint const& ep, asio::error_code& ec); void bind(udp::endpoint const& ep, error_code& ec);
void bind(int port); void bind(int port);
void close(); void close();
int local_port() const { return m_bind_port; } int local_port() const { return m_bind_port; }
@ -67,21 +67,21 @@ namespace libtorrent
callback_t m_callback; callback_t m_callback;
void on_read(udp::socket* sock, asio::error_code const& e, std::size_t bytes_transferred); void on_read(udp::socket* sock, error_code const& e, std::size_t bytes_transferred);
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);
void on_timeout(); void on_timeout();
void on_connect(int ticket); void on_connect(int ticket);
void on_connected(asio::error_code const& ec); void on_connected(error_code const& ec);
void handshake1(asio::error_code const& e); void handshake1(error_code const& e);
void handshake2(asio::error_code const& e); void handshake2(error_code const& e);
void handshake3(asio::error_code const& e); void handshake3(error_code const& e);
void handshake4(asio::error_code const& e); void handshake4(error_code const& e);
void socks_forward_udp(); void socks_forward_udp();
void connect1(asio::error_code const& e); void connect1(error_code const& e);
void connect2(asio::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 wrap(udp::endpoint const& ep, char const* p, int len, error_code& ec);
void unwrap(asio::error_code const& e, char const* buf, int size); void unwrap(error_code const& e, char const* buf, int size);
udp::socket m_ipv4_sock; udp::socket m_ipv4_sock;
udp::socket m_ipv6_sock; udp::socket m_ipv6_sock;

View File

@ -89,10 +89,10 @@ namespace libtorrent
boost::intrusive_ptr<udp_tracker_connection> self() boost::intrusive_ptr<udp_tracker_connection> self()
{ return boost::intrusive_ptr<udp_tracker_connection>(this); } { return boost::intrusive_ptr<udp_tracker_connection>(this); }
void name_lookup(asio::error_code const& error, udp::resolver::iterator i); void name_lookup(error_code const& error, udp::resolver::iterator i);
void timeout(asio::error_code const& error); 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); , char const* buf, int size);
void on_connect_response(char const* buf, int size); void on_connect_response(char const* buf, int size);
void on_announce_response(char const* buf, int size); void on_announce_response(char const* buf, int size);

View File

@ -93,7 +93,7 @@ private:
enum { default_lease_time = 3600 }; 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 void on_reply(udp::endpoint const& from, char* buffer
, std::size_t bytes_transferred); , std::size_t bytes_transferred);
@ -102,15 +102,16 @@ private:
void update_map(rootdevice& d, int i); void update_map(rootdevice& d, int i);
void on_upnp_xml(asio::error_code const& e void on_upnp_xml(error_code const& e
, libtorrent::http_parser const& p, rootdevice& d);
void on_upnp_map_response(asio::error_code const& e
, libtorrent::http_parser const& p, rootdevice& d , libtorrent::http_parser const& p, rootdevice& d
, int mapping); , http_connection& c);
void on_upnp_unmap_response(asio::error_code const& e void on_upnp_map_response(error_code const& e
, libtorrent::http_parser const& p, rootdevice& d , libtorrent::http_parser const& p, rootdevice& d
, int mapping); , int mapping, http_connection& c);
void on_expire(asio::error_code const& e); 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 disable(char const* msg);
void return_error(int mapping, int code); void return_error(int mapping, int code);
@ -237,7 +238,7 @@ private:
// current retry count // current retry count
int m_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 // the udp socket used to send and receive
// multicast messages on the network // multicast messages on the network
@ -252,7 +253,7 @@ private:
bool m_disabled; bool m_disabled;
bool m_closing; bool m_closing;
bool m_ignore_outside_network; bool m_ignore_non_routers;
connection_queue& m_cc; connection_queue& m_cc;

View File

@ -21,7 +21,11 @@
# include <boost/type_traits/add_pointer.hpp> # include <boost/type_traits/add_pointer.hpp>
# include <boost/noncopyable.hpp> # include <boost/noncopyable.hpp>
#if BOOST_VERSION < 103500
#include <asio/io_service.hpp> #include <asio/io_service.hpp>
#else
#include <boost/asio/io_service.hpp>
#endif
# define NETWORK_VARIANT_STREAM_LIMIT 5 # define NETWORK_VARIANT_STREAM_LIMIT 5
@ -48,7 +52,7 @@ namespace aux
template<class IO_Control_Command> template<class IO_Control_Command>
struct io_control_visitor_ec: boost::static_visitor<> 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_) {} : ioc(ioc), ec(ec_) {}
template <class T> template <class T>
@ -61,7 +65,7 @@ namespace aux
{} {}
IO_Control_Command& ioc; IO_Control_Command& ioc;
asio::error_code& ec; error_code& ec;
}; };
template<class IO_Control_Command> template<class IO_Control_Command>
@ -112,7 +116,7 @@ namespace aux
struct bind_visitor_ec struct bind_visitor_ec
: boost::static_visitor<> : boost::static_visitor<>
{ {
bind_visitor_ec(EndpointType const& ep, asio::error_code& ec_) bind_visitor_ec(EndpointType const& ep, error_code& ec_)
: endpoint(ep) : endpoint(ep)
, ec(ec_) , ec(ec_)
{} {}
@ -124,7 +128,7 @@ namespace aux
void operator()(boost::blank) const {} void operator()(boost::blank) const {}
EndpointType const& endpoint; EndpointType const& endpoint;
asio::error_code& ec; error_code& ec;
}; };
template <class EndpointType> template <class EndpointType>
@ -150,7 +154,7 @@ namespace aux
struct open_visitor_ec struct open_visitor_ec
: boost::static_visitor<> : boost::static_visitor<>
{ {
open_visitor_ec(Protocol const& p, asio::error_code& ec_) open_visitor_ec(Protocol const& p, error_code& ec_)
: proto(p) : proto(p)
, ec(ec_) , ec(ec_)
{} {}
@ -162,7 +166,7 @@ namespace aux
void operator()(boost::blank) const {} void operator()(boost::blank) const {}
Protocol const& proto; Protocol const& proto;
asio::error_code& ec; error_code& ec;
}; };
template <class Protocol> template <class Protocol>
@ -201,7 +205,7 @@ namespace aux
struct close_visitor_ec struct close_visitor_ec
: boost::static_visitor<> : boost::static_visitor<>
{ {
close_visitor_ec(asio::error_code& ec_) close_visitor_ec(error_code& ec_)
: ec(ec_) : ec(ec_)
{} {}
@ -211,7 +215,7 @@ namespace aux
void operator()(boost::blank) const {} void operator()(boost::blank) const {}
asio::error_code& ec; error_code& ec;
}; };
struct close_visitor struct close_visitor
@ -230,18 +234,18 @@ namespace aux
struct remote_endpoint_visitor_ec struct remote_endpoint_visitor_ec
: boost::static_visitor<EndpointType> : boost::static_visitor<EndpointType>
{ {
remote_endpoint_visitor_ec(asio::error_code& ec) remote_endpoint_visitor_ec(error_code& ec_)
: error_code(ec) : ec(ec_)
{} {}
template <class T> template <class T>
EndpointType operator()(T const* p) const EndpointType operator()(T const* p) const
{ return p->remote_endpoint(error_code); } { return p->remote_endpoint(ec); }
EndpointType operator()(boost::blank) const EndpointType operator()(boost::blank) const
{ return EndpointType(); } { return EndpointType(); }
asio::error_code& error_code; error_code& ec;
}; };
template <class EndpointType> template <class EndpointType>
@ -270,29 +274,29 @@ namespace aux
void operator()(T* p) const void operator()(T* p) const
{ p->set_option(opt_); } { p->set_option(opt_); }
void operator()(boost::blank) const {} void operator()(boost::blank) const {}
SettableSocketOption const& opt_; SettableSocketOption const& opt_;
}; };
template <class SettableSocketOption> template <class SettableSocketOption>
struct set_option_visitor_ec struct set_option_visitor_ec
: boost::static_visitor<asio::error_code> : boost::static_visitor<error_code>
{ {
set_option_visitor_ec(SettableSocketOption const& opt, asio::error_code& ec) set_option_visitor_ec(SettableSocketOption const& opt, error_code& ec)
: opt_(opt) : opt_(opt)
, ec_(ec) , ec_(ec)
{} {}
template <class T> template <class T>
asio::error_code operator()(T* p) const error_code operator()(T* p) const
{ return p->set_option(opt_, ec_); } { return p->set_option(opt_, ec_); }
asio::error_code operator()(boost::blank) const error_code operator()(boost::blank) const
{ return ec_; } { return ec_; }
SettableSocketOption const& opt_; SettableSocketOption const& opt_;
asio::error_code& ec_; error_code& ec_;
}; };
// -------------- local_endpoint ----------- // -------------- local_endpoint -----------
@ -301,14 +305,14 @@ namespace aux
struct local_endpoint_visitor_ec struct local_endpoint_visitor_ec
: boost::static_visitor<EndpointType> : boost::static_visitor<EndpointType>
{ {
local_endpoint_visitor_ec(asio::error_code& ec) local_endpoint_visitor_ec(error_code& ec_)
: error_code(ec) : ec(ec_)
{} {}
template <class T> template <class T>
EndpointType operator()(T const* p) const EndpointType operator()(T const* p) const
{ {
return p->local_endpoint(error_code); return p->local_endpoint(ec);
} }
EndpointType operator()(boost::blank) const EndpointType operator()(boost::blank) const
@ -316,7 +320,7 @@ namespace aux
return EndpointType(); return EndpointType();
} }
asio::error_code& error_code; error_code& ec;
}; };
template <class EndpointType> template <class EndpointType>
@ -372,7 +376,7 @@ namespace aux
std::size_t operator()(T* p) const std::size_t operator()(T* p) const
{ return p->read_some(buffers); } { return p->read_some(buffers); }
std::size_t operator()(boost::blank) const std::size_t operator()(boost::blank) const
{ return 0; } { return 0; }
Mutable_Buffers const& buffers; Mutable_Buffers const& buffers;
@ -382,7 +386,7 @@ namespace aux
struct read_some_visitor_ec struct read_some_visitor_ec
: boost::static_visitor<std::size_t> : boost::static_visitor<std::size_t>
{ {
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) : buffers(buffers)
, ec(ec_) , ec(ec_)
{} {}
@ -391,11 +395,11 @@ namespace aux
std::size_t operator()(T* p) const std::size_t operator()(T* p) const
{ return p->read_some(buffers, ec); } { return p->read_some(buffers, ec); }
std::size_t operator()(boost::blank) const std::size_t operator()(boost::blank) const
{ return 0; } { return 0; }
Mutable_Buffers const& buffers; Mutable_Buffers const& buffers;
asio::error_code& ec; error_code& ec;
}; };
// -------------- async_write_some ----------- // -------------- async_write_some -----------
@ -427,7 +431,7 @@ namespace aux
struct in_avail_visitor_ec struct in_avail_visitor_ec
: boost::static_visitor<std::size_t> : boost::static_visitor<std::size_t>
{ {
in_avail_visitor_ec(asio::error_code& ec_) in_avail_visitor_ec(error_code& ec_)
: ec(ec_) : ec(ec_)
{} {}
@ -442,7 +446,7 @@ namespace aux
return 0; return 0;
} }
asio::error_code& ec; error_code& ec;
}; };
struct in_avail_visitor struct in_avail_visitor
@ -524,11 +528,11 @@ public:
typedef typename S0::endpoint_type endpoint_type; typedef typename S0::endpoint_type endpoint_type;
typedef typename S0::protocol_type protocol_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()) {} : m_io_service(ios), m_variant(boost::blank()) {}
template <class S> template <class S>
void instantiate(asio::io_service& ios) void instantiate(io_service& ios)
{ {
TORRENT_ASSERT(&ios == &m_io_service); TORRENT_ASSERT(&ios == &m_io_service);
std::auto_ptr<S> owned(new S(ios)); std::auto_ptr<S> owned(new S(ios));
@ -540,7 +544,7 @@ public:
template <class S> template <class S>
S& get() S& get()
{ {
return *boost::get<S*>(m_variant); return *boost::get<S*>(m_variant);
} }
bool instantiated() const bool instantiated() const
@ -554,7 +558,7 @@ public:
} }
template <class Mutable_Buffers> template <class Mutable_Buffers>
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()); TORRENT_ASSERT(instantiated());
return boost::apply_visitor( return boost::apply_visitor(
@ -612,7 +616,7 @@ public:
} }
template <class IO_Control_Command> template <class IO_Control_Command>
void io_control(IO_Control_Command& ioc, asio::error_code& ec) void io_control(IO_Control_Command& ioc, error_code& ec)
{ {
TORRENT_ASSERT(instantiated()); TORRENT_ASSERT(instantiated());
boost::apply_visitor( boost::apply_visitor(
@ -627,7 +631,7 @@ public:
boost::apply_visitor(aux::bind_visitor<endpoint_type>(endpoint), m_variant); boost::apply_visitor(aux::bind_visitor<endpoint_type>(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()); TORRENT_ASSERT(instantiated());
boost::apply_visitor( boost::apply_visitor(
@ -641,7 +645,7 @@ public:
boost::apply_visitor(aux::open_visitor<protocol_type>(p), m_variant); boost::apply_visitor(aux::open_visitor<protocol_type>(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()); TORRENT_ASSERT(instantiated());
boost::apply_visitor( boost::apply_visitor(
@ -660,7 +664,7 @@ public:
boost::apply_visitor(aux::close_visitor(), m_variant); boost::apply_visitor(aux::close_visitor(), m_variant);
} }
void close(asio::error_code& ec) void close(error_code& ec)
{ {
if (!instantiated()) return; if (!instantiated()) return;
boost::apply_visitor( boost::apply_visitor(
@ -674,7 +678,7 @@ public:
return boost::apply_visitor(aux::in_avail_visitor(), m_variant); 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()); TORRENT_ASSERT(instantiated());
return boost::apply_visitor( return boost::apply_visitor(
@ -688,7 +692,7 @@ public:
return boost::apply_visitor(aux::remote_endpoint_visitor<endpoint_type>(), m_variant); return boost::apply_visitor(aux::remote_endpoint_visitor<endpoint_type>(), m_variant);
} }
endpoint_type remote_endpoint(asio::error_code& ec) const endpoint_type remote_endpoint(error_code& ec) const
{ {
TORRENT_ASSERT(instantiated()); TORRENT_ASSERT(instantiated());
return boost::apply_visitor( return boost::apply_visitor(
@ -705,20 +709,20 @@ public:
} }
template <class SettableSocketOption> template <class SettableSocketOption>
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()); TORRENT_ASSERT(instantiated());
return boost::apply_visitor(aux::set_option_visitor_ec<SettableSocketOption>(opt, ec) return boost::apply_visitor(aux::set_option_visitor_ec<SettableSocketOption>(opt, ec)
, m_variant); , m_variant);
} }
endpoint_type local_endpoint() const endpoint_type local_endpoint() const
{ {
TORRENT_ASSERT(instantiated()); TORRENT_ASSERT(instantiated());
return boost::apply_visitor(aux::local_endpoint_visitor<endpoint_type>(), m_variant); return boost::apply_visitor(aux::local_endpoint_visitor<endpoint_type>(), m_variant);
} }
endpoint_type local_endpoint(asio::error_code& ec) const endpoint_type local_endpoint(error_code& ec) const
{ {
TORRENT_ASSERT(instantiated()); TORRENT_ASSERT(instantiated());
return boost::apply_visitor( return boost::apply_visitor(
@ -726,7 +730,7 @@ public:
); );
} }
asio::io_service& get_io_service() io_service& get_io_service()
{ {
return m_io_service; return m_io_service;
} }
@ -740,7 +744,7 @@ public:
} }
private: private:
asio::io_service& m_io_service; io_service& m_io_service;
variant_type m_variant; variant_type m_variant;
}; };

View File

@ -102,9 +102,9 @@ namespace libtorrent
// called from the main loop when this connection has any // called from the main loop when this connection has any
// work to do. // work to do.
void on_sent(asio::error_code const& error void on_sent(error_code const& error
, std::size_t bytes_transferred); , 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::size_t bytes_transferred);
std::string const& url() const { return m_url; } std::string const& url() const { return m_url; }

View File

@ -18,7 +18,7 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/ */
#include "GeoIP.h" #include "libtorrent/GeoIP.h"
#ifndef WIN32 #ifndef WIN32
#include <netdb.h> #include <netdb.h>

View File

@ -30,8 +30,14 @@ POSSIBILITY OF SUCH DAMAGE.
*/ */
#if BOOST_VERSION < 103500
#include <asio/ip/host_name.hpp> #include <asio/ip/host_name.hpp>
#include <asio/ip/multicast.hpp> #include <asio/ip/multicast.hpp>
#else
#include <boost/asio/ip/host_name.hpp>
#include <boost/asio/ip/multicast.hpp>
#endif
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include "libtorrent/socket.hpp" #include "libtorrent/socket.hpp"
@ -75,10 +81,10 @@ namespace libtorrent
return addr.to_v6() == address_v6::any(); 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 // make a best guess of the interface we're using and its IP
asio::error_code ec; error_code ec;
std::vector<ip_interface> const& interfaces = enum_net_interfaces(ios, ec); std::vector<ip_interface> const& interfaces = enum_net_interfaces(ios, ec);
address ret = address_v4::any(); address ret = address_v4::any();
for (std::vector<ip_interface>::const_iterator i = interfaces.begin() for (std::vector<ip_interface>::const_iterator i = interfaces.begin()
@ -137,7 +143,7 @@ namespace libtorrent
- common_bits(b1.c_array(), b2.c_array(), b1.size()); - 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 , udp::endpoint const& multicast_endpoint
, receive_handler_t const& handler , receive_handler_t const& handler
, bool loopback) , bool loopback)
@ -148,7 +154,7 @@ namespace libtorrent
using namespace asio::ip::multicast; using namespace asio::ip::multicast;
asio::error_code ec; error_code ec;
std::vector<ip_interface> interfaces = enum_net_interfaces(ios, ec); std::vector<ip_interface> interfaces = enum_net_interfaces(ios, ec);
if (multicast_endpoint.address().is_v4()) if (multicast_endpoint.address().is_v4())
@ -179,7 +185,7 @@ namespace libtorrent
{ {
using namespace asio::ip::multicast; using namespace asio::ip::multicast;
asio::error_code ec; error_code ec;
boost::shared_ptr<datagram_socket> s(new datagram_socket(ios)); boost::shared_ptr<datagram_socket> s(new datagram_socket(ios));
if (addr.is_v4()) if (addr.is_v4())
s->open(udp::v4(), ec); s->open(udp::v4(), ec);
@ -205,7 +211,7 @@ namespace libtorrent
void broadcast_socket::open_unicast_socket(io_service& ios, address const& addr) void broadcast_socket::open_unicast_socket(io_service& ios, address const& addr)
{ {
using namespace asio::ip::multicast; using namespace asio::ip::multicast;
asio::error_code ec; error_code ec;
boost::shared_ptr<datagram_socket> s(new datagram_socket(ios)); boost::shared_ptr<datagram_socket> s(new datagram_socket(ios));
s->open(addr.is_v4() ? udp::v4() : udp::v6(), ec); s->open(addr.is_v4() ? udp::v4() : udp::v6(), ec);
if (ec) return; if (ec) return;
@ -220,13 +226,13 @@ namespace libtorrent
, se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2)); , 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<socket_entry>::iterator i = m_unicast_sockets.begin() for (std::list<socket_entry>::iterator i = m_unicast_sockets.begin()
, end(m_unicast_sockets.end()); i != end; ++i) , end(m_unicast_sockets.end()); i != end; ++i)
{ {
if (!i->socket) continue; if (!i->socket) continue;
asio::error_code e; error_code e;
i->socket->send_to(asio::buffer(buffer, size), m_multicast_endpoint, 0, e); i->socket->send_to(asio::buffer(buffer, size), m_multicast_endpoint, 0, e);
#ifndef NDEBUG #ifndef NDEBUG
// std::cerr << " sending on " << i->socket->local_endpoint().address().to_string() << " to: " << m_multicast_endpoint << std::endl; // 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) , std::size_t bytes_transferred)
{ {
if (ec || bytes_transferred == 0 || !m_on_receive) return; if (ec || bytes_transferred == 0 || !m_on_receive) return;

View File

@ -125,8 +125,9 @@ namespace libtorrent
bt_peer_connection::bt_peer_connection( bt_peer_connection::bt_peer_connection(
session_impl& ses session_impl& ses
, boost::shared_ptr<socket_type> s , boost::shared_ptr<socket_type> s
, tcp::endpoint const& remote
, policy::peer* peerinfo) , policy::peer* peerinfo)
: peer_connection(ses, s, peerinfo) : peer_connection(ses, s, remote, peerinfo)
, m_state(read_protocol_identifier) , m_state(read_protocol_identifier)
#ifndef TORRENT_DISABLE_EXTENSIONS #ifndef TORRENT_DISABLE_EXTENSIONS
, m_supports_extensions(false) , m_supports_extensions(false)
@ -800,13 +801,14 @@ namespace libtorrent
TORRENT_ASSERT(received > 0); TORRENT_ASSERT(received > 0);
if (packet_size() != 1) if (packet_size() != 1)
{ {
disconnect("'choke' message size != 1"); disconnect("'choke' message size != 1", 2);
return; return;
} }
m_statistics.received_bytes(0, received); m_statistics.received_bytes(0, received);
if (!packet_finished()) return; if (!packet_finished()) return;
incoming_choke(); incoming_choke();
if (is_disconnecting()) return;
if (!m_supports_fast) if (!m_supports_fast)
{ {
boost::shared_ptr<torrent> t = associated_torrent().lock(); boost::shared_ptr<torrent> t = associated_torrent().lock();
@ -834,7 +836,7 @@ namespace libtorrent
TORRENT_ASSERT(received > 0); TORRENT_ASSERT(received > 0);
if (packet_size() != 1) if (packet_size() != 1)
{ {
disconnect("'unchoke' message size != 1"); disconnect("'unchoke' message size != 1", 2);
return; return;
} }
m_statistics.received_bytes(0, received); m_statistics.received_bytes(0, received);
@ -854,7 +856,7 @@ namespace libtorrent
TORRENT_ASSERT(received > 0); TORRENT_ASSERT(received > 0);
if (packet_size() != 1) if (packet_size() != 1)
{ {
disconnect("'interested' message size != 1"); disconnect("'interested' message size != 1", 2);
return; return;
} }
m_statistics.received_bytes(0, received); m_statistics.received_bytes(0, received);
@ -874,7 +876,7 @@ namespace libtorrent
TORRENT_ASSERT(received > 0); TORRENT_ASSERT(received > 0);
if (packet_size() != 1) if (packet_size() != 1)
{ {
disconnect("'not interested' message size != 1"); disconnect("'not interested' message size != 1", 2);
return; return;
} }
m_statistics.received_bytes(0, received); m_statistics.received_bytes(0, received);
@ -894,7 +896,7 @@ namespace libtorrent
TORRENT_ASSERT(received > 0); TORRENT_ASSERT(received > 0);
if (packet_size() != 5) if (packet_size() != 5)
{ {
disconnect("'have' message size != 5"); disconnect("'have' message size != 5", 2);
return; return;
} }
m_statistics.received_bytes(0, received); m_statistics.received_bytes(0, received);
@ -926,7 +928,7 @@ namespace libtorrent
if (t->valid_metadata() if (t->valid_metadata()
&& packet_size() - 1 != ((int)get_bitfield().size() + 7) / 8) && packet_size() - 1 != ((int)get_bitfield().size() + 7) / 8)
{ {
disconnect("bitfield with invalid size"); disconnect("bitfield with invalid size", 2);
return; return;
} }
@ -963,7 +965,7 @@ namespace libtorrent
TORRENT_ASSERT(received > 0); TORRENT_ASSERT(received > 0);
if (packet_size() != 13) if (packet_size() != 13)
{ {
disconnect("'request' message size != 13"); disconnect("'request' message size != 13", 2);
return; return;
} }
m_statistics.received_bytes(0, received); m_statistics.received_bytes(0, received);
@ -1021,6 +1023,7 @@ namespace libtorrent
} }
incoming_piece_fragment(); incoming_piece_fragment();
if (is_disconnecting()) return;
if (!packet_finished()) return; if (!packet_finished()) return;
const char* ptr = recv_buffer.begin + 1; const char* ptr = recv_buffer.begin + 1;
@ -1044,7 +1047,7 @@ namespace libtorrent
TORRENT_ASSERT(received > 0); TORRENT_ASSERT(received > 0);
if (packet_size() != 13) if (packet_size() != 13)
{ {
disconnect("'cancel' message size != 13"); disconnect("'cancel' message size != 13", 2);
return; return;
} }
m_statistics.received_bytes(0, received); m_statistics.received_bytes(0, received);
@ -1071,14 +1074,14 @@ namespace libtorrent
if (!m_supports_dht_port) 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; return;
} }
TORRENT_ASSERT(received > 0); TORRENT_ASSERT(received > 0);
if (packet_size() != 3) if (packet_size() != 3)
{ {
disconnect("'dht_port' message size != 3"); disconnect("'dht_port' message size != 3", 2);
return; return;
} }
m_statistics.received_bytes(0, received); m_statistics.received_bytes(0, received);
@ -1098,7 +1101,7 @@ namespace libtorrent
if (!m_supports_fast) if (!m_supports_fast)
{ {
disconnect("got 'suggest_piece' without FAST excension support"); disconnect("got 'suggest_piece' without FAST excension support", 2);
return; return;
} }
@ -1118,7 +1121,7 @@ namespace libtorrent
if (!m_supports_fast) if (!m_supports_fast)
{ {
disconnect("got 'have_all' without FAST extension support"); disconnect("got 'have_all' without FAST extension support", 2);
return; return;
} }
m_statistics.received_bytes(0, received); m_statistics.received_bytes(0, received);
@ -1131,7 +1134,7 @@ namespace libtorrent
if (!m_supports_fast) if (!m_supports_fast)
{ {
disconnect("got 'have_none' without FAST extension support"); disconnect("got 'have_none' without FAST extension support", 2);
return; return;
} }
m_statistics.received_bytes(0, received); m_statistics.received_bytes(0, received);
@ -1144,7 +1147,7 @@ namespace libtorrent
if (!m_supports_fast) if (!m_supports_fast)
{ {
disconnect("got 'reject_request' without FAST extension support"); disconnect("got 'reject_request' without FAST extension support", 2);
return; return;
} }
@ -1168,7 +1171,7 @@ namespace libtorrent
if (!m_supports_fast) if (!m_supports_fast)
{ {
disconnect("got 'allowed_fast' without FAST extension support"); disconnect("got 'allowed_fast' without FAST extension support", 2);
return; return;
} }
@ -1193,13 +1196,13 @@ namespace libtorrent
m_statistics.received_bytes(0, received); m_statistics.received_bytes(0, received);
if (packet_size() < 2) if (packet_size() < 2)
{ {
disconnect("'extended' message smaller than 2 bytes"); disconnect("'extended' message smaller than 2 bytes", 2);
return; return;
} }
if (associated_torrent().expired()) if (associated_torrent().expired())
{ {
disconnect("'extended' message sent before proper handshake"); disconnect("'extended' message sent before proper handshake", 2);
return; return;
} }
@ -1229,7 +1232,7 @@ namespace libtorrent
std::stringstream msg; std::stringstream msg;
msg << "unknown extended message id: " << extended_id; msg << "unknown extended message id: " << extended_id;
disconnect(msg.str().c_str()); disconnect(msg.str().c_str(), 2);
return; return;
} }
@ -1298,6 +1301,12 @@ namespace libtorrent
m_max_out_request_queue = 1; 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")) if (entry* myip = root.find_key("yourip"))
{ {
// TODO: don't trust this blindly // 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) bool bt_peer_connection::dispatch_message(int received)
@ -1350,7 +1364,7 @@ namespace libtorrent
std::stringstream msg; std::stringstream msg;
msg << "unkown message id: " << packet_type << " size: " << packet_size(); msg << "unkown message id: " << packet_type << " size: " << packet_size();
disconnect(msg.str().c_str()); disconnect(msg.str().c_str(), 2);
return packet_finished(); return packet_finished();
} }
@ -1553,6 +1567,9 @@ namespace libtorrent
detail::write_address(remote().address(), out); detail::write_address(remote().address(), out);
handshake["yourip"] = remote_address; handshake["yourip"] = remote_address;
handshake["reqq"] = m_ses.settings().max_allowed_in_request_queue; handshake["reqq"] = m_ses.settings().max_allowed_in_request_queue;
boost::shared_ptr<torrent> t = associated_torrent().lock();
TORRENT_ASSERT(t);
if (t->is_finished()) handshake["upload_only"] = 1;
tcp::endpoint ep = m_ses.get_ipv6_interface(); tcp::endpoint ep = m_ses.get_ipv6_interface();
if (ep != tcp::endpoint()) if (ep != tcp::endpoint())
@ -1671,7 +1688,7 @@ namespace libtorrent
detail::write_int32(r.start, ptr); detail::write_int32(r.start, ptr);
send_buffer(msg, sizeof(msg)); 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::bind(&session_impl::free_disk_buffer
, boost::ref(m_ses), _1)); , boost::ref(m_ses), _1));
buffer.release(); buffer.release();
@ -1707,7 +1724,7 @@ namespace libtorrent
// -------------------------- // --------------------------
// throws exception when the client should be disconnected // 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) , std::size_t bytes_transferred)
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
@ -1802,7 +1819,7 @@ namespace libtorrent
if (recv_buffer.left() < 20) if (recv_buffer.left() < 20)
{ {
if (packet_finished()) if (packet_finished())
disconnect("sync hash not found"); disconnect("sync hash not found", 2);
return; return;
} }
@ -1828,7 +1845,7 @@ namespace libtorrent
m_sync_bytes_read += bytes_processed; m_sync_bytes_read += bytes_processed;
if (m_sync_bytes_read >= 512) if (m_sync_bytes_read >= 512)
{ {
disconnect("sync hash not found within 532 bytes"); disconnect("sync hash not found within 532 bytes", 2);
return; return;
} }
@ -1913,7 +1930,7 @@ namespace libtorrent
if (!m_RC4_handler.get()) 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; return;
} }
@ -1925,7 +1942,7 @@ namespace libtorrent
const char sh_vc[] = {0,0,0,0, 0,0,0,0}; const char sh_vc[] = {0,0,0,0, 0,0,0,0};
if (!std::equal(sh_vc, sh_vc+8, recv_buffer.begin + 20)) if (!std::equal(sh_vc, sh_vc+8, recv_buffer.begin + 20))
{ {
disconnect("unable to verify constant"); disconnect("unable to verify constant", 2);
return; return;
} }
@ -1947,7 +1964,7 @@ namespace libtorrent
if (recv_buffer.left() < 8) if (recv_buffer.left() < 8)
{ {
if (packet_finished()) if (packet_finished())
disconnect("sync verification constant not found"); disconnect("sync verification constant not found", 2);
return; return;
} }
@ -1972,7 +1989,7 @@ namespace libtorrent
m_sync_bytes_read += bytes_processed; m_sync_bytes_read += bytes_processed;
if (m_sync_bytes_read >= 512) 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; return;
} }
@ -2035,7 +2052,7 @@ namespace libtorrent
case pe_settings::plaintext: case pe_settings::plaintext:
if (!(crypto_field & 0x01)) if (!(crypto_field & 0x01))
{ {
disconnect("plaintext not provided"); disconnect("plaintext not provided", 1);
return; return;
} }
crypto_select = 0x01; crypto_select = 0x01;
@ -2043,7 +2060,7 @@ namespace libtorrent
case pe_settings::rc4: case pe_settings::rc4:
if (!(crypto_field & 0x02)) if (!(crypto_field & 0x02))
{ {
disconnect("rc4 not provided"); disconnect("rc4 not provided", 1);
return; return;
} }
crypto_select = 0x02; crypto_select = 0x02;
@ -2065,7 +2082,7 @@ namespace libtorrent
} }
if (!crypto_select) if (!crypto_select)
{ {
disconnect("rc4/plaintext not provided"); disconnect("rc4/plaintext not provided", 1);
return; return;
} }
break; break;
@ -2083,7 +2100,7 @@ namespace libtorrent
{ {
if (allowed_enc_level == pe_settings::plaintext) 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; return;
} }
m_rc4_encrypted = true; m_rc4_encrypted = true;
@ -2092,14 +2109,14 @@ namespace libtorrent
{ {
if (allowed_enc_level == pe_settings::rc4) 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; return;
} }
m_rc4_encrypted = false; m_rc4_encrypted = false;
} }
else else
{ {
disconnect("unsupported crypto method selected by peer"); disconnect("unsupported crypto method selected by peer", 2);
return; return;
} }
} }
@ -2107,7 +2124,7 @@ namespace libtorrent
int len_pad = detail::read_int16(recv_buffer.begin); int len_pad = detail::read_int16(recv_buffer.begin);
if (len_pad < 0 || len_pad > 512) if (len_pad < 0 || len_pad > 512)
{ {
disconnect("invalid pad length"); disconnect("invalid pad length", 2);
return; return;
} }
@ -2145,7 +2162,7 @@ namespace libtorrent
if (len_ia < 0) if (len_ia < 0)
{ {
disconnect("invalid len_ia in handshake"); disconnect("invalid len_ia in handshake", 2);
return; return;
} }
@ -2277,7 +2294,7 @@ namespace libtorrent
TORRENT_ASSERT((!is_local() && m_encrypted) || is_local()); TORRENT_ASSERT((!is_local() && m_encrypted) || is_local());
#endif // #ifndef TORRENT_DISABLE_ENCRYPTION #endif // #ifndef TORRENT_DISABLE_ENCRYPTION
disconnect("incorrect protocol identifier"); disconnect("incorrect protocol identifier", 2);
return; return;
} }
@ -2329,6 +2346,7 @@ namespace libtorrent
#endif #endif
#ifndef DISABLE_EXTENSIONS #ifndef DISABLE_EXTENSIONS
std::memcpy(m_reserved_bits, recv_buffer.begin, 20);
if ((recv_buffer[5] & 0x10)) if ((recv_buffer[5] & 0x10))
m_supports_extensions = true; m_supports_extensions = true;
#endif #endif
@ -2360,7 +2378,7 @@ namespace libtorrent
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << " received invalid info_hash\n"; (*m_logger) << " received invalid info_hash\n";
#endif #endif
disconnect("invalid info-hash in handshake"); disconnect("invalid info-hash in handshake", 2);
return; return;
} }
@ -2449,8 +2467,7 @@ namespace libtorrent
if (pid == m_ses.get_peer_id()) if (pid == m_ses.get_peer_id())
{ {
set_failed(); disconnect("closing connection to ourself", 1);
disconnect("closing connection to ourself");
return; return;
} }
@ -2466,8 +2483,7 @@ namespace libtorrent
// since it most likely is ourself then // since it most likely is ourself then
if (pid == m_ses.get_peer_id()) if (pid == m_ses.get_peer_id())
{ {
set_failed(); disconnect("closing connection to ourself", 1);
disconnect("closing connection to ourself");
return; return;
} }
@ -2475,7 +2491,7 @@ namespace libtorrent
for (extension_list_t::iterator i = m_extensions.begin() for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end;) , end(m_extensions.end()); i != end;)
{ {
if (!(*i)->on_handshake()) if (!(*i)->on_handshake(m_reserved_bits))
{ {
i = m_extensions.erase(i); i = m_extensions.erase(i);
} }
@ -2484,6 +2500,7 @@ namespace libtorrent
++i; ++i;
} }
} }
if (is_disconnecting()) return;
if (m_supports_extensions) write_extensions(); if (m_supports_extensions) write_extensions();
#endif #endif
@ -2542,13 +2559,14 @@ namespace libtorrent
// packet too large // packet too large
std::stringstream msg; std::stringstream msg;
msg << "packet > 1 MB (" << (unsigned int)packet_size << " bytes)"; msg << "packet > 1 MB (" << (unsigned int)packet_size << " bytes)";
disconnect(msg.str().c_str()); disconnect(msg.str().c_str(), 2);
return; return;
} }
if (packet_size == 0) if (packet_size == 0)
{ {
incoming_keepalive(); incoming_keepalive();
if (is_disconnecting()) return;
// keepalive message // keepalive message
m_state = read_packet_size; m_state = read_packet_size;
cut_receive_buffer(4, 4); cut_receive_buffer(4, 4);
@ -2586,8 +2604,7 @@ namespace libtorrent
// SEND DATA // SEND DATA
// -------------------------- // --------------------------
// throws exception when the client should be disconnected void bt_peer_connection::on_sent(error_code const& error
void bt_peer_connection::on_sent(asio::error_code const& error
, std::size_t bytes_transferred) , std::size_t bytes_transferred)
{ {
INVARIANT_CHECK; INVARIANT_CHECK;

View File

@ -34,6 +34,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include "libtorrent/invariant_check.hpp" #include "libtorrent/invariant_check.hpp"
#include "libtorrent/connection_queue.hpp" #include "libtorrent/connection_queue.hpp"
#include "libtorrent/socket.hpp"
namespace libtorrent namespace libtorrent
{ {
@ -112,7 +113,7 @@ namespace libtorrent
void connection_queue::close() void connection_queue::close()
{ {
asio::error_code ec; error_code ec;
m_timer.cancel(ec); m_timer.cancel(ec);
} }
@ -153,7 +154,7 @@ namespace libtorrent
if (m_queue.empty()) if (m_queue.empty())
{ {
asio::error_code ec; error_code ec;
m_timer.cancel(ec); m_timer.cancel(ec);
return; return;
} }
@ -166,7 +167,7 @@ namespace libtorrent
ptime expire = time_now() + i->timeout; ptime expire = time_now() + i->timeout;
if (m_num_connecting == 0) if (m_num_connecting == 0)
{ {
asio::error_code ec; error_code ec;
m_timer.expires_at(expire, ec); m_timer.expires_at(expire, ec);
m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1)); m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
} }
@ -206,7 +207,7 @@ namespace libtorrent
}; };
#endif #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); mutex_t::scoped_lock l(m_mutex);
@ -251,7 +252,7 @@ namespace libtorrent
if (next_expire < max_time()) if (next_expire < max_time())
{ {
asio::error_code ec; error_code ec;
m_timer.expires_at(next_expire, ec); m_timer.expires_at(next_expire, ec);
m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1)); m_timer.async_wait(boost::bind(&connection_queue::on_timeout, this, _1));
} }

View File

@ -49,6 +49,12 @@ namespace libtorrent
TORRENT_ASSERT(buf == 0 || m_iothread.is_disk_buffer(buf)); 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* disk_buffer_holder::release()
{ {
char* ret = m_buf; char* ret = m_buf;

View File

@ -182,7 +182,6 @@ namespace libtorrent
disk_io_thread::cache_t& cache disk_io_thread::cache_t& cache
, disk_io_job const& j, mutex_t::scoped_lock& l) , disk_io_job const& j, mutex_t::scoped_lock& l)
{ {
TORRENT_ASSERT(l.locked());
for (cache_t::iterator i = cache.begin() for (cache_t::iterator i = cache.begin()
, end(cache.end()); i != end; ++i) , end(cache.end()); i != end; ++i)
{ {
@ -196,7 +195,6 @@ namespace libtorrent
{ {
ptime now = time_now(); ptime now = time_now();
TORRENT_ASSERT(l.locked());
INVARIANT_CHECK; INVARIANT_CHECK;
for (;;) for (;;)
{ {
@ -213,7 +211,6 @@ namespace libtorrent
void disk_io_thread::free_piece(cached_piece_entry& p, mutex_t::scoped_lock& l) 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 piece_size = p.storage->info()->piece_size(p.piece);
int blocks_in_piece = (piece_size + m_block_size - 1) / m_block_size; 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) void disk_io_thread::flush_oldest_piece(mutex_t::scoped_lock& l)
{ {
TORRENT_ASSERT(l.locked());
INVARIANT_CHECK; INVARIANT_CHECK;
// first look if there are any read cache entries that can // first look if there are any read cache entries that can
// be cleared // be cleared
@ -275,7 +271,6 @@ namespace libtorrent
void disk_io_thread::flush(disk_io_thread::cache_t::iterator e void disk_io_thread::flush(disk_io_thread::cache_t::iterator e
, mutex_t::scoped_lock& l) , mutex_t::scoped_lock& l)
{ {
TORRENT_ASSERT(l.locked());
INVARIANT_CHECK; INVARIANT_CHECK;
cached_piece_entry& p = *e; cached_piece_entry& p = *e;
int piece_size = p.storage->info()->piece_size(p.piece); 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) void disk_io_thread::cache_block(disk_io_job& j, mutex_t::scoped_lock& l)
{ {
TORRENT_ASSERT(l.locked());
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_ASSERT(find_cached_piece(m_pieces, j, l) == m_pieces.end()); TORRENT_ASSERT(find_cached_piece(m_pieces, j, l) == m_pieces.end());
cached_piece_entry p; cached_piece_entry p;
@ -365,8 +359,6 @@ namespace libtorrent
// read or -1 if there was an error // 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) 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 piece_size = p.storage->info()->piece_size(p.piece);
int blocks_in_piece = (piece_size + m_block_size - 1) / m_block_size; int blocks_in_piece = (piece_size + m_block_size - 1) / m_block_size;
@ -436,8 +428,6 @@ namespace libtorrent
, cache_t::iterator ignore , cache_t::iterator ignore
, mutex_t::scoped_lock& l) , mutex_t::scoped_lock& l)
{ {
TORRENT_ASSERT(l.locked());
if (m_cache_size - m_cache_stats.cache_size < num_blocks) if (m_cache_size - m_cache_stats.cache_size < num_blocks)
{ {
// there's not enough room in the cache, clear a piece // there's not enough room in the cache, clear a piece
@ -452,8 +442,6 @@ namespace libtorrent
// or the number of bytes read // or the number of bytes read
int disk_io_thread::cache_read_block(disk_io_job const& j, mutex_t::scoped_lock& l) int disk_io_thread::cache_read_block(disk_io_job const& j, mutex_t::scoped_lock& l)
{ {
TORRENT_ASSERT(l.locked());
INVARIANT_CHECK; INVARIANT_CHECK;
int piece_size = j.storage->info()->piece_size(j.piece); 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) 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); TORRENT_ASSERT(j.buffer);
if (!m_use_read_cache) return -2; if (!m_use_read_cache) return -2;
@ -707,7 +694,6 @@ namespace libtorrent
char* disk_io_thread::allocate_buffer(mutex_t::scoped_lock& l) char* disk_io_thread::allocate_buffer(mutex_t::scoped_lock& l)
{ {
TORRENT_ASSERT(l.locked());
#ifdef TORRENT_STATS #ifdef TORRENT_STATS
++m_allocations; ++m_allocations;
#endif #endif
@ -720,7 +706,6 @@ namespace libtorrent
void disk_io_thread::free_buffer(char* buf, mutex_t::scoped_lock& l) void disk_io_thread::free_buffer(char* buf, mutex_t::scoped_lock& l)
{ {
TORRENT_ASSERT(l.locked());
#ifdef TORRENT_STATS #ifdef TORRENT_STATS
--m_allocations; --m_allocations;
#endif #endif

View File

@ -35,8 +35,10 @@ POSSIBILITY OF SUCH DAMAGE.
#include <algorithm> #include <algorithm>
#include <iostream> #include <iostream>
#include <iomanip> #include <iomanip>
#include <boost/bind.hpp>
#include "libtorrent/entry.hpp" #include "libtorrent/entry.hpp"
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
#include "libtorrent/escape_string.hpp"
#if defined(_MSC_VER) #if defined(_MSC_VER)
namespace std namespace std
@ -54,19 +56,6 @@ namespace
TORRENT_ASSERT(o); TORRENT_ASSERT(o);
o->~T(); o->~T();
} }
struct compare_string
{
compare_string(char const* s): m_str(s) {}
bool operator()(
std::pair<std::string
, libtorrent::entry> const& e) const
{
return m_str && e.first == m_str;
}
char const* m_str;
};
} }
namespace libtorrent namespace libtorrent
@ -94,6 +83,16 @@ namespace libtorrent
} }
entry& entry::operator[](char const* key) 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); dictionary_type::iterator i = dict().find(key);
if (i != dict().end()) return i->second; if (i != dict().end()) return i->second;
@ -103,21 +102,11 @@ namespace libtorrent
return ret->second; return ret->second;
} }
entry& entry::operator[](std::string const& key)
{
return (*this)[key.c_str()];
}
entry* entry::find_key(char const* key) entry* entry::find_key(char const* key)
{ {
dictionary_type::iterator i = std::find_if( dictionary_type::iterator i = dict().find(key);
dict().begin()
, dict().end()
, compare_string(key));
if (i == dict().end()) return 0; if (i == dict().end()) return 0;
return &i->second; return &i->second;
} }
entry const* entry::find_key(char const* key) const entry const* entry::find_key(char const* key) const
@ -127,6 +116,20 @@ namespace libtorrent
return &i->second; 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 #ifndef BOOST_NO_EXCEPTIONS
const entry& entry::operator[](char const* key) const const entry& entry::operator[](char const* key) const
{ {
@ -370,21 +373,8 @@ namespace libtorrent
break; break;
} }
} }
if (binary_string) if (binary_string) os << to_hex(string()) << "\n";
{ else os << string() << "\n";
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 int>((unsigned char)*i);
os.unsetf(std::ios_base::hex);
os.setf(std::ios_base::dec);
os << "\n";
}
else
{
os << string() << "\n";
}
} break; } break;
case list_t: case list_t:
{ {
@ -399,8 +389,21 @@ namespace libtorrent
os << "dictionary\n"; os << "dictionary\n";
for (dictionary_type::const_iterator i = dict().begin(); i != dict().end(); ++i) 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<unsigned char>(*k)))
{
binary_string = true;
break;
}
}
for (int j = 0; j < indent+1; ++j) os << " "; 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 if (i->second.type() != entry::string_t
&& i->second.type() != entry::int_t) && i->second.type() != entry::int_t)
os << "\n"; os << "\n";

View File

@ -35,8 +35,11 @@ POSSIBILITY OF SUCH DAMAGE.
#include <vector> #include <vector>
#include "libtorrent/enum_net.hpp" #include "libtorrent/enum_net.hpp"
#include "libtorrent/broadcast_socket.hpp" #include "libtorrent/broadcast_socket.hpp"
#if BOOST_VERSION < 103500
#include <asio/ip/host_name.hpp> #include <asio/ip/host_name.hpp>
#else
#include <boost/asio/ip/host_name.hpp>
#endif
#if defined TORRENT_BSD #if defined TORRENT_BSD
#include <sys/ioctl.h> #include <sys/ioctl.h>
@ -225,7 +228,7 @@ namespace libtorrent
== (iface.interface_address.to_v4().to_ulong() & iface.netmask.to_v4().to_ulong()); == (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<ip_interface> const& net = enum_net_interfaces(ios, ec); std::vector<ip_interface> const& net = enum_net_interfaces(ios, ec);
if (ec) return false; if (ec) return false;
@ -237,7 +240,7 @@ namespace libtorrent
return false; return false;
} }
std::vector<ip_interface> enum_net_interfaces(asio::io_service& ios, asio::error_code& ec) std::vector<ip_interface> enum_net_interfaces(io_service& ios, error_code& ec)
{ {
std::vector<ip_interface> ret; std::vector<ip_interface> ret;
// covers linux, MacOS X and BSD distributions // covers linux, MacOS X and BSD distributions
@ -254,7 +257,7 @@ namespace libtorrent
ifc.ifc_buf = buf; ifc.ifc_buf = buf;
if (ioctl(s, SIOCGIFCONF, &ifc) < 0) 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); close(s);
return ret; return ret;
} }
@ -283,7 +286,7 @@ namespace libtorrent
} }
else else
{ {
ec = asio::error_code(errno, asio::error::system_category); ec = error_code(errno, asio::error::system_category);
close(s); close(s);
return ret; return ret;
} }
@ -310,7 +313,7 @@ namespace libtorrent
SOCKET s = socket(AF_INET, SOCK_DGRAM, 0); SOCKET s = socket(AF_INET, SOCK_DGRAM, 0);
if (s == SOCKET_ERROR) if (s == SOCKET_ERROR)
{ {
ec = asio::error_code(WSAGetLastError(), asio::error::system_category); ec = error_code(WSAGetLastError(), asio::error::system_category);
return ret; return ret;
} }
@ -320,7 +323,7 @@ namespace libtorrent
if (WSAIoctl(s, SIO_GET_INTERFACE_LIST, 0, 0, buffer, if (WSAIoctl(s, SIO_GET_INTERFACE_LIST, 0, 0, buffer,
sizeof(buffer), &size, 0, 0) != 0) 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); closesocket(s);
return ret; return ret;
} }
@ -356,16 +359,21 @@ namespace libtorrent
return ret; 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<ip_route> ret = enum_routes(ios, ec); std::vector<ip_route> ret = enum_routes(ios, ec);
#ifdef TORRENT_WINDOWS
std::vector<ip_route>::iterator i = std::find_if(ret.begin(), ret.end()
, boost::bind(&is_loopback, boost::bind(&ip_route::destination, _1)));
#else
std::vector<ip_route>::iterator i = std::find_if(ret.begin(), ret.end() std::vector<ip_route>::iterator i = std::find_if(ret.begin(), ret.end()
, boost::bind(&ip_route::destination, _1) == address()); , boost::bind(&ip_route::destination, _1) == address());
#endif
if (i == ret.end()) return address(); if (i == ret.end()) return address();
return i->gateway; return i->gateway;
} }
std::vector<ip_route> enum_routes(asio::io_service& ios, asio::error_code& ec) std::vector<ip_route> enum_routes(io_service& ios, error_code& ec)
{ {
std::vector<ip_route> ret; std::vector<ip_route> ret;
@ -390,14 +398,14 @@ namespace libtorrent
int s = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC); int s = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC);
if (s == -1) if (s == -1)
{ {
ec = asio::error_code(errno, asio::error::system_category); ec = error_code(errno, asio::error::system_category);
return std::vector<ip_route>(); return std::vector<ip_route>();
} }
int n = write(s, &m, len); int n = write(s, &m, len);
if (n == -1) if (n == -1)
{ {
ec = asio::error_code(errno, asio::error::system_category); ec = error_code(errno, asio::error::system_category);
close(s); close(s);
return std::vector<ip_route>(); return std::vector<ip_route>();
} }
@ -412,7 +420,7 @@ namespace libtorrent
n = read(s, &m, len); n = read(s, &m, len);
if (n == -1) if (n == -1)
{ {
ec = asio::error_code(errno, asio::error::system_category); ec = error_code(errno, asio::error::system_category);
close(s); close(s);
return std::vector<ip_route>(); return std::vector<ip_route>();
} }
@ -423,7 +431,7 @@ namespace libtorrent
std::cout << " rtm_type: " << ptr->rtm_type << std::endl; std::cout << " rtm_type: " << ptr->rtm_type << std::endl;
if (ptr->rtm_errno) 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<ip_route>(); return std::vector<ip_route>();
} }
if (m.m_rtm.rtm_flags & RTF_UP == 0 if (m.m_rtm.rtm_flags & RTF_UP == 0
@ -475,7 +483,7 @@ namespace libtorrent
size_t needed = 0; size_t needed = 0;
if (sysctl(mib, 6, 0, &needed, 0, 0) < 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<ip_route>(); return std::vector<ip_route>();
} }
@ -493,7 +501,7 @@ namespace libtorrent
if (sysctl(mib, 6, buf.get(), &needed, 0, 0) < 0) 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<ip_route>(); return std::vector<ip_route>();
} }
@ -547,7 +555,6 @@ namespace libtorrent
return std::vector<ip_route>(); return std::vector<ip_route>();
} }
address ret;
if (GetAdaptersInfo(adapter_info, &out_buf_size) == NO_ERROR) if (GetAdaptersInfo(adapter_info, &out_buf_size) == NO_ERROR)
{ {
for (PIP_ADAPTER_INFO adapter = adapter_info; for (PIP_ADAPTER_INFO adapter = adapter_info;
@ -555,14 +562,14 @@ namespace libtorrent
{ {
ip_route r; 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.gateway = address::from_string(adapter->GatewayList.IpAddress.String, ec);
r.netmask = address::from_string(adapter->IpAddressList.IpMask.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) if (ec)
{ {
ec = asio::error_code(); ec = error_code();
continue; continue;
} }
ret.push_back(r); ret.push_back(r);
@ -573,8 +580,6 @@ namespace libtorrent
free(adapter_info); free(adapter_info);
FreeLibrary(iphlp); FreeLibrary(iphlp);
return ret;
#elif defined TORRENT_LINUX #elif defined TORRENT_LINUX
enum { BUFSIZE = 8192 }; enum { BUFSIZE = 8192 };
@ -582,7 +587,7 @@ namespace libtorrent
int sock = socket(PF_ROUTE, SOCK_DGRAM, NETLINK_ROUTE); int sock = socket(PF_ROUTE, SOCK_DGRAM, NETLINK_ROUTE);
if (sock < 0) if (sock < 0)
{ {
ec = asio::error_code(errno, asio::error::system_category); ec = error_code(errno, asio::error::system_category);
return std::vector<ip_route>(); return std::vector<ip_route>();
} }
@ -600,7 +605,7 @@ namespace libtorrent
if (send(sock, nl_msg, nl_msg->nlmsg_len, 0) < 0) 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); close(sock);
return std::vector<ip_route>(); return std::vector<ip_route>();
} }
@ -608,7 +613,7 @@ namespace libtorrent
int len = read_nl_sock(sock, msg, BUFSIZE, seq, getpid()); int len = read_nl_sock(sock, msg, BUFSIZE, seq, getpid());
if (len < 0) if (len < 0)
{ {
ec = asio::error_code(errno, asio::error::system_category); ec = error_code(errno, asio::error::system_category);
close(sock); close(sock);
return std::vector<ip_route>(); return std::vector<ip_route>();
} }

View File

@ -352,5 +352,17 @@ namespace libtorrent
return url.substr(pos, url.find('&', pos) - pos); 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;
}
} }

View File

@ -34,12 +34,14 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/escape_string.hpp" #include "libtorrent/escape_string.hpp"
#include "libtorrent/instantiate_connection.hpp" #include "libtorrent/instantiate_connection.hpp"
#include "libtorrent/gzip.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 <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <asio/ip/tcp.hpp>
#include <string> #include <string>
#include <algorithm>
using boost::bind; 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 auth;
std::string hostname; std::string hostname;
std::string path; std::string path;
char const* error;
int port; 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); 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"; "\r\n";
sendbuffer = headers.str(); sendbuffer = headers.str();
m_url = url;
start(hostname, boost::lexical_cast<std::string>(port), timeout, prio start(hostname, boost::lexical_cast<std::string>(port), timeout, prio
, ps, ssl, handle_redirects, bind_addr); , 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; if (ps) m_proxy = *ps;
m_timeout = timeout; m_timeout = timeout;
asio::error_code ec; error_code ec;
m_timer.expires_from_now(m_timeout, ec); m_timer.expires_from_now(m_timeout, ec);
m_timer.async_wait(bind(&http_connection::on_timeout m_timer.async_wait(bind(&http_connection::on_timeout
, boost::weak_ptr<http_connection>(shared_from_this()), _1)); , boost::weak_ptr<http_connection>(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 if (m_sock.is_open() && m_hostname == hostname && m_port == port
&& m_ssl == ssl && m_bind_addr == bind_addr) && 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)); , bind(&http_connection::on_write, shared_from_this(), _1));
} }
else else
{ {
m_ssl = ssl; m_ssl = ssl;
m_bind_addr = bind_addr; m_bind_addr = bind_addr;
asio::error_code ec; error_code ec;
m_sock.close(ec); m_sock.close(ec);
#ifdef TORRENT_USE_OPENSSL #ifdef TORRENT_USE_OPENSSL
@ -168,7 +180,7 @@ void http_connection::start(std::string const& hostname, std::string const& port
#endif #endif
if (m_bind_addr != address_v4::any()) if (m_bind_addr != address_v4::any())
{ {
asio::error_code ec; error_code ec;
m_sock.bind(tcp::endpoint(m_bind_addr, 0), ec); m_sock.bind(tcp::endpoint(m_bind_addr, 0), ec);
if (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() void http_connection::on_connect_timeout()
{ {
TORRENT_ASSERT(m_connection_ticket >= 0);
if (m_connection_ticket > -1) m_cc.done(m_connection_ticket); if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
m_connection_ticket = -1; m_connection_ticket = -1;
callback(asio::error::timed_out); if (!m_endpoints.empty())
close(); {
m_sock.close();
}
else
{
callback(asio::error::timed_out);
close();
}
} }
void http_connection::on_timeout(boost::weak_ptr<http_connection> p void http_connection::on_timeout(boost::weak_ptr<http_connection> p
, asio::error_code const& e) , error_code const& e)
{ {
boost::shared_ptr<http_connection> c = p.lock(); boost::shared_ptr<http_connection> c = p.lock();
if (!c) return; 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 (e == asio::error::operation_aborted) return;
if (c->m_last_receive + c->m_timeout < time_now()) if (c->m_last_receive + c->m_timeout < time_now())
{ {
c->callback(asio::error::timed_out); if (c->m_connection_ticket > -1 && !c->m_endpoints.empty())
c->close(); {
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; return;
} }
if (!c->m_sock.is_open()) 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.expires_at(c->m_last_receive + c->m_timeout, ec);
c->m_timer.async_wait(bind(&http_connection::on_timeout, p, _1)); c->m_timer.async_wait(bind(&http_connection::on_timeout, p, _1));
} }
void http_connection::close() void http_connection::close()
{ {
asio::error_code ec; error_code ec;
m_timer.cancel(ec); m_timer.cancel(ec);
m_limiter_timer.cancel(ec); m_limiter_timer.cancel(ec);
m_sock.close(ec); m_sock.close(ec);
m_hostname.clear(); m_hostname.clear();
m_port.clear(); m_port.clear();
if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
m_connection_ticket = -1;
m_handler.clear(); 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) , tcp::resolver::iterator i)
{ {
if (e) if (e)
@ -243,21 +268,26 @@ void http_connection::on_resolve(asio::error_code const& e
} }
TORRENT_ASSERT(i != tcp::resolver::iterator()); TORRENT_ASSERT(i != tcp::resolver::iterator());
// look for an address that has the same kind as the one std::transform(i, tcp::resolver::iterator(), std::back_inserter(m_endpoints)
// we're binding to. To make sure a tracker get our , boost::bind(&tcp::resolver::iterator::value_type::endpoint, _1));
// 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);
if (target != end) // 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,
target_address = *target; // 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())
m_cc.enqueue(bind(&http_connection::connect, shared_from_this(), _1, target_address) > (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()) , bind(&http_connection::on_connect_timeout, shared_from_this())
, m_timeout, m_priority); , m_timeout, m_priority);
} }
@ -266,35 +296,35 @@ void http_connection::connect(int ticket, tcp::endpoint target_address)
{ {
m_connection_ticket = ticket; m_connection_ticket = ticket;
m_sock.async_connect(target_address, boost::bind(&http_connection::on_connect 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 void http_connection::on_connect(error_code const& e)
/*, tcp::resolver::iterator i*/)
{ {
TORRENT_ASSERT(m_connection_ticket >= 0);
m_cc.done(m_connection_ticket);
m_last_receive = time_now();
if (!e) if (!e)
{ {
m_last_receive = time_now();
if (m_connect_handler) m_connect_handler(*this); 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)); , 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. // The connection failed. Try the next endpoint in the list.
m_sock.close(); m_sock.close();
m_cc.enqueue(bind(&http_connection::connect, shared_from_this(), _1, *i) queue_connect();
, bind(&http_connection::on_connect_timeout, shared_from_this())
, m_timeout, m_priority);
} }
*/ else else
{ {
callback(e); callback(e);
close(); 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) 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; std::string error;
if (inflate_gzip(data, size, buf, max_bottled_buffer, 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(); close();
return; return;
} }
@ -317,11 +347,11 @@ void http_connection::callback(asio::error_code const& e, char const* data, int
} }
m_called = true; m_called = true;
m_timer.cancel(); 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) if (e)
{ {
@ -340,7 +370,7 @@ void http_connection::on_write(asio::error_code const& e)
if (m_download_quota == 0) if (m_download_quota == 0)
{ {
if (!m_limiter_timer_active) if (!m_limiter_timer_active)
on_assign_bandwidth(asio::error_code()); on_assign_bandwidth(error_code());
return; return;
} }
} }
@ -350,7 +380,7 @@ void http_connection::on_write(asio::error_code const& e)
, shared_from_this(), _1, _2)); , 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) , std::size_t bytes_transferred)
{ {
if (m_rate_limit) if (m_rate_limit)
@ -394,7 +424,7 @@ void http_connection::on_read(asio::error_code const& e
if (error) if (error)
{ {
// HTTP parse error // HTTP parse error
asio::error_code ec = asio::error::fault; error_code ec = asio::error::fault;
callback(ec, 0, 0); callback(ec, 0, 0);
return; return;
} }
@ -407,17 +437,44 @@ void http_connection::on_read(asio::error_code const& e
if (code >= 300 && code < 400) if (code >= 300 && code < 400)
{ {
// attempt a redirect // attempt a redirect
std::string const& url = m_parser.header("location"); std::string const& location = m_parser.header("location");
if (url.empty()) if (location.empty())
{ {
// missing location header // missing location header
callback(e); callback(asio::error::fault);
close();
return; return;
} }
asio::error_code ec; error_code ec;
m_sock.close(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; return;
} }
@ -434,7 +491,7 @@ void http_connection::on_read(asio::error_code const& e
} }
else if (m_bottled && m_parser.finished()) else if (m_bottled && m_parser.finished())
{ {
asio::error_code ec; error_code ec;
m_timer.cancel(ec); m_timer.cancel(ec);
callback(e, m_parser.get_body().begin, m_parser.get_body().left()); 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_download_quota == 0)
{ {
if (!m_limiter_timer_active) if (!m_limiter_timer_active)
on_assign_bandwidth(asio::error_code()); on_assign_bandwidth(error_code());
return; return;
} }
} }
@ -472,7 +529,7 @@ void http_connection::on_read(asio::error_code const& e
, shared_from_this(), _1, _2)); , 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 if ((e == asio::error::operation_aborted
&& m_limiter_timer_active) && m_limiter_timer_active)
@ -499,7 +556,7 @@ void http_connection::on_assign_bandwidth(asio::error_code const& e)
, bind(&http_connection::on_read , bind(&http_connection::on_read
, shared_from_this(), _1, _2)); , shared_from_this(), _1, _2));
asio::error_code ec; error_code ec;
m_limiter_timer_active = true; m_limiter_timer_active = true;
m_limiter_timer.expires_from_now(milliseconds(250), ec); m_limiter_timer.expires_from_now(milliseconds(250), ec);
m_limiter_timer.async_wait(bind(&http_connection::on_assign_bandwidth 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) if (!m_limiter_timer_active)
{ {
asio::error_code ec; error_code ec;
m_limiter_timer_active = true; m_limiter_timer_active = true;
m_limiter_timer.expires_from_now(milliseconds(250), ec); m_limiter_timer.expires_from_now(milliseconds(250), ec);
m_limiter_timer.async_wait(bind(&http_connection::on_assign_bandwidth m_limiter_timer.async_wait(bind(&http_connection::on_assign_bandwidth

View File

@ -38,13 +38,13 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent 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<handler_type> h) , boost::shared_ptr<handler_type> h)
{ {
if (e || i == tcp::resolver::iterator()) if (e || i == tcp::resolver::iterator())
{ {
(*h)(e); (*h)(e);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
@ -53,12 +53,12 @@ namespace libtorrent
&http_stream::connected, this, _1, h)); &http_stream::connected, this, _1, h));
} }
void http_stream::connected(asio::error_code const& e, boost::shared_ptr<handler_type> h) void http_stream::connected(error_code const& e, boost::shared_ptr<handler_type> h)
{ {
if (e) if (e)
{ {
(*h)(e); (*h)(e);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
@ -82,32 +82,32 @@ namespace libtorrent
m_user + ":" + m_password) + "\r\n", p); m_user + ":" + m_password) + "\r\n", p);
} }
write_string("\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)); , boost::bind(&http_stream::handshake1, this, _1, h));
} }
void http_stream::handshake1(asio::error_code const& e, boost::shared_ptr<handler_type> h) void http_stream::handshake1(error_code const& e, boost::shared_ptr<handler_type> h)
{ {
if (e) if (e)
{ {
(*h)(e); (*h)(e);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
// read one byte from the socket // read one byte from the socket
m_buffer.resize(1); 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)); , boost::bind(&http_stream::handshake2, this, _1, h));
} }
void http_stream::handshake2(asio::error_code const& e, boost::shared_ptr<handler_type> h) void http_stream::handshake2(error_code const& e, boost::shared_ptr<handler_type> h)
{ {
if (e) if (e)
{ {
(*h)(e); (*h)(e);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
@ -138,7 +138,7 @@ namespace libtorrent
if (status == 0) if (status == 0)
{ {
(*h)(asio::error::operation_not_supported); (*h)(asio::error::operation_not_supported);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
@ -148,7 +148,7 @@ namespace libtorrent
if (code != 200) if (code != 200)
{ {
(*h)(asio::error::operation_not_supported); (*h)(asio::error::operation_not_supported);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
@ -160,7 +160,7 @@ namespace libtorrent
// read another byte from the socket // read another byte from the socket
m_buffer.resize(read_pos + 1); 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)); , boost::bind(&http_stream::handshake2, this, _1, h));
} }

View File

@ -194,7 +194,7 @@ namespace libtorrent
tracker_connection::close(); 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) , http_parser const& parser, char const* data, int size)
{ {
// keep this alive // keep this alive
@ -313,9 +313,7 @@ namespace libtorrent
if (tracker_req().kind == tracker_request::scrape_request) if (tracker_req().kind == tracker_request::scrape_request)
{ {
std::string ih; std::string ih = tracker_req().info_hash.to_string();
std::copy(tracker_req().info_hash.begin(), tracker_req().info_hash.end()
, std::back_inserter(ih));
entry const* files = e.find_key("files"); entry const* files = e.find_key("files");
if (files == 0 || files->type() != entry::dictionary_t) if (files == 0 || files->type() != entry::dictionary_t)
@ -324,7 +322,7 @@ namespace libtorrent
return; 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) if (scrape_data == 0 || scrape_data->type() != entry::dictionary_t)
{ {
fail(-1, "missing or invalid info-hash entry in scrape response"); fail(-1, "missing or invalid info-hash entry in scrape response");

View File

@ -37,12 +37,11 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/socket_type.hpp" #include "libtorrent/socket_type.hpp"
#include <boost/shared_ptr.hpp> #include <boost/shared_ptr.hpp>
#include <stdexcept> #include <stdexcept>
#include <asio/io_service.hpp>
namespace libtorrent namespace libtorrent
{ {
bool instantiate_connection(asio::io_service& ios bool instantiate_connection(io_service& ios
, proxy_settings const& ps, socket_type& s) , proxy_settings const& ps, socket_type& s)
{ {
if (ps.type == proxy_settings::none) if (ps.type == proxy_settings::none)

View File

@ -40,8 +40,6 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent { namespace dht namespace libtorrent { namespace dht
{ {
using asio::ip::udp;
closest_nodes_observer::~closest_nodes_observer() closest_nodes_observer::~closest_nodes_observer()
{ {
if (m_algorithm) m_algorithm->failed(m_self, true); if (m_algorithm) m_algorithm->failed(m_self, true);

View File

@ -51,6 +51,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/bencode.hpp" #include "libtorrent/bencode.hpp"
#include "libtorrent/io.hpp" #include "libtorrent/io.hpp"
#include "libtorrent/version.hpp" #include "libtorrent/version.hpp"
#include "libtorrent/escape_string.hpp"
using boost::ref; using boost::ref;
using boost::lexical_cast; using boost::lexical_cast;
@ -66,9 +67,6 @@ enum
key_refresh = 5 // generate a new write token key every 5 minutes key_refresh = 5 // generate a new write token key every 5 minutes
}; };
using asio::ip::udp;
typedef asio::ip::address_v4 address;
namespace namespace
{ {
const int tick_period = 1; // minutes const int tick_period = 1; // minutes
@ -228,7 +226,7 @@ namespace libtorrent { namespace dht
s.dht_global_nodes = m_dht.num_global_nodes(); 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 try
{ {
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
@ -247,7 +245,7 @@ namespace libtorrent { namespace dht
#endif #endif
}; };
void dht_tracker::refresh_timeout(asio::error_code const& e) void dht_tracker::refresh_timeout(error_code const& e)
try try
{ {
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
@ -263,7 +261,7 @@ namespace libtorrent { namespace dht
TORRENT_ASSERT(false); TORRENT_ASSERT(false);
}; };
void dht_tracker::tick(asio::error_code const& e) void dht_tracker::tick(error_code const& e)
try try
{ {
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
@ -375,6 +373,12 @@ namespace libtorrent { namespace dht
m_dht.announce(ih, listen_port, f); 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 // translate bittorrent kademlia message into the generice kademlia message
// used by the library // used by the library
void dht_tracker::on_receive(udp::endpoint const& ep, char const* buf, int bytes_transferred) 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) if (match->count == 20)
{ {
TORRENT_LOG(dht_tracker) << time_now_string() << " BANNING PEER [ ip: " TORRENT_LOG(dht_tracker) << time_now_string() << " BANNING PEER [ ip: "
<< ep << " | time: " << total_milliseconds((now - match->limit) + seconds(5)) / 1000.f << ep << " time: " << total_milliseconds((now - match->limit) + seconds(5)) / 1000.f
<< " | count: " << match->count << " ]"; << " count: " << match->count << " ]";
} }
#endif #endif
// we've received 20 messages in less than 5 seconds from // 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); entry e = bdecode(buf, buf + bytes_transferred);
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(dht_tracker) << time_now_string() << " RECEIVED [" std::stringstream log_line;
<< ep << "]:"; log_line << time_now_string() << " RECEIVED ["
" ip: " << ep;
#endif #endif
libtorrent::dht::msg m; libtorrent::dht::msg m;
@ -461,36 +466,36 @@ namespace libtorrent { namespace dht
if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "UT")) if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "UT"))
{ {
++m_ut_message_input; ++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")) else if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "LT"))
{ {
++m_lt_message_input; ++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")) else if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "MP"))
{ {
++m_mp_message_input; ++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")) else if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "GR"))
{ {
++m_gr_message_input; ++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")) else if (client.size() > 1 && std::equal(client.begin(), client.begin() + 2, "MO"))
{ {
++m_mo_message_input; ++m_mo_message_input;
TORRENT_LOG(dht_tracker) << " client: Mono Torrent"; log_line << " c: Mono Torrent";
} }
else else
{ {
TORRENT_LOG(dht_tracker) << " client: " << client; log_line << " c: " << client;
} }
} }
catch (std::exception&) catch (std::exception&)
{ {
TORRENT_LOG(dht_tracker) << " client: generic"; log_line << " c: generic";
}; };
#endif #endif
@ -499,8 +504,8 @@ namespace libtorrent { namespace dht
if (msg_type == "r") if (msg_type == "r")
{ {
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(dht_tracker) << " reply: transaction: " log_line << " r: " << messages::ids[m.message_id]
<< m.transaction_id; << " t: " << to_hex(m.transaction_id);
#endif #endif
m.reply = true; m.reply = true;
@ -528,7 +533,7 @@ namespace libtorrent { namespace dht
read_endpoint_list<tcp::endpoint>(n, m.peers); read_endpoint_list<tcp::endpoint>(n, m.peers);
} }
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(dht_tracker) << " peers: " << m.peers.size(); log_line << " p: " << m.peers.size();
#endif #endif
} }
@ -548,7 +553,7 @@ namespace libtorrent { namespace dht
id, read_v4_endpoint<udp::endpoint>(i))); id, read_v4_endpoint<udp::endpoint>(i)));
} }
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(dht_tracker) << " nodes: " << m.nodes.size(); log_line << " n: " << m.nodes.size();
#endif #endif
} }
@ -573,7 +578,7 @@ namespace libtorrent { namespace dht
id, read_v6_endpoint<udp::endpoint>(in))); id, read_v6_endpoint<udp::endpoint>(in)));
} }
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(dht_tracker) << " nodes2 + nodes: " << m.nodes.size(); log_line << " n2: " << m.nodes.size();
#endif #endif
} }
@ -590,7 +595,7 @@ namespace libtorrent { namespace dht
std::string request_kind(e["q"].string()); std::string request_kind(e["q"].string());
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(dht_tracker) << " query: " << request_kind; log_line << " q: " << request_kind;
#endif #endif
if (request_kind == "ping") 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"); if (target.size() != 20) throw std::runtime_error("invalid size of target id");
std::copy(target.begin(), target.end(), m.info_hash.begin()); std::copy(target.begin(), target.end(), m.info_hash.begin());
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(dht_tracker) << " target: " log_line << " t: " << boost::lexical_cast<std::string>(m.info_hash);
<< boost::lexical_cast<std::string>(m.info_hash);
#endif #endif
m.message_id = libtorrent::dht::messages::find_node; 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()); std::copy(info_hash.begin(), info_hash.end(), m.info_hash.begin());
m.message_id = libtorrent::dht::messages::get_peers; m.message_id = libtorrent::dht::messages::get_peers;
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(dht_tracker) << " info_hash: " log_line << " ih: " << boost::lexical_cast<std::string>(m.info_hash);
<< boost::lexical_cast<std::string>(m.info_hash);
#endif #endif
} }
else if (request_kind == "announce_peer") else if (request_kind == "announce_peer")
@ -633,9 +636,8 @@ namespace libtorrent { namespace dht
m.write_token = a["token"]; m.write_token = a["token"];
m.message_id = libtorrent::dht::messages::announce_peer; m.message_id = libtorrent::dht::messages::announce_peer;
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(dht_tracker) << " info_hash: " log_line << " ih: " << boost::lexical_cast<std::string>(m.info_hash);
<< boost::lexical_cast<std::string>(m.info_hash); log_line << " p: " << m.port;
TORRENT_LOG(dht_tracker) << " port: " << m.port;
if (!m_dht.verify_token(m)) if (!m_dht.verify_token(m))
++m_failed_announces; ++m_failed_announces;
@ -657,8 +659,8 @@ namespace libtorrent { namespace dht
m.error_msg = list.back().string(); m.error_msg = list.back().string();
m.error_code = list.front().integer(); m.error_code = list.front().integer();
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(dht_tracker) << " incoming error: " << m.error_code << " " log_line << " incoming error: " << m.error_code
<< m.error_msg; << " " << m.error_msg;
#endif #endif
throw std::runtime_error("DHT error message"); throw std::runtime_error("DHT error message");
} }
@ -677,7 +679,7 @@ namespace libtorrent { namespace dht
++m_queries_received[m.message_id]; ++m_queries_received[m.message_id];
m_queries_bytes_received[m.message_id] += int(bytes_transferred); m_queries_bytes_received[m.message_id] += int(bytes_transferred);
} }
TORRENT_LOG(dht_tracker) << e; TORRENT_LOG(dht_tracker) << log_line.str() << " ]";
#endif #endif
TORRENT_ASSERT(m.message_id != messages::error); TORRENT_ASSERT(m.message_id != messages::error);
m_dht.incoming(m); m_dht.incoming(m);
@ -739,7 +741,7 @@ namespace libtorrent { namespace dht
bind(&dht_tracker::on_name_lookup, self(), _1, _2)); 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 , udp::resolver::iterator host) try
{ {
if (e || host == udp::resolver::iterator()) return; 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)); 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 , udp::resolver::iterator host) try
{ {
if (e || host == udp::resolver::iterator()) return; if (e || host == udp::resolver::iterator()) return;
@ -809,9 +811,6 @@ namespace libtorrent { namespace dht
p.list().push_back(entry(endpoint)); 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); e["v"] = std::string(version_str, version_str + 4);
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(dht_tracker) << time_now_string() std::stringstream log_line;
<< " SENDING [" << m.addr << "]:"; log_line << time_now_string()
TORRENT_LOG(dht_tracker) << " transaction: " << m.transaction_id; << " SENDING [ ip: " << m.addr
<< " t: " << to_hex(m.transaction_id);
#endif #endif
if (m.message_id == messages::error) if (m.message_id == messages::error)
@ -843,8 +843,8 @@ namespace libtorrent { namespace dht
error_list.list().push_back(entry(m.error_msg)); error_list.list().push_back(entry(m.error_msg));
e["e"] = error_list; e["e"] = error_list;
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(dht_tracker) << time_now_string() log_line << " err: " << m.error_code
<< " outgoing error: " << m.error_code << " " << m.error_msg; << " msg: " << m.error_msg;
#endif #endif
} }
else if (m.reply) else if (m.reply)
@ -855,8 +855,7 @@ namespace libtorrent { namespace dht
r["id"] = std::string(m.id.begin(), m.id.end()); r["id"] = std::string(m.id.begin(), m.id.end());
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(dht_tracker) << time_now_string() log_line << " r: " << messages::ids[m.message_id];
<< " reply: " << messages::ids[m.message_id];
#endif #endif
if (m.write_token.type() != entry::undefined_t) if (m.write_token.type() != entry::undefined_t)
@ -892,7 +891,7 @@ namespace libtorrent { namespace dht
p.list().push_back(entry(endpoint)); p.list().push_back(entry(endpoint));
} }
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(dht_tracker) << " peers: " << m.peers.size(); log_line << " p: " << m.peers.size();
#endif #endif
} }
break; break;
@ -916,8 +915,7 @@ namespace libtorrent { namespace dht
e["q"] = messages::ids[m.message_id]; e["q"] = messages::ids[m.message_id];
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(dht_tracker) << " query: " log_line << " q: " << messages::ids[m.message_id];
<< messages::ids[m.message_id];
#endif #endif
switch (m.message_id) switch (m.message_id)
@ -926,8 +924,7 @@ namespace libtorrent { namespace dht
{ {
a["target"] = std::string(m.info_hash.begin(), m.info_hash.end()); a["target"] = std::string(m.info_hash.begin(), m.info_hash.end());
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(dht_tracker) << " target: " log_line << " target: " << boost::lexical_cast<std::string>(m.info_hash);
<< boost::lexical_cast<std::string>(m.info_hash);
#endif #endif
break; break;
} }
@ -935,8 +932,7 @@ namespace libtorrent { namespace dht
{ {
a["info_hash"] = std::string(m.info_hash.begin(), m.info_hash.end()); a["info_hash"] = std::string(m.info_hash.begin(), m.info_hash.end());
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(dht_tracker) << " info_hash: " log_line << " ih: " << boost::lexical_cast<std::string>(m.info_hash);
<< boost::lexical_cast<std::string>(m.info_hash);
#endif #endif
break; break;
} }
@ -945,9 +941,8 @@ namespace libtorrent { namespace dht
a["info_hash"] = std::string(m.info_hash.begin(), m.info_hash.end()); a["info_hash"] = std::string(m.info_hash.begin(), m.info_hash.end());
a["token"] = m.write_token; a["token"] = m.write_token;
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(dht_tracker) log_line << " p: " << m.port
<< " port: " << m.port << " ih: " << boost::lexical_cast<std::string>(m.info_hash);
<< " info_hash: " << boost::lexical_cast<std::string>(m.info_hash);
#endif #endif
break; break;
default: break; default: break;
@ -957,7 +952,7 @@ namespace libtorrent { namespace dht
m_send_buf.clear(); m_send_buf.clear();
bencode(std::back_inserter(m_send_buf), e); 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); m_sock.send(m.addr, &m_send_buf[0], (int)m_send_buf.size(), ec);
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
@ -972,7 +967,7 @@ namespace libtorrent { namespace dht
{ {
m_queries_out_bytes += m_send_buf.size(); m_queries_out_bytes += m_send_buf.size();
} }
TORRENT_LOG(dht_tracker) << e; TORRENT_LOG(dht_tracker) << log_line.str() << " ]";
#endif #endif
if (!m.piggy_backed_ping) return; if (!m.piggy_backed_ping) return;

View File

@ -36,6 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <libtorrent/kademlia/routing_table.hpp> #include <libtorrent/kademlia/routing_table.hpp>
#include <libtorrent/kademlia/rpc_manager.hpp> #include <libtorrent/kademlia/rpc_manager.hpp>
#include <libtorrent/io.hpp> #include <libtorrent/io.hpp>
#include <libtorrent/socket.hpp>
namespace libtorrent { namespace dht namespace libtorrent { namespace dht
{ {
@ -101,7 +102,7 @@ find_data::find_data(
add_requests(); 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) if (m_done)
{ {

View File

@ -65,8 +65,6 @@ namespace
// TODO: configurable? // TODO: configurable?
enum { announce_interval = 30 }; enum { announce_interval = 30 };
using asio::ip::udp;
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_DEFINE_LOG(node) TORRENT_DEFINE_LOG(node)
#endif #endif
@ -245,6 +243,11 @@ void node_impl::refresh_bucket(int bucket) try
} }
catch (std::exception&) {} catch (std::exception&) {}
void node_impl::unreachable(udp::endpoint const& ep)
{
m_rpc.unreachable(ep);
}
void node_impl::incoming(msg const& m) void node_impl::incoming(msg const& m)
{ {
if (m_rpc.incoming(m)) if (m_rpc.incoming(m))
@ -269,6 +272,9 @@ namespace
for (std::vector<node_entry>::const_iterator i = v.begin() for (std::vector<node_entry>::const_iterator i = v.begin()
, end(v.end()); i != end; ++i) , 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)); observer_ptr o(new (rpc.allocator().malloc()) get_peers_observer(ih, listen_port, rpc, f));
#ifndef NDEBUG #ifndef NDEBUG
o->m_in_constructor = false; o->m_in_constructor = false;

View File

@ -47,8 +47,6 @@ using boost::bind;
namespace libtorrent { namespace dht namespace libtorrent { namespace dht
{ {
using asio::ip::udp;
#ifdef TORRENT_DHT_VERBOSE_LOGGING #ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_DEFINE_LOG(refresh) TORRENT_DEFINE_LOG(refresh)
#endif #endif

View File

@ -50,8 +50,9 @@ using boost::uint8_t;
namespace libtorrent { namespace dht namespace libtorrent { namespace dht
{ {
using asio::ip::udp; #ifdef TORRENT_DHT_VERBOSE_LOGGING
typedef asio::ip::address_v4 address; TORRENT_DEFINE_LOG(table)
#endif
routing_table::routing_table(node_id const& id, int bucket_size routing_table::routing_table(node_id const& id, int bucket_size
, dht_settings const& settings) , dht_settings const& settings)
@ -225,6 +226,15 @@ void routing_table::node_failed(node_id const& id)
if (rb.empty()) if (rb.empty())
{ {
++i->fail_count; ++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) if (i->fail_count >= m_settings.max_fail_count)
{ {
b.erase(i); b.erase(i);

View File

@ -159,6 +159,39 @@ void rpc_manager::check_invariant() const
} }
#endif #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) bool rpc_manager::incoming(msg const& m)
{ {
INVARIANT_CHECK; INVARIANT_CHECK;

View File

@ -39,7 +39,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/bind.hpp> #include <boost/bind.hpp>
using boost::bind; using boost::bind;
using asio::ip::udp;
namespace libtorrent { namespace dht 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) void traversal_algorithm::traverse(node_id const& id, udp::endpoint addr)
{ {
#ifdef TORRENT_DHT_VERBOSE_LOGGING #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 #endif
add_entry(id, addr, 0); add_entry(id, addr, 0);
} }

View File

@ -187,6 +187,7 @@ namespace libtorrent
std::pair<char const*, lazy_entry>* tmp = new (std::nothrow) std::pair<char const*, lazy_entry>[capacity]; std::pair<char const*, lazy_entry>* tmp = new (std::nothrow) std::pair<char const*, lazy_entry>[capacity];
if (tmp == 0) return 0; if (tmp == 0) return 0;
std::memcpy(tmp, m_data.dict, sizeof(std::pair<char const*, lazy_entry>) * m_size); std::memcpy(tmp, m_data.dict, sizeof(std::pair<char const*, lazy_entry>) * m_size);
for (int i = 0; i < m_size; ++i) m_data.dict[i].second.release();
delete[] m_data.dict; delete[] m_data.dict;
m_data.dict = tmp; m_data.dict = tmp;
m_capacity = capacity; m_capacity = capacity;
@ -299,6 +300,7 @@ namespace libtorrent
lazy_entry* tmp = new (std::nothrow) lazy_entry[capacity]; lazy_entry* tmp = new (std::nothrow) lazy_entry[capacity];
if (tmp == 0) return 0; if (tmp == 0) return 0;
std::memcpy(tmp, m_data.list, sizeof(lazy_entry) * m_size); 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; delete[] m_data.list;
m_data.list = tmp; m_data.list = tmp;
m_capacity = capacity; m_capacity = capacity;
@ -330,6 +332,7 @@ namespace libtorrent
case dict_t: delete[] m_data.dict; break; case dict_t: delete[] m_data.dict; break;
default: break; default: break;
} }
m_data.start = 0;
m_size = 0; m_size = 0;
m_capacity = 0; m_capacity = 0;
m_type = none_t; m_type = none_t;
@ -370,7 +373,8 @@ namespace libtorrent
bool one_liner = (e.list_size() == 0 bool one_liner = (e.list_size() == 0
|| e.list_at(0)->type() == lazy_entry::int_t || e.list_at(0)->type() == lazy_entry::int_t
|| (e.list_at(0)->type() == lazy_entry::string_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; && e.list_size() < 5;
if (!one_liner) os << "\n"; if (!one_liner) os << "\n";
for (int i = 0; i < e.list_size(); ++i) for (int i = 0; i < e.list_size(); ++i)
@ -388,7 +392,7 @@ namespace libtorrent
bool one_liner = (e.dict_size() == 0 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::int_t
|| (e.dict_at(0).second->type() == lazy_entry::string_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_at(0).first.size() < 10)
&& e.dict_size() < 5; && e.dict_size() < 5;

View File

@ -40,8 +40,13 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/ref.hpp> #include <boost/ref.hpp>
#if BOOST_VERSION < 103500
#include <asio/ip/host_name.hpp> #include <asio/ip/host_name.hpp>
#include <asio/ip/multicast.hpp> #include <asio/ip/multicast.hpp>
#else
#include <boost/asio/ip/host_name.hpp>
#include <boost/asio/ip/multicast.hpp>
#endif
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
#include <cstdlib> #include <cstdlib>
#include <boost/config.hpp> #include <boost/config.hpp>
@ -52,7 +57,7 @@ using namespace libtorrent;
namespace libtorrent namespace libtorrent
{ {
// defined in broadcast_socket.cpp // 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 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(); std::string const& msg = btsearch.str();
m_retry_count = 1; m_retry_count = 1;
asio::error_code ec; error_code ec;
m_socket.send(msg.c_str(), int(msg.size()), ec); m_socket.send(msg.c_str(), int(msg.size()), ec);
if (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)); 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; if (e) return;
asio::error_code ec; error_code ec;
m_socket.send(msg.c_str(), int(msg.size()), ec); m_socket.send(msg.c_str(), int(msg.size()), ec);
++m_retry_count; ++m_retry_count;
@ -192,7 +197,7 @@ void lsd::on_announce(udp::endpoint const& from, char* buffer
void lsd::close() void lsd::close()
{ {
m_socket.close(); m_socket.close();
asio::error_code ec; error_code ec;
m_broadcast_timer.cancel(ec); m_broadcast_timer.cancel(ec);
m_disabled = true; m_disabled = true;
m_callback.clear(); m_callback.clear();

View File

@ -47,6 +47,11 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/utility.hpp> #include <boost/utility.hpp>
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#if BOOST_VERSION >= 103500
#include <boost/system/error_code.hpp>
#endif
#include <boost/version.hpp>
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(pop) #pragma warning(pop)
@ -57,8 +62,10 @@ using boost::iostreams::mapped_file_params;
namespace libtorrent namespace libtorrent
{ {
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
#if BOOST_VERSION >= 103500
using boost::system::error_code;
#endif
struct mapped_file_pool struct mapped_file_pool
{ {
@ -78,7 +85,7 @@ namespace libtorrent
#ifndef NDEBUG #ifndef NDEBUG
if (file_size > 0) if (file_size > 0)
{ {
fs::system_error_type ec; error_code ec;
fs::file_status st = fs::status(path, ec); fs::file_status st = fs::status(path, ec);
TORRENT_ASSERT(!fs::exists(st)); TORRENT_ASSERT(!fs::exists(st));
} }
@ -197,7 +204,11 @@ namespace libtorrent
size_type start = (offset / view_size) * view_size; size_type start = (offset / view_size) * view_size;
TORRENT_ASSERT(start + view_size >= offset + length); TORRENT_ASSERT(start + view_size >= offset + length);
#if BOOST_VERSION < 103500
fs::system_error_type ec; fs::system_error_type ec;
#else
error_code ec;
#endif
fs::file_status st = fs::status(p, ec); fs::file_status st = fs::status(p, ec);
m_files.push_back(file_entry()); m_files.push_back(file_entry());

View File

@ -55,6 +55,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/extensions.hpp" #include "libtorrent/extensions.hpp"
#include "libtorrent/extensions/metadata_transfer.hpp" #include "libtorrent/extensions/metadata_transfer.hpp"
#include "libtorrent/alert_types.hpp" #include "libtorrent/alert_types.hpp"
#include "libtorrent/buffer.hpp"
namespace libtorrent { namespace namespace libtorrent { namespace
{ {
@ -107,40 +108,37 @@ namespace libtorrent { namespace
virtual void on_files_checked() virtual void on_files_checked()
{ {
// if the torrent is a seed, copy the metadata from // if the torrent is a seed, make a reference to
// the torrent before it is deallocated // the metadata from the torrent before it is deallocated
if (m_torrent.is_seed()) if (m_torrent.is_seed()) metadata();
metadata();
} }
virtual boost::shared_ptr<peer_plugin> new_connection( virtual boost::shared_ptr<peer_plugin> new_connection(
peer_connection* pc); peer_connection* pc);
std::vector<char> const& metadata() const buffer::const_interval metadata() const
{ {
if (m_metadata.empty()) if (!m_metadata)
{ {
bencode(std::back_inserter(m_metadata) m_metadata = m_torrent.torrent_file().metadata();
, m_torrent.torrent_file().create_info_metadata()); m_metadata_size = m_torrent.torrent_file().metadata_size();
TORRENT_ASSERT(hasher(m_metadata.get(), m_metadata_size).final()
TORRENT_ASSERT(hasher(&m_metadata[0], m_metadata.size()).final()
== m_torrent.torrent_file().info_hash()); == m_torrent.torrent_file().info_hash());
} }
TORRENT_ASSERT(!m_metadata.empty()); return buffer::const_interval(m_metadata.get(), m_metadata.get()
return m_metadata; + m_metadata_size);
} }
bool received_metadata(char const* buf, int size, int offset, int total_size) bool received_metadata(char const* buf, int size, int offset, int total_size)
{ {
if (m_torrent.valid_metadata()) return false; if (m_torrent.valid_metadata()) return false;
if ((int)m_metadata.size() < total_size) if (!m_metadata || m_metadata_size < total_size)
m_metadata.resize(total_size); {
m_metadata.reset(new char[total_size]);
std::copy( m_metadata_size = total_size;
buf }
, buf + size std::copy(buf, buf + size, &m_metadata[offset]);
, &m_metadata[offset]);
if (m_have_metadata.empty()) if (m_have_metadata.empty())
m_have_metadata.resize(256, false); m_have_metadata.resize(256, false);
@ -163,7 +161,7 @@ namespace libtorrent { namespace
if (!have_all) return false; if (!have_all) return false;
hasher h; 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(); sha1_hash info_hash = h.final();
if (info_hash != m_torrent.torrent_file().info_hash()) if (info_hash != m_torrent.torrent_file().info_hash())
@ -184,9 +182,10 @@ namespace libtorrent { namespace
return false; 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; 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 // this means the metadata is correct, since we
// verified it against the info-hash, but we // verified it against the info-hash, but we
@ -240,10 +239,10 @@ namespace libtorrent { namespace
// the metadata file while downloading it from // the metadata file while downloading it from
// peers, and while sending it. // peers, and while sending it.
// it is mutable because it's generated lazily // it is mutable because it's generated lazily
mutable std::vector<char> m_metadata; mutable boost::shared_array<char> m_metadata;
int m_metadata_progress; int m_metadata_progress;
int m_metadata_size; mutable int m_metadata_size;
// this is a bitfield of size 256, each bit represents // this is a bitfield of size 256, each bit represents
// a piece of the metadata. It is set to one if we // 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()) if (m_torrent.valid_metadata() && !m_torrent.torrent_file().priv())
{ {
std::pair<int, int> offset std::pair<int, int> 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); 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); detail::write_uint8(m_message_index, i.begin);
// means 'data packet' // means 'data packet'
detail::write_uint8(1, i.begin); 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); detail::write_uint32(offset.first, i.begin);
std::vector<char> const& metadata = m_tp.metadata(); char const* metadata = m_tp.metadata().begin;
std::copy(metadata.begin() + offset.first std::copy(metadata + offset.first
, metadata.begin() + offset.first + offset.second, i.begin); , metadata + offset.first + offset.second, i.begin);
i.begin += offset.second; i.begin += offset.second;
TORRENT_ASSERT(i.begin == i.end); TORRENT_ASSERT(i.begin == i.end);
} }

View File

@ -33,7 +33,11 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/pch.hpp" #include "libtorrent/pch.hpp"
#include <boost/bind.hpp> #include <boost/bind.hpp>
#if BOOST_VERSION < 103500
#include <asio/ip/host_name.hpp> #include <asio/ip/host_name.hpp>
#else
#include <boost/asio/ip/host_name.hpp>
#endif
#include "libtorrent/natpmp.hpp" #include "libtorrent/natpmp.hpp"
#include "libtorrent/io.hpp" #include "libtorrent/io.hpp"
@ -63,7 +67,7 @@ void natpmp::rebind(address const& listen_interface)
{ {
mutex_t::scoped_lock l(m_mutex); 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); address gateway = get_default_gateway(m_socket.get_io_service(), ec);
if (ec) if (ec)
{ {
@ -198,7 +202,7 @@ void natpmp::try_next_mapping(int i)
{ {
if (m_abort) if (m_abort)
{ {
asio::error_code ec; error_code ec;
m_send_timer.cancel(ec); m_send_timer.cancel(ec);
m_socket.close(ec); m_socket.close(ec);
} }
@ -264,7 +268,7 @@ void natpmp::send_map_request(int i)
<< " ttl: " << ttl << " ]" << std::endl; << " ttl: " << ttl << " ]" << std::endl;
#endif #endif
asio::error_code ec; error_code ec;
m_socket.send_to(asio::buffer(buf, 12), m_nat_endpoint, 0, ec); m_socket.send_to(asio::buffer(buf, 12), m_nat_endpoint, 0, ec);
// linear back-off instead of exponential // linear back-off instead of exponential
++m_retry_count; ++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)); 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; if (e) return;
@ -290,7 +294,7 @@ void natpmp::resend_request(int i, asio::error_code const& e)
send_map_request(i); 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) , std::size_t bytes_transferred)
{ {
using namespace libtorrent::detail; using namespace libtorrent::detail;
@ -305,7 +309,7 @@ void natpmp::on_reply(asio::error_code const& e
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
asio::error_code ec; error_code ec;
m_send_timer.cancel(ec); m_send_timer.cancel(ec);
TORRENT_ASSERT(m_currently_mapping >= 0); TORRENT_ASSERT(m_currently_mapping >= 0);
@ -439,7 +443,7 @@ void natpmp::update_expiration_timer()
<< " ttl: " << total_seconds(min_expire - time_now()) << " ttl: " << total_seconds(min_expire - time_now())
<< " ]" << std::endl; << " ]" << std::endl;
#endif #endif
asio::error_code ec; error_code ec;
if (m_next_refresh >= 0) m_refresh_timer.cancel(ec); if (m_next_refresh >= 0) m_refresh_timer.cancel(ec);
m_refresh_timer.expires_from_now(min_expire - now, ec); m_refresh_timer.expires_from_now(min_expire - now, ec);
m_refresh_timer.async_wait(bind(&natpmp::mapping_expired, self(), _1, min_index)); 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; if (e) return;
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
@ -463,7 +467,7 @@ void natpmp::close()
{ {
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
m_abort = true; m_abort = true;
asio::error_code ec; error_code ec;
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING) #if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
m_log << time_now_string() << " close" << std::endl; m_log << time_now_string() << " close" << std::endl;
#endif #endif

View File

@ -64,7 +64,7 @@ namespace libtorrent
session_impl& ses session_impl& ses
, boost::weak_ptr<torrent> tor , boost::weak_ptr<torrent> tor
, shared_ptr<socket_type> s , shared_ptr<socket_type> s
, tcp::endpoint const& remote , tcp::endpoint const& endp
, policy::peer* peerinfo) , policy::peer* peerinfo)
: :
#ifndef NDEBUG #ifndef NDEBUG
@ -73,41 +73,28 @@ namespace libtorrent
#endif #endif
m_ses(ses) m_ses(ses)
, m_max_out_request_queue(m_ses.settings().max_out_request_queue) , 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_piece(time_now())
, m_last_request(time_now()) , m_last_request(time_now())
, m_last_incoming_request(min_time()) , m_last_incoming_request(min_time())
, m_last_unchoke(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_packet_size(0)
, m_recv_pos(0) , m_recv_pos(0)
, m_disk_recv_buffer_size(0) , m_disk_recv_buffer_size(0)
, m_disk_recv_buffer(0)
, m_reading_bytes(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_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_priority(1)
, m_upload_limit(bandwidth_limit::inf) , m_upload_limit(bandwidth_limit::inf)
, m_download_limit(bandwidth_limit::inf) , m_download_limit(bandwidth_limit::inf)
@ -116,13 +103,27 @@ namespace libtorrent
, m_connection_ticket(-1) , m_connection_ticket(-1)
, m_remote_bytes_dled(0) , m_remote_bytes_dled(0)
, m_remote_dl_rate(0) , m_remote_dl_rate(0)
, m_remote_dl_update(time_now())
, m_outstanding_writing_bytes(0) , m_outstanding_writing_bytes(0)
, m_fast_reconnect(false)
, m_rtt(0)
, m_downloaded_at_last_unchoke(0)
, m_download_rate_peak(0) , m_download_rate_peak(0)
, m_upload_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 #ifndef NDEBUG
, m_in_constructor(true) , m_in_constructor(true)
#endif #endif
@ -164,6 +165,7 @@ namespace libtorrent
peer_connection::peer_connection( peer_connection::peer_connection(
session_impl& ses session_impl& ses
, boost::shared_ptr<socket_type> s , boost::shared_ptr<socket_type> s
, tcp::endpoint const& endp
, policy::peer* peerinfo) , policy::peer* peerinfo)
: :
#ifndef NDEBUG #ifndef NDEBUG
@ -172,39 +174,27 @@ namespace libtorrent
#endif #endif
m_ses(ses) m_ses(ses)
, m_max_out_request_queue(m_ses.settings().max_out_request_queue) , 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_piece(time_now())
, m_last_request(time_now()) , m_last_request(time_now())
, m_last_incoming_request(min_time()) , m_last_incoming_request(min_time())
, m_last_unchoke(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_packet_size(0)
, m_recv_pos(0) , m_recv_pos(0)
, m_disk_recv_buffer_size(0) , m_disk_recv_buffer_size(0)
, m_disk_recv_buffer(0)
, m_reading_bytes(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_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_priority(1)
, m_upload_limit(bandwidth_limit::inf) , m_upload_limit(bandwidth_limit::inf)
, m_download_limit(bandwidth_limit::inf) , m_download_limit(bandwidth_limit::inf)
@ -213,13 +203,27 @@ namespace libtorrent
, m_connection_ticket(-1) , m_connection_ticket(-1)
, m_remote_bytes_dled(0) , m_remote_bytes_dled(0)
, m_remote_dl_rate(0) , m_remote_dl_rate(0)
, m_remote_dl_update(time_now())
, m_outstanding_writing_bytes(0) , m_outstanding_writing_bytes(0)
, m_fast_reconnect(false)
, m_rtt(0)
, m_downloaded_at_last_unchoke(0)
, m_download_rate_peak(0) , m_download_rate_peak(0)
, m_upload_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 #ifndef NDEBUG
, m_in_constructor(true) , m_in_constructor(true)
#endif #endif
@ -243,8 +247,8 @@ namespace libtorrent
#endif #endif
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
asio::error_code ec; error_code ec;
TORRENT_ASSERT(m_socket->remote_endpoint() == remote() || ec); TORRENT_ASSERT(m_socket->remote_endpoint(ec) == m_remote || ec);
m_logger = m_ses.create_log(remote().address().to_string(ec) + "_" m_logger = m_ses.create_log(remote().address().to_string(ec) + "_"
+ boost::lexical_cast<std::string>(remote().port()), m_ses.listen_port()); + boost::lexical_cast<std::string>(remote().port()), m_ses.listen_port());
(*m_logger) << "*** INCOMING CONNECTION\n"; (*m_logger) << "*** INCOMING CONNECTION\n";
@ -286,12 +290,13 @@ namespace libtorrent
void peer_connection::start() void peer_connection::start()
{ {
TORRENT_ASSERT(m_peer_info == 0 || m_peer_info->connection == this);
boost::shared_ptr<torrent> t = m_torrent.lock(); boost::shared_ptr<torrent> t = m_torrent.lock();
if (!t) if (!t)
{ {
tcp::socket::non_blocking_io ioc(true); tcp::socket::non_blocking_io ioc(true);
asio::error_code ec; error_code ec;
m_socket->io_control(ioc, ec); m_socket->io_control(ioc, ec);
if (ec) if (ec)
{ {
@ -439,7 +444,7 @@ namespace libtorrent
// if this is a web seed. we don't have a peer_info struct // if this is a web seed. we don't have a peer_info struct
if (m_peer_info) m_peer_info->seed = true; if (m_peer_info) m_peer_info->seed = true;
// if we're a seed too, disconnect // 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"); disconnect("seed to seed connection redundant");
return; return;
@ -476,12 +481,7 @@ namespace libtorrent
TORRENT_ASSERT(!m_in_constructor); TORRENT_ASSERT(!m_in_constructor);
TORRENT_ASSERT(m_disconnecting); TORRENT_ASSERT(m_disconnecting);
if (m_disk_recv_buffer) m_disk_recv_buffer_size = 0;
{
m_ses.free_disk_buffer(m_disk_recv_buffer);
m_disk_recv_buffer = 0;
m_disk_recv_buffer_size = 0;
}
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
if (m_logger) if (m_logger)
@ -616,6 +616,7 @@ namespace libtorrent
#endif #endif
} }
#endif #endif
if (is_disconnecting()) return;
if (peer_info_struct()) if (peer_info_struct())
{ {
@ -701,7 +702,7 @@ namespace libtorrent
(*m_logger) << " " << i->second->torrent_file().info_hash() << "\n"; (*m_logger) << " " << i->second->torrent_file().info_hash() << "\n";
} }
#endif #endif
disconnect("got invalid info-hash"); disconnect("got invalid info-hash", 2);
return; return;
} }
@ -785,6 +786,7 @@ namespace libtorrent
if ((*i)->on_choke()) return; if ((*i)->on_choke()) return;
} }
#endif #endif
if (is_disconnecting()) return;
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << time_now_string() << " <== CHOKE\n"; (*m_logger) << time_now_string() << " <== CHOKE\n";
@ -838,6 +840,8 @@ namespace libtorrent
} }
#endif #endif
if (is_disconnecting()) return;
std::deque<piece_block>::iterator i = std::find_if( std::deque<piece_block>::iterator i = std::find_if(
m_download_queue.begin(), m_download_queue.end() m_download_queue.begin(), m_download_queue.end()
, bind(match_request, boost::cref(r), _1, t->block_size())); , bind(match_request, boost::cref(r), _1, t->block_size()));
@ -921,6 +925,7 @@ namespace libtorrent
} }
#endif #endif
if (is_disconnecting()) return;
if (t->have_piece(index)) return; if (t->have_piece(index)) return;
if (m_suggested_pieces.size() > 9) if (m_suggested_pieces.size() > 9)
@ -956,6 +961,8 @@ namespace libtorrent
(*m_logger) << time_now_string() << " <== UNCHOKE\n"; (*m_logger) << time_now_string() << " <== UNCHOKE\n";
#endif #endif
m_peer_choked = false; m_peer_choked = false;
if (is_disconnecting()) return;
t->get_policy().unchoked(*this); t->get_policy().unchoked(*this);
} }
@ -982,6 +989,7 @@ namespace libtorrent
(*m_logger) << time_now_string() << " <== INTERESTED\n"; (*m_logger) << time_now_string() << " <== INTERESTED\n";
#endif #endif
m_peer_interested = true; m_peer_interested = true;
if (is_disconnecting()) return;
t->get_policy().interested(*this); t->get_policy().interested(*this);
} }
@ -1006,11 +1014,12 @@ namespace libtorrent
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << time_now_string() << " <== NOT_INTERESTED\n"; (*m_logger) << time_now_string() << " <== NOT_INTERESTED\n";
#endif #endif
m_peer_interested = false;
if (is_disconnecting()) return;
boost::shared_ptr<torrent> t = m_torrent.lock(); boost::shared_ptr<torrent> t = m_torrent.lock();
TORRENT_ASSERT(t); TORRENT_ASSERT(t);
m_peer_interested = false;
t->get_policy().not_interested(*this); t->get_policy().not_interested(*this);
} }
@ -1033,6 +1042,8 @@ namespace libtorrent
} }
#endif #endif
if (is_disconnecting()) return;
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << time_now_string() (*m_logger) << time_now_string()
<< " <== HAVE [ piece: " << index << "]\n"; << " <== HAVE [ piece: " << index << "]\n";
@ -1059,7 +1070,7 @@ namespace libtorrent
// if we got an invalid message, abort // if we got an invalid message, abort
if (index >= int(m_have_piece.size()) || index < 0) 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; return;
} }
@ -1099,11 +1110,11 @@ namespace libtorrent
} }
} }
if (is_seed()) if (upload_only())
{ {
TORRENT_ASSERT(m_peer_info); TORRENT_ASSERT(m_peer_info);
m_peer_info->seed = true; if (is_seed()) m_peer_info->seed = true;
if (t->is_finished()) if (t->is_finished() && m_ses.settings().close_redundant_connections)
{ {
disconnect("seed to seed connection redundant"); disconnect("seed to seed connection redundant");
return; return;
@ -1131,6 +1142,8 @@ namespace libtorrent
} }
#endif #endif
if (is_disconnecting()) return;
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << time_now_string() << " <== BITFIELD "; (*m_logger) << time_now_string() << " <== BITFIELD ";
@ -1151,7 +1164,7 @@ namespace libtorrent
msg << "got bitfield with invalid size: " << (bitfield.size() / 8) msg << "got bitfield with invalid size: " << (bitfield.size() / 8)
<< "bytes. expected: " << (m_have_piece.size() / 8) << "bytes. expected: " << (m_have_piece.size() / 8)
<< " bytes"; << " bytes";
disconnect(msg.str().c_str()); disconnect(msg.str().c_str(), 2);
return; return;
} }
@ -1178,7 +1191,7 @@ namespace libtorrent
// if this is a web seed. we don't have a peer_info struct // if this is a web seed. we don't have a peer_info struct
if (m_peer_info) m_peer_info->seed = true; if (m_peer_info) m_peer_info->seed = true;
// if we're a seed too, disconnect // 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"); disconnect("seed to seed connection redundant, disconnecting");
return; return;
@ -1220,6 +1233,7 @@ namespace libtorrent
m_num_pieces = num_pieces; m_num_pieces = num_pieces;
if (interesting) t->get_policy().peer_is_interesting(*this); 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; if ((*i)->on_request(r)) return;
} }
#endif #endif
if (is_disconnecting()) return;
if (!t->valid_metadata()) if (!t->valid_metadata())
{ {
@ -1426,7 +1441,7 @@ namespace libtorrent
boost::shared_ptr<torrent> t = m_torrent.lock(); boost::shared_ptr<torrent> t = m_torrent.lock();
TORRENT_ASSERT(t); TORRENT_ASSERT(t);
TORRENT_ASSERT(m_disk_recv_buffer == 0); TORRENT_ASSERT(!m_disk_recv_buffer);
TORRENT_ASSERT(m_disk_recv_buffer_size == 0); TORRENT_ASSERT(m_disk_recv_buffer_size == 0);
#ifndef TORRENT_DISABLE_EXTENSIONS #ifndef TORRENT_DISABLE_EXTENSIONS
@ -1436,6 +1451,7 @@ namespace libtorrent
if ((*i)->on_piece(p, data)) return; if ((*i)->on_piece(p, data)) return;
} }
#endif #endif
if (is_disconnecting()) return;
#ifndef NDEBUG #ifndef NDEBUG
check_postcondition post_checker_(t); check_postcondition post_checker_(t);
@ -1461,7 +1477,7 @@ namespace libtorrent
"start: " << p.start << " | " "start: " << p.start << " | "
"length: " << p.length << " ]\n"; "length: " << p.length << " ]\n";
#endif #endif
disconnect("got invalid piece packet"); disconnect("got invalid piece packet", 2);
return; return;
} }
@ -1648,6 +1664,7 @@ namespace libtorrent
if ((*i)->on_cancel(r)) return; if ((*i)->on_cancel(r)) return;
} }
#endif #endif
if (is_disconnecting()) return;
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << time_now_string() (*m_logger) << time_now_string()
@ -1717,6 +1734,7 @@ namespace libtorrent
if ((*i)->on_have_all()) return; if ((*i)->on_have_all()) return;
} }
#endif #endif
if (is_disconnecting()) return;
m_have_all = true; m_have_all = true;
@ -1739,7 +1757,7 @@ namespace libtorrent
#endif #endif
// if we're a seed too, disconnect // 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"); disconnect("seed to seed connection redundant, disconnecting");
return; return;
@ -1762,13 +1780,13 @@ namespace libtorrent
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
boost::shared_ptr<torrent> t = m_torrent.lock();
TORRENT_ASSERT(t);
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << time_now_string() << " <== HAVE_NONE\n"; (*m_logger) << time_now_string() << " <== HAVE_NONE\n";
#endif #endif
boost::shared_ptr<torrent> t = m_torrent.lock();
TORRENT_ASSERT(t);
#ifndef TORRENT_DISABLE_EXTENSIONS #ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin() for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i) , end(m_extensions.end()); i != end; ++i)
@ -1776,8 +1794,9 @@ namespace libtorrent
if ((*i)->on_have_none()) return; if ((*i)->on_have_none()) return;
} }
#endif #endif
if (is_disconnecting()) return;
if (m_peer_info) m_peer_info->seed = false; if (m_peer_info) m_peer_info->seed = false;
TORRENT_ASSERT(!m_have_piece.empty() || !t->ready_for_connections()); TORRENT_ASSERT(!m_have_piece.empty() || !t->ready_for_connections());
} }
@ -1803,6 +1822,7 @@ namespace libtorrent
if ((*i)->on_allowed_fast(index)) return; if ((*i)->on_allowed_fast(index)) return;
} }
#endif #endif
if (is_disconnecting()) return;
if (index < 0 || index >= int(m_have_piece.size())) if (index < 0 || index >= int(m_have_piece.size()))
{ {
@ -2109,6 +2129,7 @@ namespace libtorrent
{ {
if (handled = (*i)->write_request(r)) break; if (handled = (*i)->write_request(r)) break;
} }
if (is_disconnecting()) return;
if (!handled) if (!handled)
{ {
write_request(r); write_request(r);
@ -2141,24 +2162,38 @@ namespace libtorrent
(*m_ses.m_logger) << time_now_string() << " CONNECTION TIMED OUT: " << m_remote.address().to_string() (*m_ses.m_logger) << time_now_string() << " CONNECTION TIMED OUT: " << m_remote.address().to_string()
<< "\n"; << "\n";
#endif #endif
set_failed(); disconnect("timed out: connect", 1);
disconnect("timed out");
} }
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); session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING #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 #endif
// we cannot do this in a constructor // we cannot do this in a constructor
TORRENT_ASSERT(m_in_constructor == false); TORRENT_ASSERT(m_in_constructor == false);
if (error > 0) m_failed = true;
if (m_disconnecting) return;
boost::intrusive_ptr<peer_connection> me(this); boost::intrusive_ptr<peer_connection> me(this);
INVARIANT_CHECK; INVARIANT_CHECK;
if (m_disconnecting) return;
if (m_connecting && m_connection_ticket >= 0) if (m_connecting && m_connection_ticket >= 0)
{ {
m_ses.m_half_open.done(m_connection_ticket); m_ses.m_half_open.done(m_connection_ticket);
@ -2167,13 +2202,18 @@ namespace libtorrent
boost::shared_ptr<torrent> t = m_torrent.lock(); boost::shared_ptr<torrent> t = m_torrent.lock();
if (message && m_ses.m_alerts.should_post(alert::debug)) if (message)
{ {
m_ses.m_alerts.post_alert( if (error > 1 && m_ses.m_alerts.should_post(alert::info))
peer_error_alert( {
remote() m_ses.m_alerts.post_alert(
, pid() peer_error_alert(remote(), pid(), message));
, 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) if (t)
@ -2207,7 +2247,7 @@ namespace libtorrent
#endif #endif
m_disconnecting = true; m_disconnecting = true;
asio::error_code ec; error_code ec;
m_socket->close(ec); m_socket->close(ec);
m_ses.close_connection(this, message); m_ses.close_connection(this, message);
} }
@ -2372,17 +2412,17 @@ namespace libtorrent
TORRENT_ASSERT(m_packet_size > 0); TORRENT_ASSERT(m_packet_size > 0);
TORRENT_ASSERT(m_recv_pos <= m_packet_size - disk_buffer_size); 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); TORRENT_ASSERT(disk_buffer_size <= 16 * 1024);
if (disk_buffer_size > 16 * 1024) if (disk_buffer_size > 16 * 1024)
{ {
disconnect("invalid piece size"); disconnect("invalid piece size", 2);
return false; return false;
} }
m_disk_recv_buffer = m_ses.allocate_disk_buffer(); m_disk_recv_buffer.reset(m_ses.allocate_disk_buffer());
if (m_disk_recv_buffer == 0) if (!m_disk_recv_buffer)
{ {
disconnect("out of memory"); disconnect("out of memory");
return false; return false;
@ -2393,10 +2433,8 @@ namespace libtorrent
char* peer_connection::release_disk_receive_buffer() char* peer_connection::release_disk_receive_buffer()
{ {
char* ret = m_disk_recv_buffer;
m_disk_recv_buffer = 0;
m_disk_recv_buffer_size = 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) void peer_connection::cut_receive_buffer(int size, int packet_size)
@ -2420,11 +2458,17 @@ namespace libtorrent
m_packet_size = packet_size; m_packet_size = packet_size;
} }
void peer_connection::calc_ip_overhead()
{
m_statistics.calc_ip_overhead();
}
void peer_connection::second_tick(float tick_interval) void peer_connection::second_tick(float tick_interval)
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
ptime now(time_now()); ptime now(time_now());
boost::intrusive_ptr<peer_connection> me(self());
boost::shared_ptr<torrent> t = m_torrent.lock(); boost::shared_ptr<torrent> t = m_torrent.lock();
if (!t || m_disconnecting) if (!t || m_disconnecting)
@ -2466,6 +2510,7 @@ namespace libtorrent
} }
#endif #endif
} }
if (is_disconnecting()) return;
if (!t->valid_metadata()) return; if (!t->valid_metadata()) return;
@ -2829,7 +2874,7 @@ namespace libtorrent
if (int(m_recv_buffer.size()) < regular_buffer_size) if (int(m_recv_buffer.size()) < regular_buffer_size)
m_recv_buffer.resize(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 // only receive into regular buffer
TORRENT_ASSERT(m_recv_pos + max_receive <= int(m_recv_buffer.size())); TORRENT_ASSERT(m_recv_pos + max_receive <= int(m_recv_buffer.size()));
@ -2841,7 +2886,7 @@ namespace libtorrent
// only receive into disk buffer // only receive into disk buffer
TORRENT_ASSERT(m_recv_pos - regular_buffer_size >= 0); TORRENT_ASSERT(m_recv_pos - regular_buffer_size >= 0);
TORRENT_ASSERT(m_recv_pos - regular_buffer_size + max_receive <= m_disk_recv_buffer_size); 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) , max_receive)
, bind(&peer_connection::on_receive_data, self(), _1, _2)); , bind(&peer_connection::on_receive_data, self(), _1, _2));
} }
@ -2856,7 +2901,7 @@ namespace libtorrent
boost::array<asio::mutable_buffer, 2> vec; boost::array<asio::mutable_buffer, 2> vec;
vec[0] = asio::buffer(&m_recv_buffer[m_recv_pos] vec[0] = asio::buffer(&m_recv_buffer[m_recv_pos]
, regular_buffer_size - 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); , max_receive - regular_buffer_size + m_recv_pos);
m_socket->async_read_some(vec, bind(&peer_connection::on_receive_data m_socket->async_read_some(vec, bind(&peer_connection::on_receive_data
, self(), _1, _2)); , self(), _1, _2));
@ -2874,7 +2919,7 @@ namespace libtorrent
std::pair<buffer::interval, buffer::interval> vec; std::pair<buffer::interval, buffer::interval> vec;
int regular_buffer_size = m_packet_size - m_disk_recv_buffer_size; int regular_buffer_size = m_packet_size - m_disk_recv_buffer_size;
TORRENT_ASSERT(regular_buffer_size >= 0); 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] vec.first = buffer::interval(&m_recv_buffer[0]
+ m_recv_pos - bytes, &m_recv_buffer[0] + m_recv_pos); + 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) else if (m_recv_pos - bytes >= regular_buffer_size)
{ {
vec.first = buffer::interval(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 + m_recv_pos - regular_buffer_size - bytes, m_disk_recv_buffer.get() + m_recv_pos
- regular_buffer_size); - regular_buffer_size);
vec.second = buffer::interval(0,0); vec.second = buffer::interval(0,0);
} }
@ -2893,8 +2938,8 @@ namespace libtorrent
TORRENT_ASSERT(m_recv_pos > regular_buffer_size); TORRENT_ASSERT(m_recv_pos > regular_buffer_size);
vec.first = buffer::interval(&m_recv_buffer[0] + m_recv_pos - bytes vec.first = buffer::interval(&m_recv_buffer[0] + m_recv_pos - bytes
, &m_recv_buffer[0] + regular_buffer_size); , &m_recv_buffer[0] + regular_buffer_size);
vec.second = buffer::interval(m_disk_recv_buffer vec.second = buffer::interval(m_disk_recv_buffer.get()
, m_disk_recv_buffer + m_recv_pos - regular_buffer_size); , m_disk_recv_buffer.get() + m_recv_pos - regular_buffer_size);
} }
TORRENT_ASSERT(vec.first.left() + vec.second.left() == bytes); TORRENT_ASSERT(vec.first.left() + vec.second.left() == bytes);
return vec; return vec;
@ -2998,7 +3043,7 @@ namespace libtorrent
// -------------------------- // --------------------------
// throws exception when the client should be disconnected // 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) , std::size_t bytes_transferred)
{ {
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
@ -3014,7 +3059,6 @@ namespace libtorrent
(*m_logger) << time_now_string() << " **ERROR**: " (*m_logger) << time_now_string() << " **ERROR**: "
<< error.message() << "[in peer_connection::on_receive_data]\n"; << error.message() << "[in peer_connection::on_receive_data]\n";
#endif #endif
set_failed();
on_receive(error, bytes_transferred); on_receive(error, bytes_transferred);
disconnect(error.message().c_str()); disconnect(error.message().c_str());
return; return;
@ -3063,8 +3107,8 @@ namespace libtorrent
if (int(m_recv_buffer.size()) < regular_buffer_size) if (int(m_recv_buffer.size()) < regular_buffer_size)
m_recv_buffer.resize(regular_buffer_size); m_recv_buffer.resize(regular_buffer_size);
asio::error_code ec; error_code ec;
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 // only receive into regular buffer
TORRENT_ASSERT(m_recv_pos + max_receive <= int(m_recv_buffer.size())); TORRENT_ASSERT(m_recv_pos + max_receive <= int(m_recv_buffer.size()));
@ -3076,7 +3120,7 @@ namespace libtorrent
// only receive into disk buffer // only receive into disk buffer
TORRENT_ASSERT(m_recv_pos - regular_buffer_size >= 0); TORRENT_ASSERT(m_recv_pos - regular_buffer_size >= 0);
TORRENT_ASSERT(m_recv_pos - regular_buffer_size + max_receive <= m_disk_recv_buffer_size); 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 - regular_buffer_size, (std::min)(m_packet_size
- m_recv_pos, max_receive)), ec); - m_recv_pos, max_receive)), ec);
} }
@ -3091,7 +3135,7 @@ namespace libtorrent
boost::array<asio::mutable_buffer, 2> vec; boost::array<asio::mutable_buffer, 2> vec;
vec[0] = asio::buffer(&m_recv_buffer[m_recv_pos] vec[0] = asio::buffer(&m_recv_buffer[m_recv_pos]
, regular_buffer_size - 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 , (std::min)(m_disk_recv_buffer_size
, max_receive - regular_buffer_size + m_recv_pos)); , max_receive - regular_buffer_size + m_recv_pos));
bytes_transferred = m_socket->read_some(vec, ec); bytes_transferred = m_socket->read_some(vec, ec);
@ -3107,27 +3151,6 @@ namespace libtorrent
setup_receive(); setup_receive();
} }
/*
catch (file_error& e)
{
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
boost::shared_ptr<torrent> 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 bool peer_connection::can_write() const
{ {
@ -3158,7 +3181,7 @@ namespace libtorrent
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
asio::error_code ec; error_code ec;
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING #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_ses.m_logger) << time_now_string() << " CONNECTING: " << m_remote.address().to_string(ec)
<< ":" << m_remote.port() << "\n"; << ":" << 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(); ptime completed = time_now();
@ -3230,8 +3253,7 @@ namespace libtorrent
(*m_ses.m_logger) << time_now_string() << " CONNECTION FAILED: " << m_remote.address().to_string() (*m_ses.m_logger) << time_now_string() << " CONNECTION FAILED: " << m_remote.address().to_string()
<< ": " << e.message() << "\n"; << ": " << e.message() << "\n";
#endif #endif
set_failed(); disconnect(e.message().c_str(), 1);
disconnect(e.message().c_str());
return; return;
} }
@ -3247,7 +3269,7 @@ namespace libtorrent
if (m_remote.address().is_v4()) 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); 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 // 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) , std::size_t bytes_transferred)
{ {
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); 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 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
(*m_logger) << "**ERROR**: " << error.message() << " [in peer_connection::on_send_data]\n"; (*m_logger) << "**ERROR**: " << error.message() << " [in peer_connection::on_send_data]\n";
#endif #endif
set_failed();
disconnect(error.message().c_str()); disconnect(error.message().c_str());
return; return;
} }
@ -3306,7 +3327,7 @@ namespace libtorrent
#ifndef NDEBUG #ifndef NDEBUG
void peer_connection::check_invariant() const 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<torrent> t = m_torrent.lock(); boost::shared_ptr<torrent> t = m_torrent.lock();
if (m_disconnecting) if (m_disconnecting)

View File

@ -133,22 +133,8 @@ namespace libtorrent
{ {
int index = static_cast<int>(i - pieces.begin()); int index = static_cast<int>(i - pieces.begin());
piece_pos& p = m_piece_map[index]; piece_pos& p = m_piece_map[index];
if (*i) if (*i) we_have(index);
{ else TORRENT_ASSERT(p.index == 0);
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;
}
} }
} }

View File

@ -225,7 +225,7 @@ namespace libtorrent
// blocks be from whole pieces, possibly by returning more blocks // blocks be from whole pieces, possibly by returning more blocks
// than we requested. // than we requested.
#ifndef NDEBUG #ifndef NDEBUG
asio::error_code ec; error_code ec;
TORRENT_ASSERT(c.remote() == c.get_socket()->remote_endpoint(ec) || ec); TORRENT_ASSERT(c.remote() == c.get_socket()->remote_endpoint(ec) || ec);
#endif #endif
@ -348,6 +348,7 @@ namespace libtorrent
, m_torrent(t) , m_torrent(t)
, m_available_free_upload(0) , m_available_free_upload(0)
, m_num_connect_candidates(0) , m_num_connect_candidates(0)
, m_num_seeds(0)
{ TORRENT_ASSERT(t); } { TORRENT_ASSERT(t); }
// disconnects and removes all peers that are now filtered // disconnects and removes all peers that are now filtered
@ -420,49 +421,6 @@ namespace libtorrent
return true; return true;
} }
policy::iterator policy::find_disconnect_candidate()
{
INVARIANT_CHECK;
iterator disconnect_peer = m_peers.end();
double slowest_transfer_rate = (std::numeric_limits<double>::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() policy::iterator policy::find_connect_candidate()
{ {
// too expensive // too expensive
@ -625,7 +583,7 @@ namespace libtorrent
// TODO: only allow _one_ connection to use this // TODO: only allow _one_ connection to use this
// override at a time // override at a time
asio::error_code ec; error_code ec;
TORRENT_ASSERT(c.remote() == c.get_socket()->remote_endpoint(ec) || ec); TORRENT_ASSERT(c.remote() == c.get_socket()->remote_endpoint(ec) || ec);
aux::session_impl& ses = m_torrent->session(); aux::session_impl& ses = m_torrent->session();
@ -697,7 +655,7 @@ namespace libtorrent
{ {
// we don't have any info about this peer. // we don't have any info about this peer.
// add a new entry // add a new entry
asio::error_code ec; error_code ec;
TORRENT_ASSERT(c.remote() == c.get_socket()->remote_endpoint(ec) || ec); TORRENT_ASSERT(c.remote() == c.get_socket()->remote_endpoint(ec) || ec);
peer p(c.remote(), peer::not_connectable, 0); peer p(c.remote(), peer::not_connectable, 0);
@ -1073,19 +1031,6 @@ namespace libtorrent
return true; 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 // this is called whenever a peer connection is closed
void policy::connection_closed(const peer_connection& c) void policy::connection_closed(const peer_connection& c)
{ {
@ -1156,7 +1101,7 @@ namespace libtorrent
// INVARIANT_CHECK; // INVARIANT_CHECK;
TORRENT_ASSERT(c); TORRENT_ASSERT(c);
asio::error_code ec; error_code ec;
TORRENT_ASSERT(c->remote() == c->get_socket()->remote_endpoint(ec) || ec); TORRENT_ASSERT(c->remote() == c->get_socket()->remote_endpoint(ec) || ec);
return std::find_if( return std::find_if(

View File

@ -253,7 +253,6 @@ namespace libtorrent
, bool paused , bool paused
, storage_constructor_type sc) , storage_constructor_type sc)
{ {
TORRENT_ASSERT(!ti.m_half_metadata);
boost::intrusive_ptr<torrent_info> tip(new torrent_info(ti)); boost::intrusive_ptr<torrent_info> tip(new torrent_info(ti));
add_torrent_params p(sc); add_torrent_params p(sc);
p.ti = tip; p.ti = tip;
@ -273,7 +272,6 @@ namespace libtorrent
, storage_constructor_type sc , storage_constructor_type sc
, void* userdata) , void* userdata)
{ {
TORRENT_ASSERT(!ti->m_half_metadata);
add_torrent_params p(sc); add_torrent_params p(sc);
p.ti = ti; p.ti = ti;
p.save_path = save_path; p.save_path = save_path;

View File

@ -76,6 +76,10 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/enum_net.hpp" #include "libtorrent/enum_net.hpp"
#include "libtorrent/config.hpp" #include "libtorrent/config.hpp"
#ifndef TORRENT_WINDOWS
#include <sys/resource.h>
#endif
#ifndef TORRENT_DISABLE_ENCRYPTION #ifndef TORRENT_DISABLE_ENCRYPTION
#include <openssl/crypto.h> #include <openssl/crypto.h>
@ -162,6 +166,7 @@ namespace aux {
, m_auto_manage_time_scaler(0) , m_auto_manage_time_scaler(0)
, m_optimistic_unchoke_time_scaler(0) , m_optimistic_unchoke_time_scaler(0)
, m_disconnect_time_scaler(90) , m_disconnect_time_scaler(90)
, m_auto_scrape_time_scaler(180)
, m_incoming_connection(false) , m_incoming_connection(false)
, m_last_tick(time_now()) , m_last_tick(time_now())
, m_torrent_sequence(0) , m_torrent_sequence(0)
@ -207,6 +212,11 @@ namespace aux {
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
m_logger = create_log("main_session", listen_port(), false); m_logger = create_log("main_session", listen_port(), false);
(*m_logger) << time_now_string() << "\n"; (*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 #endif
#ifdef TORRENT_STATS #ifdef TORRENT_STATS
@ -250,7 +260,7 @@ namespace aux {
*i = printable[rand() % (sizeof(printable)-1)]; *i = printable[rand() % (sizeof(printable)-1)];
} }
asio::error_code ec; error_code ec;
m_timer.expires_from_now(seconds(1), ec); m_timer.expires_from_now(seconds(1), ec);
m_timer.async_wait( m_timer.async_wait(
bind(&session_impl::second_tick, this, _1)); bind(&session_impl::second_tick, this, _1));
@ -396,7 +406,7 @@ namespace aux {
if (m_dht) m_dht->stop(); if (m_dht) m_dht->stop();
m_dht_socket.close(); m_dht_socket.close();
#endif #endif
asio::error_code ec; error_code ec;
m_timer.cancel(ec); m_timer.cancel(ec);
// close the listen sockets // close the listen sockets
@ -535,7 +545,7 @@ namespace aux {
session_impl::listen_socket_t session_impl::setup_listener(tcp::endpoint ep session_impl::listen_socket_t session_impl::setup_listener(tcp::endpoint ep
, int retries, bool v6_only) , int retries, bool v6_only)
{ {
asio::error_code ec; error_code ec;
listen_socket_t s; listen_socket_t s;
s.sock.reset(new socket_acceptor(m_io_service)); s.sock.reset(new socket_acceptor(m_io_service));
s.sock->open(ep.protocol(), ec); s.sock->open(ep.protocol(), ec);
@ -544,7 +554,7 @@ namespace aux {
s.sock->bind(ep, ec); s.sock->bind(ep, ec);
while (ec && retries > 0) while (ec && retries > 0)
{ {
ec = asio::error_code(); ec = error_code();
TORRENT_ASSERT(!ec); TORRENT_ASSERT(!ec);
--retries; --retries;
ep.port(ep.port() + 1); ep.port(ep.port() + 1);
@ -555,7 +565,7 @@ namespace aux {
// instead of giving up, try // instead of giving up, try
// let the OS pick a port // let the OS pick a port
ep.port(0); ep.port(0);
ec = asio::error_code(); ec = error_code();
s.sock->bind(ep, ec); s.sock->bind(ep, ec);
} }
if (ec) if (ec)
@ -661,7 +671,7 @@ namespace aux {
for (std::list<listen_socket_t>::const_iterator i = m_listen_sockets.begin() for (std::list<listen_socket_t>::const_iterator i = m_listen_sockets.begin()
, end(m_listen_sockets.end()); i != end; ++i) , end(m_listen_sockets.end()); i != end; ++i)
{ {
asio::error_code ec; error_code ec;
tcp::endpoint ep = i->sock->local_endpoint(ec); tcp::endpoint ep = i->sock->local_endpoint(ec);
if (ec || ep.address().is_v4()) continue; if (ec || ep.address().is_v4()) continue;
@ -691,7 +701,7 @@ namespace aux {
if (!m_listen_sockets.empty()) if (!m_listen_sockets.empty())
{ {
asio::error_code ec; error_code ec;
tcp::endpoint local = m_listen_sockets.front().sock->local_endpoint(ec); tcp::endpoint local = m_listen_sockets.front().sock->local_endpoint(ec);
if (!ec) if (!ec)
{ {
@ -713,11 +723,16 @@ namespace aux {
#ifndef TORRENT_DISABLE_DHT #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) , udp::endpoint const& ep, char const* buf, int len)
{ {
if (e) 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)) if (m_alerts.should_post(alert::info))
{ {
std::string msg = "UDP socket error from '" std::string msg = "UDP socket error from '"
@ -746,7 +761,7 @@ namespace aux {
} }
void session_impl::on_incoming_connection(shared_ptr<socket_type> const& s void session_impl::on_incoming_connection(shared_ptr<socket_type> const& s
, weak_ptr<socket_acceptor> listen_socket, asio::error_code const& e) , weak_ptr<socket_acceptor> listen_socket, error_code const& e)
{ {
boost::shared_ptr<socket_acceptor> listener = listen_socket.lock(); boost::shared_ptr<socket_acceptor> listener = listen_socket.lock();
if (!listener) return; if (!listener) return;
@ -756,7 +771,7 @@ namespace aux {
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
if (m_abort) return; if (m_abort) return;
asio::error_code ec; error_code ec;
if (e) if (e)
{ {
tcp::endpoint ep = listener->local_endpoint(ec); tcp::endpoint ep = listener->local_endpoint(ec);
@ -842,7 +857,13 @@ namespace aux {
// check if we have any active torrents // check if we have any active torrents
// if we don't reject the connection // 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; bool has_active_torrent = false;
for (torrent_map::iterator i = m_torrents.begin() for (torrent_map::iterator i = m_torrents.begin()
@ -854,10 +875,16 @@ namespace aux {
break; 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<peer_connection> c( boost::intrusive_ptr<peer_connection> c(
new bt_peer_connection(*this, s, 0)); new bt_peer_connection(*this, s, endp, 0));
#ifndef NDEBUG #ifndef NDEBUG
c->m_in_constructor = false; c->m_in_constructor = false;
#endif #endif
@ -926,7 +953,7 @@ namespace aux {
return port; 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); 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; float tick_interval = total_microseconds(time_now() - m_last_tick) / 1000000.f;
m_last_tick = time_now(); m_last_tick = time_now();
asio::error_code ec; error_code ec;
m_timer.expires_from_now(seconds(1), ec); m_timer.expires_from_now(seconds(1), ec);
m_timer.async_wait( m_timer.async_wait(
bind(&session_impl::second_tick, this, _1)); bind(&session_impl::second_tick, this, _1));
@ -986,7 +1013,6 @@ namespace aux {
<< m_disk_thread.disk_allocations() << "\t" << m_disk_thread.disk_allocations() << "\t"
<< std::endl; << std::endl;
#endif #endif
// -------------------------------------------------------------- // --------------------------------------------------------------
// second_tick every torrent // second_tick every torrent
// -------------------------------------------------------------- // --------------------------------------------------------------
@ -1002,6 +1028,9 @@ namespace aux {
// count the number of peers of downloading torrents // count the number of peers of downloading torrents
int num_downloads_peers = 0; 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 // check each torrent for tracker updates
// TODO: do this in a timer-event in each torrent instead // TODO: do this in a timer-event in each torrent instead
for (torrent_map::iterator i = m_torrents.begin(); for (torrent_map::iterator i = m_torrents.begin();
@ -1014,6 +1043,17 @@ namespace aux {
else else
++uncongested_torrents; ++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()) if (t.is_finished())
{ {
++num_seeds; ++num_seeds;
@ -1046,9 +1086,29 @@ namespace aux {
++i; ++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); 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 // connect new peers
// -------------------------------------------------------------- // --------------------------------------------------------------
@ -1156,20 +1216,10 @@ namespace aux {
peer_connection& c = *j->get(); peer_connection& c = *j->get();
if (c.has_timed_out()) 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) #if defined(TORRENT_VERBOSE_LOGGING)
(*c.m_logger) << "*** CONNECTION TIMED OUT\n"; (*c.m_logger) << "*** CONNECTION TIMED OUT\n";
#endif #endif
c.disconnect("timed out: inactive", 1);
c.set_failed();
c.disconnect("timed out");
continue; continue;
} }
@ -1205,17 +1255,37 @@ namespace aux {
{ {
m_disconnect_time_scaler = 90; 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 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() 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, _1))
< bind(&torrent::num_peers, bind(&torrent_map::value_type::second, _2))); < bind(&torrent::num_peers, bind(&torrent_map::value_type::second, _2)));
TORRENT_ASSERT(i != m_torrents.end()); TORRENT_ASSERT(i != m_torrents.end());
// TODO: make the number of peers a percentage of the number of connected peers int peers_to_disconnect = (std::min)((std::max)(int(i->second->num_peers()
i->second->get_policy().disconnect_one_peer(); * 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<torrent> 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)); , bind(&torrent::sequence_number, _1) < bind(&torrent::sequence_number, _2));
std::sort(seeds.begin(), seeds.end() std::sort(seeds.begin(), seeds.end()
, bind(&torrent::seed_cycles_int, _1, boost::ref(m_settings)) , bind(&torrent::seed_rank, _1, boost::ref(m_settings))
< bind(&torrent::seed_cycles_int, _2, boost::ref(m_settings))); > bind(&torrent::seed_rank, _2, boost::ref(m_settings)));
} }
for (std::vector<torrent*>::iterator i = downloaders.begin() for (std::vector<torrent*>::iterator i = downloaders.begin()
@ -2111,7 +2181,19 @@ namespace aux {
INVARIANT_CHECK; INVARIANT_CHECK;
if (limit <= 0) limit = (std::numeric_limits<int>::max)(); if (limit <= 0)
{
limit = (std::numeric_limits<int>::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; m_max_connections = limit;
} }

View File

@ -37,13 +37,13 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent 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<handler_type> h) , boost::shared_ptr<handler_type> h)
{ {
if (e) if (e)
{ {
(*h)(e); (*h)(e);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
@ -54,7 +54,7 @@ namespace libtorrent
if (i == tcp::resolver::iterator()) if (i == tcp::resolver::iterator())
{ {
asio::error_code ec = asio::error::operation_not_supported; error_code ec = asio::error::operation_not_supported;
(*h)(ec); (*h)(ec);
close(ec); close(ec);
return; return;
@ -64,12 +64,12 @@ namespace libtorrent
&socks4_stream::connected, this, _1, h)); &socks4_stream::connected, this, _1, h));
} }
void socks4_stream::connected(asio::error_code const& e, boost::shared_ptr<handler_type> h) void socks4_stream::connected(error_code const& e, boost::shared_ptr<handler_type> h)
{ {
if (e) if (e)
{ {
(*h)(e); (*h)(e);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
@ -86,31 +86,31 @@ namespace libtorrent
p += m_user.size(); p += m_user.size();
write_uint8(0, p); // NULL terminator 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)); , boost::bind(&socks4_stream::handshake1, this, _1, h));
} }
void socks4_stream::handshake1(asio::error_code const& e, boost::shared_ptr<handler_type> h) void socks4_stream::handshake1(error_code const& e, boost::shared_ptr<handler_type> h)
{ {
if (e) if (e)
{ {
(*h)(e); (*h)(e);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
m_buffer.resize(8); 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)); , boost::bind(&socks4_stream::handshake2, this, _1, h));
} }
void socks4_stream::handshake2(asio::error_code const& e, boost::shared_ptr<handler_type> h) void socks4_stream::handshake2(error_code const& e, boost::shared_ptr<handler_type> h)
{ {
if (e) if (e)
{ {
(*h)(e); (*h)(e);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
@ -123,7 +123,7 @@ namespace libtorrent
if (reply_version != 0) if (reply_version != 0)
{ {
asio::error_code ec = asio::error::operation_not_supported; error_code ec = asio::error::operation_not_supported;
(*h)(ec); (*h)(ec);
close(ec); close(ec);
return; return;
@ -137,7 +137,7 @@ namespace libtorrent
return; return;
} }
asio::error_code ec = asio::error::fault; error_code ec = asio::error::fault;
switch (status_code) switch (status_code)
{ {
case 91: ec = asio::error::connection_refused; break; case 91: ec = asio::error::connection_refused; break;

View File

@ -38,13 +38,13 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent 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<handler_type> h) , boost::shared_ptr<handler_type> h)
{ {
if (e || i == tcp::resolver::iterator()) if (e || i == tcp::resolver::iterator())
{ {
(*h)(e); (*h)(e);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
@ -53,12 +53,12 @@ namespace libtorrent
&socks5_stream::connected, this, _1, h)); &socks5_stream::connected, this, _1, h));
} }
void socks5_stream::connected(asio::error_code const& e, boost::shared_ptr<handler_type> h) void socks5_stream::connected(error_code const& e, boost::shared_ptr<handler_type> h)
{ {
if (e) if (e)
{ {
(*h)(e); (*h)(e);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
@ -79,31 +79,31 @@ namespace libtorrent
write_uint8(0, p); // no authentication write_uint8(0, p); // no authentication
write_uint8(2, p); // username/password 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)); , boost::bind(&socks5_stream::handshake1, this, _1, h));
} }
void socks5_stream::handshake1(asio::error_code const& e, boost::shared_ptr<handler_type> h) void socks5_stream::handshake1(error_code const& e, boost::shared_ptr<handler_type> h)
{ {
if (e) if (e)
{ {
(*h)(e); (*h)(e);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
m_buffer.resize(2); 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)); , boost::bind(&socks5_stream::handshake2, this, _1, h));
} }
void socks5_stream::handshake2(asio::error_code const& e, boost::shared_ptr<handler_type> h) void socks5_stream::handshake2(error_code const& e, boost::shared_ptr<handler_type> h)
{ {
if (e) if (e)
{ {
(*h)(e); (*h)(e);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
@ -117,7 +117,7 @@ namespace libtorrent
if (version < 5) if (version < 5)
{ {
(*h)(asio::error::operation_not_supported); (*h)(asio::error::operation_not_supported);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
@ -131,7 +131,7 @@ namespace libtorrent
if (m_user.empty()) if (m_user.empty())
{ {
(*h)(asio::error::operation_not_supported); (*h)(asio::error::operation_not_supported);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
@ -144,41 +144,41 @@ namespace libtorrent
write_string(m_user, p); write_string(m_user, p);
write_uint8(m_password.size(), p); write_uint8(m_password.size(), p);
write_string(m_password, 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)); , boost::bind(&socks5_stream::handshake3, this, _1, h));
} }
else else
{ {
(*h)(asio::error::operation_not_supported); (*h)(asio::error::operation_not_supported);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
} }
void socks5_stream::handshake3(asio::error_code const& e void socks5_stream::handshake3(error_code const& e
, boost::shared_ptr<handler_type> h) , boost::shared_ptr<handler_type> h)
{ {
if (e) if (e)
{ {
(*h)(e); (*h)(e);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
m_buffer.resize(2); 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)); , 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<handler_type> h) , boost::shared_ptr<handler_type> h)
{ {
if (e) if (e)
{ {
(*h)(e); (*h)(e);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
@ -192,7 +192,7 @@ namespace libtorrent
if (version != 1) if (version != 1)
{ {
(*h)(asio::error::operation_not_supported); (*h)(asio::error::operation_not_supported);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
@ -200,7 +200,7 @@ namespace libtorrent
if (status != 0) if (status != 0)
{ {
(*h)(asio::error::operation_not_supported); (*h)(asio::error::operation_not_supported);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
@ -223,31 +223,31 @@ namespace libtorrent
write_endpoint(m_remote_endpoint, p); write_endpoint(m_remote_endpoint, p);
TORRENT_ASSERT(p - &m_buffer[0] == int(m_buffer.size())); 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)); , boost::bind(&socks5_stream::connect1, this, _1, h));
} }
void socks5_stream::connect1(asio::error_code const& e, boost::shared_ptr<handler_type> h) void socks5_stream::connect1(error_code const& e, boost::shared_ptr<handler_type> h)
{ {
if (e) if (e)
{ {
(*h)(e); (*h)(e);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
m_buffer.resize(6 + 4); // assume an IPv4 address 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)); , boost::bind(&socks5_stream::connect2, this, _1, h));
} }
void socks5_stream::connect2(asio::error_code const& e, boost::shared_ptr<handler_type> h) void socks5_stream::connect2(error_code const& e, boost::shared_ptr<handler_type> h)
{ {
if (e) if (e)
{ {
(*h)(e); (*h)(e);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
@ -260,14 +260,14 @@ namespace libtorrent
if (version < 5) if (version < 5)
{ {
(*h)(asio::error::operation_not_supported); (*h)(asio::error::operation_not_supported);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
int response = read_uint8(p); int response = read_uint8(p);
if (response != 0) if (response != 0)
{ {
asio::error_code e = asio::error::fault; error_code e = asio::error::fault;
switch (response) switch (response)
{ {
case 1: e = asio::error::fault; break; case 1: e = asio::error::fault; break;
@ -280,7 +280,7 @@ namespace libtorrent
case 8: e = asio::error::address_family_not_supported; break; case 8: e = asio::error::address_family_not_supported; break;
} }
(*h)(e); (*h)(e);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
@ -305,22 +305,22 @@ namespace libtorrent
else else
{ {
(*h)(asio::error::operation_not_supported); (*h)(asio::error::operation_not_supported);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }
m_buffer.resize(skip_bytes); 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)); , boost::bind(&socks5_stream::connect3, this, _1, h));
} }
void socks5_stream::connect3(asio::error_code const& e, boost::shared_ptr<handler_type> h) void socks5_stream::connect3(error_code const& e, boost::shared_ptr<handler_type> h)
{ {
if (e) if (e)
{ {
(*h)(e); (*h)(e);
asio::error_code ec; error_code ec;
close(ec); close(ec);
return; return;
} }

View File

@ -47,47 +47,23 @@ POSSIBILITY OF SUCH DAMAGE.
#define for if (false) {} else for #define for if (false) {} else for
#endif #endif
using namespace libtorrent; namespace libtorrent
{
void libtorrent::stat::second_tick(float tick_interval) void stat_channel::second_tick(float tick_interval)
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
m_rate_sum -= m_rate_history[history-1];
for (int i = history - 2; i >= 0; --i) for (int i = history - 2; i >= 0; --i)
{ m_rate_history[i + 1] = m_rate_history[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_download_rate_history[0] = (m_downloaded_payload + m_downloaded_protocol) m_rate_history[0] = m_counter / tick_interval;
/ tick_interval; m_rate_sum += m_rate_history[0];
m_upload_rate_history[0] = (m_uploaded_payload + m_uploaded_protocol) m_counter = 0;
/ 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;
} }
}

View File

@ -527,12 +527,23 @@ namespace libtorrent
std::pair<iter_t, bool> ret = directories.insert((m_save_path / bp).string()); std::pair<iter_t, bool> ret = directories.insert((m_save_path / bp).string());
bp = bp.branch_path(); 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) if (std::remove(p.c_str()) != 0 && errno != ENOENT)
{ {
error = std::strerror(errno); error = std::strerror(errno);
error_file = p; error_file = p;
result = errno; result = errno;
} }
#endif
} }
// remove the directories. Reverse order to delete // remove the directories. Reverse order to delete
@ -541,12 +552,23 @@ namespace libtorrent
for (std::set<std::string>::reverse_iterator i = directories.rbegin() for (std::set<std::string>::reverse_iterator i = directories.rbegin()
, end(directories.rend()); i != end; ++i) , 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) if (std::remove(i->c_str()) != 0 && errno != ENOENT)
{ {
error = std::strerror(errno); error = std::strerror(errno);
error_file = *i; error_file = *i;
result = errno; result = errno;
} }
#endif
} }
if (!error.empty()) if (!error.empty())
@ -1230,7 +1252,7 @@ namespace libtorrent
{ {
TORRENT_ASSERT(r.length <= 16 * 1024); TORRENT_ASSERT(r.length <= 16 * 1024);
// the buffer needs to be allocated through the io_thread // 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; disk_io_job j;
j.storage = this; j.storage = this;
@ -1238,7 +1260,7 @@ namespace libtorrent
j.piece = r.piece; j.piece = r.piece;
j.offset = r.start; j.offset = r.start;
j.buffer_size = r.length; j.buffer_size = r.length;
j.buffer = buffer.buffer(); j.buffer = buffer.get();
m_io_thread.add_job(j, handler); m_io_thread.add_job(j, handler);
buffer.release(); buffer.release();
} }
@ -2465,7 +2487,8 @@ namespace libtorrent
&& m_free_slots.empty() && m_free_slots.empty()
&& m_state == state_finished) && 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) if (m_storage_mode != storage_mode_compact)

View File

@ -59,6 +59,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/session.hpp" #include "libtorrent/session.hpp"
#include "libtorrent/torrent_info.hpp" #include "libtorrent/torrent_info.hpp"
#include "libtorrent/tracker_manager.hpp" #include "libtorrent/tracker_manager.hpp"
#include "libtorrent/parse_url.hpp"
#include "libtorrent/bencode.hpp" #include "libtorrent/bencode.hpp"
#include "libtorrent/hasher.hpp" #include "libtorrent/hasher.hpp"
#include "libtorrent/entry.hpp" #include "libtorrent/entry.hpp"
@ -95,20 +96,6 @@ namespace
, tracker_failed_max = 5 , 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 struct find_peer_by_ip
{ {
find_peer_by_ip(tcp::endpoint const& a, const torrent* t) find_peer_by_ip(tcp::endpoint const& a, const torrent* t)
@ -160,23 +147,18 @@ namespace libtorrent
, entry const* resume_data , entry const* resume_data
, int seq , int seq
, bool auto_managed) , bool auto_managed)
: m_torrent_file(tf) : m_policy(this)
, m_abort(false) , m_active_time(seconds(0))
, m_paused(paused) , m_seeding_time(seconds(0))
, m_just_paused(false) , m_total_uploaded(0)
, m_auto_managed(auto_managed) , m_total_downloaded(0)
, m_started(time_now())
, m_last_scrape(min_time())
, m_torrent_file(tf)
, m_event(tracker_request::started) , m_event(tracker_request::started)
, m_block_size(0)
, m_storage(0) , m_storage(0)
, m_next_request(time_now()) , m_next_request(time_now())
, m_duration(1800)
, m_complete(-1)
, m_incomplete(-1)
, m_host_resolver(ses.m_io_service) , 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) , m_announce_timer(ses.m_io_service)
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT
, m_last_dht_announce(time_now() - minutes(15)) , m_last_dht_announce(time_now() - minutes(15))
@ -184,35 +166,41 @@ namespace libtorrent
, m_ses(ses) , m_ses(ses)
, m_picker(0) , m_picker(0)
, m_trackers(m_torrent_file->trackers()) , m_trackers(m_torrent_file->trackers())
, m_last_working_tracker(-1)
, m_currently_trying_tracker(0)
, m_failed_trackers(0)
, 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_failed_bytes(0)
, m_total_redundant_bytes(0) , m_total_redundant_bytes(0)
, m_net_interface(net_interface.address(), 0) , m_net_interface(net_interface.address(), 0)
, m_save_path(complete(save_path)) , m_save_path(complete(save_path))
, m_storage_mode(storage_mode) , m_storage_mode(storage_mode)
, m_state(torrent_status::queued_for_checking) , 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_settings(ses.settings())
, m_storage_constructor(sc) , m_storage_constructor(sc)
, m_progress(0.f)
, m_num_pieces(0)
, m_ratio(0.f)
, m_max_uploads((std::numeric_limits<int>::max)()) , m_max_uploads((std::numeric_limits<int>::max)())
, m_num_uploads(0) , m_num_uploads(0)
, m_max_connections((std::numeric_limits<int>::max)()) , m_max_connections((std::numeric_limits<int>::max)())
, m_block_size(block_size)
, m_complete(-1)
, m_incomplete(-1)
, m_deficit_counter(0) , m_deficit_counter(0)
, m_policy(this) , m_duration(1800)
, m_sequence_number(seq) , m_sequence_number(seq)
, m_active_time(seconds(0)) , m_last_working_tracker(-1)
, m_seeding_time(seconds(0)) , m_currently_trying_tracker(0)
, m_total_uploaded(0) , m_failed_trackers(0)
, m_total_downloaded(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; if (resume_data) m_resume_data = *resume_data;
#ifndef NDEBUG #ifndef NDEBUG
@ -234,58 +222,59 @@ namespace libtorrent
, entry const* resume_data , entry const* resume_data
, int seq , int seq
, bool auto_managed) , bool auto_managed)
: m_torrent_file(new torrent_info(info_hash)) : m_policy(this)
, m_abort(false) , m_active_time(seconds(0))
, m_paused(paused) , m_seeding_time(seconds(0))
, m_just_paused(false) , m_total_uploaded(0)
, m_auto_managed(auto_managed) , 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_event(tracker_request::started)
, m_block_size(0)
, m_storage(0) , m_storage(0)
, m_next_request(time_now()) , m_next_request(time_now())
, m_duration(1800)
, m_complete(-1)
, m_incomplete(-1)
, m_host_resolver(ses.m_io_service) , 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) , m_announce_timer(ses.m_io_service)
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT
, m_last_dht_announce(time_now() - minutes(15)) , m_last_dht_announce(time_now() - minutes(15))
#endif #endif
, m_ses(ses) , m_ses(ses)
, m_picker(0) , 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_failed_bytes(0)
, m_total_redundant_bytes(0) , m_total_redundant_bytes(0)
, m_net_interface(net_interface.address(), 0) , m_net_interface(net_interface.address(), 0)
, m_save_path(complete(save_path)) , m_save_path(complete(save_path))
, m_storage_mode(storage_mode) , m_storage_mode(storage_mode)
, m_state(torrent_status::queued_for_checking) , 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_settings(ses.settings())
, m_storage_constructor(sc) , m_storage_constructor(sc)
, m_progress(0.f)
, m_num_pieces(0)
, m_ratio(0.f)
, m_max_uploads((std::numeric_limits<int>::max)()) , m_max_uploads((std::numeric_limits<int>::max)())
, m_num_uploads(0) , m_num_uploads(0)
, m_max_connections((std::numeric_limits<int>::max)()) , m_max_connections((std::numeric_limits<int>::max)())
, m_block_size(block_size)
, m_complete(-1)
, m_incomplete(-1)
, m_deficit_counter(0) , m_deficit_counter(0)
, m_policy(this) , m_duration(1800)
, m_sequence_number(seq) , m_sequence_number(seq)
, m_active_time(seconds(0)) , m_last_working_tracker(-1)
, m_seeding_time(seconds(0)) , m_currently_trying_tracker(0)
, m_total_uploaded(0) , m_failed_trackers(0)
, m_total_downloaded(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; if (resume_data) m_resume_data = *resume_data;
#ifndef NDEBUG #ifndef NDEBUG
@ -307,7 +296,7 @@ namespace libtorrent
boost::weak_ptr<torrent> self(shared_from_this()); boost::weak_ptr<torrent> self(shared_from_this());
if (m_torrent_file->is_valid()) init(); if (m_torrent_file->is_valid()) init();
if (m_abort) return; if (m_abort) return;
asio::error_code ec; error_code ec;
m_announce_timer.expires_from_now(seconds(1), ec); m_announce_timer.expires_from_now(seconds(1), ec);
m_announce_timer.async_wait( m_announce_timer.async_wait(
bind(&torrent::on_announce_disp, self, _1)); 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_save_path, m_ses.m_files, m_ses.m_disk_thread, m_storage_constructor
, m_storage_mode); , m_storage_mode);
m_storage = m_owning_storage.get(); 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_picker.reset(new piece_picker(
m_torrent_file->piece_length() / m_block_size m_torrent_file->piece_length() / m_block_size
, int((m_torrent_file->total_size()+m_block_size-1)/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<bool>::iterator i = m_have_pieces.begin()
, end(m_have_pieces.end()); i != end; ++i, ++index)
{
if (*i) m_picker->we_have(index);
}
} }
files_checked(); files_checked();
@ -654,6 +649,8 @@ namespace libtorrent
{ {
m_have_pieces[j.offset] = true; m_have_pieces[j.offset] = true;
++m_num_pieces; ++m_num_pieces;
TORRENT_ASSERT(m_picker);
m_picker->we_have(j.offset);
} }
// we're not done checking yet // we're not done checking yet
@ -673,7 +670,7 @@ namespace libtorrent
} }
void torrent::on_announce_disp(boost::weak_ptr<torrent> p void torrent::on_announce_disp(boost::weak_ptr<torrent> p
, asio::error_code const& e) , error_code const& e)
{ {
if (e) return; if (e) return;
boost::shared_ptr<torrent> t = p.lock(); boost::shared_ptr<torrent> t = p.lock();
@ -687,7 +684,7 @@ namespace libtorrent
boost::weak_ptr<torrent> self(shared_from_this()); boost::weak_ptr<torrent> self(shared_from_this());
asio::error_code ec; error_code ec;
if (!m_torrent_file->priv()) if (!m_torrent_file->priv())
{ {
// announce on local network every 5 minutes // announce on local network every 5 minutes
@ -759,6 +756,8 @@ namespace libtorrent
req.url = m_trackers[m_currently_trying_tracker].url; 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 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()); , 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 // 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 (complete >= 0) m_complete = complete;
if (incomplete >= 0) m_incomplete = incomplete; if (incomplete >= 0) m_incomplete = incomplete;
if (complete >= 0 && incomplete >= 0)
m_last_scrape = time_now();
// connect to random peers from the list // connect to random peers from the list
std::random_shuffle(peer_list.begin(), peer_list.end()); std::random_shuffle(peer_list.begin(), peer_list.end());
@ -865,7 +866,7 @@ namespace libtorrent
if (i->pid == m_ses.get_peer_id()) if (i->pid == m_ses.get_peer_id())
continue; continue;
asio::error_code ec; error_code ec;
tcp::endpoint a(address::from_string(i->ip, ec), i->port); tcp::endpoint a(address::from_string(i->ip, ec), i->port);
if (ec) if (ec)
@ -875,7 +876,7 @@ namespace libtorrent
tcp::resolver::query q(i->ip, boost::lexical_cast<std::string>(i->port)); tcp::resolver::query q(i->ip, boost::lexical_cast<std::string>(i->port));
m_host_resolver.async_resolve(q, 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 else
{ {
@ -905,7 +906,7 @@ namespace libtorrent
m_got_tracker_response = true; 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) , peer_id pid)
{ {
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); 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)); bind(&torrent::on_files_released, shared_from_this(), _1, _2));
m_owning_storage = 0; m_owning_storage = 0;
asio::error_code ec; error_code ec;
m_announce_timer.cancel(ec); m_announce_timer.cancel(ec);
m_host_resolver.cancel(); m_host_resolver.cancel();
} }
@ -1487,9 +1488,8 @@ namespace libtorrent
#endif #endif
if (is_seed()) if (is_seed())
{ {
m_state = torrent_status::seeding;
m_picker.reset(); 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 // the torrent just became finished
if (is_finished() && !was_finished) if (is_finished() && !was_finished)
finished(); finished();
else if (!is_finished() && was_finished)
resume_download();
} }
void torrent::filter_piece(int index, bool filter) void torrent::filter_piece(int index, bool filter)
@ -1912,9 +1914,20 @@ namespace libtorrent
std::string hostname; std::string hostname;
int port; int port;
std::string path; 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); = 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 #ifdef TORRENT_USE_OPENSSL
if (protocol != "http" && protocol != "https") if (protocol != "http" && protocol != "https")
#else #else
@ -1968,6 +1981,18 @@ namespace libtorrent
} }
else 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<std::string>(port)); tcp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
m_host_resolver.async_resolve(q, m_host_resolver.async_resolve(q,
bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url 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) , std::string url)
{ {
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); 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)) 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( 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 // the name lookup failed for the http host. Don't try
@ -2010,9 +2033,21 @@ namespace libtorrent
using boost::tuples::ignore; using boost::tuples::ignore;
std::string hostname; std::string hostname;
int port; int port;
boost::tie(ignore, ignore, hostname, port, ignore) char const* error;
boost::tie(ignore, ignore, hostname, port, ignore, error)
= parse_url_components(url); = 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_ip_filter.access(a.address()) & ip_filter::blocked)
{ {
if (m_ses.m_alerts.should_post(alert::info)) 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)); 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) , std::string url, tcp::endpoint proxy)
{ {
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
@ -2090,7 +2125,7 @@ namespace libtorrent
} }
std::pair<int, int> const& out_ports = m_settings.outgoing_ports; std::pair<int, int> 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) if (out_ports.first > 0 && out_ports.second >= out_ports.first)
s->bind(tcp::endpoint(address(), m_ses.next_port()), ec); 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 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
(*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << e.what() << "\n"; (*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << e.what() << "\n";
#endif #endif
c->disconnect(e.what(), 1);
// TODO: post an error alert!
c->disconnect(e.what());
} }
#endif #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<peer_connection> p) const , intrusive_ptr<peer_connection> p) const
{ {
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex); 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); m_active_time = seconds((e != 0 && e->type() == entry::int_t)?e->integer():0);
e = rd.find_key("seeding_time"); e = rd.find_key("seeding_time");
m_seeding_time = seconds((e != 0 && e->type() == entry::int_t)?e->integer():0); 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 void torrent::write_resume_data(entry& ret) const
@ -2299,6 +2345,16 @@ namespace libtorrent
ret["active_time"] = total_seconds(m_active_time); ret["active_time"] = total_seconds(m_active_time);
ret["seeding_time"] = total_seconds(m_seeding_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" ret["allocation"] = m_storage_mode == storage_mode_sparse?"sparse"
:m_storage_mode == storage_mode_allocate?"full":"compact"; :m_storage_mode == storage_mode_allocate?"full":"compact";
@ -2369,7 +2425,7 @@ namespace libtorrent
for (policy::const_iterator i = m_policy.begin_peer() for (policy::const_iterator i = m_policy.begin_peer()
, end(m_policy.end_peer()); i != end; ++i) , end(m_policy.end_peer()); i != end; ++i)
{ {
asio::error_code ec; error_code ec;
if (i->second.banned) if (i->second.banned)
{ {
tcp::endpoint ip = i->second.ip; 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); bool ret = instantiate_connection(m_ses.m_io_service, m_ses.peer_proxy(), *s);
TORRENT_ASSERT(ret); TORRENT_ASSERT(ret);
std::pair<int, int> const& out_ports = m_ses.settings().outgoing_ports; std::pair<int, int> 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) if (out_ports.first > 0 && out_ports.second >= out_ports.first)
s->bind(tcp::endpoint(address(), m_ses.next_port()), ec); 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 // add the newly connected peer to this torrent's peer list
m_connections.insert(boost::get_pointer(c)); m_connections.insert(boost::get_pointer(c));
m_ses.m_connections.insert(c); m_ses.m_connections.insert(c);
peerinfo->connection = c.get();
c->start(); c->start();
int timeout = settings().peer_connect_timeout; int timeout = settings().peer_connect_timeout;
@ -2595,11 +2652,10 @@ namespace libtorrent
return false; return false;
} }
#endif #endif
peerinfo->connection = c.get();
return true; 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; INVARIANT_CHECK;
@ -2683,7 +2739,7 @@ namespace libtorrent
TORRENT_ASSERT(m_connections.find(p) == m_connections.end()); TORRENT_ASSERT(m_connections.find(p) == m_connections.end());
peer_iterator ci = m_connections.insert(p).first; peer_iterator ci = m_connections.insert(p).first;
#ifndef NDEBUG #ifndef NDEBUG
asio::error_code ec; error_code ec;
TORRENT_ASSERT(p->remote() == p->get_socket()->remote_endpoint(ec) || ec); TORRENT_ASSERT(p->remote() == p->get_socket()->remote_endpoint(ec) || ec);
#endif #endif
@ -2698,7 +2754,8 @@ namespace libtorrent
return int(m_connections.size()) < m_max_connections return int(m_connections.size()) < m_max_connections
&& !m_paused && !m_paused
&& m_state != torrent_status::checking_files && 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; && 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<peer_connection*> 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<peer_connection*>::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 int torrent::bandwidth_throttle(int channel) const
{ {
return m_bandwidth_limit[channel].throttle(); return m_bandwidth_limit[channel].throttle();
@ -2844,7 +2966,7 @@ namespace libtorrent
{ {
peer_connection* p = *i; peer_connection* p = *i;
TORRENT_ASSERT(p->associated_torrent().lock().get() == this); 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 #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
(*p->m_logger) << "*** SEED, CLOSING CONNECTION\n"; (*p->m_logger) << "*** SEED, CLOSING CONNECTION\n";
@ -2853,14 +2975,23 @@ namespace libtorrent
} }
} }
std::for_each(seeds.begin(), seeds.end() 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); TORRENT_ASSERT(m_storage);
// we need to keep the object alive during this operation // we need to keep the object alive during this operation
m_storage->async_release_files( m_storage->async_release_files(
bind(&torrent::on_files_released, shared_from_this(), _1, _2)); 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) // called when torrent is complete (all pieces downloaded)
void torrent::completed() void torrent::completed()
{ {
@ -2900,7 +3031,7 @@ namespace libtorrent
if ((unsigned)m_currently_trying_tracker >= m_trackers.size()) if ((unsigned)m_currently_trying_tracker >= m_trackers.size())
{ {
int delay = tracker_retry_delay_min 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_retry_delay_max - tracker_retry_delay_min)
/ tracker_failed_max; / tracker_failed_max;
@ -2968,8 +3099,6 @@ namespace libtorrent
{ {
m_state = torrent_status::seeding; m_state = torrent_status::seeding;
m_picker.reset(); m_picker.reset();
if (m_ses.settings().free_torrent_hashes)
m_torrent_file->seed_free();
} }
if (!m_connections_initialized) if (!m_connections_initialized)
@ -3285,27 +3414,59 @@ namespace libtorrent
m_ses.m_auto_manage_time_scaler = 0; 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); if (!is_seed()) return 0;
int downloading = total_seconds(m_active_time) - seeding;
// if the seed time limit is set to less than 60 minutes int ret = 0;
// use 60 minutes, to avoid oscillation
float ret = seeding / float((std::max)(s.seed_time_limit, 60 * 60));
// if it took less than 30 minutes to download, disregard the ptime now(time_now());
// 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));
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()); size_type downloaded = (std::max)(m_total_downloaded, m_torrent_file->total_size());
if (downloaded > 0 && s.share_ratio_limit >= 1.f) if (seed_time < s.seed_time_limit
ret = (std::max)(ret, float(m_total_uploaded) / downloaded && (seed_time > 1 && download_time / float(seed_time) < s.seed_time_ratio_limit)
/ s.share_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; return ret;
} }
@ -3402,6 +3563,7 @@ namespace libtorrent
#endif #endif
m_paused = false; m_paused = false;
m_started = time_now();
// tell the tracker that we're back // tell the tracker that we're back
m_event = tracker_request::started; m_event = tracker_request::started;
@ -3489,6 +3651,7 @@ namespace libtorrent
{ {
peer_connection* p = *i; peer_connection* p = *i;
++i; ++i;
p->calc_ip_overhead();
m_stat += p->statistics(); m_stat += p->statistics();
// updates the peer connection's ul/dl bandwidth // updates the peer connection's ul/dl bandwidth
// resource requests // resource requests
@ -3504,8 +3667,7 @@ namespace libtorrent
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING #if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_ERROR_LOGGING
(*p->m_logger) << "**ERROR**: " << e.what() << "\n"; (*p->m_logger) << "**ERROR**: " << e.what() << "\n";
#endif #endif
p->set_failed(); p->disconnect(e.what(), 1);
p->disconnect(e.what());
} }
#endif #endif
} }
@ -3643,8 +3805,18 @@ namespace libtorrent
, m_have_pieces.end() , m_have_pieces.end()
, 0) == m_num_pieces); , 0) == m_num_pieces);
ptime now = time_now();
torrent_status st; 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.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(); 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_peers = m_policy.num_peers();
st.list_seeds = m_policy.num_seeds(); st.list_seeds = m_policy.num_seeds();
st.connect_candidates = m_policy.num_connect_candidates(); 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_upload = m_total_uploaded;
st.all_time_download = m_total_downloaded; st.all_time_download = m_total_downloaded;
@ -3668,6 +3840,7 @@ namespace libtorrent
st.num_incomplete = m_incomplete; st.num_incomplete = m_incomplete;
st.paused = m_paused; st.paused = m_paused;
boost::tie(st.total_done, st.total_wanted_done) = bytes_done(); 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); TORRENT_ASSERT(st.total_done >= st.total_wanted_done);
// payload transfer // payload transfer
@ -3691,7 +3864,7 @@ namespace libtorrent
st.upload_payload_rate = m_stat.upload_payload_rate(); st.upload_payload_rate = m_stat.upload_payload_rate();
st.next_announce = boost::posix_time::seconds( st.next_announce = boost::posix_time::seconds(
total_seconds(next_announce() - time_now())); total_seconds(next_announce() - now));
if (st.next_announce.is_negative()) if (st.next_announce.is_negative())
st.next_announce = boost::posix_time::seconds(0); st.next_announce = boost::posix_time::seconds(0);
@ -3713,7 +3886,7 @@ namespace libtorrent
if (!valid_metadata()) 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; st.state = torrent_status::connecting_to_tracker;
else else
st.state = torrent_status::downloading_metadata; st.state = torrent_status::downloading_metadata;
@ -3728,6 +3901,7 @@ namespace libtorrent
// fill in status that depends on metadata // fill in status that depends on metadata
st.total_wanted = m_torrent_file->total_size(); st.total_wanted = m_torrent_file->total_size();
TORRENT_ASSERT(st.total_wanted >= 0);
if (m_picker.get() && (m_picker->num_filtered() > 0 if (m_picker.get() && (m_picker->num_filtered() > 0
|| m_picker->num_have_filtered() > 0)) || m_picker->num_have_filtered() > 0))

View File

@ -1,6 +1,6 @@
/* /*
Copyright (c) 2003, Arvid Norberg Copyright (c) 2008, Arvid Norberg
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -46,6 +46,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/filesystem/path.hpp> #include <boost/filesystem/path.hpp>
#include <boost/filesystem.hpp>
#include <boost/next_prior.hpp> #include <boost/next_prior.hpp>
#include <boost/bind.hpp> #include <boost/bind.hpp>
@ -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) , std::string const& root_dir)
{ {
entry const* length = dict.find_key("length"); lazy_entry const* length = dict.dict_find("length");
if (length == 0 || length->type() != entry::int_t) if (length == 0 || length->type() != lazy_entry::int_t)
return false; return false;
target.size = length->integer(); target.size = length->int_value();
target.path = root_dir; target.path = root_dir;
target.file_base = 0; target.file_base = 0;
@ -173,27 +174,19 @@ namespace
// because if it exists, it is more // because if it exists, it is more
// likely to be correctly encoded // likely to be correctly encoded
const entry::list_type* list = 0; lazy_entry const* p = dict.dict_find("path.utf-8");
entry const* p8 = dict.find_key("path.utf-8"); if (p == 0 || p->type() != lazy_entry::list_t)
if (p8 != 0 && p8->type() == entry::list_t) p = dict.dict_find("path");
{ if (p == 0 || p->type() != lazy_entry::list_t)
list = &p8->list(); return false;
}
else
{
entry const* p = dict.find_key("path");
if (p == 0 || p->type() != entry::list_t)
return false;
list = &p->list();
}
for (entry::list_type::const_iterator i = list->begin(); for (int i = 0, end(p->list_size()); i < end; ++i)
i != list->end(); ++i)
{ {
if (i->type() != entry::string_t) if (p->list_at(i)->type() != lazy_entry::string_t)
return false; return false;
if (i->string() != "..") std::string path_element = p->list_at(i)->string_value();
target.path /= i->string(); if (path_element != "..")
target.path /= path_element;
} }
verify_encoding(target); verify_encoding(target);
if (target.path.is_complete()) if (target.path.is_complete())
@ -201,14 +194,15 @@ namespace
return true; return true;
} }
bool extract_files(const entry::list_type& list, std::vector<file_entry>& target bool extract_files(lazy_entry const& list, std::vector<file_entry>& target
, std::string const& root_dir) , std::string const& root_dir)
{ {
size_type offset = 0; 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()); 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; return false;
target.back().offset = offset; target.back().offset = offset;
offset += target.back().size; offset += target.back().size;
@ -231,25 +225,65 @@ namespace libtorrent
{ {
// standard constructor that parses a torrent file // 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_num_pieces(0)
, m_creation_date(pt::ptime(pt::not_a_date_time)) , m_creation_date(pt::ptime(pt::not_a_date_time))
, m_multifile(false) , m_multifile(false)
, m_private(false) , m_private(false)
, m_extra_info(entry::dictionary_t) , m_info_section_size(0)
#ifndef NDEBUG , m_piece_hashes(0)
, m_half_metadata(false) {
std::vector<char> tmp;
std::back_insert_iterator<std::vector<char> > 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 #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; std::string error;
#ifndef BOOST_NO_EXCEPTIONS #ifndef BOOST_NO_EXCEPTIONS
if (!read_torrent_info(torrent_file, error)) if (!parse_torrent_file(torrent_file, error))
throw invalid_torrent_file(); throw invalid_torrent_file();
#else #else
read_torrent_info(torrent_file, error); read_torrent_info(torrent_file, error);
#endif #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 // constructor used for creating new torrents
// will not contain any hashes, comments, creation date // will not contain any hashes, comments, creation date
// just the necessary to use it with piece manager // just the necessary to use it with piece manager
@ -263,10 +297,8 @@ namespace libtorrent
, m_creation_date(pt::second_clock::universal_time()) , m_creation_date(pt::second_clock::universal_time())
, m_multifile(false) , m_multifile(false)
, m_private(false) , m_private(false)
, m_extra_info(entry::dictionary_t) , m_info_section_size(0)
#ifndef NDEBUG , m_piece_hashes(0)
, m_half_metadata(false)
#endif
{ {
} }
@ -279,13 +311,35 @@ namespace libtorrent
, m_creation_date(pt::second_clock::universal_time()) , m_creation_date(pt::second_clock::universal_time())
, m_multifile(false) , m_multifile(false)
, m_private(false) , m_private(false)
, m_extra_info(entry::dictionary_t) , m_info_section_size(0)
#ifndef NDEBUG , m_piece_hashes(0)
, m_half_metadata(false)
#endif
{ {
} }
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<char> 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() torrent_info::~torrent_info()
{} {}
@ -294,9 +348,8 @@ namespace libtorrent
using std::swap; using std::swap;
m_urls.swap(ti.m_urls); m_urls.swap(ti.m_urls);
m_url_seeds.swap(ti.m_url_seeds); 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_files);
m_files.swap(ti.m_remapped_files);
m_nodes.swap(ti.m_nodes); m_nodes.swap(ti.m_nodes);
swap(m_num_pieces, ti.m_num_pieces); swap(m_num_pieces, ti.m_num_pieces);
swap(m_info_hash, ti.m_info_hash); swap(m_info_hash, ti.m_info_hash);
@ -306,83 +359,51 @@ namespace libtorrent
m_created_by.swap(ti.m_created_by); m_created_by.swap(ti.m_created_by);
swap(m_multifile, ti.m_multifile); swap(m_multifile, ti.m_multifile);
swap(m_private, ti.m_private); swap(m_private, ti.m_private);
m_extra_info.swap(ti.m_extra_info); swap(m_info_section, ti.m_info_section);
#ifndef NDEBUG swap(m_info_section_size, ti.m_info_section_size);
swap(m_half_metadata, ti.m_half_metadata); swap(m_piece_hashes, ti.m_piece_hashes);
#endif 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 if (info.type() != lazy_entry::dict_t)
#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<int>(
(m_total_size + m_piece_length - 1) / m_piece_length);
int old_num_pieces = static_cast<int>(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)
{ {
error = "'info' entry is not a dictionary"; error = "'info' entry is not a dictionary";
return false; return false;
} }
// encode the info-field in order to calculate it's sha1-hash // hash the info-field to calculate info-hash
std::vector<char> buf;
bencode(std::back_inserter(buf), info);
hasher h; hasher h;
h.update(&buf[0], (int)buf.size()); std::pair<char const*, int> section = info.data_section();
h.update(section.first, section.second);
m_info_hash = h.final(); 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 // extract piece length
entry const* piece_length = info.find_key("piece length"); m_piece_length = info.dict_find_int_value("piece length", -1);
if (piece_length == 0 || piece_length->type() != entry::int_t) if (m_piece_length <= 0)
{ {
error = "invalid or missing 'piece length' entry in torrent file"; error = "invalid or missing 'piece length' entry in torrent file";
return false; 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; 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; fs::path tmp = m_name;
if (tmp.is_complete()) if (tmp.is_complete())
{ {
@ -401,32 +422,31 @@ namespace libtorrent
} }
if (m_name == ".." || m_name == ".") if (m_name == ".." || m_name == ".")
{ {
error = "invalid 'name' of torrent (possible exploit attempt)"; error = "invalid 'name' of torrent (possible exploit attempt)";
return false; return false;
} }
// extract file list // extract file list
entry const* i = info.find_key("files"); lazy_entry const* i = info.dict_find_list("files");
if (i == 0) 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 // if there's no list of files, there has to be a length
// field. // field.
file_entry e; file_entry e;
e.path = m_name; e.path = m_name;
e.offset = 0; 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_files.push_back(e);
m_multifile = false;
} }
else 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"; error = "failed to parse files from torrent file";
return false; return false;
@ -443,84 +463,51 @@ namespace libtorrent
// we want this division to round upwards, that's why we have the // we want this division to round upwards, that's why we have the
// extra addition // extra addition
entry const* pieces_ent = info.find_key("pieces"); m_num_pieces = static_cast<int>((m_total_size + m_piece_length - 1) / m_piece_length);
if (pieces_ent == 0 || pieces_ent->type() != entry::string_t)
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"; error = "invalid or missing 'pieces' entry in torrent file";
return false; return false;
} }
m_num_pieces = static_cast<int>((m_total_size + m_piece_length - 1) / m_piece_length); if (pieces->string_length() != m_num_pieces * 20)
m_piece_hash.resize(m_num_pieces);
const std::string& hash_string = pieces_ent->string();
if ((int)hash_string.length() != m_num_pieces * 20)
{ {
error = "incorrect number of piece hashes in torrent file"; error = "incorrect number of piece hashes in torrent file";
return false; return false;
} }
for (int i = 0; i < m_num_pieces; ++i) m_piece_hashes = m_info_section.get() + (pieces->string_ptr() - section.first);
std::copy( TORRENT_ASSERT(m_piece_hashes >= m_info_section.get());
hash_string.begin() + i*20 TORRENT_ASSERT(m_piece_hashes < m_info_section.get() + m_info_section_size);
, hash_string.begin() + (i+1)*20
, m_piece_hash[i].begin());
for (entry::dictionary_type::const_iterator i = info.dict().begin() m_private = info.dict_find_int_value("private", 0);
, 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<char> 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
return true; return true;
} }
// extracts information from a libtorrent file and fills in the structures in bool torrent_info::parse_torrent_file(lazy_entry const& torrent_file, std::string& error)
// the torrent object
bool torrent_info::read_torrent_info(const entry& 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"; error = "torrent file is not a dictionary";
return false; return false;
} }
// extract the url of the tracker // extract the url of the tracker
entry const* i = torrent_file.find_key("announce-list"); lazy_entry const* i = torrent_file.dict_find_list("announce-list");
if (i && i->type() == entry::list_t) if (i)
{ {
const entry::list_type& l = i->list(); m_urls.reserve(i->list_size());
for (entry::list_type::const_iterator j = l.begin(); j != l.end(); ++j) for (int j = 0, end(i->list_size()); j < end; ++j)
{ {
if (j->type() != entry::list_t) break; lazy_entry const* tier = i->list_at(j);
const entry::list_type& ll = j->list(); if (tier->type() != lazy_entry::list_t) continue;
for (entry::list_type::const_iterator k = ll.begin(); k != ll.end(); ++k) for (int k = 0, end(tier->list_size()); k < end; ++k)
{ {
if (k->type() != entry::string_t) break; announce_entry e(tier->list_string_value_at(k));
announce_entry e(k->string()); if (e.url.empty()) continue;
e.tier = (int)std::distance(l.begin(), j); e.tier = j;
m_urls.push_back(e); m_urls.push_back(e);
} }
} }
@ -541,71 +528,62 @@ namespace libtorrent
std::random_shuffle(start, stop); 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"); lazy_entry const* nodes = torrent_file.dict_find_list("nodes");
if (nodes && nodes->type() == entry::list_t) if (nodes)
{ {
entry::list_type const& list = nodes->list(); for (int i = 0, end(nodes->list_size()); i < end; ++i)
for (entry::list_type::const_iterator i(list.begin())
, end(list.end()); i != end; ++i)
{ {
if (i->type() != entry::list_t) continue; lazy_entry const* n = nodes->list_at(i);
entry::list_type const& l = i->list(); if (n->type() != lazy_entry::list_t
entry::list_type::const_iterator iter = l.begin(); || n->list_size() < 2
if (l.size() < 1) continue; || n->list_at(0)->type() != lazy_entry::string_t
if (iter->type() != entry::string_t) continue; || n->list_at(1)->type() != lazy_entry::int_t)
std::string const& hostname = iter->string(); continue;
++iter; m_nodes.push_back(std::make_pair(
int port = 6881; n->list_at(0)->string_value()
if (iter->type() != entry::int_t) continue; , int(n->list_at(1)->int_value())));
if (l.end() != iter) port = int(iter->integer());
m_nodes.push_back(std::make_pair(hostname, port));
} }
} }
// extract creation date // extract creation date
entry const* creation_date = torrent_file.find_key("creation date"); size_type cd = torrent_file.dict_find_int_value("creation date", -1);
if (creation_date && creation_date->type() == entry::int_t) if (cd >= 0)
{ {
m_creation_date = pt::ptime(gr::date(1970, gr::Jan, 1)) 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 // if there are any url-seeds, extract them
entry const* url_seeds = torrent_file.find_key("url-list"); lazy_entry const* url_seeds = torrent_file.dict_find("url-list");
if (url_seeds && url_seeds->type() == entry::string_t) 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 (int i = 0, end(url_seeds->list_size()); i < end; ++i)
for (entry::list_type::const_iterator i = l.begin();
i != l.end(); ++i)
{ {
if (i->type() != entry::string_t) continue; lazy_entry const* url = url_seeds->list_at(i);
m_url_seeds.push_back(i->string()); if (url->type() != lazy_entry::string_t) continue;
m_url_seeds.push_back(url->string_value());
} }
} }
// extract comment m_comment = torrent_file.dict_find_string_value("comment.utf-8");
if (entry const* e = torrent_file.find_key("comment.utf-8")) if (m_comment.empty()) m_comment = torrent_file.dict_find_string_value("comment");
{ m_comment = e->string(); }
else if (entry const* e = torrent_file.find_key("comment"))
{ m_comment = e->string(); }
if (entry const* e = torrent_file.find_key("created by.utf-8")) m_created_by = torrent_file.dict_find_string_value("created by.utf-8");
{ m_created_by = e->string(); } if (m_created_by.empty()) m_created_by = torrent_file.dict_find_string_value("created by");
else if (entry const* e = torrent_file.find_key("created by"))
{ m_created_by = e->string(); }
entry const* info = torrent_file.find_key("info"); lazy_entry const* info = torrent_file.dict_find_dict("info");
if (info == 0 || info->type() != entry::dictionary_t) if (info == 0)
{ {
error = "missing or invalid 'info' section in torrent file"; error = "missing or invalid 'info' section in torrent file";
return false; return false;
@ -634,234 +612,6 @@ namespace libtorrent
, bind(&announce_entry::tier, _1), bind(&announce_entry::tier, _2))); , 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<int>(
(m_total_size + m_piece_length - 1) / m_piece_length);
int old_num_pieces = static_cast<int>(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<file_entry>::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<sha1_hash>::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<announce_entry>::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<std::string>::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<char> 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<std::string>().swap(m_url_seeds);
nodes_t().swap(m_nodes);
std::vector<sha1_hash>().swap(m_piece_hash);
#ifndef NDEBUG
m_half_metadata = true;
#endif
}
// ------- start deprecation ------- // ------- start deprecation -------
void torrent_info::print(std::ostream& os) const void torrent_info::print(std::ostream& os) const
@ -901,11 +651,6 @@ namespace libtorrent
return piece_length(); return piece_length();
} }
void torrent_info::add_node(std::pair<std::string, int> const& node)
{
m_nodes.push_back(node);
}
bool torrent_info::remap_files(std::vector<file_entry> const& map) bool torrent_info::remap_files(std::vector<file_entry> const& map)
{ {
size_type offset = 0; size_type offset = 0;

View File

@ -84,7 +84,7 @@ namespace libtorrent
int timeout = (std::min)( int timeout = (std::min)(
m_read_timeout, (std::min)(m_completion_timeout, m_read_timeout)); 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.expires_at(m_read_time + seconds(timeout), ec);
m_timeout.async_wait(bind( m_timeout.async_wait(bind(
&timeout_handler::timeout_callback, self(), _1)); &timeout_handler::timeout_callback, self(), _1));
@ -99,11 +99,11 @@ namespace libtorrent
{ {
m_abort = true; m_abort = true;
m_completion_timeout = 0; m_completion_timeout = 0;
asio::error_code ec; error_code ec;
m_timeout.cancel(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 (error) return;
if (m_completion_timeout == 0) return; if (m_completion_timeout == 0) return;
@ -125,7 +125,7 @@ namespace libtorrent
int timeout = (std::min)( int timeout = (std::min)(
m_read_timeout, (std::min)(m_completion_timeout, m_read_timeout)); 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.expires_at(m_read_time + seconds(timeout), ec);
m_timeout.async_wait( m_timeout.async_wait(
bind(&timeout_handler::timeout_callback, self(), _1)); bind(&timeout_handler::timeout_callback, self(), _1));
@ -180,83 +180,6 @@ namespace libtorrent
m_connections.erase(i); m_connections.erase(i);
} }
// returns protocol, auth, hostname, port, path
tuple<std::string, std::string, std::string, int, std::string>
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( void tracker_manager::queue_request(
io_service& ios io_service& ios
, connection_queue& cc , connection_queue& cc

View File

@ -4,7 +4,11 @@
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/lexical_cast.hpp> #include <boost/lexical_cast.hpp>
#include <boost/array.hpp> #include <boost/array.hpp>
#if BOOST_VERSION < 103500
#include <asio/read.hpp> #include <asio/read.hpp>
#else
#include <boost/asio/read.hpp>
#endif
using namespace libtorrent; 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; 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); 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; 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; 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 // 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; 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() void udp_socket::close()
{ {
asio::error_code ec; error_code ec;
m_ipv4_sock.close(ec); m_ipv4_sock.close(ec);
m_ipv6_sock.close(ec); m_ipv6_sock.close(ec);
m_socks5_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_ipv4_sock.is_open()) m_ipv4_sock.close(ec);
if (m_ipv6_sock.is_open()) m_ipv6_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) 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_ipv4_sock.is_open()) m_ipv4_sock.close(ec);
if (m_ipv6_sock.is_open()) m_ipv6_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) void udp_socket::set_proxy_settings(proxy_settings const& ps)
{ {
asio::error_code ec; error_code ec;
m_socks5_sock.close(ec); m_socks5_sock.close(ec);
m_tunnel_packets = false; 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; if (e) return;
m_proxy_addr.address(i->endpoint().address()); 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() void udp_socket::on_timeout()
{ {
asio::error_code ec; error_code ec;
m_socks5_sock.close(ec); m_socks5_sock.close(ec);
m_connection_ticket = -1; m_connection_ticket = -1;
} }
@ -275,13 +279,13 @@ void udp_socket::on_timeout()
void udp_socket::on_connect(int ticket) void udp_socket::on_connect(int ticket)
{ {
m_connection_ticket = 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.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()) m_socks5_sock.async_connect(tcp::endpoint(m_proxy_addr.address(), m_proxy_addr.port())
, boost::bind(&udp_socket::on_connected, this, _1)); , 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_cc.done(m_connection_ticket);
m_connection_ticket = -1; 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)); , 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; if (e) return;
@ -316,7 +320,7 @@ void udp_socket::handshake1(asio::error_code const& e)
, boost::bind(&udp_socket::handshake2, this, _1)); , 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; if (e) return;
@ -336,7 +340,7 @@ void udp_socket::handshake2(asio::error_code const& e)
{ {
if (m_proxy_settings.username.empty()) if (m_proxy_settings.username.empty())
{ {
asio::error_code ec; error_code ec;
m_socks5_sock.close(ec); m_socks5_sock.close(ec);
return; return;
} }
@ -353,13 +357,13 @@ void udp_socket::handshake2(asio::error_code const& e)
} }
else else
{ {
asio::error_code ec; error_code ec;
m_socks5_sock.close(ec); m_socks5_sock.close(ec);
return; return;
} }
} }
void udp_socket::handshake3(asio::error_code const& e) void udp_socket::handshake3(error_code const& e)
{ {
if (e) return; if (e) return;
@ -367,7 +371,7 @@ void udp_socket::handshake3(asio::error_code const& e)
, boost::bind(&udp_socket::handshake4, this, _1)); , 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; if (e) return;
@ -400,7 +404,7 @@ void udp_socket::socks_forward_udp()
, boost::bind(&udp_socket::connect1, this, _1)); , 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; if (e) return;
@ -408,7 +412,7 @@ void udp_socket::connect1(asio::error_code const& e)
, boost::bind(&udp_socket::connect2, this, _1)); , 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; if (e) return;

View File

@ -52,6 +52,7 @@ POSSIBILITY OF SUCH DAMAGE.
#endif #endif
#include "libtorrent/tracker_manager.hpp" #include "libtorrent/tracker_manager.hpp"
#include "libtorrent/parse_url.hpp"
#include "libtorrent/udp_tracker_connection.hpp" #include "libtorrent/udp_tracker_connection.hpp"
#include "libtorrent/io.hpp" #include "libtorrent/io.hpp"
@ -95,10 +96,18 @@ namespace libtorrent
std::string hostname; std::string hostname;
int port; int port;
char const* error;
using boost::tuples::ignore; 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<std::string>(port)); udp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
m_name_lookup.async_resolve(q m_name_lookup.async_resolve(q
, boost::bind( , boost::bind(
@ -113,7 +122,7 @@ namespace libtorrent
#endif #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) , udp::resolver::iterator i)
{ {
if (error == asio::error::operation_aborted) return; 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()); if (cb) cb->m_tracker_address = tcp::endpoint(target_address.address(), target_address.port());
m_target = target_address; m_target = target_address;
asio::error_code ec; error_code ec;
m_socket.bind(udp::endpoint(bind_interface(), 0), ec); m_socket.bind(udp::endpoint(bind_interface(), 0), ec);
if (ec) if (ec)
{ {
@ -179,13 +188,13 @@ namespace libtorrent
void udp_tracker_connection::close() void udp_tracker_connection::close()
{ {
asio::error_code ec; error_code ec;
m_socket.close(); m_socket.close();
m_name_lookup.cancel(); m_name_lookup.cancel();
tracker_connection::close(); 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) , udp::endpoint const& ep, char const* buf, int size)
{ {
// ignore resposes before we've sent any requests // ignore resposes before we've sent any requests
@ -305,7 +314,7 @@ namespace libtorrent
detail::write_int32(m_transaction_id, ptr); // transaction_id detail::write_int32(m_transaction_id, ptr); // transaction_id
TORRENT_ASSERT(ptr - buf == sizeof(buf)); TORRENT_ASSERT(ptr - buf == sizeof(buf));
asio::error_code ec; error_code ec;
m_socket.send(m_target, buf, 16, ec); m_socket.send(m_target, buf, 16, ec);
m_state = action_connect; m_state = action_connect;
++m_attempts; ++m_attempts;
@ -334,7 +343,7 @@ namespace libtorrent
out += 20; out += 20;
TORRENT_ASSERT(out - buf == sizeof(buf)); TORRENT_ASSERT(out - buf == sizeof(buf));
asio::error_code ec; error_code ec;
m_socket.send(m_target, buf, sizeof(buf), ec); m_socket.send(m_target, buf, sizeof(buf), ec);
m_state = action_scrape; m_state = action_scrape;
++m_attempts; ++m_attempts;
@ -494,7 +503,7 @@ namespace libtorrent
} }
#endif #endif
asio::error_code ec; error_code ec;
m_socket.send(m_target, buf, sizeof(buf), ec); m_socket.send(m_target, buf, sizeof(buf), ec);
m_state = action_announce; m_state = action_announce;
++m_attempts; ++m_attempts;

View File

@ -35,15 +35,20 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/socket.hpp" #include "libtorrent/socket.hpp"
#include "libtorrent/upnp.hpp" #include "libtorrent/upnp.hpp"
#include "libtorrent/io.hpp" #include "libtorrent/io.hpp"
#include "libtorrent/http_tracker_connection.hpp" #include "libtorrent/parse_url.hpp"
#include "libtorrent/xml_parse.hpp" #include "libtorrent/xml_parse.hpp"
#include "libtorrent/connection_queue.hpp" #include "libtorrent/connection_queue.hpp"
#include "libtorrent/enum_net.hpp" #include "libtorrent/enum_net.hpp"
#include <boost/bind.hpp> #include <boost/bind.hpp>
#include <boost/ref.hpp> #include <boost/ref.hpp>
#if BOOST_VERSION < 103500
#include <asio/ip/host_name.hpp> #include <asio/ip/host_name.hpp>
#include <asio/ip/multicast.hpp> #include <asio/ip/multicast.hpp>
#else
#include <boost/asio/ip/host_name.hpp>
#include <boost/asio/ip/multicast.hpp>
#endif
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
#include <cstdlib> #include <cstdlib>
@ -54,12 +59,6 @@ POSSIBILITY OF SUCH DAMAGE.
using boost::bind; using boost::bind;
using namespace libtorrent; 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 upnp::upnp(io_service& ios, connection_queue& cc
, address const& listen_interface, std::string const& user_agent , address const& listen_interface, std::string const& user_agent
, portmap_callback_t const& cb, bool ignore_nonrouters) , 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_refresh_timer(ios)
, m_disabled(false) , m_disabled(false)
, m_closing(false) , m_closing(false)
, m_ignore_outside_network(ignore_nonrouters) , m_ignore_non_routers(ignore_nonrouters)
, m_cc(cc) , m_cc(cc)
{ {
#ifdef TORRENT_UPNP_LOGGING #ifdef TORRENT_UPNP_LOGGING
@ -103,7 +102,7 @@ void upnp::discover_device_impl()
"MX:3\r\n" "MX:3\r\n"
"\r\n\r\n"; "\r\n\r\n";
asio::error_code ec; error_code ec;
#ifdef TORRENT_DEBUG_UPNP #ifdef TORRENT_DEBUG_UPNP
// simulate packet loss // simulate packet loss
if (m_retry_count & 1) 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; if (e) return;
@ -254,9 +253,10 @@ void upnp::resend_request(asio::error_code const& e)
m_log << time_now_string() m_log << time_now_string()
<< " ==> connecting to " << d.url << std::endl; << " ==> connecting to " << d.url << std::endl;
#endif #endif
if (d.upnp_connection) d.upnp_connection->close();
d.upnp_connection.reset(new http_connection(m_io_service d.upnp_connection.reset(new http_connection(m_io_service
, m_cc, bind(&upnp::on_upnp_xml, self(), _1, _2 , 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); d.upnp_connection->get(d.url, seconds(30), 1);
} }
catch (std::exception& e) 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 Server:Microsoft-Windows-NT/5.1 UPnP/1.0 UPnP-Device-Host/1.0
*/ */
asio::error_code ec; error_code ec;
if (m_ignore_outside_network && !in_local_network(m_io_service, from.address(), 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<ip_interface> const& net = enum_net_interfaces(m_io_service, ec);
for (std::vector<ip_interface>::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<ip_route> 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 // this upnp device is filtered because it's not in the
// list of configured routers // list of configured routers
@ -319,13 +345,12 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer
} }
else else
{ {
std::vector<ip_interface> const& net = enum_net_interfaces(m_io_service, ec);
m_log << time_now_string() << " <== (" << from << ") UPnP device " m_log << time_now_string() << " <== (" << from << ") UPnP device "
"ignored because it's not on our network "; "ignored because it's not a router on our network ";
for (std::vector<ip_interface>::const_iterator i = net.begin() for (std::vector<ip_route>::const_iterator i = routes.begin()
, end(net.end()); i != end; ++i) , end(routes.end()); i != end; ++i)
{ {
m_log << "(" << i->interface_address << ", " << i->netmask << ") "; m_log << "(" << i->gateway << ", " << i->netmask << ") ";
} }
m_log << std::endl; m_log << std::endl;
} }
@ -392,10 +417,21 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer
std::string protocol; std::string protocol;
std::string auth; std::string auth;
char const* error;
// we don't have this device in our list. Add it // 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); = 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 // ignore the auth here. It will be re-parsed
// by the http connection later // 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 // just to make sure we find all devices
if (m_retry_count >= 4 && !m_devices.empty()) if (m_retry_count >= 4 && !m_devices.empty())
{ {
asio::error_code ec; error_code ec;
m_broadcast_timer.cancel(ec); m_broadcast_timer.cancel(ec);
for (std::set<rootdevice>::iterator i = m_devices.begin() for (std::set<rootdevice>::iterator i = m_devices.begin()
@ -473,9 +509,10 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer
m_log << time_now_string() m_log << time_now_string()
<< " ==> connecting to " << d.url << std::endl; << " ==> connecting to " << d.url << std::endl;
#endif #endif
if (d.upnp_connection) d.upnp_connection->close();
d.upnp_connection.reset(new http_connection(m_io_service d.upnp_connection.reset(new http_connection(m_io_service
, m_cc, bind(&upnp::on_upnp_xml, self(), _1, _2 , 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); d.upnp_connection->get(d.url, seconds(30), 1);
#ifndef BOOST_NO_EXCEPTIONS #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/\">" "s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\">"
"<s:Body><u:" << soap_action << " xmlns:u=\"" << d.service_namespace << "\">"; "<s:Body><u:" << soap_action << " xmlns:u=\"" << d.service_namespace << "\">";
asio::error_code ec; error_code ec;
soap << "<NewRemoteHost></NewRemoteHost>" soap << "<NewRemoteHost></NewRemoteHost>"
"<NewExternalPort>" << d.mapping[i].external_port << "</NewExternalPort>" "<NewExternalPort>" << d.mapping[i].external_port << "</NewExternalPort>"
"<NewProtocol>" << (d.mapping[i].protocol == udp ? "UDP" : "TCP") << "</NewProtocol>" "<NewProtocol>" << (d.mapping[i].protocol == udp ? "UDP" : "TCP") << "</NewProtocol>"
@ -612,9 +649,10 @@ void upnp::update_map(rootdevice& d, int i)
return; return;
} }
if (d.upnp_connection) d.upnp_connection->close();
d.upnp_connection.reset(new http_connection(m_io_service d.upnp_connection.reset(new http_connection(m_io_service
, m_cc, bind(&upnp::on_upnp_map_response, self(), _1, _2 , 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))); , bind(&upnp::create_port_mapping, self(), _1, boost::ref(d), i)));
d.upnp_connection->start(d.hostname, boost::lexical_cast<std::string>(d.port) d.upnp_connection->start(d.hostname, boost::lexical_cast<std::string>(d.port)
@ -622,9 +660,10 @@ void upnp::update_map(rootdevice& d, int i)
} }
else if (m.action == mapping_t::action_delete) 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 d.upnp_connection.reset(new http_connection(m_io_service
, m_cc, bind(&upnp::on_upnp_unmap_response, self(), _1, _2 , 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))); , bind(&upnp::delete_port_mapping, self(), boost::ref(d), i)));
d.upnp_connection->start(d.hostname, boost::lexical_cast<std::string>(d.port) d.upnp_connection->start(d.hostname, boost::lexical_cast<std::string>(d.port)
, seconds(10), 1); , seconds(10), 1);
@ -732,13 +771,14 @@ namespace
} }
void upnp::on_upnp_xml(asio::error_code const& e void upnp::on_upnp_xml(error_code const& e
, libtorrent::http_parser const& p, rootdevice& d) , libtorrent::http_parser const& p, rootdevice& d
, http_connection& c)
{ {
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
TORRENT_ASSERT(d.magic == 1337); 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->close();
d.upnp_connection.reset(); d.upnp_connection.reset();
@ -816,7 +856,7 @@ void upnp::on_upnp_xml(asio::error_code const& e
d.control_url = s.control_url; d.control_url = s.control_url;
update_map(d, 0); if (num_mappings() > 0) update_map(d, 0);
} }
void upnp::disable(char const* msg) void upnp::disable(char const* msg)
@ -833,7 +873,7 @@ void upnp::disable(char const* msg)
} }
m_devices.clear(); m_devices.clear();
asio::error_code ec; error_code ec;
m_broadcast_timer.cancel(ec); m_broadcast_timer.cancel(ec);
m_refresh_timer.cancel(ec); m_refresh_timer.cancel(ec);
m_socket.close(); m_socket.close();
@ -891,13 +931,14 @@ namespace
} }
void upnp::on_upnp_map_response(asio::error_code const& e void upnp::on_upnp_map_response(error_code const& e
, libtorrent::http_parser const& p, rootdevice& d, int mapping) , libtorrent::http_parser const& p, rootdevice& d, int mapping
, http_connection& c)
{ {
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
TORRENT_ASSERT(d.magic == 1337); 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->close();
d.upnp_connection.reset(); d.upnp_connection.reset();
@ -1014,7 +1055,7 @@ void upnp::on_upnp_map_response(asio::error_code const& e
if (next_expire < time_now() if (next_expire < time_now()
|| next_expire > m.expires) || next_expire > m.expires)
{ {
asio::error_code ec; error_code ec;
m_refresh_timer.expires_at(m.expires, ec); m_refresh_timer.expires_at(m.expires, ec);
m_refresh_timer.async_wait(bind(&upnp::on_expire, self(), _1)); 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); m_callback(mapping, 0, error_string);
} }
void upnp::on_upnp_unmap_response(asio::error_code const& e void upnp::on_upnp_unmap_response(error_code const& e
, libtorrent::http_parser const& p, rootdevice& d, int mapping) , libtorrent::http_parser const& p, rootdevice& d, int mapping
, http_connection& c)
{ {
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
TORRENT_ASSERT(d.magic == 1337); 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->close();
d.upnp_connection.reset(); d.upnp_connection.reset();
@ -1093,7 +1135,7 @@ void upnp::on_upnp_unmap_response(asio::error_code const& e
next(d, mapping); next(d, mapping);
} }
void upnp::on_expire(asio::error_code const& e) void upnp::on_expire(error_code const& e)
{ {
if (e) return; if (e) return;
@ -1125,7 +1167,7 @@ void upnp::on_expire(asio::error_code const& e)
} }
if (next_expire != max_time()) if (next_expire != max_time())
{ {
asio::error_code ec; error_code ec;
m_refresh_timer.expires_at(next_expire, ec); m_refresh_timer.expires_at(next_expire, ec);
m_refresh_timer.async_wait(bind(&upnp::on_expire, self(), _1)); 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); mutex_t::scoped_lock l(m_mutex);
asio::error_code ec; error_code ec;
m_refresh_timer.cancel(ec); m_refresh_timer.cancel(ec);
m_broadcast_timer.cancel(ec); m_broadcast_timer.cancel(ec);
m_closing = true; m_closing = true;
@ -1159,7 +1201,7 @@ void upnp::close()
j->action = mapping_t::action_delete; j->action = mapping_t::action_delete;
m_mappings[j - d.mapping.begin()].protocol = none; m_mappings[j - d.mapping.begin()].protocol = none;
} }
update_map(d, 0); if (num_mappings() > 0) update_map(d, 0);
} }
} }

View File

@ -54,7 +54,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/bencode.hpp" #include "libtorrent/bencode.hpp"
#include "libtorrent/torrent.hpp" #include "libtorrent/torrent.hpp"
#include "libtorrent/extensions.hpp" #include "libtorrent/extensions.hpp"
#include "libtorrent/extensions/metadata_transfer.hpp" #include "libtorrent/extensions/ut_metadata.hpp"
#include "libtorrent/alert_types.hpp" #include "libtorrent/alert_types.hpp"
#ifdef TORRENT_STATS #ifdef TORRENT_STATS
#include "libtorrent/aux_/session_impl.hpp" #include "libtorrent/aux_/session_impl.hpp"
@ -89,39 +89,38 @@ namespace libtorrent { namespace
virtual boost::shared_ptr<peer_plugin> new_connection( virtual boost::shared_ptr<peer_plugin> new_connection(
peer_connection* pc); peer_connection* pc);
std::vector<char> const& metadata() const buffer::const_interval metadata() const
{ {
TORRENT_ASSERT(m_torrent.valid_metadata()); TORRENT_ASSERT(m_torrent.valid_metadata());
if (!m_metadata)
if (m_metadata.empty())
{ {
bencode(std::back_inserter(m_metadata) m_metadata = m_torrent.torrent_file().metadata();
, m_torrent.torrent_file().create_info_metadata()); m_metadata_size = m_torrent.torrent_file().metadata_size();
TORRENT_ASSERT(hasher(m_metadata.get(), m_metadata_size).final()
TORRENT_ASSERT(hasher(&m_metadata[0], m_metadata.size()).final()
== m_torrent.torrent_file().info_hash()); == m_torrent.torrent_file().info_hash());
} }
TORRENT_ASSERT(!m_metadata.empty()); return buffer::const_interval(m_metadata.get(), m_metadata.get()
return m_metadata; + m_metadata_size);
} }
bool received_metadata(char const* buf, int size, int piece, int total_size) bool received_metadata(char const* buf, int size, int piece, int total_size)
{ {
if (m_torrent.valid_metadata()) return false; if (m_torrent.valid_metadata()) return false;
if (m_metadata.empty()) if (!m_metadata)
{ {
// verify the total_size // verify the total_size
if (total_size <= 0 || total_size > 500 * 1024) return false; 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_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())) if (piece < 0 || piece >= int(m_requested_metadata.size()))
return false; 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); std::memcpy(&m_metadata[piece * 16 * 1024], buf, size);
// mark this piece has 'have' // mark this piece has 'have'
m_requested_metadata[piece] = (std::numeric_limits<int>::max)(); m_requested_metadata[piece] = (std::numeric_limits<int>::max)();
@ -133,7 +132,7 @@ namespace libtorrent { namespace
if (!have_all) return false; if (!have_all) return false;
hasher h; 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(); sha1_hash info_hash = h.final();
if (info_hash != m_torrent.torrent_file().info_hash()) if (info_hash != m_torrent.torrent_file().info_hash())
@ -149,7 +148,8 @@ namespace libtorrent { namespace
return false; 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; std::string error;
if (!m_torrent.set_metadata(metadata, 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; if (m_metadata_size > 0 || size <= 0 || size > 500 * 1024) return;
m_metadata_size = size; 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); 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 // the metadata file while downloading it from
// peers, and while sending it. // peers, and while sending it.
// it is mutable because it's generated lazily // it is mutable because it's generated lazily
mutable std::vector<char> m_metadata; mutable boost::shared_array<char> m_metadata;
int m_metadata_progress; int m_metadata_progress;
int m_metadata_size; mutable int m_metadata_size;
// this vector keeps track of how many times each meatdata // this vector keeps track of how many times each meatdata
// block has been requested // block has been requested
@ -231,7 +231,7 @@ namespace libtorrent { namespace
entry& messages = h["m"]; entry& messages = h["m"];
messages["ut_metadata"] = 15; messages["ut_metadata"] = 15;
if (m_torrent.valid_metadata()) 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 // called when the extension handshake from the other end is received
@ -273,14 +273,14 @@ namespace libtorrent { namespace
if (type == 1) if (type == 1)
{ {
TORRENT_ASSERT(m_pc.associated_torrent().lock()->valid_metadata()); 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; int offset = piece * 16 * 1024;
metadata = &m_tp.metadata()[0] + offset; metadata = m_tp.metadata().begin + offset;
metadata_piece_size = (std::min)( 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(metadata_piece_size > 0);
TORRENT_ASSERT(offset >= 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]; char msg[200];

View File

@ -113,7 +113,7 @@ namespace libtorrent { namespace
for (torrent::peer_iterator i = m_torrent.begin() for (torrent::peer_iterator i = m_torrent.begin()
, end(m_torrent.end()); i != end; ++i) , end(m_torrent.end()); i != end; ++i)
{ {
peer_connection* peer = *i; peer_connection* peer = *i;
if (!send_peer(*peer)) continue; if (!send_peer(*peer)) continue;
tcp::endpoint const& remote = peer->remote(); tcp::endpoint const& remote = peer->remote();

View File

@ -49,6 +49,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/io.hpp" #include "libtorrent/io.hpp"
#include "libtorrent/version.hpp" #include "libtorrent/version.hpp"
#include "libtorrent/aux_/session_impl.hpp" #include "libtorrent/aux_/session_impl.hpp"
#include "libtorrent/parse_url.hpp"
using boost::bind; using boost::bind;
using boost::shared_ptr; using boost::shared_ptr;
@ -72,6 +73,8 @@ namespace libtorrent
// we want large blocks as well, so // we want large blocks as well, so
// we can request more bytes at once // we can request more bytes at once
request_large_blocks(true); request_large_blocks(true);
set_upload_only(true);
// we only want left-over bandwidth // we only want left-over bandwidth
set_priority(0); set_priority(0);
shared_ptr<torrent> tor = t.lock(); shared_ptr<torrent> tor = t.lock();
@ -95,8 +98,10 @@ namespace libtorrent
#endif #endif
std::string protocol; 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); = parse_url_components(url);
TORRENT_ASSERT(error == 0);
if (!m_auth.empty()) if (!m_auth.empty())
m_auth = base64encode(m_auth); 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) , std::size_t bytes_transferred)
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
@ -349,7 +354,7 @@ namespace libtorrent
if (error) if (error)
{ {
disconnect("failed to parse HTTP response"); disconnect("failed to parse HTTP response", 2);
return; return;
} }
@ -380,7 +385,7 @@ namespace libtorrent
m_ses.m_alerts.post_alert(url_seed_alert(t->get_handle(), url() m_ses.m_alerts.post_alert(url_seed_alert(t->get_handle(), url()
, error_msg)); , error_msg));
} }
disconnect(error_msg.c_str()); disconnect(error_msg.c_str(), 1);
return; return;
} }
if (!m_parser.header_finished()) break; if (!m_parser.header_finished()) break;
@ -406,7 +411,7 @@ namespace libtorrent
{ {
// we should not try this server again. // we should not try this server again.
t->remove_url_seed(m_url); t->remove_url_seed(m_url);
disconnect("got HTTP redirection status without location header"); disconnect("got HTTP redirection status without location header", 2);
return; return;
} }
@ -430,7 +435,7 @@ namespace libtorrent
std::stringstream msg; std::stringstream msg;
msg << "got invalid HTTP redirection location (\"" << location << "\") " msg << "got invalid HTTP redirection location (\"" << location << "\") "
"expected it to end with: " << path; "expected it to end with: " << path;
disconnect(msg.str().c_str()); disconnect(msg.str().c_str(), 2);
return; return;
} }
location.resize(i); location.resize(i);
@ -475,7 +480,7 @@ namespace libtorrent
t->remove_url_seed(m_url); t->remove_url_seed(m_url);
std::stringstream msg; std::stringstream msg;
msg << "invalid range in HTTP response: " << range_str.str(); msg << "invalid range in HTTP response: " << range_str.str();
disconnect(msg.str().c_str()); disconnect(msg.str().c_str(), 2);
return; return;
} }
// the http range is inclusive // the http range is inclusive
@ -489,7 +494,7 @@ namespace libtorrent
{ {
// we should not try this server again. // we should not try this server again.
t->remove_url_seed(m_url); t->remove_url_seed(m_url);
disconnect("no content-length in HTTP response"); disconnect("no content-length in HTTP response", 2);
return; return;
} }
} }
@ -501,7 +506,7 @@ namespace libtorrent
if (m_requests.empty() || m_file_requests.empty()) if (m_requests.empty() || m_file_requests.empty())
{ {
disconnect("unexpected HTTP response"); disconnect("unexpected HTTP response", 2);
return; return;
} }
@ -534,7 +539,7 @@ namespace libtorrent
{ {
// this means the end of the incoming request ends _before_ the // this means the end of the incoming request ends _before_ the
// first expected byte (fs + m_piece.size()) // first expected byte (fs + m_piece.size())
disconnect("invalid range in HTTP response"); disconnect("invalid range in HTTP response", 2);
return; return;
} }
@ -662,7 +667,7 @@ namespace libtorrent
} }
// throws exception when the client should be disconnected // 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) , std::size_t bytes_transferred)
{ {
INVARIANT_CHECK; INVARIANT_CHECK;

View File

@ -85,15 +85,10 @@ if not os.environ.has_key("CPP"):
# The libtorrent extension # The libtorrent extension
_extra_compile_args = [ _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", "-DTORRENT_USE_OPENSSL=1",
"-DHAVE_SSL=1",
"-O2", "-O2",
"-D_FILE_OFFSET_BITS=64", "-D_FILE_OFFSET_BITS=64",
"-DNDEBUG" "-DNDEBUG",
] ]
if windows_check(): if windows_check():