fix duplicant_torrent and libtorrent bugfixes

This commit is contained in:
Marcos Pinto 2007-12-01 03:54:42 +00:00
parent 2eb3868115
commit cfe1bd241d
21 changed files with 535 additions and 605 deletions

View File

@ -43,6 +43,7 @@ POSSIBILITY OF SUCH DAMAGE.
#endif #endif
#include <boost/thread/mutex.hpp> #include <boost/thread/mutex.hpp>
#include <boost/thread/condition.hpp>
#include <boost/preprocessor/repetition/enum_params_with_a_default.hpp> #include <boost/preprocessor/repetition/enum_params_with_a_default.hpp>
#include <boost/preprocessor/repetition/enum.hpp> #include <boost/preprocessor/repetition/enum.hpp>
@ -99,10 +100,13 @@ namespace libtorrent {
void set_severity(alert::severity_t severity); void set_severity(alert::severity_t severity);
bool should_post(alert::severity_t severity) const; bool should_post(alert::severity_t severity) const;
alert const* wait_for_alert(time_duration max_wait);
private: private:
std::queue<alert*> m_alerts; std::queue<alert*> m_alerts;
alert::severity_t m_severity; alert::severity_t m_severity;
mutable boost::mutex m_mutex; mutable boost::mutex m_mutex;
boost::condition m_condition;
}; };
struct TORRENT_EXPORT unhandled_alert : std::exception struct TORRENT_EXPORT unhandled_alert : std::exception

View File

@ -280,6 +280,8 @@ namespace libtorrent
void set_severity_level(alert::severity_t s); void set_severity_level(alert::severity_t s);
std::auto_ptr<alert> pop_alert(); std::auto_ptr<alert> pop_alert();
alert const* wait_for_alert(time_duration max_wait);
int upload_rate_limit() const; int upload_rate_limit() const;
int download_rate_limit() const; int download_rate_limit() const;

View File

@ -60,6 +60,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/session_status.hpp" #include "libtorrent/session_status.hpp"
#include "libtorrent/version.hpp" #include "libtorrent/version.hpp"
#include "libtorrent/fingerprint.hpp" #include "libtorrent/fingerprint.hpp"
#include "libtorrent/time.hpp"
#include "libtorrent/storage.hpp" #include "libtorrent/storage.hpp"
@ -264,6 +265,8 @@ namespace libtorrent
std::auto_ptr<alert> pop_alert(); std::auto_ptr<alert> pop_alert();
void set_severity_level(alert::severity_t s); void set_severity_level(alert::severity_t s);
alert const* wait_for_alert(time_duration max_wait);
connection_queue& get_connection_queue(); connection_queue& get_connection_queue();
// starts/stops UPnP, NATPMP or LSD port mappers // starts/stops UPnP, NATPMP or LSD port mappers

View File

@ -95,6 +95,7 @@ namespace libtorrent
, peer_timeout(120) , peer_timeout(120)
, urlseed_timeout(20) , urlseed_timeout(20)
, urlseed_pipeline_size(5) , urlseed_pipeline_size(5)
, urlseed_wait_retry(30)
, file_pool_size(40) , file_pool_size(40)
, allow_multiple_connections_per_ip(false) , allow_multiple_connections_per_ip(false)
, max_failcount(3) , max_failcount(3)
@ -186,6 +187,9 @@ namespace libtorrent
// controls the pipelining size of url-seeds // controls the pipelining size of url-seeds
int urlseed_pipeline_size; int urlseed_pipeline_size;
// time to wait until a new retry takes place
int urlseed_wait_retry;
// sets the upper limit on the total number of files this // sets the upper limit on the total number of files this
// session will keep open. The reason why files are // session will keep open. The reason why files are
// left open at all is that some anti virus software // left open at all is that some anti virus software

View File

@ -98,6 +98,7 @@ namespace libtorrent
time_duration() {} time_duration() {}
time_duration operator/(int rhs) const { return time_duration(diff / rhs); } time_duration operator/(int rhs) const { return time_duration(diff / rhs); }
explicit time_duration(boost::int64_t d) : diff(d) {} explicit time_duration(boost::int64_t d) : diff(d) {}
time_duration& operator-=(time_duration const& c) { diff -= c.diff; return *this; }
boost::int64_t diff; boost::int64_t diff;
}; };

View File

@ -206,7 +206,7 @@ namespace libtorrent
tcp::endpoint const& get_interface() const { return m_net_interface; } tcp::endpoint const& get_interface() const { return m_net_interface; }
void connect_to_url_seed(std::string const& url); void connect_to_url_seed(std::string const& url);
bool connect_to_peer(policy::peer* peerinfo) throw(); bool connect_to_peer(policy::peer* peerinfo);
void set_ratio(float ratio) void set_ratio(float ratio)
{ TORRENT_ASSERT(ratio >= 0.0f); m_ratio = ratio; } { TORRENT_ASSERT(ratio >= 0.0f); m_ratio = ratio; }
@ -254,6 +254,8 @@ namespace libtorrent
void remove_url_seed(std::string const& url) void remove_url_seed(std::string const& url)
{ m_web_seeds.erase(url); } { m_web_seeds.erase(url); }
void retry_url_seed(std::string const& url);
std::set<std::string> url_seeds() const std::set<std::string> url_seeds() const
{ return m_web_seeds; } { return m_web_seeds; }
@ -293,6 +295,9 @@ namespace libtorrent
void resolve_peer_country(boost::intrusive_ptr<peer_connection> const& p) const; void resolve_peer_country(boost::intrusive_ptr<peer_connection> const& p) const;
void get_peer_info(std::vector<peer_info>& v);
void get_download_queue(std::vector<partial_piece_info>& queue);
// -------------------------------------------- // --------------------------------------------
// TRACKER MANAGEMENT // TRACKER MANAGEMENT
@ -624,6 +629,10 @@ namespace libtorrent
// with fatal errors are removed from the set // with fatal errors are removed from the set
std::set<std::string> m_web_seeds; std::set<std::string> m_web_seeds;
// a list of web seeds that have failed and are
// waiting to be retried
std::map<std::string, ptime> m_web_seeds_next_retry;
// urls of the web seeds that we are currently // urls of the web seeds that we are currently
// resolving the address for // resolving the address for
std::set<std::string> m_resolving_web_seeds; std::set<std::string> m_resolving_web_seeds;

View File

