finish sync

This commit is contained in:
Marcos Pinto 2007-09-21 00:05:59 +00:00
parent b2fe562dd4
commit a9961adda7
39 changed files with 1277 additions and 213 deletions

View File

@ -33,12 +33,14 @@ POSSIBILITY OF SUCH DAMAGE.
#include <cassert>
#ifndef NDEBUG
#if defined __linux__ && defined __GNUC__
#if (defined __linux__ || defined __MACH__) && defined __GNUC__
#ifdef assert
#undef assert
#endif
void assert_fail(const char* expr, int line, char const* file, char const* function);
#include "libtorrent/config.hpp"
TORRENT_EXPORT void assert_fail(const char* expr, int line, char const* file, char const* function);
#define assert(x) if (x) {} else assert_fail(#x, __LINE__, __FILE__, __PRETTY_FUNCTION__)

View File

@ -185,7 +185,7 @@ namespace libtorrent
~session_impl();
#ifndef TORRENT_DISABLE_EXTENSIONS
void add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*)> ext);
void add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> ext);
#endif
void operator()();
@ -246,7 +246,8 @@ namespace libtorrent
, entry const& resume_data
, bool compact_mode
, storage_constructor_type sc
, bool paused);
, bool paused
, void* userdata);
torrent_handle add_torrent(
char const* tracker_url
@ -256,7 +257,8 @@ namespace libtorrent
, entry const& resume_data
, bool compact_mode
, storage_constructor_type sc
, bool paused);
, bool paused
, void* userdata);
void remove_torrent(torrent_handle const& h);
@ -519,7 +521,7 @@ namespace libtorrent
#ifndef TORRENT_DISABLE_EXTENSIONS
typedef std::list<boost::function<boost::shared_ptr<
torrent_plugin>(torrent*)> > extension_list_t;
torrent_plugin>(torrent*, void*)> > extension_list_t;
extension_list_t m_extensions;
#endif

View File

@ -180,6 +180,7 @@ struct bandwidth_manager
, m_limit(bandwidth_limit::inf)
, m_current_quota(0)
, m_channel(channel)
, m_in_hand_out_bandwidth(false)
{}
void throttle(int limit) throw()
@ -328,6 +329,10 @@ private:
void hand_out_bandwidth() throw()
{
// if we're already handing out bandwidth, just return back
// to the loop further down on the callstack
if (m_in_hand_out_bandwidth) return;
m_in_hand_out_bandwidth = true;
#ifndef NDEBUG
try {
#endif
@ -361,6 +366,7 @@ private:
if (qe.peer->is_disconnecting())
{
t->expire_bandwidth(m_channel, qe.max_block_size);
assert(amount == limit - m_current_quota);
continue;
}
@ -374,6 +380,7 @@ private:
if (max_assignable == 0)
{
t->expire_bandwidth(m_channel, qe.max_block_size);
assert(amount == limit - m_current_quota);
continue;
}
@ -388,15 +395,15 @@ private:
// the history window is one second, and the block will be forgotten
// after one second.
int block_size = (std::min)(qe.peer->bandwidth_throttle(m_channel)
, m_limit / 10);
, limit / 10);
if (block_size < min_bandwidth_block_size)
{
block_size = (std::min)(int(min_bandwidth_block_size), m_limit);
block_size = (std::min)(int(min_bandwidth_block_size), limit);
}
else if (block_size > max_bandwidth_block_size)
{
if (m_limit == bandwidth_limit::inf)
if (limit == bandwidth_limit::inf)
{
block_size = max_bandwidth_block_size;
}
@ -407,8 +414,8 @@ private:
// as possible
// TODO: move this calculcation to where the limit
// is changed
block_size = m_limit
/ (m_limit / max_bandwidth_block_size);
block_size = limit
/ (limit / max_bandwidth_block_size);
}
}
if (block_size > qe.max_block_size) block_size = qe.max_block_size;
@ -428,18 +435,21 @@ private:
int hand_out_amount = (std::min)((std::min)(block_size, max_assignable)
, amount);
assert(hand_out_amount > 0);
assert(amount == limit - m_current_quota);
amount -= hand_out_amount;
assert(hand_out_amount <= qe.max_block_size);
t->assign_bandwidth(m_channel, hand_out_amount, qe.max_block_size);
qe.peer->assign_bandwidth(m_channel, hand_out_amount);
add_history_entry(history_entry<PeerConnection, Torrent>(
qe.peer, t, hand_out_amount, now + bw_window_size));
assert(amount == limit - m_current_quota);
}
#ifndef NDEBUG
}
catch (std::exception& e)
{ assert(false); };
#endif
m_in_hand_out_bandwidth = false;
}
@ -472,6 +482,11 @@ private:
// this is the channel within the consumers
// that bandwidth is assigned to (upload or download)
int m_channel;
// this is true while we're in the hand_out_bandwidth loop
// to prevent recursive invocations to interfere
bool m_in_hand_out_bandwidth;
};
}

View File

@ -42,6 +42,9 @@ namespace libtorrent
{
bool is_local(address const& a);
bool is_loopback(address const& addr);
bool is_multicast(address const& addr);
address_v4 guess_local_address(asio::io_service&);
typedef boost::function<void(udp::endpoint const& from
@ -51,7 +54,8 @@ namespace libtorrent
{
public:
broadcast_socket(asio::io_service& ios, udp::endpoint const& multicast_endpoint
, receive_handler_t const& handler);
, receive_handler_t const& handler, bool loopback = true);
~broadcast_socket() { close(); }
void send(char const* buffer, int size, asio::error_code& ec);
void close();

View File

@ -34,7 +34,6 @@ POSSIBILITY OF SUCH DAMAGE.
#define TORRENT_CONFIG_HPP_INCLUDED
#include <boost/config.hpp>
#include "libtorrent/assert.hpp"
#if defined(__GNUC__) && __GNUC__ >= 4

View File

@ -30,6 +30,10 @@ POSSIBILITY OF SUCH DAMAGE.
*/
#ifdef TORRENT_DISK_STATS
#include <fstream>
#endif
#include "libtorrent/storage.hpp"
#include <boost/thread/thread.hpp>
#include <boost/function.hpp>
@ -50,6 +54,7 @@ namespace libtorrent
, buffer_size(0)
, piece(0)
, offset(0)
, priority(0)
{}
enum action_t
@ -72,6 +77,12 @@ namespace libtorrent
// to the error message
std::string str;
// priority decides whether or not this
// job will skip entries in the queue or
// not. It always skips in front of entries
// with lower priority
int priority;
// this is called when operation completes
boost::function<void(int, disk_io_job const&)> callback;
};
@ -115,6 +126,10 @@ namespace libtorrent
int m_block_size;
#endif
#ifdef TORRENT_DISK_STATS
std::ofstream m_log;
#endif
// thread for performing blocking disk io operations
boost::thread m_disk_io_thread;
};

View File

@ -149,6 +149,12 @@ namespace libtorrent
virtual bool on_cancel(peer_request const& req)
{ return false; }
virtual bool on_reject(peer_request const& req)
{ return false; }
virtual bool on_suggest(int index)
{ return false; }
// called when an extended message is received. If returning true,
// the message is not processed by any other plugin and if false
// is returned the next plugin in the chain will receive it to

View File

@ -48,7 +48,7 @@ namespace libtorrent
{
struct torrent_plugin;
class torrent;
TORRENT_EXPORT boost::shared_ptr<torrent_plugin> create_metadata_plugin(torrent*);
TORRENT_EXPORT boost::shared_ptr<torrent_plugin> create_metadata_plugin(torrent*, void*);
}
#endif // TORRENT_METADATA_TRANSFER_HPP_INCLUDED

View File

@ -48,7 +48,7 @@ namespace libtorrent
{
struct torrent_plugin;
class torrent;
TORRENT_EXPORT boost::shared_ptr<torrent_plugin> create_ut_pex_plugin(torrent*);
TORRENT_EXPORT boost::shared_ptr<torrent_plugin> create_ut_pex_plugin(torrent*, void*);
}
#endif // TORRENT_UT_PEX_EXTENSION_HPP_INCLUDED

View File

@ -180,4 +180,3 @@ namespace libtorrent
#endif // TORRENT_HTTP_TRACKER_CONNECTION_HPP_INCLUDED

View File

@ -42,7 +42,7 @@ namespace libtorrent
template<class T>
struct intrusive_ptr_base
{
intrusive_ptr_base(const intrusive_ptr_base<T>& b)
intrusive_ptr_base(intrusive_ptr_base<T> const&)
: m_refs(0) {}
friend void intrusive_ptr_add_ref(intrusive_ptr_base<T> const* s)

View File

@ -72,7 +72,8 @@ namespace libtorrent
dht = 0x2,
pex = 0x4,
lsd = 0x8,
resume_data = 0x10
resume_data = 0x10,
incoming = 0x20
};
int source;

View File

