@@ -584,6 +585,10 @@ struct torrent_handle
void connect_peer(const address& adr) const;
void set_ratio(float ratio);
+ void pause();
+ void resume();
+ bool is_paused() const;
+
void set_tracker_login(std::string const& username, std::string const& password);
void use_interface(const char* net_interface);
@@ -620,6 +625,11 @@ in return. With this setting it will work much like the standard clients.
attempt to upload in return for each download. e.g. if set to 2, the client will try to upload
2 bytes for every byte received. The default setting for this is 0, which will make it work
as a standard client.
+
This alert is generated when a peer sends invalid data over the peer-peer protocol. The peer
diff --git a/docs/manual.rst b/docs/manual.rst
index c2dd79f22..3de747af2 100755
--- a/docs/manual.rst
+++ b/docs/manual.rst
@@ -584,6 +584,10 @@ Its declaration looks like this::
void connect_peer(const address& adr) const;
void set_ratio(float ratio);
+ void pause();
+ void resume();
+ bool is_paused() const;
+
void set_tracker_login(std::string const& username, std::string const& password);
void use_interface(const char* net_interface);
@@ -626,6 +630,12 @@ attempt to upload in return for each download. e.g. if set to 2, the client will
2 bytes for every byte received. The default setting for this is 0, which will make it work
as a standard client.
+``pause()``, and ``resume()`` will disconnect all peers and reconnect all peers respectively.
+When a torrent is paused, it will however remember all share ratios to all peers and remember
+all potential (not connected) peers. You can use ``is_paused()`` to determine if a torrent
+is currently paused. Torrents may be paused automatically if there is a file error (eg. disk full)
+or something similar. See file_error_alert_.
+
``set_tracker_login()`` sets a username and password that will be sent along in the HTTP-request
of the tracker announce. Set this if the tracker requires authorization.
@@ -1213,7 +1223,7 @@ file_error_alert
----------------
If the storage fails to read or write files that it needs access to, this alert is
-generated and the torrent is aborted. It is generated as severity level ``fatal``.
+generated and the torrent is paused. It is generated as severity level ``fatal``.
::
@@ -1271,6 +1281,29 @@ This alert is generated as severity level ``info``.
};
+peer_ban_alert
+--------------
+
+This alert is generated when a peer is banned because it has sent too many corrupt pieces
+to us. It is generated at severity level ``info``. The ``handle`` member is a torrent_handle_
+to the torrent that this peer was a member of.
+
+::
+
+ struct peer_ban_alert: alert
+ {
+ peer_error_alert(
+ address const& pip
+ , torrent_handle h
+ , const std::string& msg);
+
+ virtual std::auto_ptr clone() const;
+
+ address ip;
+ torrent_handle handle;
+ };
+
+
peer_error_alert
----------------
diff --git a/examples/client_test.cpp b/examples/client_test.cpp
index 1803f5f08..6a46552da 100755
--- a/examples/client_test.cpp
+++ b/examples/client_test.cpp
@@ -319,6 +319,25 @@ int main(int argc, char* argv[])
, handles.end()
, boost::bind(&torrent_handle::force_reannounce, _1));
}
+
+ if(c == 'p')
+ {
+ // pause all torrents
+ std::for_each(
+ handles.begin()
+ , handles.end()
+ , boost::bind(&torrent_handle::pause, _1));
+ }
+
+ if(c == 'u')
+ {
+ // unpause all torrents
+ std::for_each(
+ handles.begin()
+ , handles.end()
+ , boost::bind(&torrent_handle::resume, _1));
+ }
+
}
std::auto_ptr a;
diff --git a/include/libtorrent/alert_types.hpp b/include/libtorrent/alert_types.hpp
index 1bd782197..5c6d87408 100755
--- a/include/libtorrent/alert_types.hpp
+++ b/include/libtorrent/alert_types.hpp
@@ -72,6 +72,22 @@ namespace libtorrent
int piece_index;
};
+ struct peer_ban_alert: alert
+ {
+ peer_ban_alert(const address& pip, torrent_handle h, const std::string& msg)
+ : alert(alert::info, msg)
+ , ip(pip)
+ , handle(h)
+ {}
+
+ virtual std::auto_ptr clone() const
+ { return std::auto_ptr(new peer_ban_alert(*this)); }
+
+ address ip;
+ torrent_handle handle;
+ };
+
+
struct peer_error_alert: alert
{
peer_error_alert(const address& pip, const std::string& msg)
diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp
index cd648389f..ca69940be 100755
--- a/include/libtorrent/peer_connection.hpp
+++ b/include/libtorrent/peer_connection.hpp
@@ -199,6 +199,9 @@ namespace libtorrent
// if it was an incoming connection, it is remote
bool is_local() const { return m_active; }
+ void set_failed() { m_failed = true; }
+ bool failed() const { return m_failed; }
+
#ifndef NDEBUG
boost::shared_ptr m_logger;
#endif
@@ -385,6 +388,12 @@ namespace libtorrent
// 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;
+
// this is set to true if the handshake from
// the peer indicated that it supports the
// extension protocol
diff --git a/include/libtorrent/policy.hpp b/include/libtorrent/policy.hpp
index 50a481d79..a956db4b4 100755
--- a/include/libtorrent/policy.hpp
+++ b/include/libtorrent/policy.hpp
@@ -76,6 +76,11 @@ namespace libtorrent
// return false if the connection closed
void new_connection(peer_connection& c);
+ // this is called if a peer timed-out or
+ // forcefully closed the connection. This
+ // will mark the connection as non-reconnectale
+ void peer_failed(peer_connection const& c);
+
// the given connection was just closed
void connection_closed(const peer_connection& c);
@@ -163,6 +168,11 @@ namespace libtorrent
peer_connection* connection;
};
+ int num_peers() const
+ {
+ return m_num_peers;
+ }
+
private:
bool unchoke_one_peer();
diff --git a/include/libtorrent/session.hpp b/include/libtorrent/session.hpp
index d8abeb26a..d3f827109 100755
--- a/include/libtorrent/session.hpp
+++ b/include/libtorrent/session.hpp
@@ -188,9 +188,14 @@ namespace libtorrent
// in loops that iterate over them.
std::vector m_disconnect_peer;
- // the peer id that is generated at the start of each torrent
+ // the peer id that is generated at the start of the session
peer_id m_peer_id;
+ // the key is an id that is used to identify the
+ // client with the tracker only. It is randomized
+ // at startup
+ int m_key;
+
// the range of ports we try to listen on
std::pair m_listen_port_range;
diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp
index f98ab0163..c15b11d57 100755
--- a/include/libtorrent/torrent.hpp
+++ b/include/libtorrent/torrent.hpp
@@ -101,14 +101,15 @@ namespace libtorrent
// tracker request
bool should_request() const
{
-// boost::posix_time::time_duration d = m_next_request - boost::posix_time::second_clock::local_time();
-// return d.is_negative();
- return m_next_request < boost::posix_time::second_clock::local_time();
+ namespace time = boost::posix_time;
+ return !m_paused &&
+ m_next_request < time::second_clock::local_time();
}
void force_tracker_request()
{
- m_next_request = boost::posix_time::second_clock::local_time();
+ namespace time = boost::posix_time;
+ m_next_request = time::second_clock::local_time();
}
void print(std::ostream& os) const;
@@ -121,6 +122,10 @@ namespace libtorrent
size_type bytes_left() const;
size_type bytes_done() const;
+ void pause();
+ void resume();
+ bool is_paused() const { return m_paused; }
+
torrent_status status() const;
void use_interface(const char* net_interface);
@@ -188,7 +193,7 @@ namespace libtorrent
// generates a request string for sending
// to the tracker
- tracker_request generate_tracker_request(int port);
+ tracker_request generate_tracker_request();
std::string tracker_password() const;
boost::posix_time::ptime next_announce() const
@@ -293,6 +298,9 @@ namespace libtorrent
// been aborted.
bool m_abort;
+ // is true if this torrent has been paused
+ bool m_paused;
+
tracker_request::event_t m_event;
void parse_response(const entry& e, std::vector& peer_list);
diff --git a/include/libtorrent/torrent_handle.hpp b/include/libtorrent/torrent_handle.hpp
index 8c36a0d07..3a85dd9a0 100755
--- a/include/libtorrent/torrent_handle.hpp
+++ b/include/libtorrent/torrent_handle.hpp
@@ -96,6 +96,7 @@ namespace libtorrent
};
state_t state;
+ bool paused;
float progress;
boost::posix_time::time_duration next_announce;
boost::posix_time::time_duration announce_interval;
@@ -152,6 +153,10 @@ namespace libtorrent
const torrent_info& get_torrent_info() const;
bool is_valid() const;
+ bool is_paused() const;
+ void pause();
+ void resume();
+
// set the interface to bind outgoing connections
// to.
void use_interface(const char* net_interface);
diff --git a/include/libtorrent/tracker_manager.hpp b/include/libtorrent/tracker_manager.hpp
index 88f367ff8..7e853e2a9 100755
--- a/include/libtorrent/tracker_manager.hpp
+++ b/include/libtorrent/tracker_manager.hpp
@@ -90,6 +90,8 @@ namespace libtorrent
unsigned short listen_port;
event_t event;
std::string url;
+ int key;
+ int num_want;
};
struct request_callback
diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp
index 65a7815b0..76a635975 100755
--- a/src/http_tracker_connection.cpp
+++ b/src/http_tracker_connection.cpp
@@ -151,11 +151,16 @@ namespace libtorrent
m_send_buffer += "&event=";
m_send_buffer += event_string[req.event - 1];
}
+ m_send_buffer += "&key=";
+ // TODO: this should be encoded as hex
+ m_send_buffer += boost::lexical_cast((unsigned int)req.key);
+ m_send_buffer += "&compact=1";
+ m_send_buffer += "&num_want=";
+ m_send_buffer += boost::lexical_cast(req.num_want);
// extension that tells the tracker that
// we don't need any peer_id's in the response
m_send_buffer += "&no_peer_id=1";
- m_send_buffer += "&compact=1";
m_send_buffer += " HTTP/1.0\r\nAccept-Encoding: gzip\r\n"
"User-Agent: ";
diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp
index c4fd80da6..b80621ba2 100755
--- a/src/peer_connection.cpp
+++ b/src/peer_connection.cpp
@@ -97,6 +97,7 @@ namespace libtorrent
, m_peer_choked(true)
, m_interesting(false)
, m_choked(true)
+ , m_failed(false)
, m_supports_extensions(false)
, m_num_pieces(0)
, m_free_upload(0)
@@ -159,6 +160,7 @@ namespace libtorrent
, m_peer_choked(true)
, m_interesting(false)
, m_choked(true)
+ , m_failed(false)
, m_supports_extensions(false)
, m_num_pieces(0)
, m_free_upload(0)
@@ -247,8 +249,10 @@ namespace libtorrent
void peer_connection::received_invalid_data()
{
- m_trust_points--;
- if (m_trust_points < -5) m_trust_points = -5;
+ // we decrease more than we increase, to keep the
+ // allowed failed/passed ratio low.
+ m_trust_points -= 2;
+ if (m_trust_points < -7) m_trust_points = -7;
}
int peer_connection::trust_points() const
@@ -1530,6 +1534,16 @@ namespace libtorrent
throw protocol_error("got info-hash that is not in our session");
}
+ if (m_torrent->is_paused())
+ {
+ // paused torrents will not accept
+ // incoming connections
+ #ifndef NDEBUG
+ (*m_logger) << " rejected connection to paused torrent\n";
+ #endif
+ throw protocol_error("connection rejected by paused torrent");
+ }
+
// assume the other end has no pieces
m_have_piece.resize(m_torrent->torrent_file().num_pieces());
std::fill(m_have_piece.begin(), m_have_piece.end(), false);
@@ -1576,6 +1590,13 @@ namespace libtorrent
std::copy(m_recv_buffer.begin(), m_recv_buffer.begin() + 20, (char*)tmp.begin());
std::stringstream s;
s << "received peer_id: " << tmp << " client: " << identify_client(tmp) << "\n";
+ s << "as ascii: ";
+ for (peer_id::iterator i = tmp.begin(); i != tmp.end(); ++i)
+ {
+ if (std::isprint(*i)) s << *i;
+ else s << ".";
+ }
+ s << "\n";
(*m_logger) << s.str();
}
#endif
diff --git a/src/policy.cpp b/src/policy.cpp
index a217fb68e..fde900a14 100755
--- a/src/policy.cpp
+++ b/src/policy.cpp
@@ -456,12 +456,11 @@ namespace libtorrent
{
if(i->connection) continue;
if(i->banned) continue;
- if(i->type==peer::not_connectable) continue;
+ if(i->type == peer::not_connectable) continue;
assert(i->connected <= local_time);
- boost::posix_time::ptime next_connect
- = i->connected + boost::posix_time::seconds(10 * 60);
+ boost::posix_time::ptime next_connect = i->connected;
if (next_connect <= ptime)
{
@@ -736,6 +735,8 @@ namespace libtorrent
assert(i != m_peers.end());
+ i->type = peer::not_connectable;
+ i->id.port = address::any_port;
i->banned = true;
}
@@ -782,7 +783,7 @@ namespace libtorrent
if (i->connection != 0)
throw protocol_error("duplicate connection, closing");
if (i->banned)
- throw protocol_error("ip address banned, disconnected");
+ throw protocol_error("ip address banned, closing");
}
assert(i->connection == 0);
@@ -948,6 +949,11 @@ namespace libtorrent
c.add_free_upload(-diff);
}
}
+ if (!c.is_choked())
+ {
+ c.send_choke();
+ --m_num_unchoked;
+ }
}
bool policy::unchoke_one_peer()
@@ -999,7 +1005,7 @@ namespace libtorrent
bool policy::disconnect_one_peer()
{
- peer *p=find_disconnect_candidate();
+ peer *p = find_disconnect_candidate();
if(!p)
return false;
p->connection->disconnect();
@@ -1014,16 +1020,26 @@ namespace libtorrent
, m_peers.end()
, match_peer_connection(c));
+ // if we couldn't find the connection in our list, just ignore it.
if (i == m_peers.end()) return;
assert(i->connection == &c);
i->connected = boost::posix_time::second_clock::local_time();
if (!i->connection->is_choked() && !m_torrent->is_aborted())
{
+ // if the peer that is diconnecting is unchoked
+ // then unchoke another peer in order to maintain
+ // the total number of unchoked peers
--m_num_unchoked;
unchoke_one_peer();
}
+ if (c.failed())
+ {
+ i->type = peer::not_connectable;
+ i->id.port = address::any_port;
+ }
+
// if the share ratio is 0 (infinite), the
// m_available_free_upload isn't used,
// because it isn't necessary.
diff --git a/src/session.cpp b/src/session.cpp
index e9607ce07..e590f93f8 100755
--- a/src/session.cpp
+++ b/src/session.cpp
@@ -277,6 +277,7 @@ namespace libtorrent { namespace detail
std::srand((unsigned int)std::time(0));
+ m_key = rand() + (rand() << 15) + (rand() << 30);
std::string print = cl_fprint.to_string();
assert(print.length() == 8);
@@ -423,7 +424,10 @@ namespace libtorrent { namespace detail
++i)
{
i->second->abort();
- m_tracker_manager.queue_request(i->second->generate_tracker_request(m_listen_interface.port));
+ tracker_request req = i->second->generate_tracker_request();
+ req.listen_port = m_listen_interface.port;
+ req.key = m_key;
+ m_tracker_manager.queue_request(req);
}
m_connections.clear();
m_torrents.clear();
@@ -438,7 +442,7 @@ namespace libtorrent { namespace detail
// SEND SOCKETS
// ************************
- // let the writable clients send data
+ // let the writable connections send data
for (std::vector >::iterator i
= writable_clients.begin();
i != writable_clients.end();
@@ -473,10 +477,9 @@ namespace libtorrent { namespace detail
, e.what()));
}
- m_selector.remove(*i);
- m_connections.erase(p);
+ // pause the torrent
+ t->pause();
assert(m_selector.count_read_monitors() == (int)m_connections.size() + (bool)m_listen_socket);
- t->abort();
}
catch (std::exception& e)
{
@@ -488,6 +491,7 @@ namespace libtorrent { namespace detail
peer_error_alert(p->first->sender(), e.what()));
}
+ p->second->set_failed();
m_selector.remove(*i);
m_connections.erase(p);
assert(m_selector.count_read_monitors() == (int)m_connections.size() + (bool)m_listen_socket);
@@ -547,7 +551,6 @@ namespace libtorrent { namespace detail
{
try
{
-// (*m_logger) << "readable: " << p->first->sender().as_string() << "\n";
p->second->receive_data();
}
catch (file_error& e)
@@ -563,10 +566,8 @@ namespace libtorrent { namespace detail
, e.what()));
}
- m_selector.remove(*i);
- m_connections.erase(p);
assert(m_selector.count_read_monitors() == (int)m_connections.size() + (bool)m_listen_socket);
- t->abort();
+ t->pause();
}
catch (std::exception& e)
{
@@ -577,6 +578,7 @@ namespace libtorrent { namespace detail
}
// the connection wants to disconnect for some reason, remove it
// from the connection-list
+ p->second->set_failed();
m_selector.remove(*i);
m_connections.erase(p);
assert(m_selector.count_read_monitors() == (int)m_connections.size() + (bool)m_listen_socket);
@@ -611,6 +613,7 @@ namespace libtorrent { namespace detail
// the connection may have been disconnected in the receive or send phase
if (p != m_connections.end())
{
+ p->second->set_failed();
m_connections.erase(p);
assert(m_selector.count_read_monitors() == (int)m_connections.size() + (bool)m_listen_socket);
}
@@ -651,6 +654,7 @@ namespace libtorrent { namespace detail
m_alerts.post_alert(
peer_error_alert(j->first->sender(), "connection timed out"));
}
+ j->second->set_failed();
m_selector.remove(j->first);
m_connections.erase(j);
assert(m_selector.count_read_monitors() == (int)m_connections.size() + (bool)m_listen_socket);
@@ -668,8 +672,10 @@ namespace libtorrent { namespace detail
{
if (i->second->is_aborted())
{
- m_tracker_manager.queue_request(
- i->second->generate_tracker_request(m_listen_interface.port));
+ tracker_request req = i->second->generate_tracker_request();
+ req.listen_port = m_listen_interface.port;
+ req.key = m_key;
+ m_tracker_manager.queue_request(req);
i->second->disconnect_all();
purge_connections();
#ifndef NDEBUG
@@ -683,8 +689,11 @@ namespace libtorrent { namespace detail
}
else if (i->second->should_request())
{
+ tracker_request req = i->second->generate_tracker_request();
+ req.listen_port = m_listen_interface.port;
+ req.key = m_key;
m_tracker_manager.queue_request(
- i->second->generate_tracker_request(m_listen_interface.port)
+ req
, boost::get_pointer(i->second));
}
diff --git a/src/torrent.cpp b/src/torrent.cpp
index 9455db14a..1a14d4114 100755
--- a/src/torrent.cpp
+++ b/src/torrent.cpp
@@ -220,6 +220,7 @@ namespace libtorrent
, address const& net_interface)
: m_block_size(calculate_block_size(torrent_file))
, m_abort(false)
+ , m_paused(false)
, m_event(tracker_request::started)
, m_torrent_file(torrent_file)
, m_storage(m_torrent_file, save_path)
@@ -419,11 +420,18 @@ namespace libtorrent
if (p == m_connections.end()) continue;
p->second->received_invalid_data();
- if (p->second->trust_points() <= -5)
+ if (p->second->trust_points() <= -7)
{
// we don't trust this peer anymore
// ban it.
m_policy->ban_peer(*p->second);
+ if (m_ses.m_alerts.should_post(alert::info))
+ {
+ m_ses.m_alerts.post_alert(peer_ban_alert(
+ p->first
+ , get_handle()
+ , "banning peer because of too many corrupt pieces"));
+ }
}
}
@@ -473,10 +481,8 @@ namespace libtorrent
return m_username + ":" + m_password;
}
- tracker_request torrent::generate_tracker_request(int port)
+ tracker_request torrent::generate_tracker_request()
{
- assert(port > 0);
- assert((unsigned short)port == port);
m_duration = 1800;
m_next_request = boost::posix_time::second_clock::local_time() + boost::posix_time::seconds(m_duration);
@@ -486,9 +492,16 @@ namespace libtorrent
req.downloaded = m_stat.total_payload_download();
req.uploaded = m_stat.total_payload_upload();
req.left = bytes_left();
- req.listen_port = port;
req.event = m_event;
req.url = m_torrent_file.trackers()[m_currently_trying_tracker].url;
+ req.num_want = (m_policy->get_max_connections()
+ - m_policy->num_peers()) * 2;
+
+ // default initialize, these should be set by caller
+ // before passing the request to the tracker_manager
+ req.listen_port = 0;
+ req.key = 0;
+
return req;
}
@@ -530,9 +543,6 @@ namespace libtorrent
m_policy->connection_closed(*p);
m_connections.erase(i);
- #ifndef NDEBUG
-// m_picker.integrity_check(this);
- #endif
}
peer_connection& torrent::connect_to_peer(const address& a)
@@ -670,12 +680,31 @@ namespace libtorrent
}
#endif
+ void torrent::pause()
+ {
+ disconnect_all();
+ // TODO: announce to tracker that we stopped!
+ // possibly with some delay
+ m_paused = true;
+ }
+
+ void torrent::resume()
+ {
+ m_paused = false;
+ // TODO: announce to the tracker that we started.
+ // possibly with some delay
+ // make pulse be called as soon as possible
+ m_time_scaler = 0;
+ }
+
void torrent::second_tick()
{
- m_time_scaler++;
- if (m_time_scaler >= 10)
+ if (m_paused) return;
+
+ m_time_scaler--;
+ if (m_time_scaler <= 0)
{
- m_time_scaler = 0;
+ m_time_scaler = 10;
m_policy->pulse();
}
@@ -738,6 +767,7 @@ namespace libtorrent
= m_torrent_file.trackers()[m_last_working_tracker].url;
}
+ st.paused = m_paused;
st.total_done = bytes_done();
// payload transfer
@@ -759,9 +789,10 @@ namespace libtorrent
st.next_announce = next_announce()
- boost::posix_time::second_clock::local_time();
+ if (st.next_announce.is_negative()) st.next_announce
+ = boost::posix_time::seconds(0);
st.announce_interval = boost::posix_time::seconds(m_duration);
-
st.num_peers = (int)m_connections.size();
st.pieces = &m_have_pieces;
diff --git a/src/torrent_handle.cpp b/src/torrent_handle.cpp
index 83f77589b..0afd51b5b 100755
--- a/src/torrent_handle.cpp
+++ b/src/torrent_handle.cpp
@@ -204,7 +204,18 @@ namespace libtorrent
else
st.state = torrent_status::queued_for_checking;
st.progress = d->progress;
+ st.paused = false;
st.next_announce = boost::posix_time::time_duration();
+ st.announce_interval = boost::posix_time::time_duration();
+ st.total_download = 0;
+ st.total_upload = 0;
+ st.total_payload_download = 0;
+ st.total_payload_upload = 0;
+ st.download_rate = 0.f;
+ st.upload_rate = 0.f;
+ st.num_peers = 0;
+ st.pieces = 0;
+ st.total_done = 0;
return st;
}
}
@@ -234,6 +245,73 @@ namespace libtorrent
throw invalid_handle();
}
+ bool torrent_handle::is_paused() const
+ {
+ INVARIANT_CHECK;
+
+ if (m_ses == 0) throw invalid_handle();
+
+ {
+ boost::mutex::scoped_lock l(m_ses->m_mutex);
+ torrent* t = m_ses->find_torrent(m_info_hash);
+ if (t != 0) return t->is_paused();
+ }
+
+ if (m_chk)
+ {
+ boost::mutex::scoped_lock l(m_chk->m_mutex);
+ detail::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
+ if (d != 0) return d->torrent_ptr->is_paused();
+ }
+
+ throw invalid_handle();
+ }
+
+
+ void torrent_handle::pause()
+ {
+ INVARIANT_CHECK;
+
+ if (m_ses == 0) throw invalid_handle();
+
+ {
+ boost::mutex::scoped_lock l(m_ses->m_mutex);
+ torrent* t = m_ses->find_torrent(m_info_hash);
+ if (t != 0) return t->pause();
+ }
+
+ if (m_chk)
+ {
+ boost::mutex::scoped_lock l(m_chk->m_mutex);
+ detail::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
+ if (d != 0) return d->torrent_ptr->pause();
+ }
+
+ throw invalid_handle();
+ }
+
+ void torrent_handle::resume()
+ {
+ INVARIANT_CHECK;
+
+ if (m_ses == 0) throw invalid_handle();
+
+ {
+ boost::mutex::scoped_lock l(m_ses->m_mutex);
+ torrent* t = m_ses->find_torrent(m_info_hash);
+ if (t != 0) return t->resume();
+ }
+
+ if (m_chk)
+ {
+ boost::mutex::scoped_lock l(m_chk->m_mutex);
+ detail::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
+ if (d != 0) return d->torrent_ptr->resume();
+ }
+
+ throw invalid_handle();
+ }
+
void torrent_handle::set_tracker_login(std::string const& name, std::string const& password)
{
INVARIANT_CHECK;
diff --git a/src/udp_tracker_connection.cpp b/src/udp_tracker_connection.cpp
index d87af5bfb..718df786a 100755
--- a/src/udp_tracker_connection.cpp
+++ b/src/udp_tracker_connection.cpp
@@ -180,7 +180,7 @@ namespace libtorrent
// ip address
detail::write_int32(0, ptr);
// num_want
- detail::write_int32(-1, ptr);
+ detail::write_int32(m_request.num_want, ptr);
// port
detail::write_uint16(m_request.listen_port, ptr);