@ -69,9 +69,15 @@ namespace libtorrent
struct TORRENT_EXPORT file_entry struct TORRENT_EXPORT file_entry
{ {
file_entry(): offset(0), size(0), file_base(0) {}
fs::path path; fs::path path;
size_type offset; // the offset of this file inside the torrent size_type offset; // the offset of this file inside the torrent
size_type size; // the size of this file size_type size; // the size of this file
// the offset in the file where the storage starts.
// This is always 0 unless parts of the torrent is
// compressed into a single file, such as a so-called part file.
size_type file_base;
// if the path was incorrectly encoded, this is // if the path was incorrectly encoded, this is
// the original corrupt encoded string. It is // the original corrupt encoded string. It is
// preserved in order to be able to reproduce // preserved in order to be able to reproduce
@ -117,7 +123,7 @@ namespace libtorrent
void add_file(fs::path file, size_type size); void add_file(fs::path file, size_type size);
void add_url_seed(std::string const& url); void add_url_seed(std::string const& url);
bool remap_files(std::vector<std::pair<std::string, libtorrent::size_type> > const& map); bool remap_files(std::vector<file_entry> const& map);
std::vector<file_slice> map_block(int piece, size_type offset std::vector<file_slice> map_block(int piece, size_type offset
, int size, bool storage = false) const; , int size, bool storage = false) const;
@ -271,7 +277,7 @@ namespace libtorrent
// this vector is typically empty. If it is not // this vector is typically empty. If it is not
// empty, it means the user has re-mapped the // empty, it means the user has re-mapped the
// files in this torrent to diffefrent names // files in this torrent to different names
// on disk. This is only used when reading and // on disk. This is only used when reading and
// writing the disk. // writing the disk.
std::vector<file_entry> m_remapped_files; std::vector<file_entry> m_remapped_files;

View File

@ -64,18 +64,18 @@ am__libtorrent_la_SOURCES_DIST = entry.cpp escape_string.cpp \
peer_connection.cpp bt_peer_connection.cpp \ peer_connection.cpp bt_peer_connection.cpp \
web_peer_connection.cpp natpmp.cpp piece_picker.cpp policy.cpp \ web_peer_connection.cpp natpmp.cpp piece_picker.cpp policy.cpp \
session.cpp session_impl.cpp sha1.cpp stat.cpp storage.cpp \ session.cpp session_impl.cpp sha1.cpp stat.cpp storage.cpp \
torrent.cpp torrent_handle.cpp pe_crypto.cpp torrent_info.cpp \ mapped_storage.cpp torrent.cpp torrent_handle.cpp \
tracker_manager.cpp http_connection.cpp \ pe_crypto.cpp torrent_info.cpp tracker_manager.cpp \
http_tracker_connection.cpp udp_tracker_connection.cpp \ http_connection.cpp http_tracker_connection.cpp \
alert.cpp identify_client.cpp ip_filter.cpp file.cpp \ udp_tracker_connection.cpp alert.cpp identify_client.cpp \
metadata_transfer.cpp logger.cpp file_pool.cpp ut_pex.cpp \ ip_filter.cpp file.cpp metadata_transfer.cpp logger.cpp \
lsd.cpp upnp.cpp instantiate_connection.cpp socks5_stream.cpp \ file_pool.cpp ut_pex.cpp lsd.cpp upnp.cpp \
socks4_stream.cpp http_stream.cpp connection_queue.cpp \ instantiate_connection.cpp socks5_stream.cpp socks4_stream.cpp \
disk_io_thread.cpp kademlia/closest_nodes.cpp \ http_stream.cpp connection_queue.cpp disk_io_thread.cpp \
kademlia/dht_tracker.cpp kademlia/find_data.cpp \ kademlia/closest_nodes.cpp kademlia/dht_tracker.cpp \
kademlia/node.cpp kademlia/node_id.cpp kademlia/refresh.cpp \ kademlia/find_data.cpp kademlia/node.cpp kademlia/node_id.cpp \
kademlia/routing_table.cpp kademlia/rpc_manager.cpp \ kademlia/refresh.cpp kademlia/routing_table.cpp \
kademlia/traversal_algorithm.cpp kademlia/rpc_manager.cpp kademlia/traversal_algorithm.cpp
@USE_DHT_TRUE@am__objects_1 = closest_nodes.lo dht_tracker.lo \ @USE_DHT_TRUE@am__objects_1 = closest_nodes.lo dht_tracker.lo \
@USE_DHT_TRUE@ find_data.lo node.lo node_id.lo refresh.lo \ @USE_DHT_TRUE@ find_data.lo node.lo node_id.lo refresh.lo \
@USE_DHT_TRUE@ routing_table.lo rpc_manager.lo \ @USE_DHT_TRUE@ routing_table.lo rpc_manager.lo \
@ -84,8 +84,9 @@ am_libtorrent_la_OBJECTS = entry.lo escape_string.lo assert.lo \
enum_net.lo broadcast_socket.lo peer_connection.lo \ enum_net.lo broadcast_socket.lo peer_connection.lo \
bt_peer_connection.lo web_peer_connection.lo natpmp.lo \ bt_peer_connection.lo web_peer_connection.lo natpmp.lo \
piece_picker.lo policy.lo session.lo session_impl.lo sha1.lo \ piece_picker.lo policy.lo session.lo session_impl.lo sha1.lo \
stat.lo storage.lo torrent.lo torrent_handle.lo pe_crypto.lo \ stat.lo storage.lo mapped_storage.lo torrent.lo \
torrent_info.lo tracker_manager.lo http_connection.lo \ torrent_handle.lo pe_crypto.lo torrent_info.lo \
tracker_manager.lo http_connection.lo \
http_tracker_connection.lo udp_tracker_connection.lo alert.lo \ http_tracker_connection.lo udp_tracker_connection.lo alert.lo \
identify_client.lo ip_filter.lo file.lo metadata_transfer.lo \ identify_client.lo ip_filter.lo file.lo metadata_transfer.lo \
logger.lo file_pool.lo ut_pex.lo lsd.lo upnp.lo \ logger.lo file_pool.lo ut_pex.lo lsd.lo upnp.lo \
@ -251,7 +252,7 @@ libtorrent_la_SOURCES = entry.cpp escape_string.cpp \
assert.cpp enum_net.cpp broadcast_socket.cpp \ assert.cpp enum_net.cpp broadcast_socket.cpp \
peer_connection.cpp bt_peer_connection.cpp web_peer_connection.cpp \ peer_connection.cpp bt_peer_connection.cpp web_peer_connection.cpp \
natpmp.cpp piece_picker.cpp policy.cpp session.cpp session_impl.cpp sha1.cpp \ natpmp.cpp piece_picker.cpp policy.cpp session.cpp session_impl.cpp sha1.cpp \
stat.cpp storage.cpp torrent.cpp torrent_handle.cpp pe_crypto.cpp \ stat.cpp storage.cpp mapped_storage.cpp torrent.cpp torrent_handle.cpp pe_crypto.cpp \
torrent_info.cpp tracker_manager.cpp http_connection.cpp \ torrent_info.cpp tracker_manager.cpp http_connection.cpp \
http_tracker_connection.cpp udp_tracker_connection.cpp \ http_tracker_connection.cpp udp_tracker_connection.cpp \
alert.cpp identify_client.cpp ip_filter.cpp file.cpp metadata_transfer.cpp \ alert.cpp identify_client.cpp ip_filter.cpp file.cpp metadata_transfer.cpp \
@ -422,6 +423,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ip_filter.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ip_filter.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logger.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logger.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsd.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mapped_storage.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/metadata_transfer.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/metadata_transfer.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/natpmp.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/natpmp.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/node.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/node.Plo@am__quote@

View File

@ -33,6 +33,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/pch.hpp" #include "libtorrent/pch.hpp"
#include "libtorrent/alert.hpp" #include "libtorrent/alert.hpp"
#include <boost/thread/xtime.hpp>
namespace libtorrent { namespace libtorrent {
@ -77,6 +78,30 @@ namespace libtorrent {
} }
} }
alert const* alert_manager::wait_for_alert(time_duration max_wait)
{
boost::mutex::scoped_lock lock(m_mutex);
if (!m_alerts.empty()) return m_alerts.front();
int secs = total_seconds(max_wait);
max_wait -= seconds(secs);
boost::xtime xt;
boost::xtime_get(&xt, boost::TIME_UTC);
xt.sec += secs;
boost::int64_t nsec = xt.nsec + total_microseconds(max_wait) * 1000;
if (nsec > 1000000000)
{
nsec -= 1000000000;
xt.sec += 1;
}
xt.nsec = nsec;
if (!m_condition.timed_wait(lock, xt)) return 0;
TORRENT_ASSERT(!m_alerts.empty());
if (m_alerts.empty()) return 0;
return m_alerts.front();
}
void alert_manager::post_alert(const alert& alert_) void alert_manager::post_alert(const alert& alert_)
{ {
boost::mutex::scoped_lock lock(m_mutex); boost::mutex::scoped_lock lock(m_mutex);
@ -90,6 +115,7 @@ namespace libtorrent {
delete result; delete result;
} }
m_alerts.push(alert_.clone().release()); m_alerts.push(alert_.clone().release());
m_condition.notify_all();
} }
std::auto_ptr<alert> alert_manager::get() std::auto_ptr<alert> alert_manager::get()

View File

@ -273,6 +273,9 @@ namespace libtorrent { namespace dht
udp::endpoint ep(listen_interface, listen_port); udp::endpoint ep(listen_interface, listen_port);
m_socket.open(ep.protocol()); m_socket.open(ep.protocol());
m_socket.bind(ep); m_socket.bind(ep);
m_socket.async_receive_from(asio::buffer(&m_in_buf[m_buffer][0]
, m_in_buf[m_buffer].size()), m_remote_endpoint[m_buffer]
, m_strand.wrap(bind(&dht_tracker::on_receive, self(), _1, _2)));
} }
void dht_tracker::tick(asio::error_code const& e) void dht_tracker::tick(asio::error_code const& e)

View File

@ -226,6 +226,10 @@ bool rpc_manager::incoming(msg const& m)
std::ofstream reply_stats("libtorrent_logs/round_trip_ms.log", std::ios::app); std::ofstream reply_stats("libtorrent_logs/round_trip_ms.log", std::ios::app);
reply_stats << m.addr << "\t" << total_milliseconds(time_now() - o->sent) reply_stats << m.addr << "\t" << total_milliseconds(time_now() - o->sent)
<< std::endl; << std::endl;
#endif
#ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(rpc) << "Reply with transaction id: "
<< tid << " from " << m.addr;
#endif #endif
o->reply(m); o->reply(m);
m_transactions[tid] = 0; m_transactions[tid] = 0;
@ -284,6 +288,10 @@ time_duration rpc_manager::tick()
try try
{ {
m_transactions[m_oldest_transaction_id] = 0; m_transactions[m_oldest_transaction_id] = 0;
#ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(rpc) << "Timing out transaction id: "
<< m_oldest_transaction_id << " from " << o->target_addr;
#endif
timeouts.push_back(o); timeouts.push_back(o);
} catch (std::exception) {} } catch (std::exception) {}
} }
@ -309,7 +317,13 @@ unsigned int rpc_manager::new_transaction_id(observer_ptr o)
// moving the observer into the set of aborted transactions // moving the observer into the set of aborted transactions
// it will prevent it from spawning new requests right now, // it will prevent it from spawning new requests right now,
// since that would break the invariant // since that would break the invariant
m_aborted_transactions.push_back(m_transactions[m_next_transaction_id]); observer_ptr o = m_transactions[m_next_transaction_id];
m_aborted_transactions.push_back(o);
#ifdef TORRENT_DHT_VERBOSE_LOGGING
TORRENT_LOG(rpc) << "[new_transaction_id] Aborting message with transaction id: "
<< m_next_transaction_id << " sent to " << o->target_addr
<< " " << total_seconds(time_now() - o->sent) << " seconds ago";
#endif
m_transactions[m_next_transaction_id] = 0; m_transactions[m_next_transaction_id] = 0;
TORRENT_ASSERT(m_oldest_transaction_id == m_next_transaction_id); TORRENT_ASSERT(m_oldest_transaction_id == m_next_transaction_id);
} }