@ -233,7 +233,7 @@ namespace libtorrent
bool is_finished(piece_block block) const;
// marks this piece-block as queued for downloading
void mark_as_downloading(piece_block block, void* peer
bool mark_as_downloading(piece_block block, void* peer
, piece_state_t s);
void mark_as_writing(piece_block block, void* peer);
void mark_as_finished(piece_block block, void* peer);

View File

@ -150,7 +150,8 @@ namespace libtorrent
, entry const& resume_data = entry()
, bool compact_mode = true
, bool paused = false
, storage_constructor_type sc = default_storage_constructor);
, storage_constructor_type sc = default_storage_constructor
, void* userdata = 0);
torrent_handle add_torrent(
char const* tracker_url
@ -160,7 +161,8 @@ namespace libtorrent
, entry const& resume_data = entry()
, bool compact_mode = true
, bool paused = false
, storage_constructor_type sc = default_storage_constructor);
, storage_constructor_type sc = default_storage_constructor
, void* userdata = 0);
session_proxy abort() { return session_proxy(m_impl); }
@ -181,7 +183,7 @@ namespace libtorrent
#endif
#ifndef TORRENT_DISABLE_EXTENSIONS
void add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*)> ext);
void add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> ext);
#endif
void set_ip_filter(ip_filter const& f);

View File