View File

@ -422,6 +422,11 @@ namespace libtorrent
return m_impl->pop_alert(); return m_impl->pop_alert();
} }
alert const* session::wait_for_alert(time_duration max_wait)
{
return m_impl->wait_for_alert(max_wait);
}
void session::set_severity_level(alert::severity_t s) void session::set_severity_level(alert::severity_t s)
{ {
m_impl->set_severity_level(s); m_impl->set_severity_level(s);

View File

@ -2252,6 +2252,11 @@ namespace detail
return std::auto_ptr<alert>(0); return std::auto_ptr<alert>(0);
} }
alert const* session_impl::wait_for_alert(time_duration max_wait)
{
return m_alerts.wait_for_alert(max_wait);
}
void session_impl::set_severity_level(alert::severity_t s) void session_impl::set_severity_level(alert::severity_t s)
{ {
mutex_t::scoped_lock l(m_mutex); mutex_t::scoped_lock l(m_mutex);
@ -2414,6 +2419,11 @@ namespace detail
{ {
TORRENT_ASSERT(false); TORRENT_ASSERT(false);
} }
for (std::map<sha1_hash, boost::shared_ptr<torrent> >::const_iterator j
= m_torrents.begin(); j != m_torrents.end(); ++j)
{
TORRENT_ASSERT(boost::get_pointer(j->second));
}
} }
#endif #endif

View File

@ -43,7 +43,8 @@ namespace libtorrent
if (e) if (e)
{ {
(*h)(e); (*h)(e);
close(); asio::error_code ec;
close(ec);
return; return;
} }
@ -54,8 +55,8 @@ namespace libtorrent
if (i == tcp::resolver::iterator()) if (i == tcp::resolver::iterator())
{ {
asio::error_code ec = asio::error::operation_not_supported; asio::error_code ec = asio::error::operation_not_supported;
(*h)(e); (*h)(ec);
close(); close(ec);
return; return;
} }
@ -68,7 +69,8 @@ namespace libtorrent
if (e) if (e)
{ {
(*h)(e); (*h)(e);
close(); asio::error_code ec;
close(ec);
return; return;
} }
@ -93,7 +95,8 @@ namespace libtorrent
if (e) if (e)
{ {
(*h)(e); (*h)(e);
close(); asio::error_code ec;
close(ec);
return; return;
} }
@ -107,7 +110,8 @@ namespace libtorrent
if (e) if (e)
{ {
(*h)(e); (*h)(e);
close(); asio::error_code ec;
close(ec);
return; return;
} }
@ -119,8 +123,9 @@ namespace libtorrent
if (reply_version != 0) if (reply_version != 0)
{ {
(*h)(asio::error::operation_not_supported); asio::error_code ec = asio::error::operation_not_supported;
close(); (*h)(ec);
close(ec);
return; return;
} }
@ -140,7 +145,7 @@ namespace libtorrent
case 93: ec = asio::error::no_permission; break; case 93: ec = asio::error::no_permission; break;
} }
(*h)(ec); (*h)(ec);
close(); close(ec);
} }
} }

View File

@ -44,7 +44,8 @@ namespace libtorrent
if (e || i == tcp::resolver::iterator()) if (e || i == tcp::resolver::iterator())
{ {
(*h)(e); (*h)(e);
close(); asio::error_code ec;
close(ec);
return; return;
} }
@ -57,7 +58,8 @@ namespace libtorrent
if (e) if (e)
{ {
(*h)(e); (*h)(e);
close(); asio::error_code ec;
close(ec);
return; return;
} }
@ -86,7 +88,8 @@ namespace libtorrent
if (e) if (e)
{ {
(*h)(e); (*h)(e);
close(); asio::error_code ec;
close(ec);
return; return;
} }
@ -100,7 +103,8 @@ namespace libtorrent
if (e) if (e)
{ {
(*h)(e); (*h)(e);
close(); asio::error_code ec;
close(ec);
return; return;
} }
@ -113,7 +117,8 @@ namespace libtorrent
if (version < 5) if (version < 5)
{ {
(*h)(asio::error::operation_not_supported); (*h)(asio::error::operation_not_supported);
close(); asio::error_code ec;
close(ec);
return; return;
} }
@ -126,7 +131,8 @@ namespace libtorrent
if (m_user.empty()) if (m_user.empty())
{ {
(*h)(asio::error::operation_not_supported); (*h)(asio::error::operation_not_supported);
close(); asio::error_code ec;
close(ec);
return; return;
} }
@ -144,7 +150,8 @@ namespace libtorrent
else else
{ {
(*h)(asio::error::operation_not_supported); (*h)(asio::error::operation_not_supported);
close(); asio::error_code ec;
close(ec);
return; return;
} }
} }
@ -155,7 +162,8 @@ namespace libtorrent
if (e) if (e)
{ {
(*h)(e); (*h)(e);
close(); asio::error_code ec;
close(ec);
return; return;
} }
@ -170,7 +178,8 @@ namespace libtorrent
if (e) if (e)
{ {
(*h)(e); (*h)(e);
close(); asio::error_code ec;
close(ec);
return; return;
} }
@ -183,19 +192,21 @@ namespace libtorrent
if (version != 1) if (version != 1)
{ {
(*h)(asio::error::operation_not_supported); (*h)(asio::error::operation_not_supported);
close(); asio::error_code ec;
close(ec);
return; return;
} }
if (status != 0) if (status != 0)
{ {
(*h)(asio::error::operation_not_supported); (*h)(asio::error::operation_not_supported);
close(); asio::error_code ec;
close(ec);
return; return;
} }
std::vector<char>().swap(m_buffer); std::vector<char>().swap(m_buffer);
(*h)(e); socks_connect(h);
} }
void socks5_stream::socks_connect(boost::shared_ptr<handler_type> h) void socks5_stream::socks_connect(boost::shared_ptr<handler_type> h)
@ -222,7 +233,8 @@ namespace libtorrent
if (e) if (e)
{ {
(*h)(e); (*h)(e);
close(); asio::error_code ec;
close(ec);
return; return;
} }
@ -236,7 +248,8 @@ namespace libtorrent
if (e) if (e)
{ {
(*h)(e); (*h)(e);
close(); asio::error_code ec;
close(ec);
return; return;
} }
@ -248,7 +261,8 @@ namespace libtorrent
if (version < 5) if (version < 5)
{ {
(*h)(asio::error::operation_not_supported); (*h)(asio::error::operation_not_supported);
close(); asio::error_code ec;
close(ec);
return; return;
} }
int response = read_uint8(p); int response = read_uint8(p);
@ -267,7 +281,8 @@ 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);
close(); asio::error_code ec;
close(ec);
return; return;
} }
p += 1; // reserved p += 1; // reserved
@ -291,7 +306,8 @@ namespace libtorrent
else else
{ {
(*h)(asio::error::operation_not_supported); (*h)(asio::error::operation_not_supported);
close(); asio::error_code ec;
close(ec);
return; return;
} }
m_buffer.resize(skip_bytes); m_buffer.resize(skip_bytes);
@ -305,7 +321,8 @@ namespace libtorrent
if (e) if (e)
{ {
(*h)(e); (*h)(e);
close(); asio::error_code ec;
close(ec);
return; return;
} }

View File

@ -768,10 +768,10 @@ namespace libtorrent
TORRENT_ASSERT(file_offset < file_iter->size); TORRENT_ASSERT(file_offset < file_iter->size);
TORRENT_ASSERT(slices[0].offset == file_offset); TORRENT_ASSERT(slices[0].offset == file_offset + file_iter->file_base);
size_type new_pos = in->seek(file_offset); size_type new_pos = in->seek(file_offset + file_iter->file_base);
if (new_pos != file_offset) if (new_pos != file_offset + file_iter->file_base)
{ {
// the file was not big enough // the file was not big enough
if (!fill_zero) if (!fill_zero)
@ -782,7 +782,7 @@ namespace libtorrent
#ifndef NDEBUG #ifndef NDEBUG
size_type in_tell = in->tell(); size_type in_tell = in->tell();
TORRENT_ASSERT(in_tell == file_offset); TORRENT_ASSERT(in_tell == file_offset + file_iter->file_base);
#endif #endif
int left_to_read = size; int left_to_read = size;
@ -846,7 +846,7 @@ namespace libtorrent
file_offset = 0; file_offset = 0;
in = m_files.open_file( in = m_files.open_file(
this, path, file::in); this, path, file::in);
in->seek(0); in->seek(file_iter->file_base);
} }
} }
return result; return result;
@ -892,11 +892,11 @@ namespace libtorrent
this, p, file::out | file::in); this, p, file::out | file::in);
TORRENT_ASSERT(file_offset < file_iter->size); TORRENT_ASSERT(file_offset < file_iter->size);
TORRENT_ASSERT(slices[0].offset == file_offset); TORRENT_ASSERT(slices[0].offset == file_offset + file_iter->file_base);
size_type pos = out->seek(file_offset); size_type pos = out->seek(file_offset + file_iter->file_base);
if (pos != file_offset) if (pos != file_offset + file_iter->file_base)
{ {
std::stringstream s; std::stringstream s;
s << "no storage for slot " << slot; s << "no storage for slot " << slot;
@ -962,7 +962,7 @@ namespace libtorrent
out = m_files.open_file( out = m_files.open_file(
this, p, file::out | file::in); this, p, file::out | file::in);
out->seek(0); out->seek(file_iter->file_base);
} }
} }
} }

View File