@ -0,0 +1,594 @@
/*
Copyright (c) 2006, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TORRENT_SESSION_IMPL_HPP_INCLUDED
#define TORRENT_SESSION_IMPL_HPP_INCLUDED
#include <ctime>
#include <algorithm>
#include <vector>
#include <set>
#include <list>
#include <deque>
#ifdef _MSC_VER
#pragma warning(push, 1)
#endif
#include <boost/limits.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/filesystem/path.hpp>
#include <boost/thread.hpp>
#include <boost/thread/recursive_mutex.hpp>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include "libtorrent/torrent_handle.hpp"
#include "libtorrent/entry.hpp"
#include "libtorrent/torrent_info.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/peer_connection.hpp"
#include "libtorrent/peer_id.hpp"
#include "libtorrent/policy.hpp"
#include "libtorrent/tracker_manager.hpp"
#include "libtorrent/peer_info.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/fingerprint.hpp"
#include "libtorrent/debug.hpp"
#include "libtorrent/peer_request.hpp"
#include "libtorrent/piece_block_progress.hpp"
#include "libtorrent/ip_filter.hpp"
#include "libtorrent/config.hpp"
#include "libtorrent/session_settings.hpp"
#include "libtorrent/kademlia/dht_tracker.hpp"
#include "libtorrent/session_status.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/stat.hpp"
#include "libtorrent/file_pool.hpp"
#include "libtorrent/bandwidth_manager.hpp"
#include "libtorrent/natpmp.hpp"
#include "libtorrent/upnp.hpp"
#include "libtorrent/lsd.hpp"
#include "libtorrent/socket_type.hpp"
#include "libtorrent/connection_queue.hpp"
#include "libtorrent/disk_io_thread.hpp"
namespace libtorrent
{
namespace fs = boost::filesystem;
namespace aux
{
struct session_impl;
// this data is shared between the main thread and the
// thread that initialize pieces
struct piece_checker_data
{
piece_checker_data()
: processing(false), progress(0.f), abort(false) {}
boost::shared_ptr<torrent> torrent_ptr;
fs::path save_path;
sha1_hash info_hash;
void parse_resume_data(
const entry& rd
, const torrent_info& info
, std::string& error);
std::vector<int> piece_map;
std::vector<piece_picker::downloading_piece> unfinished_pieces;
std::vector<piece_picker::block_info> block_info;
std::vector<tcp::endpoint> peers;
entry resume_data;
// this is true if this torrent is being processed (checked)
// if it is not being processed, then it can be removed from
// the queue without problems, otherwise the abort flag has
// to be set.
bool processing;
// is filled in by storage::initialize_pieces()
// and represents the progress. It should be a
// value in the range [0, 1]
float progress;
// abort defaults to false and is typically
// filled in by torrent_handle when the user
// aborts the torrent
bool abort;
};
struct checker_impl: boost::noncopyable
{
checker_impl(session_impl& s): m_ses(s), m_abort(false) {}
void operator()();
piece_checker_data* find_torrent(const sha1_hash& info_hash);
void remove_torrent(sha1_hash const& info_hash);
#ifndef NDEBUG
void check_invariant() const;
#endif
// when the files has been checked
// the torrent is added to the session
session_impl& m_ses;
mutable boost::mutex m_mutex;
boost::condition m_cond;
// a list of all torrents that are currently in queue
// or checking their files
std::deque<boost::shared_ptr<piece_checker_data> > m_torrents;
std::deque<boost::shared_ptr<piece_checker_data> > m_processing;
bool m_abort;
};
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
struct tracker_logger;
#endif
// this is the link between the main thread and the
// thread started to run the main downloader loop
struct session_impl: boost::noncopyable
{
#ifndef NDEBUG
friend class ::libtorrent::peer_connection;
#endif
friend struct checker_impl;
friend class invariant_access;
typedef std::map<boost::shared_ptr<socket_type>
, boost::intrusive_ptr<peer_connection> >
connection_map;
typedef std::map<sha1_hash, boost::shared_ptr<torrent> > torrent_map;
session_impl(
std::pair<int, int> listen_port_range
, fingerprint const& cl_fprint
, char const* listen_interface = "0.0.0.0");
~session_impl();
#ifndef TORRENT_DISABLE_EXTENSIONS
void add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*)> ext);
#endif
void operator()();
void open_listen_port();
void async_accept();
void on_incoming_connection(boost::shared_ptr<socket_type> const& s
, boost::weak_ptr<socket_acceptor> const& as, asio::error_code const& e);
// must be locked to access the data
// in this struct
typedef boost::recursive_mutex mutex_t;
mutable mutex_t m_mutex;
boost::weak_ptr<torrent> find_torrent(const sha1_hash& info_hash);
peer_id const& get_peer_id() const { return m_peer_id; }
void close_connection(boost::intrusive_ptr<peer_connection> const& p);
void connection_failed(boost::shared_ptr<socket_type> const& s
, tcp::endpoint const& a, char const* message);
void set_settings(session_settings const& s);
session_settings const& settings() const { return m_settings; }
#ifndef TORRENT_DISABLE_DHT
void add_dht_node(std::pair<std::string, int> const& node);
void add_dht_node(udp::endpoint n);
void add_dht_router(std::pair<std::string, int> const& node);
void set_dht_settings(dht_settings const& s);
dht_settings const& get_dht_settings() const { return m_dht_settings; }
void start_dht(entry const& startup_state);
void stop_dht();
entry dht_state() const;
#endif
#ifndef TORRENT_DISABLE_ENCRYPTION
void set_pe_settings(pe_settings const& settings);
pe_settings const& get_pe_settings() const { return m_pe_settings; }
#endif
// called when a port mapping is successful, or a router returns
// a failure to map a port
void on_port_mapping(int tcp_port, int udp_port, std::string const& errmsg);
bool is_aborted() const { return m_abort; }
void set_ip_filter(ip_filter const& f);
void set_port_filter(port_filter const& f);
bool listen_on(
std::pair<int, int> const& port_range
, const char* net_interface = 0);
bool is_listening() const;
torrent_handle add_torrent(
torrent_info const& ti
, fs::path const& save_path
, entry const& resume_data
, bool compact_mode
, int block_size
, storage_constructor_type sc);
torrent_handle add_torrent(
char const* tracker_url
, sha1_hash const& info_hash
, char const* name
, fs::path const& save_path
, entry const& resume_data
, bool compact_mode
, int block_size
, storage_constructor_type sc);
void remove_torrent(torrent_handle const& h);
std::vector<torrent_handle> get_torrents();
void set_severity_level(alert::severity_t s);
std::auto_ptr<alert> pop_alert();
int upload_rate_limit() const;
int download_rate_limit() const;
void set_download_rate_limit(int bytes_per_second);
void set_upload_rate_limit(int bytes_per_second);
void set_max_half_open_connections(int limit);
void set_max_connections(int limit);
void set_max_uploads(int limit);
int max_connections() const { return m_max_connections; }
int max_uploads() const { return m_max_uploads; }
int num_uploads() const { return m_num_unchoked; }
int num_connections() const
{ return m_connections.size(); }
void unchoke_peer(peer_connection& c)
{
c.send_unchoke();
++m_num_unchoked;
}
session_status status() const;
void set_peer_id(peer_id const& id);
void set_key(int key);
unsigned short listen_port() const;
void abort();
torrent_handle find_torrent_handle(sha1_hash const& info_hash);
void announce_lsd(sha1_hash const& ih);
void set_peer_proxy(proxy_settings const& s)
{ m_peer_proxy = s; }
void set_web_seed_proxy(proxy_settings const& s)
{ m_web_seed_proxy = s; }
void set_tracker_proxy(proxy_settings const& s)
{ m_tracker_proxy = s; }
proxy_settings const& peer_proxy() const
{ return m_peer_proxy; }
proxy_settings const& web_seed_proxy() const
{ return m_web_seed_proxy; }
proxy_settings const& tracker_proxy() const
{ return m_tracker_proxy; }
#ifndef TORRENT_DISABLE_DHT
void set_dht_proxy(proxy_settings const& s)
{ m_dht_proxy = s; }
proxy_settings const& dht_proxy() const
{ return m_dht_proxy; }
#endif
void start_lsd();
void start_natpmp();
void start_upnp();
void stop_lsd();
void stop_natpmp();
void stop_upnp();
// handles delayed alerts
alert_manager m_alerts;
// private:
void on_lsd_peer(tcp::endpoint peer, sha1_hash const& ih);
// this is where all active sockets are stored.
// the selector can sleep while there's no activity on
// them
io_service m_io_service;
asio::strand m_strand;
// the file pool that all storages in this session's
// torrents uses. It sets a limit on the number of
// open files by this session.
// file pool must be destructed after the torrents
// since they will still have references to it
// when they are destructed.
file_pool m_files;
// handles disk io requests asynchronously
disk_io_thread m_disk_thread;
// this is a list of half-open tcp connections
// (only outgoing connections)
// this has to be one of the last
// members to be destructed
connection_queue m_half_open;
// the bandwidth manager is responsible for
// handing out bandwidth to connections that
// asks for it, it can also throttle the
// rate.
bandwidth_manager<peer_connection, torrent> m_download_channel;
bandwidth_manager<peer_connection, torrent> m_upload_channel;
bandwidth_manager<peer_connection, torrent>* m_bandwidth_manager[2];
tracker_manager m_tracker_manager;
torrent_map m_torrents;
// this maps sockets to their peer_connection
// object. It is the complete list of all connected
// peers.
connection_map m_connections;
// filters incoming connections
ip_filter m_ip_filter;
// filters outgoing connections
port_filter m_port_filter;
// 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<int, int> m_listen_port_range;
// the ip-address of the interface
// we are supposed to listen on.
// if the ip is set to zero, it means
// that we should let the os decide which
// interface to listen on
tcp::endpoint m_listen_interface;
// this is typically set to the same as the local
// listen port. In case a NAT port forward was
// successfully opened, this will be set to the
// port that is open on the external (NAT) interface
// on the NAT box itself. This is the port that has
// to be published to peers, since this is the port
// the client is reachable through.
int m_external_listen_port;
boost::shared_ptr<socket_acceptor> m_listen_socket;
// the settings for the client
session_settings m_settings;
// the proxy settings for different
// kinds of connections
proxy_settings m_peer_proxy;
proxy_settings m_web_seed_proxy;
proxy_settings m_tracker_proxy;
#ifndef TORRENT_DISABLE_DHT
proxy_settings m_dht_proxy;
#endif
// set to true when the session object
// is being destructed and the thread
// should exit
volatile bool m_abort;
int m_max_uploads;
int m_max_connections;
// the number of unchoked peers
int m_num_unchoked;
// this is initialized to the unchoke_interval
// session_setting and decreased every second.
// when it reaches zero, it is reset to the
// unchoke_interval and the unchoke set is
// recomputed.
int m_unchoke_time_scaler;
// works like unchoke_time_scaler but it
// is only decresed when the unchoke set
// is recomputed, and when it reaches zero,
// the optimistic unchoke is moved to another peer.
int m_optimistic_unchoke_time_scaler;
// works like unchoke_time_scaler. Each time
// it reaches 0, and all the connections are
// used, the worst connection will be disconnected
// from the torrent with the most peers
int m_disconnect_time_scaler;
// statistics gathered from all torrents.
stat m_stat;
// is false by default and set to true when
// the first incoming connection is established
// this is used to know if the client is behind
// NAT or not.
bool m_incoming_connection;
void second_tick(asio::error_code const& e);
ptime m_last_tick;
#ifndef TORRENT_DISABLE_DHT
boost::intrusive_ptr<dht::dht_tracker> m_dht;
dht_settings m_dht_settings;
// if this is set to true, the dht listen port
// will be set to the same as the tcp listen port
// and will be synchronlized with it as it changes
// it defaults to true
bool m_dht_same_port;
// see m_external_listen_port. This is the same
// but for the udp port used by the DHT.
int m_external_udp_port;
#endif
#ifndef TORRENT_DISABLE_ENCRYPTION
pe_settings m_pe_settings;
#endif
boost::shared_ptr<natpmp> m_natpmp;
boost::shared_ptr<upnp> m_upnp;
boost::shared_ptr<lsd> m_lsd;
// the timer used to fire the second_tick
deadline_timer m_timer;
// the index of the torrent that will be offered to
// connect to a peer next time second_tick is called.
// This implements a round robin.
int m_next_connect_torrent;
#ifndef NDEBUG
void check_invariant(const char *place = 0);
#endif
#ifdef TORRENT_STATS
// logger used to write bandwidth usage statistics
std::ofstream m_stats_logger;
int m_second_counter;
#endif
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
boost::shared_ptr<logger> create_log(std::string const& name
, int instance, bool append = true);
// this list of tracker loggers serves as tracker_callbacks when
// shutting down. This list is just here to keep them alive during
// whe shutting down process
std::list<boost::shared_ptr<tracker_logger> > m_tracker_loggers;
public:
boost::shared_ptr<logger> m_logger;
private:
#endif
#ifndef TORRENT_DISABLE_EXTENSIONS
typedef std::list<boost::function<boost::shared_ptr<
torrent_plugin>(torrent*)> > extension_list_t;
extension_list_t m_extensions;
#endif
// data shared between the main thread
// and the checker thread
checker_impl m_checker_impl;
// the main working thread
boost::scoped_ptr<boost::thread> m_thread;
// the thread that calls initialize_pieces()
// on all torrents before they start downloading
boost::scoped_ptr<boost::thread> m_checker_thread;
};
#if defined(TORRENT_LOGGING) || defined(TORRENT_VERBOSE_LOGGING)
struct tracker_logger : request_callback
{
tracker_logger(session_impl& ses): m_ses(ses) {}
void tracker_warning(std::string const& str)
{
debug_log("*** tracker warning: " + str);
}
void tracker_response(tracker_request const&
, std::vector<peer_entry>& peers
, int interval
, int complete
, int incomplete)
{
std::stringstream s;
s << "TRACKER RESPONSE:\n"
"interval: " << interval << "\n"
"peers:\n";
for (std::vector<peer_entry>::const_iterator i = peers.begin();
i != peers.end(); ++i)
{
s << " " << std::setfill(' ') << std::setw(16) << i->ip
<< " " << std::setw(5) << std::dec << i->port << " ";
if (!i->pid.is_all_zeros()) s << " " << i->pid;
s << "\n";
}
debug_log(s.str());
}
void tracker_request_timed_out(
tracker_request const&)
{
debug_log("*** tracker timed out");
}
void tracker_request_error(
tracker_request const&
, int response_code
, const std::string& str)
{
debug_log(std::string("*** tracker error: ")
+ boost::lexical_cast<std::string>(response_code) + ": "
+ str);
}
void debug_log(const std::string& line)
{
(*m_ses.m_logger) << line << "\n";
}
session_impl& m_ses;
};
#endif
}
}
#endif

View File

@ -202,7 +202,8 @@ namespace libtorrent
void async_read(
peer_request const& r
, boost::function<void(int, disk_io_job const&)> const& handler
, char* buffer = 0);
, char* buffer = 0
, int priority = 0);
void async_write(
peer_request const& r
@ -343,7 +344,8 @@ namespace libtorrent
std::multimap<sha1_hash, int> m_hash_to_piece;
// this map contains partial hashes for downloading
// pieces.
// pieces. This is only accessed from within the
// disk-io thread.
std::map<int, partial_hash> m_piece_hasher;
disk_io_thread& m_io_thread;

View File

@ -399,6 +399,7 @@ namespace libtorrent
, m_info_hash(h)
{
assert(m_ses != 0);
assert(m_chk != 0);
}
#ifndef NDEBUG

View File

@ -194,11 +194,10 @@ namespace libtorrent
, address bind_interface
, boost::weak_ptr<request_callback> r);
request_callback& requester();
boost::shared_ptr<request_callback> requester();
virtual ~tracker_connection() {}
tracker_request const& tracker_req() const { return m_req; }
bool has_requester() const { return !m_requester.expired(); }
void fail(int code, char const* msg);
void fail_timeout();

View File

@ -13,7 +13,7 @@ kademlia/traversal_algorithm.cpp
endif
libtorrent_la_SOURCES = entry.cpp escape_string.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 \
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 \
@ -28,6 +28,7 @@ $(kademlia_sources)
noinst_HEADERS = \
$(top_srcdir)/include/libtorrent/alert.hpp \
$(top_srcdir)/include/libtorrent/alert_types.hpp \
$(top_srcdir)/include/libtorrent/assert.hpp \
$(top_srcdir)/include/libtorrent/aux_/session_impl.hpp \
$(top_srcdir)/include/libtorrent/bandwidth_manager.hpp \
$(top_srcdir)/include/libtorrent/bencode.hpp \

View File

@ -34,7 +34,10 @@ POSSIBILITY OF SUCH DAMAGE.
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#if defined __linux__ && defined __GNUC__
#include <execinfo.h>
#endif
void assert_fail(char const* expr, int line, char const* file, char const* function)
{
@ -48,6 +51,7 @@ void assert_fail(char const* expr, int line, char const* file, char const* funct
"expression: %s\n"
"stack:\n", file, line, function, expr);
#if defined __linux__ && defined __GNUC__
void* stack[50];
int size = backtrace(stack, 50);
char** symbols = backtrace_symbols(stack, size);
@ -58,7 +62,11 @@ void assert_fail(char const* expr, int line, char const* file, char const* funct
}
free(symbols);
exit(1);
#endif
// send SIGINT to the current process
// to break into the debugger
raise(SIGINT);
abort();
}
#endif

View File

@ -43,7 +43,7 @@ namespace libtorrent
{
bool is_local(address const& a)
{
if (a.is_v6()) return false;
if (a.is_v6()) return a.to_v6().is_link_local();
address_v4 a4 = a.to_v4();
unsigned long ip = a4.to_ulong();
return ((ip & 0xff000000) == 0x0a000000
@ -58,25 +58,40 @@ namespace libtorrent
udp::resolver::iterator i = r.resolve(udp::resolver::query(asio::ip::host_name(), "0"));
for (;i != udp::resolver_iterator(); ++i)
{
// ignore the loopback
if (i->endpoint().address() == address_v4((127 << 24) + 1)) continue;
// ignore addresses that are not on a local network
if (!is_local(i->endpoint().address())) continue;
address const& a = i->endpoint().address();
// ignore non-IPv4 addresses
if (i->endpoint().address().is_v4()) break;
if (!a.is_v4()) break;
// ignore the loopback
if (a.to_v4() == address_v4::loopback()) continue;
}
if (i == udp::resolver_iterator()) return address_v4::any();
return i->endpoint().address().to_v4();
}
bool is_loopback(address const& addr)
{
if (addr.is_v4())
return addr.to_v4() == address_v4::loopback();
else
return addr.to_v6() == address_v6::loopback();
}
bool is_multicast(address const& addr)
{
if (addr.is_v4())
return addr.to_v4().is_multicast();
else
return addr.to_v6().is_multicast();
}
broadcast_socket::broadcast_socket(asio::io_service& ios
, udp::endpoint const& multicast_endpoint
, receive_handler_t const& handler)
, receive_handler_t const& handler
, bool loopback)
: m_multicast_endpoint(multicast_endpoint)
, m_on_receive(handler)
{
assert(m_multicast_endpoint.address().is_v4());
assert(m_multicast_endpoint.address().to_v4().is_multicast());
assert(is_multicast(m_multicast_endpoint.address()));
using namespace asio::ip::multicast;
@ -87,26 +102,51 @@ namespace libtorrent
, end(interfaces.end()); i != end; ++i)
{
// only broadcast to IPv4 addresses that are not local
if (!i->is_v4() || !is_local(*i)) continue;
// ignore the loopback interface
if (i->to_v4() == address_v4((127 << 24) + 1)) continue;
if (!is_local(*i)) continue;
// only multicast on compatible networks
if (i->is_v4() != multicast_endpoint.address().is_v4()) continue;
// ignore any loopback interface
if (is_loopback(*i)) continue;
boost::shared_ptr<datagram_socket> s(new datagram_socket(ios));
s->open(udp::v4(), ec);
if (i->is_v4())
{
s->open(udp::v4(), ec);
if (ec) continue;
s->set_option(datagram_socket::reuse_address(true), ec);
if (ec) continue;
s->bind(udp::endpoint(address_v4::any(), multicast_endpoint.port()), ec);
if (ec) continue;
s->set_option(join_group(multicast_endpoint.address()), ec);
if (ec) continue;
s->set_option(outbound_interface(i->to_v4()), ec);
if (ec) continue;
}
else
{
s->open(udp::v6(), ec);
if (ec) continue;
s->set_option(datagram_socket::reuse_address(true), ec);
if (ec) continue;
s->bind(udp::endpoint(address_v6::any(), multicast_endpoint.port()), ec);
if (ec) continue;
s->set_option(join_group(multicast_endpoint.address()), ec);
if (ec) continue;
// s->set_option(outbound_interface(i->to_v6()), ec);
// if (ec) continue;
}
s->set_option(hops(255), ec);
if (ec) continue;
s->set_option(datagram_socket::reuse_address(true), ec);
s->set_option(enable_loopback(loopback), ec);
if (ec) continue;
s->bind(udp::endpoint(*i, 0), ec);
if (ec) continue;
s->set_option(join_group(multicast_endpoint.address()), ec);
if (ec) continue;
s->set_option(outbound_interface(i->to_v4()), ec);
if (ec) continue;
s->set_option(hops(255));
m_sockets.push_back(socket_entry(s));
socket_entry& se = m_sockets.back();
s->async_receive_from(asio::buffer(se.buffer, sizeof(se.buffer))
, se.remote, bind(&broadcast_socket::on_receive, this, &se, _1, _2));
#ifndef NDEBUG
// std::cerr << "broadcast socket [ if: " << i->to_v4().to_string()
// << " group: " << multicast_endpoint.address() << " ]" << std::endl;
#endif
}
}
@ -117,7 +157,9 @@ namespace libtorrent
{
asio::error_code e;
i->socket->send_to(asio::buffer(buffer, size), m_multicast_endpoint, 0, e);
#ifndef NDEBUG
// std::cerr << " sending on " << i->socket->local_endpoint().address().to_string() << std::endl;
#endif
if (e) ec = e;
}
}

View File

@ -50,6 +50,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/version.hpp"
#include "libtorrent/extensions.hpp"
#include "libtorrent/aux_/session_impl.hpp"
#include "libtorrent/enum_net.hpp"
#ifndef TORRENT_DISABLE_ENCRYPTION
#include "libtorrent/pe_crypto.hpp"
@ -1221,7 +1222,7 @@ namespace libtorrent
{
tcp::endpoint adr(remote().address()
, (unsigned short)listen_port->integer());
t->get_policy().peer_from_tracker(adr, pid(), 0, 0);
t->get_policy().peer_from_tracker(adr, pid(), peer_info::incoming, 0);
}
}
// there should be a version too
@ -1474,6 +1475,19 @@ namespace libtorrent
detail::write_address(remote().address(), out);
handshake["yourip"] = remote_address;
handshake["reqq"] = m_ses.settings().max_allowed_in_request_queue;
asio::error_code ec;
std::vector<address> const& interfaces = enum_net_interfaces(get_socket()->io_service(), ec);
for (std::vector<address>::const_iterator i = interfaces.begin()
, end(interfaces.end()); i != end; ++i)
{
// TODO: only use global IPv6 addresses
if (!i->is_v6() || i->to_v6().is_link_local()) continue;
std::string ipv6_address;
std::back_insert_iterator<std::string> out(ipv6_address);
detail::write_address(*i, out);
handshake["ipv6"] = ipv6_address;
break;
}
// loop backwards, to make the first extension be the last
// to fill in the handshake (i.e. give the first extensions priority)

View File

@ -34,6 +34,24 @@ POSSIBILITY OF SUCH DAMAGE.
#include <deque>
#include "libtorrent/disk_io_thread.hpp"
#ifdef TORRENT_DISK_STATS
#include "libtorrent/time.hpp"
#include <boost/lexical_cast.hpp>
namespace
{
std::string log_time()
{
using namespace libtorrent;
static ptime start = time_now();
return boost::lexical_cast<std::string>(
total_milliseconds(time_now() - start));
}
}
#endif
namespace libtorrent
{
@ -45,7 +63,12 @@ namespace libtorrent
, m_block_size(block_size)
#endif
, m_disk_io_thread(boost::ref(*this))
{}
{
#ifdef TORRENT_DISK_STATS
m_log.open("disk_io_thread.log", std::ios::trunc);
#endif
}
disk_io_thread::~disk_io_thread()
{
@ -89,8 +112,15 @@ namespace libtorrent
namespace
{
// The semantic of this operator is:
// shouls lhs come before rhs in the job queue
bool operator<(disk_io_job const& lhs, disk_io_job const& rhs)
{
// NOTE: comparison inverted to make higher priority
// skip _in_front_of_ lower priority
if (lhs.priority > rhs.priority) return true;
if (lhs.priority < rhs.priority) return false;
if (lhs.storage.get() < rhs.storage.get()) return true;
if (lhs.storage.get() > rhs.storage.get()) return false;
if (lhs.piece < rhs.piece) return true;
@ -165,6 +195,9 @@ namespace libtorrent
{
for (;;)
{
#ifdef TORRENT_DISK_STATS
m_log << log_time() << " idle" << std::endl;
#endif
boost::mutex::scoped_lock l(m_mutex);
while (m_jobs.empty() && !m_abort)
m_signal.wait(l);
@ -182,10 +215,16 @@ namespace libtorrent
bool free_buffer = true;
try
{
#ifdef TORRENT_DISK_STATS
ptime start = time_now();
#endif
// std::cerr << "DISK THREAD: executing job: " << j.action << std::endl;
switch (j.action)
{
case disk_io_job::read:
#ifdef TORRENT_DISK_STATS
m_log << log_time() << " read " << j.buffer_size << std::endl;
#endif
if (j.buffer == 0)
{
l.lock();
@ -210,6 +249,9 @@ namespace libtorrent
// usleep(300);
break;
case disk_io_job::write:
#ifdef TORRENT_DISK_STATS
m_log << log_time() << " write " << j.buffer_size << std::endl;
#endif
assert(j.buffer);
assert(j.buffer_size <= m_block_size);
j.storage->write_impl(j.buffer, j.piece, j.offset
@ -220,16 +262,25 @@ namespace libtorrent
break;
case disk_io_job::hash:
{
#ifdef TORRENT_DISK_STATS
m_log << log_time() << " hash" << std::endl;
#endif
sha1_hash h = j.storage->hash_for_piece_impl(j.piece);
j.str.resize(20);
std::memcpy(&j.str[0], &h[0], 20);
}
break;
case disk_io_job::move_storage:
#ifdef TORRENT_DISK_STATS
m_log << log_time() << " move" << std::endl;
#endif
ret = j.storage->move_storage_impl(j.str) ? 1 : 0;
j.str = j.storage->save_path().string();
break;
case disk_io_job::release_files:
#ifdef TORRENT_DISK_STATS
m_log << log_time() << " release" << std::endl;
#endif
j.storage->release_files_impl();
break;
}

View File

@ -72,8 +72,17 @@ namespace libtorrent
ifreq const& item = *reinterpret_cast<ifreq*>(ifr);
if (item.ifr_addr.sa_family == AF_INET)
{
ret.push_back(address::from_string(
inet_ntoa(((sockaddr_in const*)&item.ifr_addr)->sin_addr)));
typedef asio::ip::address_v4::bytes_type bytes_t;
bytes_t b;
memcpy(&b[0], &((sockaddr_in const*)&item.ifr_addr)->sin_addr, b.size());
ret.push_back(address_v4(b));
}
else if (item.ifr_addr.sa_family == AF_INET6)
{
typedef asio::ip::address_v6::bytes_type bytes_t;
bytes_t b;
memcpy(&b[0], &((sockaddr_in6 const*)&item.ifr_addr)->sin6_addr, b.size());
ret.push_back(address_v6(b));
}
#if defined __MACH__ || defined(__FreeBSD__)

View File

@ -247,19 +247,16 @@ namespace libtorrent
void set_size(size_type s)
{
size_type pos = tell();
// Only set size if current file size not equals s.
// 2 as "m" argument is to be sure seek() sets SEEK_END on
// all compilers.
if(s != seek(0, 2))
#ifdef _WIN32
#error file.cpp is for posix systems only. use file_win.cpp on windows
#else
if (ftruncate(m_fd, s) < 0)
{
seek(s - 1);
char dummy = 0;
read(&dummy, 1);
seek(s - 1);
write(&dummy, 1);
std::stringstream msg;
msg << "ftruncate failed: '" << strerror(errno);
throw file_error(msg.str());
}
seek(pos);
#endif
}
size_type seek(size_type offset, int m = 1)

View File

@ -952,4 +952,3 @@ namespace libtorrent
}

View File

@ -556,7 +556,7 @@ namespace libtorrent { namespace
namespace libtorrent
{
boost::shared_ptr<torrent_plugin> create_metadata_plugin(torrent* t)
boost::shared_ptr<torrent_plugin> create_metadata_plugin(torrent* t, void*)
{
return boost::shared_ptr<torrent_plugin>(new metadata_plugin(*t));
}

View File

@ -687,6 +687,14 @@ namespace libtorrent
boost::shared_ptr<torrent> t = m_torrent.lock();
assert(t);
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
if ((*i)->on_reject(r)) return;
}
#endif
std::deque<piece_block>::iterator i = std::find_if(
m_download_queue.begin(), m_download_queue.end()
, bind(match_request, boost::cref(r), _1, t->block_size()));
@ -743,7 +751,7 @@ namespace libtorrent
void peer_connection::incoming_suggest(int index)
{
INVARIANT_CHECK;
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << time_now_string()
<< " <== SUGGEST_PIECE [ piece: " << index << " ]\n";
@ -751,6 +759,14 @@ namespace libtorrent
boost::shared_ptr<torrent> t = m_torrent.lock();
if (!t) return;
#ifndef TORRENT_DISABLE_EXTENSIONS
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
if ((*i)->on_suggest(index)) return;
}
#endif
if (t->have_piece(index)) return;
if (m_suggested_pieces.size() > 9)
@ -1647,7 +1663,9 @@ namespace libtorrent
state = piece_picker::slow;
}
t->picker().mark_as_downloading(block, peer_info_struct(), state);
if (!t->picker().mark_as_downloading(block, peer_info_struct(), state))
return;
if (t->alerts().should_post(alert::info))
{
t->alerts().post_alert(block_downloading_alert(t->get_handle(),
@ -1934,7 +1952,6 @@ namespace libtorrent
}
t->remove_peer(this);
m_torrent.reset();
}
@ -2838,6 +2855,8 @@ namespace libtorrent
return;
}
assert(t->connection_for(remote()) != 0 || m_in_constructor);
if (!m_in_constructor && t->connection_for(remote()) != this
&& !m_ses.settings().allow_multiple_connections_per_ip)
{
@ -2897,11 +2916,6 @@ namespace libtorrent
// TODO: the timeout should be called by an event
INVARIANT_CHECK;
#ifndef NDEBUG
// allow step debugging without timing out
return false;
#endif
ptime now(time_now());
// if the socket is still connecting, don't
@ -2915,6 +2929,10 @@ namespace libtorrent
d = now - m_last_receive;
if (d > seconds(m_timeout)) return true;
// if it takes more than 5 seconds to receive
// handshake, disconnect
if (in_handshake() && d > seconds(5)) return true;
// disconnect peers that we unchoked, but
// they didn't send a request within 20 seconds.
// but only if we're a seed

View File

@ -1229,6 +1229,7 @@ namespace libtorrent
bool piece_picker::can_pick(int piece, std::vector<bool> const& bitmask) const
{
assert(piece >= 0 && piece < int(m_piece_map.size()));
return bitmask[piece]
&& !m_piece_map[piece].have()
&& !m_piece_map[piece].downloading
@ -1375,10 +1376,8 @@ namespace libtorrent
{
// ignore completed blocks and already requested blocks
block_info const& info = i->info[j];
if (info.state == block_info::state_finished
|| info.state == block_info::state_writing
|| info.state == block_info::state_requested)
continue;
if (info.state != block_info::state_none)
continue;
assert(i->info[j].state == block_info::state_none);
@ -1432,6 +1431,80 @@ namespace libtorrent
if (num_blocks <= 0) return 0;
if (prefer_whole_pieces > 0)
{
for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin()
, end(m_downloads.end()); i != end; ++i)
{
if (!pieces[i->index]) continue;
int num_blocks_in_piece = blocks_in_piece(i->index);
bool exclusive;
bool exclusive_active;
boost::tie(exclusive, exclusive_active)
= requested_from(*i, num_blocks_in_piece, peer);
if (exclusive_active) continue;
for (int j = 0; j < num_blocks_in_piece; ++j)
{
block_info const& info = i->info[j];
if (info.state != block_info::state_none) continue;
backup_blocks.push_back(piece_block(i->index, j));
}
}
}
if (int(backup_blocks.size()) >= num_blocks) return num_blocks;
#ifndef NDEBUG
// make sure that we at this point has added requests to all unrequested blocks
// in all downloading pieces
for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin()
, end(m_downloads.end()); i != end; ++i)
{
if (!pieces[i->index]) continue;
int num_blocks_in_piece = blocks_in_piece(i->index);
for (int j = 0; j < num_blocks_in_piece; ++j)
{
block_info const& info = i->info[j];
if (info.state != block_info::state_none) continue;
std::vector<piece_block>::iterator k = std::find(
interesting_blocks.begin(), interesting_blocks.end()
, piece_block(i->index, j));
if (k != interesting_blocks.end()) continue;
k = std::find(backup_blocks.begin()
, backup_blocks.end(), piece_block(i->index, j));
if (k != backup_blocks.end()) continue;
std::cerr << "interesting blocks:" << std::endl;
for (k = interesting_blocks.begin(); k != interesting_blocks.end(); ++k)
std::cerr << "(" << k->piece_index << ", " << k->block_index << ") ";
std::cerr << std::endl;
std::cerr << "backup blocks:" << std::endl;
for (k = backup_blocks.begin(); k != backup_blocks.end(); ++k)
std::cerr << "(" << k->piece_index << ", " << k->block_index << ") ";
std::cerr << std::endl;
std::cerr << "num_blocks: " << num_blocks << std::endl;
for (std::vector<downloading_piece>::const_iterator l = m_downloads.begin()
, end(m_downloads.end()); l != end; ++l)
{
std::cerr << l->index << " : ";
int num_blocks_in_piece = blocks_in_piece(l->index);
for (int m = 0; m < num_blocks_in_piece; ++m)
std::cerr << l->info[m].state;
std::cerr << std::endl;
}
assert(false);
}
}
#endif
for (std::vector<downloading_piece>::const_iterator i = m_downloads.begin()
, end(m_downloads.end()); i != end; ++i)
{
@ -1554,7 +1627,7 @@ namespace libtorrent
}
void piece_picker::mark_as_downloading(piece_block block
bool piece_picker::mark_as_downloading(piece_block block
, void* peer, piece_state_t state)
{
TORRENT_PIECE_PICKER_INVARIANT_CHECK;
@ -1589,6 +1662,9 @@ namespace libtorrent
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
assert(i != m_downloads.end());
block_info& info = i->info[block.block_index];
if (info.state == block_info::state_writing
|| info.state == block_info::state_finished)
return false;
assert(info.state == block_info::state_none
|| (info.state == block_info::state_requested
&& (info.num_peers > 0)));
@ -1601,6 +1677,7 @@ namespace libtorrent
++info.num_peers;
if (i->state == none) i->state = state;
}
return true;
}
int piece_picker::num_peers(piece_block block) const

View File

@ -138,28 +138,28 @@ namespace
return free_upload;
}
struct match_peer_ip
struct match_peer_address
{
match_peer_ip(address const& ip)
: m_ip(ip)
match_peer_address(address const& addr)
: m_addr(addr)
{}
bool operator()(policy::peer const& p) const
{ return p.ip.address() == m_ip; }
{ return p.ip.address() == m_addr; }
address const& m_ip;
address const& m_addr;
};
struct match_peer_id
struct match_peer_endpoint
{
match_peer_id(peer_id const& id_)
: m_id(id_)
match_peer_endpoint(tcp::endpoint const& ep)
: m_ep(ep)
{}
bool operator()(policy::peer const& p) const
{ return p.connection && p.connection->pid() == m_id; }
{ return p.ip == m_ep; }
peer_id const& m_id;
tcp::endpoint const& m_ep;
};
struct match_peer_connection
@ -939,7 +939,7 @@ namespace libtorrent
i = std::find_if(
m_peers.begin()
, m_peers.end()
, match_peer_ip(c.remote().address()));
, match_peer_address(c.remote().address()));
}
if (i != m_peers.end())
@ -1029,14 +1029,14 @@ namespace libtorrent
i = std::find_if(
m_peers.begin()
, m_peers.end()
, match_peer_id(pid));
, match_peer_endpoint(remote));
}
else
{
i = std::find_if(
m_peers.begin()
, m_peers.end()
, match_peer_ip(remote.address()));
, match_peer_address(remote.address()));
}
if (i == m_peers.end())
@ -1291,9 +1291,15 @@ namespace libtorrent
try
{
INVARIANT_CHECK;
p->connected = time_now();
p->connection = m_torrent->connect_to_peer(&*p);
if (p->connection == 0) return false;
assert(p->connection == m_torrent->connection_for(p->ip));
if (p->connection == 0)
{
++p->failcount;
return false;
}
p->connection->add_stat(p->prev_amount_download, p->prev_amount_upload);
p->prev_amount_download = 0;
p->prev_amount_upload = 0;
@ -1305,6 +1311,7 @@ namespace libtorrent
(*m_torrent->session().m_logger) << "*** CONNECTION FAILED '"
<< e.what() << "'\n";
#endif
std::cerr << e.what() << std::endl;
++p->failcount;
return false;
}
@ -1402,15 +1409,22 @@ namespace libtorrent
int nonempty_connections = 0;
std::set<address> unique_test;
std::set<tcp::endpoint> unique_test2;
for (const_iterator i = m_peers.begin();
i != m_peers.end(); ++i)
{
peer const& p = *i;
if (!m_torrent->settings().allow_multiple_connections_per_ip)
assert(unique_test.find(p.ip.address()) == unique_test.end());
assert(unique_test2.find(p.ip) == unique_test2.end());
unique_test.insert(p.ip.address());
unique_test2.insert(p.ip);
++total_connections;
if (!p.connection) continue;
if (!p.connection)
{
// assert(m_torrent->connection_for(p.ip) == 0);
continue;
}
if (!m_torrent->settings().allow_multiple_connections_per_ip)
{
std::vector<peer_connection*> conns;

View File

@ -132,7 +132,7 @@ namespace libtorrent
m_impl->abort();
}
void session::add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*)> ext)
void session::add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> ext)
{
m_impl->add_extension(ext);
}
@ -185,7 +185,7 @@ namespace libtorrent
assert(!ti.m_half_metadata);
boost::intrusive_ptr<torrent_info> tip(new torrent_info(ti));
return m_impl->add_torrent(tip, save_path, resume_data
, compact_mode, sc, paused);
, compact_mode, sc, paused, 0);
}
torrent_handle session::add_torrent(
@ -194,11 +194,12 @@ namespace libtorrent
, entry const& resume_data
, bool compact_mode
, bool paused
, storage_constructor_type sc)
, storage_constructor_type sc
, void* userdata)
{
assert(!ti->m_half_metadata);
return m_impl->add_torrent(ti, save_path, resume_data
, compact_mode, sc, paused);
, compact_mode, sc, paused, userdata);
}
torrent_handle session::add_torrent(
@ -209,10 +210,11 @@ namespace libtorrent
, entry const& e
, bool compact_mode
, bool paused
, storage_constructor_type sc)
, storage_constructor_type sc
, void* userdata)
{
return m_impl->add_torrent(tracker_url, info_hash, name, save_path, e
, compact_mode, sc, paused);
, compact_mode, sc, paused, userdata);
}
void session::remove_torrent(const torrent_handle& h)

View File

@ -593,7 +593,7 @@ namespace detail
#ifndef TORRENT_DISABLE_EXTENSIONS
void session_impl::add_extension(
boost::function<boost::shared_ptr<torrent_plugin>(torrent*)> ext)
boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> ext)
{
m_extensions.push_back(ext);
}
@ -1474,7 +1474,8 @@ namespace detail
, entry const& resume_data
, bool compact_mode
, storage_constructor_type sc
, bool paused)
, bool paused
, void* userdata)
{
// if you get this assert, you haven't managed to
// open a listen port. call listen_on() first.
@ -1514,7 +1515,7 @@ namespace detail
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
boost::shared_ptr<torrent_plugin> tp((*i)(torrent_ptr.get()));
boost::shared_ptr<torrent_plugin> tp((*i)(torrent_ptr.get(), userdata));
if (tp) torrent_ptr->add_extension(tp);
}
#endif
@ -1554,7 +1555,8 @@ namespace detail
, entry const&
, bool compact_mode
, storage_constructor_type sc
, bool paused)
, bool paused
, void* userdata)
{
// TODO: support resume data in this case
@ -1593,7 +1595,7 @@ namespace detail
for (extension_list_t::iterator i = m_extensions.begin()
, end(m_extensions.end()); i != end; ++i)
{
boost::shared_ptr<torrent_plugin> tp((*i)(torrent_ptr.get()));
boost::shared_ptr<torrent_plugin> tp((*i)(torrent_ptr.get(), userdata));
if (tp) torrent_ptr->add_extension(tp);
}
#endif

View File

@ -403,13 +403,19 @@ namespace libtorrent
assert(ph.offset == 0 || partial_copy.final() == partial.final());
#endif
int slot_size = piece_size - ph.offset;
if (slot_size == 0) return ph.h.final();
m_scratch_buffer.resize(slot_size);
read_impl(&m_scratch_buffer[0], slot, ph.offset, slot_size, true);
ph.h.update(&m_scratch_buffer[0], slot_size);
if (slot_size > 0)
{
m_scratch_buffer.resize(slot_size);
read_impl(&m_scratch_buffer[0], slot, ph.offset, slot_size, true);
ph.h.update(&m_scratch_buffer[0], slot_size);
}
#ifndef NDEBUG
sha1_hash ret = ph.h.final();
assert(whole.final() == ret);
assert(ret == whole.final());
return ret;
#else
return ph.h.final();
#endif
}
void storage::initialize(bool allocate_files)
@ -996,9 +1002,6 @@ namespace libtorrent
int err = statfs(query_path.native_directory_string().c_str(), &buf);
if (err == 0)
{
#ifndef NDEBUG
std::cerr << "buf.f_type " << std::hex << buf.f_type << std::endl;
#endif
switch (buf.f_type)
{
case 0x5346544e: // NTFS
@ -1084,7 +1087,8 @@ namespace libtorrent
void piece_manager::async_read(
peer_request const& r
, boost::function<void(int, disk_io_job const&)> const& handler
, char* buffer)
, char* buffer
, int priority)
{
disk_io_job j;
j.storage = this;
@ -1093,6 +1097,7 @@ namespace libtorrent
j.offset = r.start;
j.buffer_size = r.length;
j.buffer = buffer;
j.priority = priority;
// if a buffer is not specified, only one block can be read
// since that is the size of the pool allocator's buffers
assert(r.length <= 16 * 1024 || buffer != 0);
@ -1295,6 +1300,7 @@ namespace libtorrent
if (i != m_piece_hasher.end())
{
assert(i->second.offset > 0);
assert(offset >= i->second.offset);
if (offset == i->second.offset)
{
i->second.offset += size;

View File

@ -1653,6 +1653,7 @@ namespace libtorrent
assert(m_connections.find(a) == m_connections.end());
// add the newly connected peer to this torrent's peer list
assert(m_connections.find(a) == m_connections.end());
m_connections.insert(
std::make_pair(a, boost::get_pointer(c)));
m_ses.m_connections.insert(std::make_pair(s, c));
@ -1669,8 +1670,8 @@ namespace libtorrent
#endif
// TODO: post an error alert!
std::map<tcp::endpoint, peer_connection*>::iterator i = m_connections.find(a);
if (i != m_connections.end()) m_connections.erase(i);
// std::map<tcp::endpoint, peer_connection*>::iterator i = m_connections.find(a);
// if (i != m_connections.end()) m_connections.erase(i);
m_ses.connection_failed(s, a, e.what());
c->disconnect();
}
@ -1857,6 +1858,8 @@ namespace libtorrent
try
{
assert(m_connections.find(a) == m_connections.end());
// add the newly connected peer to this torrent's peer list
m_connections.insert(
std::make_pair(a, boost::get_pointer(c)));
@ -1869,6 +1872,7 @@ namespace libtorrent
}
catch (std::exception& e)
{
assert(false);
// TODO: post an error alert!
std::map<tcp::endpoint, peer_connection*>::iterator i = m_connections.find(a);
if (i != m_connections.end()) m_connections.erase(i);
@ -1925,6 +1929,7 @@ namespace libtorrent
= m_connections.find(p->remote());
if (c != m_connections.end())
{
assert(p != c->second);
// we already have a peer_connection to this ip.
// It may currently be waiting for completing a
// connection attempt that might fail. So,
@ -1948,6 +1953,7 @@ namespace libtorrent
throw protocol_error("session is closing");
}
assert(m_connections.find(p->remote()) == m_connections.end());
peer_iterator ci = m_connections.insert(
std::make_pair(p->remote(), p)).first;
try
@ -2408,6 +2414,12 @@ namespace libtorrent
assert(m_abort || m_have_pieces.empty());
}
/* for (policy::const_iterator i = m_policy->begin_peer()
, end(m_policy->end_peer()); i != end; ++i)
{
assert(i->connection == const_cast<torrent*>(this)->connection_for(i->ip));
}
*/
size_type total_done = quantized_bytes_done();
if (m_torrent_file->is_valid())
{

View File

@ -94,18 +94,11 @@ namespace libtorrent
, aux::checker_impl* chk
, sha1_hash const& hash)
{
if (ses == 0) throw_invalid_handle();
aux::piece_checker_data* d = chk->find_torrent(hash);
if (d != 0) return d->torrent_ptr;
if (chk)
{
aux::piece_checker_data* d = chk->find_torrent(hash);
if (d != 0) return d->torrent_ptr;
}
{
boost::shared_ptr<torrent> t = ses->find_torrent(hash).lock();
if (t) return t;
}
boost::shared_ptr<torrent> t = ses->find_torrent(hash).lock();
if (t) return t;
// throwing directly instead of calling
// the throw_invalid_handle() function
@ -118,7 +111,7 @@ namespace libtorrent
void torrent_handle::check_invariant() const
{
assert((m_ses == 0 && m_chk == 0) || (m_ses != 0));
assert((m_ses == 0 && m_chk == 0) || (m_ses != 0 && m_chk != 0));
}
#endif
@ -127,6 +120,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
assert(m_chk);
assert(max_uploads >= 2 || max_uploads == -1);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
@ -138,6 +134,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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);
@ -147,6 +146,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
assert(m_chk);
assert(max_connections >= 2 || max_connections == -1);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
@ -159,6 +161,9 @@ namespace libtorrent
INVARIANT_CHECK;
assert(limit >= -1);
if (m_ses == 0) throw_invalid_handle();
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);
@ -169,6 +174,9 @@ namespace libtorrent
INVARIANT_CHECK;
assert(limit >= -1);
if (m_ses == 0) throw_invalid_handle();
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);
@ -178,6 +186,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
assert(m_chk);
assert(limit >= -1);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
@ -188,6 +199,10 @@ namespace libtorrent
int torrent_handle::upload_limit() const
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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();
@ -197,6 +212,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
assert(m_chk);
assert(limit >= -1);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
@ -208,6 +226,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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();
@ -218,6 +239,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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);
@ -227,6 +251,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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();
@ -236,6 +263,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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();
@ -245,6 +275,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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();
@ -254,6 +287,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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();
@ -263,6 +299,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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();
@ -273,6 +312,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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);
@ -283,31 +325,27 @@ namespace libtorrent
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
assert(m_chk);
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
if (m_chk)
aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
if (d != 0)
{
mutex::scoped_lock l(m_chk->m_mutex);
aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
if (d != 0)
if (!d->processing)
{
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);
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;
}
{
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) return t->file_progress(progress);
}
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
if (t) return t->file_progress(progress);
throw_invalid_handle();
}
@ -317,36 +355,32 @@ namespace libtorrent
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
assert(m_chk);
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
if (m_chk)
aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
if (d != 0)
{
mutex::scoped_lock l(m_chk->m_mutex);
torrent_status st;
aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
if (d != 0)
if (d->processing)
{
torrent_status st;
if (d->processing)
{
if (d->torrent_ptr->is_allocating())
st.state = torrent_status::allocating;
else
st.state = torrent_status::checking_files;
}
if (d->torrent_ptr->is_allocating())
st.state = torrent_status::allocating;
else
st.state = torrent_status::queued_for_checking;
st.progress = d->progress;
st.paused = d->torrent_ptr->is_paused();
return st;
st.state = torrent_status::checking_files;
}
else
st.state = torrent_status::queued_for_checking;
st.progress = d->progress;
st.paused = d->torrent_ptr->is_paused();
return st;
}
{
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) return t->status();
}
boost::shared_ptr<torrent> t = m_ses->find_torrent(m_info_hash).lock();
if (t) return t->status();
throw_invalid_handle();
return torrent_status();
@ -355,6 +389,10 @@ namespace libtorrent
void torrent_handle::set_sequenced_download_threshold(int threshold) const
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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);
@ -364,6 +402,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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();
@ -374,6 +415,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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);
@ -383,6 +427,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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);
@ -392,6 +439,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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);
@ -401,6 +451,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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);
@ -409,6 +462,10 @@ namespace libtorrent
std::vector<int> torrent_handle::piece_priorities() const
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
assert(m_chk);
std::vector<int> ret;
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
@ -420,6 +477,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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);
@ -430,6 +490,10 @@ namespace libtorrent
void torrent_handle::filter_piece(int index, bool filter) const
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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);
@ -438,6 +502,10 @@ namespace libtorrent
void torrent_handle::filter_pieces(std::vector<bool> const& pieces) const
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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);
@ -446,6 +514,10 @@ namespace libtorrent
bool torrent_handle::is_piece_filtered(int index) const
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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);
@ -454,6 +526,10 @@ namespace libtorrent
std::vector<bool> torrent_handle::filtered_pieces() const
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
assert(m_chk);
std::vector<bool> ret;
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
@ -464,6 +540,10 @@ namespace libtorrent
void torrent_handle::filter_files(std::vector<bool> const& files) const
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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);
@ -476,6 +556,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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();
@ -485,6 +568,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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);
@ -494,6 +580,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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);
@ -503,6 +592,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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();
@ -513,6 +605,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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);
@ -521,6 +616,10 @@ namespace libtorrent
torrent_info const& torrent_handle::get_torrent_info() const
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
assert(m_chk);
session_impl::mutex_t::scoped_lock l1(m_ses->m_mutex);
mutex::scoped_lock l2(m_chk->m_mutex);
boost::shared_ptr<torrent> t = find_torrent(m_ses, m_chk, m_info_hash);
@ -533,16 +632,14 @@ namespace libtorrent
INVARIANT_CHECK;
if (m_ses == 0) return false;
assert(m_chk);
if (m_chk)
{
mutex::scoped_lock l(m_chk->m_mutex);
aux::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
if (d != 0) return true;
}
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) return true;
{
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
boost::weak_ptr<torrent> t = m_ses->find_torrent(m_info_hash);
if (!t.expired()) return true;
}
@ -556,6 +653,7 @@ namespace libtorrent
std::vector<int> piece_index;
if (m_ses == 0) return entry();
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();
@ -674,6 +772,9 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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();
@ -684,6 +785,7 @@ namespace libtorrent
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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();
@ -712,6 +814,7 @@ namespace libtorrent
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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();
@ -726,6 +829,7 @@ namespace libtorrent
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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();
@ -738,8 +842,10 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
assert(m_chk);
assert(ratio >= 0.f);
if (ratio < 1.f && ratio > 0.f)
ratio = 1.f;
@ -752,6 +858,10 @@ namespace libtorrent
void torrent_handle::resolve_countries(bool r)
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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);
@ -760,6 +870,10 @@ namespace libtorrent
bool torrent_handle::resolve_countries() const
{
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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();
@ -770,8 +884,10 @@ namespace libtorrent
{
INVARIANT_CHECK;
v.clear();
if (m_ses == 0) throw_invalid_handle();
assert(m_chk);
v.clear();
session_impl::mutex_t::scoped_lock l(m_ses->m_mutex);
@ -803,6 +919,7 @@ namespace libtorrent
INVARIANT_CHECK;
if (m_ses == 0) throw_invalid_handle();
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();

View File

@ -365,23 +365,22 @@ namespace libtorrent
, m_req(req)
{}
request_callback& tracker_connection::requester()
boost::shared_ptr<request_callback> tracker_connection::requester()
{
boost::shared_ptr<request_callback> r = m_requester.lock();
assert(r);
return *r;
return m_requester.lock();
}
void tracker_connection::fail(int code, char const* msg)
{
if (has_requester()) requester().tracker_request_error(
m_req, code, msg);
boost::shared_ptr<request_callback> cb = requester();
if (cb) cb->tracker_request_error(m_req, code, msg);
close();
}
void tracker_connection::fail_timeout()
{
if (has_requester()) requester().tracker_request_timed_out(m_req);
boost::shared_ptr<request_callback> cb = requester();
if (cb) cb->tracker_request_timed_out(m_req);
close();
}
@ -548,7 +547,8 @@ namespace libtorrent
m_connections.push_back(con);
if (con->has_requester()) con->requester().m_manager = this;
boost::shared_ptr<request_callback> cb = con->requester();
if (cb) cb->m_manager = this;
}
catch (std::exception& e)
{

View File

@ -110,8 +110,9 @@ namespace libtorrent
return;
}
boost::shared_ptr<request_callback> cb = requester();
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
if (has_requester()) requester().debug_log("udp tracker name lookup successful");
if (cb) cb->debug_log("udp tracker name lookup successful");
#endif
restart_read_timeout();
@ -126,11 +127,11 @@ namespace libtorrent
if (target == end)
{
assert(target_address.address().is_v4() != bind_interface().is_v4());
if (has_requester())
if (cb)
{
std::string tracker_address_type = target_address.address().is_v4() ? "IPv4" : "IPv6";
std::string bind_address_type = bind_interface().is_v4() ? "IPv4" : "IPv6";
requester().tracker_warning("the tracker only resolves to an "
cb->tracker_warning("the tracker only resolves to an "
+ tracker_address_type + " address, and you're listening on an "
+ bind_address_type + " socket. This may prevent you from receiving incoming connections.");
}
@ -140,7 +141,7 @@ namespace libtorrent
target_address = *target;
}
if (has_requester()) requester().m_tracker_address = tcp::endpoint(target_address.address(), target_address.port());
if (cb) cb->m_tracker_address = tcp::endpoint(target_address.address(), target_address.port());
m_target = target_address;
m_socket.reset(new datagram_socket(m_name_lookup.io_service()));
m_socket->open(target_address.protocol());
@ -163,9 +164,10 @@ namespace libtorrent
void udp_tracker_connection::send_udp_connect()
{
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
if (has_requester())
boost::shared_ptr<request_callback> cb = requester();
if (cb)
{
requester().debug_log("==> UDP_TRACKER_CONNECT ["
cb->debug_log("==> UDP_TRACKER_CONNECT ["
+ lexical_cast<std::string>(tracker_req().info_hash) + "]");
}
#endif
@ -259,9 +261,10 @@ namespace libtorrent
m_connection_id = detail::read_int64(ptr);
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
if (has_requester())
boost::shared_ptr<request_callback> cb = requester();
if (cb)
{
requester().debug_log("<== UDP_TRACKER_CONNECT_RESPONSE ["
cb->debug_log("<== UDP_TRACKER_CONNECT_RESPONSE ["
+ lexical_cast<std::string>(m_connection_id) + "]");
}
#endif
@ -321,9 +324,10 @@ namespace libtorrent
detail::write_uint16(0, out);
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
if (has_requester())
boost::shared_ptr<request_callback> cb = requester();
if (cb)
{
requester().debug_log("==> UDP_TRACKER_ANNOUNCE ["
cb->debug_log("==> UDP_TRACKER_ANNOUNCE ["
+ lexical_cast<std::string>(req.info_hash) + "]");
}
#endif
@ -431,14 +435,15 @@ namespace libtorrent
return;
}
boost::shared_ptr<request_callback> cb = requester();
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
if (has_requester())
if (cb)
{
requester().debug_log("<== UDP_TRACKER_ANNOUNCE_RESPONSE");
cb->debug_log("<== UDP_TRACKER_ANNOUNCE_RESPONSE");
}
#endif
if (!has_requester())
if (!cb)
{
m_man.remove_request(this);
return;
@ -459,7 +464,7 @@ namespace libtorrent
peer_list.push_back(e);
}
requester().tracker_response(tracker_req(), peer_list, interval
cb->tracker_response(tracker_req(), peer_list, interval
, complete, incomplete);
m_man.remove_request(this);
@ -534,14 +539,15 @@ namespace libtorrent
/*int downloaded = */detail::read_int32(buf);
int incomplete = detail::read_int32(buf);
if (!has_requester())
boost::shared_ptr<request_callback> cb = requester();
if (!cb)
{
m_man.remove_request(this);
return;
}
std::vector<peer_entry> peer_list;
requester().tracker_response(tracker_req(), peer_list, 0
cb->tracker_response(tracker_req(), peer_list, 0
, complete, incomplete);
m_man.remove_request(this);

View File

@ -997,4 +997,3 @@ void upnp::close()
}
}

View File

@ -67,8 +67,6 @@ namespace libtorrent { namespace
if (!p.is_local()) return false;
// don't send out peers that we haven't successfully connected to
if (p.is_connecting()) return false;
// ut pex does not support IPv6
if (!p.remote().address().is_v4()) return false;
return true;
}
@ -98,9 +96,15 @@ namespace libtorrent { namespace
std::string& pla = pex["added"].string();
std::string& pld = pex["dropped"].string();
std::string& plf = pex["added.f"].string();
std::string& pla6 = pex["added6"].string();
std::string& pld6 = pex["dropped6"].string();
std::string& plf6 = pex["added6.f"].string();
std::back_insert_iterator<std::string> pla_out(pla);
std::back_insert_iterator<std::string> pld_out(pld);
std::back_insert_iterator<std::string> plf_out(plf);
std::back_insert_iterator<std::string> pla6_out(pla6);
std::back_insert_iterator<std::string> pld6_out(pld6);
std::back_insert_iterator<std::string> plf6_out(plf6);
std::set<tcp::endpoint> dropped;
m_old_peers.swap(dropped);
@ -123,8 +127,6 @@ namespace libtorrent { namespace
bt_peer_connection* p = dynamic_cast<bt_peer_connection*>(i->second);
if (!p) continue;
// i->first was added since the last time
detail::write_endpoint(i->first, pla_out);
// no supported flags to set yet
// 0x01 - peer supports encryption
// 0x02 - peer is a seed
@ -132,7 +134,17 @@ namespace libtorrent { namespace
#ifndef TORRENT_DISABLE_ENCRYPTION
flags |= p->supports_encryption() ? 1 : 0;
#endif
detail::write_uint8(flags, plf_out);
// i->first was added since the last time
if (i->first.address().is_v4())
{
detail::write_endpoint(i->first, pla_out);
detail::write_uint8(flags, plf_out);
}
else
{
detail::write_endpoint(i->first, pla6_out);
detail::write_uint8(flags, plf6_out);
}
++num_added;
}
else
@ -146,8 +158,10 @@ namespace libtorrent { namespace
for (std::set<tcp::endpoint>::const_iterator i = dropped.begin()
, end(dropped.end());i != end; ++i)
{
if (!i->address().is_v4()) continue;
detail::write_endpoint(*i, pld_out);
if (i->address().is_v4())
detail::write_endpoint(*i, pld_out);
else
detail::write_endpoint(*i, pld6_out);
}
m_ut_pex_msg.clear();
@ -227,6 +241,28 @@ namespace libtorrent { namespace
char flags = detail::read_uint8(fin);
p.peer_from_tracker(adr, pid, peer_info::pex, flags);
}
if (entry const* p6 = pex_msg.find_key("added6"))
{
std::string const& peers6 = p6->string();
std::string const& peer6_flags = pex_msg["added6.f"].string();
int num_peers = peers6.length() / 18;
char const* in = peers6.c_str();
char const* fin = peer6_flags.c_str();
if (int(peer6_flags.size()) != num_peers)
return true;
peer_id pid(0);
policy& p = m_torrent.get_policy();
for (int i = 0; i < num_peers; ++i)
{
tcp::endpoint adr = detail::read_v6_endpoint<tcp::endpoint>(in);
char flags = detail::read_uint8(fin);
p.peer_from_tracker(adr, pid, peer_info::pex, flags);
}
}
}
catch (std::exception&)
{
@ -279,8 +315,13 @@ namespace libtorrent { namespace
pex["dropped"].string();
std::string& pla = pex["added"].string();
std::string& plf = pex["added.f"].string();
pex["dropped6"].string();
std::string& pla6 = pex["added6"].string();
std::string& plf6 = pex["added6.f"].string();
std::back_insert_iterator<std::string> pla_out(pla);
std::back_insert_iterator<std::string> plf_out(plf);
std::back_insert_iterator<std::string> pla6_out(pla6);
std::back_insert_iterator<std::string> plf6_out(plf6);
int num_added = 0;
for (torrent::peer_iterator i = m_torrent.begin()
@ -295,8 +336,6 @@ namespace libtorrent { namespace
bt_peer_connection* p = dynamic_cast<bt_peer_connection*>(i->second);
if (!p) continue;
// i->first was added since the last time
detail::write_endpoint(i->first, pla_out);
// no supported flags to set yet
// 0x01 - peer supports encryption
// 0x02 - peer is a seed
@ -304,7 +343,17 @@ namespace libtorrent { namespace
#ifndef TORRENT_DISABLE_ENCRYPTION
flags |= p->supports_encryption() ? 1 : 0;
#endif
detail::write_uint8(flags, plf_out);
// i->first was added since the last time
if (i->first.address().is_v4())
{
detail::write_endpoint(i->first, pla_out);
detail::write_uint8(flags, plf_out);
}
else
{
detail::write_endpoint(i->first, pla6_out);
detail::write_uint8(flags, plf6_out);
}
++num_added;
}
std::vector<char> pex_msg;
@ -347,7 +396,7 @@ namespace libtorrent { namespace
namespace libtorrent
{
boost::shared_ptr<torrent_plugin> create_ut_pex_plugin(torrent* t)
boost::shared_ptr<torrent_plugin> create_ut_pex_plugin(torrent* t, void*)
{
if (t->torrent_file().priv())
{