@ -287,6 +287,10 @@ namespace libtorrent
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT
bool torrent::should_announce_dht() const bool torrent::should_announce_dht() const
{ {
if (m_ses.m_listen_sockets.empty()) return false;
if (!m_ses.m_dht) return false;
// don't announce private torrents // don't announce private torrents
if (m_torrent_file->is_valid() && m_torrent_file->priv()) return false; if (m_torrent_file->is_valid() && m_torrent_file->priv()) return false;
@ -434,6 +438,7 @@ namespace libtorrent
bind(&torrent::on_announce_disp, self, _1))); bind(&torrent::on_announce_disp, self, _1)));
// announce with the local discovery service // announce with the local discovery service
if (!m_paused)
m_ses.announce_lsd(m_torrent_file->info_hash()); m_ses.announce_lsd(m_torrent_file->info_hash());
} }
else else
@ -444,14 +449,12 @@ namespace libtorrent
} }
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT
if (m_paused) return;
if (!m_ses.m_dht) return; if (!m_ses.m_dht) return;
ptime now = time_now(); ptime now = time_now();
if (should_announce_dht() && now - m_last_dht_announce > minutes(14)) if (should_announce_dht() && now - m_last_dht_announce > minutes(14))
{ {
m_last_dht_announce = now; m_last_dht_announce = now;
// TODO: There should be a way to abort an announce operation on the dht.
// when the torrent is destructed
if (m_ses.m_listen_sockets.empty()) return;
m_ses.m_dht->announce(m_torrent_file->info_hash() m_ses.m_dht->announce(m_torrent_file->info_hash()
, m_ses.m_listen_sockets.front().external_port , m_ses.m_listen_sockets.front().external_port
, m_ses.m_strand.wrap(bind(&torrent::on_dht_announce_response_disp, self, _1))); , m_ses.m_strand.wrap(bind(&torrent::on_dht_announce_response_disp, self, _1)));
@ -701,7 +704,7 @@ namespace libtorrent
const int last_piece = m_torrent_file->num_pieces() - 1; const int last_piece = m_torrent_file->num_pieces() - 1;
size_type total_done size_type total_done
= m_num_pieces * m_torrent_file->piece_length(); = size_type(m_num_pieces) * m_torrent_file->piece_length();
// if we have the last piece, we have to correct // if we have the last piece, we have to correct
// the amount we have, since the first calculation // the amount we have, since the first calculation
@ -726,16 +729,17 @@ namespace libtorrent
return tuple<size_type, size_type>(0,0); return tuple<size_type, size_type>(0,0);
const int last_piece = m_torrent_file->num_pieces() - 1; const int last_piece = m_torrent_file->num_pieces() - 1;
const int piece_size = m_torrent_file->piece_length();
if (is_seed()) if (is_seed())
return make_tuple(m_torrent_file->total_size() return make_tuple(m_torrent_file->total_size()
, m_torrent_file->total_size()); , m_torrent_file->total_size());
size_type wanted_done = (m_num_pieces - m_picker->num_have_filtered()) size_type wanted_done = size_type(m_num_pieces - m_picker->num_have_filtered())
* m_torrent_file->piece_length(); * piece_size;
size_type total_done size_type total_done
= m_num_pieces * m_torrent_file->piece_length(); = size_type(m_num_pieces) * piece_size;
TORRENT_ASSERT(m_num_pieces < m_torrent_file->num_pieces()); TORRENT_ASSERT(m_num_pieces < m_torrent_file->num_pieces());
// if we have the last piece, we have to correct // if we have the last piece, we have to correct
@ -743,12 +747,18 @@ namespace libtorrent
// assumed all pieces were of equal size // assumed all pieces were of equal size
if (m_have_pieces[last_piece]) if (m_have_pieces[last_piece])
{ {
TORRENT_ASSERT(total_done >= piece_size);
int corr = m_torrent_file->piece_size(last_piece) int corr = m_torrent_file->piece_size(last_piece)
- m_torrent_file->piece_length(); - piece_size;
TORRENT_ASSERT(corr <= 0);
TORRENT_ASSERT(corr > -piece_size);
total_done += corr; total_done += corr;
if (m_picker->piece_priority(last_piece) != 0) if (m_picker->piece_priority(last_piece) != 0)
{
TORRENT_ASSERT(wanted_done >= piece_size);
wanted_done += corr; wanted_done += corr;
} }
}
TORRENT_ASSERT(total_done <= m_torrent_file->total_size()); TORRENT_ASSERT(total_done <= m_torrent_file->total_size());
TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size()); TORRENT_ASSERT(wanted_done <= m_torrent_file->total_size());
@ -757,7 +767,7 @@ namespace libtorrent
= m_picker->get_download_queue(); = m_picker->get_download_queue();
const int blocks_per_piece = static_cast<int>( const int blocks_per_piece = static_cast<int>(
m_torrent_file->piece_length() / m_block_size); piece_size / m_block_size);
for (std::vector<piece_picker::downloading_piece>::const_iterator i = for (std::vector<piece_picker::downloading_piece>::const_iterator i =
dl_queue.begin(); i != dl_queue.end(); ++i) dl_queue.begin(); i != dl_queue.end(); ++i)
@ -779,6 +789,7 @@ namespace libtorrent
{ {
TORRENT_ASSERT(m_picker->is_finished(piece_block(index, j)) == (i->info[j].state == piece_picker::block_info::state_finished)); TORRENT_ASSERT(m_picker->is_finished(piece_block(index, j)) == (i->info[j].state == piece_picker::block_info::state_finished));
corr += (i->info[j].state == piece_picker::block_info::state_finished) * m_block_size; corr += (i->info[j].state == piece_picker::block_info::state_finished) * m_block_size;
TORRENT_ASSERT(corr >= 0);
TORRENT_ASSERT(index != last_piece || j < m_picker->blocks_in_last_piece() TORRENT_ASSERT(index != last_piece || j < m_picker->blocks_in_last_piece()
|| i->info[j].state != piece_picker::block_info::state_finished); || i->info[j].state != piece_picker::block_info::state_finished);
} }
@ -1913,7 +1924,101 @@ namespace libtorrent
} }
#endif #endif
bool torrent::connect_to_peer(policy::peer* peerinfo) throw() void torrent::get_peer_info(std::vector<peer_info>& v)
{
v.clear();
for (peer_iterator i = begin();
i != end(); ++i)
{
peer_connection* peer = *i;
// incoming peers that haven't finished the handshake should
// not be included in this list
if (peer->associated_torrent().expired()) continue;
v.push_back(peer_info());
peer_info& p = v.back();
peer->get_peer_info(p);
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
if (resolving_countries())
resolve_peer_country(intrusive_ptr<peer_connection>(peer));
#endif
}
}
void torrent::get_download_queue(std::vector<partial_piece_info>& queue)
{
queue.clear();
if (!valid_metadata() || is_seed()) return;
piece_picker const& p = picker();
std::vector<piece_picker::downloading_piece> const& q
= p.get_download_queue();
for (std::vector<piece_picker::downloading_piece>::const_iterator i
= q.begin(); i != q.end(); ++i)
{
partial_piece_info pi;
pi.piece_state = (partial_piece_info::state_t)i->state;
pi.blocks_in_piece = p.blocks_in_piece(i->index);
pi.finished = (int)i->finished;
pi.writing = (int)i->writing;
pi.requested = (int)i->requested;
int piece_size = torrent_file().piece_size(i->index);
for (int j = 0; j < pi.blocks_in_piece; ++j)
{
block_info& bi = pi.blocks[j];
bi.state = i->info[j].state;
bi.block_size = j < pi.blocks_in_piece - 1 ? m_block_size
: piece_size - (j * m_block_size);
bool complete = bi.state == block_info::writing
|| bi.state == block_info::finished;
if (i->info[j].peer == 0)
{
bi.peer = tcp::endpoint();
bi.bytes_progress = complete ? bi.block_size : 0;
}
else
{
policy::peer* p = static_cast<policy::peer*>(i->info[j].peer);
if (p->connection)
{
bi.peer = p->connection->remote();
if (bi.state == block_info::requested)
{
boost::optional<piece_block_progress> pbp
= p->connection->downloading_piece_progress();
if (pbp && pbp->piece_index == i->index && pbp->block_index == j)
{
bi.bytes_progress = pbp->bytes_downloaded;
TORRENT_ASSERT(bi.bytes_progress <= bi.block_size);
}
else
{
bi.bytes_progress = 0;
}
}
else
{
bi.bytes_progress = complete ? bi.block_size : 0;
}
}
else
{
bi.peer = p->ip;
bi.bytes_progress = complete ? bi.block_size : 0;
}
}
pi.blocks[j].num_peers = i->info[j].num_peers;
}
pi.piece_index = i->index;
queue.push_back(pi);
}
}
bool torrent::connect_to_peer(policy::peer* peerinfo)
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
@ -2249,16 +2354,18 @@ namespace libtorrent
m_next_request = time_now() + seconds(delay); m_next_request = time_now() + seconds(delay);
#ifndef TORRENT_DISABLE_DHT #ifndef TORRENT_DISABLE_DHT
// only start the announce if we want to announce with the dht
if (should_announce_dht())
{
if (m_abort) return; if (m_abort) return;
// only start the announce if we want to announce with the dht
ptime now = time_now();
if (should_announce_dht() && now - m_last_dht_announce > minutes(14))
{
// force the DHT to reannounce // force the DHT to reannounce
m_last_dht_announce = time_now() - minutes(15); m_last_dht_announce = now;
boost::weak_ptr<torrent> self(shared_from_this()); boost::weak_ptr<torrent> self(shared_from_this());
m_announce_timer.expires_from_now(seconds(1)); m_ses.m_dht->announce(m_torrent_file->info_hash()
m_announce_timer.async_wait(m_ses.m_strand.wrap( , m_ses.m_listen_sockets.front().external_port
bind(&torrent::on_announce_disp, self, _1))); , m_ses.m_strand.wrap(bind(&torrent::on_dht_announce_response_disp, self, _1)));
} }
#endif #endif
@ -2747,6 +2854,18 @@ namespace libtorrent
// ---- WEB SEEDS ---- // ---- WEB SEEDS ----
// re-insert urls that are to be retries into the m_web_seeds
typedef std::map<std::string, ptime>::iterator iter_t;
for (iter_t i = m_web_seeds_next_retry.begin(); i != m_web_seeds_next_retry.end();)
{
iter_t erase_element = i++;
if (erase_element->second <= time_now())
{
m_web_seeds.insert(erase_element->first);
m_web_seeds_next_retry.erase(erase_element);
}
}
// if we have everything we want we don't need to connect to any web-seed // if we have everything we want we don't need to connect to any web-seed
if (!is_finished() && !m_web_seeds.empty()) if (!is_finished() && !m_web_seeds.empty())
{ {
@ -2809,6 +2928,12 @@ namespace libtorrent
} }
} }
void torrent::retry_url_seed(std::string const& url)
{
m_web_seeds_next_retry[url] = time_now()
+ seconds(m_ses.settings().urlseed_wait_retry);
}
bool torrent::try_connect_peer() bool torrent::try_connect_peer()
{ {
TORRENT_ASSERT(want_more_peers()); TORRENT_ASSERT(want_more_peers());

View File

@ -78,32 +78,90 @@ using boost::bind;
using boost::mutex; using boost::mutex;
using libtorrent::aux::session_impl; using libtorrent::aux::session_impl;
#ifdef BOOST_NO_EXCEPTIONS
#define TORRENT_FORWARD(call) \
if (m_ses == 0) return; \
TORRENT_ASSERT(m_chk); \
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
mutex::scoped_lock l2(m_chk->m_mutex); \
torrent* t = find_torrent(m_ses, m_chk, m_info_hash); \
if (t == 0) return; \
t->call
#define TORRENT_FORWARD_RETURN(call, def) \
if (m_ses == 0) return def; \
TORRENT_ASSERT(m_chk); \
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
mutex::scoped_lock l2(m_chk->m_mutex); \
torrent* t = find_torrent(m_ses, m_chk, m_info_hash); \
if (t == 0) return def; \
return t->call
#define TORRENT_FORWARD_RETURN2(call, def) \
if (m_ses == 0) return def; \
TORRENT_ASSERT(m_chk); \
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
mutex::scoped_lock l2(m_chk->m_mutex); \
torrent* t = find_torrent(m_ses, m_chk, m_info_hash); \
if (t == 0) return def; \
t->call
#else
#define TORRENT_FORWARD(call) \
if (m_ses == 0) throw_invalid_handle(); \
TORRENT_ASSERT(m_chk); \
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
mutex::scoped_lock l2(m_chk->m_mutex); \
torrent* t = find_torrent(m_ses, m_chk, m_info_hash); \
if (t == 0) throw_invalid_handle(); \
t->call
#define TORRENT_FORWARD_RETURN(call, def) \
if (m_ses == 0) throw_invalid_handle(); \
TORRENT_ASSERT(m_chk); \
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
mutex::scoped_lock l2(m_chk->m_mutex); \
torrent* t = find_torrent(m_ses, m_chk, m_info_hash); \
if (t == 0) return def; \
return t->call
#define TORRENT_FORWARD_RETURN2(call, def) \
if (m_ses == 0) throw_invalid_handle(); \
TORRENT_ASSERT(m_chk); \
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); \
mutex::scoped_lock l2(m_chk->m_mutex); \
torrent* t = find_torrent(m_ses, m_chk, m_info_hash); \
if (t == 0) return def; \
t->call
#endif
namespace libtorrent namespace libtorrent
{ {
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
namespace namespace
{ {
#ifndef BOOST_NO_EXCEPTIONS
void throw_invalid_handle() void throw_invalid_handle()
{ {
throw invalid_handle(); throw invalid_handle();
} }
#endif
boost::shared_ptr<torrent> find_torrent( torrent* find_torrent(
session_impl* ses session_impl* ses
, aux::checker_impl* chk , aux::checker_impl* chk
, sha1_hash const& hash) , sha1_hash const& hash)
{ {
aux::piece_checker_data* d = chk->find_torrent(hash); aux::piece_checker_data* d = chk->find_torrent(hash);
if (d != 0) return d->torrent_ptr; if (d != 0) return d->torrent_ptr.get();
boost::shared_ptr<torrent> t = ses->find_torrent(hash).lock(); boost::shared_ptr<torrent> t = ses->find_torrent(hash).lock();
if (t) return t; if (t) return t.get();
return 0;
// throwing directly instead of calling
// the throw_invalid_handle() function
// avoids a warning in gcc
throw invalid_handle();
} }
} }
@ -119,132 +177,68 @@ namespace libtorrent
void torrent_handle::set_max_uploads(int max_uploads) const void torrent_handle::set_max_uploads(int max_uploads) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
TORRENT_ASSERT(max_uploads >= 2 || max_uploads == -1); TORRENT_ASSERT(max_uploads >= 2 || max_uploads == -1);
TORRENT_FORWARD(set_max_uploads(max_uploads));
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->set_max_uploads(max_uploads);
} }
void torrent_handle::use_interface(const char* net_interface) const void torrent_handle::use_interface(const char* net_interface) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(use_interface(net_interface));
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->use_interface(net_interface);
} }
void torrent_handle::set_max_connections(int max_connections) const void torrent_handle::set_max_connections(int max_connections) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
TORRENT_ASSERT(max_connections >= 2 || max_connections == -1); TORRENT_ASSERT(max_connections >= 2 || max_connections == -1);
TORRENT_FORWARD(set_max_connections(max_connections));
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->set_max_connections(max_connections);
} }
void torrent_handle::set_peer_upload_limit(tcp::endpoint ip, int limit) const void torrent_handle::set_peer_upload_limit(tcp::endpoint ip, int limit) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_ASSERT(limit >= -1); TORRENT_ASSERT(limit >= -1);
TORRENT_FORWARD(set_peer_upload_limit(ip, limit));
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->set_peer_upload_limit(ip, limit);
} }
void torrent_handle::set_peer_download_limit(tcp::endpoint ip, int limit) const void torrent_handle::set_peer_download_limit(tcp::endpoint ip, int limit) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_ASSERT(limit >= -1); TORRENT_ASSERT(limit >= -1);
TORRENT_FORWARD(set_peer_download_limit(ip, limit));
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->set_peer_download_limit(ip, limit);
} }
void torrent_handle::set_upload_limit(int limit) const void torrent_handle::set_upload_limit(int limit) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
TORRENT_ASSERT(limit >= -1); TORRENT_ASSERT(limit >= -1);
TORRENT_FORWARD(set_upload_limit(limit));
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->set_upload_limit(limit);
} }
int torrent_handle::upload_limit() const int torrent_handle::upload_limit() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD_RETURN(upload_limit(), 0);
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
return find_torrent(m_ses, m_chk, m_info_hash)->upload_limit();
} }
void torrent_handle::set_download_limit(int limit) const void torrent_handle::set_download_limit(int limit) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
TORRENT_ASSERT(limit >= -1); TORRENT_ASSERT(limit >= -1);
TORRENT_FORWARD(set_download_limit(limit));
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->set_download_limit(limit);
} }
int torrent_handle::download_limit() const int torrent_handle::download_limit() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD_RETURN(download_limit(), 0);
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
return find_torrent(m_ses, m_chk, m_info_hash)->download_limit();
} }
void torrent_handle::move_storage( void torrent_handle::move_storage(
fs::path const& save_path) const fs::path const& save_path) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(move_storage(save_path));
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->move_storage(save_path);
} }
void torrent_handle::add_extension( void torrent_handle::add_extension(
@ -252,123 +246,62 @@ namespace libtorrent
, void* userdata) , void* userdata)
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(add_extension(ext, userdata));
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
return find_torrent(m_ses, m_chk, m_info_hash)->add_extension(ext, userdata);
} }
bool torrent_handle::has_metadata() const bool torrent_handle::has_metadata() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD_RETURN(valid_metadata(), false);
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
return find_torrent(m_ses, m_chk, m_info_hash)->valid_metadata();
} }
bool torrent_handle::is_seed() const bool torrent_handle::is_seed() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD_RETURN(is_seed(), false);
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
return find_torrent(m_ses, m_chk, m_info_hash)->is_seed();
} }
bool torrent_handle::is_paused() const bool torrent_handle::is_paused() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD_RETURN(is_paused(), false);
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
return find_torrent(m_ses, m_chk, m_info_hash)->is_paused();
} }
void torrent_handle::pause() const void torrent_handle::pause() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(pause());
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->pause();
} }
void torrent_handle::resume() const void torrent_handle::resume() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(resume());
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->resume();
} }
void torrent_handle::set_tracker_login(std::string const& name void torrent_handle::set_tracker_login(std::string const& name
, std::string const& password) const , std::string const& password) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(resume());
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->set_tracker_login(name, password);
} }
void torrent_handle::file_progress(std::vector<float>& progress) void torrent_handle::file_progress(std::vector<float>& progress)
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(file_progress(progress));
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
if (d != 0)
{
if (!d->processing)
{
torrent_info const& info = d->torrent_ptr->torrent_file();
progress.clear();
progress.resize(info.num_files(), 0.f);
return;
}
d->torrent_ptr->file_progress(progress);
return;
}
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
if (t) return t->file_progress(progress);
throw_invalid_handle();
} }
torrent_status torrent_handle::status() const torrent_status torrent_handle::status() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle(); if (m_ses == 0)
#ifdef BOOST_NO_EXCEPTIONS
return torrent_status();
#else
throw_invalid_handle();
#endif
TORRENT_ASSERT(m_chk); TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
@ -396,107 +329,60 @@ namespace libtorrent
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock(); boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
if (t) return t->status(); if (t) return t->status();
#ifndef BOOST_NO_EXCEPTIONS
throw_invalid_handle(); throw_invalid_handle();
#endif
return torrent_status(); return torrent_status();
} }
void torrent_handle::set_sequenced_download_threshold(int threshold) const void torrent_handle::set_sequenced_download_threshold(int threshold) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(set_sequenced_download_threshold(threshold));
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->set_sequenced_download_threshold(threshold);
} }
std::string torrent_handle::name() const std::string torrent_handle::name() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD_RETURN(name(), "");
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
return find_torrent(m_ses, m_chk, m_info_hash)->name();
} }
void torrent_handle::piece_availability(std::vector<int>& avail) const void torrent_handle::piece_availability(std::vector<int>& avail) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(piece_availability(avail));
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->piece_availability(avail);
} }
void torrent_handle::piece_priority(int index, int priority) const void torrent_handle::piece_priority(int index, int priority) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(set_piece_priority(index, priority));
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->set_piece_priority(index, priority);
} }
int torrent_handle::piece_priority(int index) const int torrent_handle::piece_priority(int index) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD_RETURN(piece_priority(index), 0);
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
return find_torrent(m_ses, m_chk, m_info_hash)->piece_priority(index);
} }
void torrent_handle::prioritize_pieces(std::vector<int> const& pieces) const void torrent_handle::prioritize_pieces(std::vector<int> const& pieces) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(prioritize_pieces(pieces));
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->prioritize_pieces(pieces);
} }
std::vector<int> torrent_handle::piece_priorities() const std::vector<int> torrent_handle::piece_priorities() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
std::vector<int> ret; std::vector<int> ret;
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); TORRENT_FORWARD_RETURN2(piece_priorities(ret), ret);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->piece_priorities(ret);
return ret; return ret;
} }
void torrent_handle::prioritize_files(std::vector<int> const& files) const void torrent_handle::prioritize_files(std::vector<int> const& files) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(prioritize_files(files));
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->prioritize_files(files);
} }
// ============ start deprecation =============== // ============ start deprecation ===============
@ -504,63 +390,33 @@ namespace libtorrent
void torrent_handle::filter_piece(int index, bool filter) const void torrent_handle::filter_piece(int index, bool filter) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(filter_piece(index, filter));
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->filter_piece(index, filter);
} }
void torrent_handle::filter_pieces(std::vector<bool> const& pieces) const void torrent_handle::filter_pieces(std::vector<bool> const& pieces) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(filter_pieces(pieces));
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->filter_pieces(pieces);
} }
bool torrent_handle::is_piece_filtered(int index) const bool torrent_handle::is_piece_filtered(int index) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD_RETURN(is_piece_filtered(index), false);
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
return find_torrent(m_ses, m_chk, m_info_hash)->is_piece_filtered(index);
} }
std::vector<bool> torrent_handle::filtered_pieces() const std::vector<bool> torrent_handle::filtered_pieces() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
std::vector<bool> ret; std::vector<bool> ret;
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); TORRENT_FORWARD_RETURN2(filtered_pieces(ret), ret);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->filtered_pieces(ret);
return ret; return ret;
} }
void torrent_handle::filter_files(std::vector<bool> const& files) const void torrent_handle::filter_files(std::vector<bool> const& files) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(filter_files(files));
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->filter_files(files);
} }
// ============ end deprecation =============== // ============ end deprecation ===============
@ -569,111 +425,91 @@ namespace libtorrent
std::vector<announce_entry> const& torrent_handle::trackers() const std::vector<announce_entry> const& torrent_handle::trackers() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
const static std::vector<announce_entry> empty;
if (m_ses == 0) throw_invalid_handle(); TORRENT_FORWARD_RETURN(trackers(), empty);
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
return find_torrent(m_ses, m_chk, m_info_hash)->trackers();
} }
void torrent_handle::add_url_seed(std::string const& url) const void torrent_handle::add_url_seed(std::string const& url) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(add_url_seed(url));
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->add_url_seed(url);
} }
void torrent_handle::remove_url_seed(std::string const& url) const void torrent_handle::remove_url_seed(std::string const& url) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(remove_url_seed(url));
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->remove_url_seed(url);
} }
std::set<std::string> torrent_handle::url_seeds() const std::set<std::string> torrent_handle::url_seeds() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
const static std::set<std::string> empty;
if (m_ses == 0) throw_invalid_handle(); TORRENT_FORWARD_RETURN(url_seeds(), empty);
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
return find_torrent(m_ses, m_chk, m_info_hash)->url_seeds();
} }
void torrent_handle::replace_trackers( void torrent_handle::replace_trackers(
std::vector<announce_entry> const& urls) const std::vector<announce_entry> const& urls) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(replace_trackers(urls));
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->replace_trackers(urls);
} }
torrent_info const& torrent_handle::get_torrent_info() const torrent_info const& torrent_handle::get_torrent_info() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
#ifdef BOOST_NO_EXCEPTIONS
const static torrent_info empty;
if (m_ses == 0) return empty;
#else
if (m_ses == 0) throw_invalid_handle(); if (m_ses == 0) throw_invalid_handle();
#endif
TORRENT_ASSERT(m_chk); TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex); session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex);
boost::shared_ptr<torrent> t = find_torrent(m_ses, m_chk, m_info_hash); torrent* t = find_torrent(m_ses, m_chk, m_info_hash);
if (!t->valid_metadata()) throw_invalid_handle(); if (t == 0 || !t->valid_metadata())
#ifdef BOOST_NO_EXCEPTIONS
return empty;
#else
throw_invalid_handle();
#endif
return t->torrent_file(); return t->torrent_file();
} }
bool torrent_handle::is_valid() const bool torrent_handle::is_valid() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
if (m_ses == 0) return false; if (m_ses == 0) return false;
TORRENT_ASSERT(m_chk); TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex);
aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash); torrent* t = find_torrent(m_ses, m_chk, m_info_hash);
if (d != 0) return true; return t;
{
boost::weak_ptr<torrent> t = m_ses->find_torrent(m_info_hash);
if (!t.expired()) return true;
}
return false;
} }
entry torrent_handle::write_resume_data() const entry torrent_handle::write_resume_data() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
std::vector<int> piece_index; if (m_ses == 0)
if (m_ses == 0) return entry(); #ifdef BOOST_NO_EXCEPTIONS
return entry();
#else
throw_invalid_handle();
#endif
TORRENT_ASSERT(m_chk); TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock(); mutex::scoped_lock l2(m_chk->m_mutex);
if (!t) return entry();
if (!t->valid_metadata()) return entry(); boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
if (!t || !t->valid_metadata())
#ifdef BOOST_NO_EXCEPTIONS
return entry();
#else
throw_invalid_handle();
#endif
std::vector<bool> have_pieces = t->pieces(); std::vector<bool> have_pieces = t->pieces();
@ -748,6 +584,7 @@ namespace libtorrent
} }
} }
std::vector<int> piece_index;
t->filesystem().export_piece_map(piece_index, have_pieces); t->filesystem().export_piece_map(piece_index, have_pieces);
entry::list_type& slots = ret["slots"].list(); entry::list_type& slots = ret["slots"].list();
std::copy(piece_index.begin(), piece_index.end(), std::back_inserter(slots)); std::copy(piece_index.begin(), piece_index.end(), std::back_inserter(slots));
@ -796,20 +633,19 @@ namespace libtorrent
fs::path torrent_handle::save_path() const fs::path torrent_handle::save_path() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD_RETURN(save_path(), fs::path());
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
return find_torrent(m_ses, m_chk, m_info_hash)->save_path();
} }
void torrent_handle::connect_peer(tcp::endpoint const& adr, int source) const void torrent_handle::connect_peer(tcp::endpoint const& adr, int source) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle(); if (m_ses == 0)
#ifdef BOOST_NO_EXCEPTIONS
return;
#else
throw_invalid_handle();
#endif
TORRENT_ASSERT(m_chk); TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex); session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
@ -823,7 +659,12 @@ namespace libtorrent
mutex::scoped_lock l2(m_chk->m_mutex); mutex::scoped_lock l2(m_chk->m_mutex);
aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash); aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
if (d == 0) throw_invalid_handle(); if (d == 0)
#ifdef BOOST_NO_EXCEPTIONS
return;
#else
throw_invalid_handle();
#endif
d->peers.push_back(adr); d->peers.push_back(adr);
return; return;
} }
@ -837,205 +678,55 @@ namespace libtorrent
boost::posix_time::time_duration duration) const boost::posix_time::time_duration duration) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(force_tracker_request(time_now() + seconds(duration.total_seconds())));
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
if (!t) throw_invalid_handle();
t->force_tracker_request(time_now()
+ seconds(duration.total_seconds()));
} }
void torrent_handle::force_reannounce() const void torrent_handle::force_reannounce() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(force_tracker_request());
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
if (!t) throw_invalid_handle();
t->force_tracker_request();
} }
void torrent_handle::scrape_tracker() const void torrent_handle::scrape_tracker() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(scrape_tracker());
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
if (!t) throw_invalid_handle();
t->scrape_tracker();
} }
void torrent_handle::set_ratio(float ratio) const void torrent_handle::set_ratio(float ratio) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
TORRENT_ASSERT(ratio >= 0.f); TORRENT_ASSERT(ratio >= 0.f);
if (ratio < 1.f && ratio > 0.f) if (ratio < 1.f && ratio > 0.f)
ratio = 1.f; ratio = 1.f;
TORRENT_FORWARD(set_ratio(ratio));
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->set_ratio(ratio);
} }
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
void torrent_handle::resolve_countries(bool r) void torrent_handle::resolve_countries(bool r)
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(resolve_countries(r));
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
find_torrent(m_ses, m_chk, m_info_hash)->resolve_countries(r);
} }
bool torrent_handle::resolve_countries() const bool torrent_handle::resolve_countries() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD_RETURN(resolving_countries(), false);
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
return find_torrent(m_ses, m_chk, m_info_hash)->resolving_countries();
} }
#endif #endif
void torrent_handle::get_peer_info(std::vector<peer_info>& v) const void torrent_handle::get_peer_info(std::vector<peer_info>& v) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(get_peer_info(v));
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
v.clear();
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
boost::shared_ptr<const torrent> t = m_ses->find_torrent(m_info_hash).lock();
if (!t) return;
for (torrent::const_peer_iterator i = t->begin();
i != t->end(); ++i)
{
peer_connection* peer = *i;
// incoming peers that haven't finished the handshake should
// not be included in this list
if (peer->associated_torrent().expired()) continue;
v.push_back(peer_info());
peer_info& p = v.back();
peer->get_peer_info(p);
#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
if (t->resolving_countries())
t->resolve_peer_country(intrusive_ptr<peer_connection>(peer));
#endif
}
} }
void torrent_handle::get_download_queue(std::vector<partial_piece_info>& queue) const void torrent_handle::get_download_queue(std::vector<partial_piece_info>& queue) const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
TORRENT_FORWARD(get_download_queue(queue));
if (m_ses == 0) throw_invalid_handle();
TORRENT_ASSERT(m_chk);
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
queue.clear();
if (!t) return;
if (!t->valid_metadata()) return;
// if we're a seed, the piece picker has been removed
if (t->is_seed()) return;
const piece_picker& p = t->picker();
const std::vector<piece_picker::downloading_piece>& q
= p.get_download_queue();
int block_size = t->block_size();
for (std::vector<piece_picker::downloading_piece>::const_iterator i
= q.begin(); i != q.end(); ++i)
{
partial_piece_info pi;
pi.piece_state = (partial_piece_info::state_t)i->state;
pi.blocks_in_piece = p.blocks_in_piece(i->index);
pi.finished = (int)i->finished;
pi.writing = (int)i->writing;
pi.requested = (int)i->requested;
int piece_size = t->torrent_file().piece_size(i->index);
for (int j = 0; j < pi.blocks_in_piece; ++j)
{
block_info& bi = pi.blocks[j];
bi.state = i->info[j].state;
bi.block_size = j < pi.blocks_in_piece - 1 ? block_size
: piece_size - (j * block_size);
bool complete = bi.state == block_info::writing
|| bi.state == block_info::finished;
if (i->info[j].peer == 0)
{
bi.peer = tcp::endpoint();
bi.bytes_progress = complete ? bi.block_size : 0;
}
else
{
policy::peer* p = static_cast<policy::peer*>(i->info[j].peer);
if (p->connection)
{
bi.peer = p->connection->remote();
if (bi.state == block_info::requested)
{
boost::optional<piece_block_progress> pbp
= p->connection->downloading_piece_progress();
if (pbp && pbp->piece_index == i->index && pbp->block_index == j)
{
bi.bytes_progress = pbp->bytes_downloaded;
TORRENT_ASSERT(bi.bytes_progress <= bi.block_size);
}
else
{
bi.bytes_progress = 0;
}
}
else
{
bi.bytes_progress = complete ? bi.block_size : 0;
}
}
else
{
bi.peer = p->ip;
bi.bytes_progress = complete ? bi.block_size : 0;
}
}
pi.blocks[j].num_peers = i->info[j].num_peers;
}
pi.piece_index = i->index;
queue.push_back(pi);
}
} }
} }

View File

@ -165,7 +165,7 @@ namespace
{ {
target.size = dict["length"].integer(); target.size = dict["length"].integer();
target.path = root_dir; target.path = root_dir;
target.file_base = 0;
// prefer the name.utf-8 // prefer the name.utf-8
// because if it exists, it is more // because if it exists, it is more
@ -824,20 +824,19 @@ namespace libtorrent
m_nodes.push_back(node); m_nodes.push_back(node);
} }
bool torrent_info::remap_files(std::vector<std::pair<std::string bool torrent_info::remap_files(std::vector<file_entry> const& map)
, libtorrent::size_type> > const& map)
{ {
typedef std::vector<std::pair<std::string, size_type> > files_t;
size_type offset = 0; size_type offset = 0;
m_remapped_files.resize(map.size()); m_remapped_files.resize(map.size());
for (int i = 0; i < int(map.size()); ++i) for (int i = 0; i < int(map.size()); ++i)
{ {
file_entry& fe = m_remapped_files[i]; file_entry& fe = m_remapped_files[i];
fe.path = map[i].first; fe.path = map[i].path;
fe.offset = offset; fe.offset = offset;
fe.size = map[i].second; fe.size = map[i].size;
fe.file_base = map[i].file_base;
fe.orig_path.reset();
offset += fe.size; offset += fe.size;
} }
if (offset != total_size()) if (offset != total_size())
@ -846,6 +845,26 @@ namespace libtorrent
return false; return false;
} }
#ifndef NDEBUG
std::vector<file_entry> map2(m_remapped_files);
std::sort(map2.begin(), map2.end()
, bind(&file_entry::file_base, _1) < bind(&file_entry::file_base, _2));
std::stable_sort(map2.begin(), map2.end()
, bind(&file_entry::path, _1) < bind(&file_entry::path, _2));
fs::path last_path;
size_type last_end = 0;
for (std::vector<file_entry>::iterator i = map2.begin(), end(map2.end());
i != end; ++i)
{
if (last_path == i->path)
{
assert(last_end <= i->file_base);
}
last_end = i->file_base + i->size;
last_path = i->path;
}
#endif
return true; return true;
} }
@ -871,7 +890,7 @@ namespace libtorrent
{ {
file_slice f; file_slice f;
f.file_index = counter; f.file_index = counter;
f.offset = file_offset; f.offset = file_offset + file_iter->file_base;
f.size = (std::min)(file_iter->size - file_offset, (size_type)size); f.size = (std::min)(file_iter->size - file_offset, (size_type)size);
size -= f.size; size -= f.size;
file_offset += f.size; file_offset += f.size;

View File

@ -306,10 +306,12 @@ namespace libtorrent
namespace namespace
{ {
bool range_contains(peer_request const& range, peer_request const& req) bool range_contains(peer_request const& range, peer_request const& req, int piece_size)
{ {
return range.start <= req.start size_type range_start = size_type(range.piece) * piece_size + range.start;
&& range.start + range.length >= req.start + req.length; size_type req_start = size_type(req.piece) * piece_size + req.start;
return range_start <= req_start
&& range_start + range.length >= req_start + req.length;
} }
} }
@ -358,7 +360,11 @@ namespace libtorrent
&& !(m_parser.status_code() >= 300 // redirect && !(m_parser.status_code() >= 300 // redirect
&& m_parser.status_code() < 400)) && m_parser.status_code() < 400))
{ {
// we should not try this server again. if (m_parser.status_code() == 503)
{
// temporarily unavailable, retry later
t->retry_url_seed(m_url);
}
t->remove_url_seed(m_url); t->remove_url_seed(m_url);
std::string error_msg = boost::lexical_cast<std::string>(m_parser.status_code()) std::string error_msg = boost::lexical_cast<std::string>(m_parser.status_code())
+ " " + m_parser.message(); + " " + m_parser.message();
@ -470,6 +476,9 @@ namespace libtorrent
} }
} }
// std::cerr << "REQUESTS: m_requests: " << m_requests.size()
// << " file_requests: " << m_file_requests.size() << std::endl;
torrent_info const& info = t->torrent_file(); torrent_info const& info = t->torrent_file();
if (m_requests.empty() || m_file_requests.empty()) if (m_requests.empty() || m_file_requests.empty())
@ -484,16 +493,13 @@ namespace libtorrent
size_type rs = size_type(in_range.piece) * info.piece_length() + in_range.start; size_type rs = size_type(in_range.piece) * info.piece_length() + in_range.start;
size_type re = rs + in_range.length; size_type re = rs + in_range.length;
size_type fs = size_type(front_request.piece) * info.piece_length() + front_request.start; size_type fs = size_type(front_request.piece) * info.piece_length() + front_request.start;
/*
size_type fe = fs + front_request.length; size_type fe = fs + front_request.length;
if (fs < rs || fe > re)
{
throw std::runtime_error("invalid range in HTTP response");
}
// skip the http header and the blocks we've already read. The std::cerr << "RANGE: r = (" << rs << ", " << re << " ) "
// http_body.begin is now in sync with the request at the front "f = (" << fs << ", " << fe << ") "
// of the request queue "file_index = " << file_index << " received_body = " << m_received_body << std::endl;
// TORRENT_ASSERT(in_range.start - int(m_piece.size()) <= front_request.start); */
// the http response body consists of 3 parts // the http response body consists of 3 parts
// 1. the middle of a block or the ending of a block // 1. the middle of a block or the ending of a block
@ -501,14 +507,20 @@ namespace libtorrent
// 3. the start of a block // 3. the start of a block
// in that order, these parts are parsed. // in that order, these parts are parsed.
bool range_overlaps_request = in_range.start + in_range.length bool range_overlaps_request = re > fs + int(m_piece.size());
> front_request.start + int(m_piece.size());
if (!range_overlaps_request)
{
// this means the end of the incoming request ends _before_ the
// first expected byte (fs + m_piece.size())
throw std::runtime_error("invalid range in HTTP response");
}
// if the request is contained in the range (i.e. the entire request // if the request is contained in the range (i.e. the entire request
// fits in the range) we should not start a partial piece, since we soon // fits in the range) we should not start a partial piece, since we soon
// will receive enough to call incoming_piece() and pass the read buffer // will receive enough to call incoming_piece() and pass the read buffer
// directly (in the next loop below). // directly (in the next loop below).
if (range_overlaps_request && !range_contains(in_range, front_request)) if (range_overlaps_request && !range_contains(in_range, front_request, info.piece_length()))
{ {
// the start of the next block to receive is stored // the start of the next block to receive is stored
// in m_piece. We need to append the rest of that // in m_piece. We need to append the rest of that
@ -549,7 +561,7 @@ namespace libtorrent
// report all received blocks to the bittorrent engine // report all received blocks to the bittorrent engine
while (!m_requests.empty() while (!m_requests.empty()
&& range_contains(in_range, m_requests.front()) && range_contains(in_range, m_requests.front(), info.piece_length())
&& recv_buffer.left() >= m_requests.front().length) && recv_buffer.left() >= m_requests.front().length)
{ {
peer_request r = m_requests.front(); peer_request r = m_requests.front();

View File

@ -273,13 +273,15 @@ boost::filesystem::path const& save_path)
return (new_torrent.unique_ID); return (new_torrent.unique_ID);
} }
catch (invalid_encoding&) catch (invalid_encoding&)
{ { RAISE_PTR(InvalidEncodingError, ""); }
printf("invalid encoding...bad torrent\n");
}
catch (invalid_handle&) catch (invalid_handle&)
{ { printf("invalid handle error on add_torrent"); }
printf("invalid handle. something bad happened in libtorrent\n"); catch (invalid_torrent_file&)
} { RAISE_PTR(InvalidTorrentError, ""); }
catch (boost::filesystem::filesystem_error&)
{ RAISE_PTR(FilesystemError, ""); }
catch (duplicate_torrent&)
{ RAISE_PTR(DuplicateTorrentError, "libtorrent reports this is a duplicate torrent"); }
catch (...) {} catch (...) {}
} }
@ -1999,35 +2001,6 @@ static PyObject *torrent_add_url_seed(PyObject *self, PyObject *args)
Py_INCREF(Py_None); return Py_None; Py_INCREF(Py_None); return Py_None;
} }
static PyObject *torrent_remap_files(PyObject *self, PyObject *args)
{
python_long unique_ID;
PyObject *file_path_object;
PyObject *file_size_object;
if (!PyArg_ParseTuple(args, "iOO", &unique_ID, &file_path_object, &file_size_object))
return NULL;
long index = get_index_from_unique_ID(unique_ID);
if (PyErr_Occurred())
return NULL;
if (M_torrents->at(index).handle.is_valid()){
std::vector<std::pair<std::string, libtorrent::size_type> > remap_vector;
for (long i = 0; i < PyList_Size(file_size_object); i++) {
remap_vector.push_back(std::make_pair(PyString_AsString(PyList_GetItem(file_path_object, i)), PyInt_AsLong(PyList_GetItem(file_size_object, i))));
}
torrent_info t = M_torrents->at(index).handle.get_torrent_info();
bool ret = t.remap_files(remap_vector);
if (ret){
printf("remap worked!\n");
}
else{
printf("remap failed!\n");
}
}
Py_INCREF(Py_None); return Py_None;
}
static PyObject *torrent_scrape_tracker(PyObject *self, PyObject *args) static PyObject *torrent_scrape_tracker(PyObject *self, PyObject *args)
{ {
python_long unique_ID; python_long unique_ID;
@ -2112,7 +2085,6 @@ static PyMethodDef deluge_core_methods[] =
{"get_piece_info", torrent_get_piece_info, METH_VARARGS, "."}, {"get_piece_info", torrent_get_piece_info, METH_VARARGS, "."},
{"get_all_piece_info", torrent_get_all_piece_info, METH_VARARGS, "."}, {"get_all_piece_info", torrent_get_all_piece_info, METH_VARARGS, "."},
{"get_file_piece_range", torrent_get_file_piece_range, METH_VARARGS, "."}, {"get_file_piece_range", torrent_get_file_piece_range, METH_VARARGS, "."},
{"remap_files", torrent_remap_files, METH_VARARGS, "."},
{"scrape_tracker", torrent_scrape_tracker, METH_VARARGS, "."}, {"scrape_tracker", torrent_scrape_tracker, METH_VARARGS, "."},
{NULL} {NULL}
}; };