*** empty log message ***
This commit is contained in:
parent
b62f8f1a85
commit
5f9ae41e86
|
@ -423,12 +423,24 @@ Its declaration looks like this::
|
|||
void get_peer_info(std::vector<peer_info>& v);
|
||||
const torrent_info& get_torrent_info();
|
||||
bool is_valid();
|
||||
|
||||
boost::filsystem::path save_path() const;
|
||||
|
||||
sha1_hash info_hash() const;
|
||||
|
||||
bool operator==(const torrent_handle&) const;
|
||||
bool operator!=(const torrent_handle&) const;
|
||||
bool operator<(const torrent_handle&) const;
|
||||
};
|
||||
|
||||
The default constructor will initialize the handle to an invalid state. Which means you cannot
|
||||
perform any operation on it, unless you first assign it a valid handle. If you try to perform
|
||||
any operation they will simply return.
|
||||
|
||||
``save_path()`` returns the path that were given to ``add_torrent()`` when this torrent
|
||||
was started.
|
||||
|
||||
``info_hash()`` returns the info hash for the torrent.
|
||||
|
||||
status()
|
||||
~~~~~~~~
|
||||
|
@ -453,6 +465,8 @@ It contains the following fields::
|
|||
boost::posix_time::time_duration next_announce;
|
||||
std::size_t total_download;
|
||||
std::size_t total_upload;
|
||||
float download_rate;
|
||||
float upload_rate;
|
||||
std::vector<bool> pieces;
|
||||
std::size_t total_done;
|
||||
};
|
||||
|
@ -486,6 +500,10 @@ uploaded to all peers, accumulated, *this session* only.
|
|||
``pieces`` is the bitmask that representw which pieces we have (set to true) and
|
||||
the pieces we don't have.
|
||||
|
||||
``download_rate`` and ``upload_rate`` are the total rates for all peers for this
|
||||
torrent. These will usually have better precision than summing the rates from
|
||||
all peers.
|
||||
|
||||
``total_done`` is the total number of bytes of the file(s) that we have.
|
||||
|
||||
get_download_queue()
|
||||
|
@ -579,7 +597,8 @@ in the torrent. Each boolean tells you if the peer has that piece (if it's set t
|
|||
or if the peer miss that piece (set to false).
|
||||
|
||||
``upload_limit`` is the number of bytes per second we are allowed to send to this
|
||||
peer every second. It may be -1 if there's no limit.
|
||||
peer every second. It may be -1 if there's no limit. The upload limits of all peers
|
||||
should sum up to the upload limit set by ``session::set_upload_limit``.
|
||||
|
||||
|
||||
get_torrent_info()
|
||||
|
@ -657,6 +676,21 @@ that will be sent to the tracker. The user-agent is a good way to identify your
|
|||
int tracker_maximum_response_length;
|
||||
};
|
||||
|
||||
``proxy_ip`` may be a hostname or ip to a http proxy to use. If this is
|
||||
an empty string, no http proxy will be used.
|
||||
|
||||
``proxy_port`` is the port on which the http proxy listens. If ``proxy_ip``
|
||||
is empty, this will be ignored.
|
||||
|
||||
``proxy_login`` should be the login username for the http proxy, if this
|
||||
empty, the http proxy will be trid to be used without authentication.
|
||||
|
||||
``proxy_password`` the password string for the http proxy.
|
||||
|
||||
``user_agent`` this is the client identification to the tracker. It will
|
||||
be followed by the string "(libtorrent)" to identify that this library
|
||||
is being used. This should be set to your client's name and version number.
|
||||
|
||||
``tracker_timeout`` is the number of seconds the tracker connection will
|
||||
wait until it considers the tracker to have timed-out. Default value is 10
|
||||
seconds.
|
||||
|
@ -669,7 +703,6 @@ expand to 2 megs, it will be interrupted before the entire response has been
|
|||
uncompressed (given your limit is lower than 2 megs). Default limit is
|
||||
1 megabyte.
|
||||
|
||||
TODO: finish document http_settings
|
||||
|
||||
big_number
|
||||
----------
|
||||
|
|
|
@ -152,7 +152,7 @@ int main(int argc, char* argv[])
|
|||
using namespace libtorrent;
|
||||
|
||||
// TEMPORARY
|
||||
boost::filesystem::path::default_name_check(boost::filesystem::no_check);
|
||||
// boost::filesystem::path::default_name_check(boost::filesystem::no_check);
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
|
@ -172,7 +172,10 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
std::vector<torrent_handle> handles;
|
||||
session s(6881, "E\x1");
|
||||
// s.set_upload_rate_limit(20 * 1024);
|
||||
|
||||
// limit upload rate to 100 kB/s
|
||||
// s.set_upload_rate_limit(100 * 1024);
|
||||
|
||||
s.set_http_settings(settings);
|
||||
for (int i = 0; i < argc-1; ++i)
|
||||
{
|
||||
|
@ -182,7 +185,6 @@ int main(int argc, char* argv[])
|
|||
in.unsetf(std::ios_base::skipws);
|
||||
entry e = bdecode(std::istream_iterator<char>(in), std::istream_iterator<char>());
|
||||
torrent_info t(e);
|
||||
// t.convert_file_names();
|
||||
t.print(std::cout);
|
||||
handles.push_back(s.add_torrent(t, boost::filesystem::path("", boost::filesystem::native)));
|
||||
}
|
||||
|
@ -229,19 +231,11 @@ int main(int argc, char* argv[])
|
|||
|
||||
// calculate download and upload speeds
|
||||
i->get_peer_info(peers);
|
||||
float down = 0.f;
|
||||
float up = 0.f;
|
||||
float down = s.download_rate;
|
||||
float up = s.upload_rate;
|
||||
unsigned int total_down = s.total_download;
|
||||
unsigned int total_up = s.total_upload;
|
||||
int num_peers = peers.size();
|
||||
|
||||
for (std::vector<peer_info>::iterator i = peers.begin();
|
||||
i != peers.end();
|
||||
++i)
|
||||
{
|
||||
down += i->down_speed;
|
||||
up += i->up_speed;
|
||||
}
|
||||
/*
|
||||
std::cout << boost::format("%f%% p:%d d:(%s) %s/s u:(%s) %s/s\n")
|
||||
% (s.progress*100)
|
||||
|
@ -259,6 +253,22 @@ int main(int argc, char* argv[])
|
|||
// std::cout << "next announce: " << boost::posix_time::to_simple_string(t) << "\n";
|
||||
std::cout << "next announce: " << t.hours() << ":" << t.minutes() << ":" << t.seconds() << "\n";
|
||||
|
||||
for (std::vector<peer_info>::iterator i = peers.begin();
|
||||
i != peers.end();
|
||||
++i)
|
||||
{
|
||||
std::cout << "d: " << add_suffix(i->down_speed) << "/s (" << add_suffix(i->total_download)
|
||||
<< ") u: " << add_suffix(i->up_speed) << "/s (" << add_suffix(i->total_upload)
|
||||
<< ") ratio: " << static_cast<float>(i->total_upload+1) / static_cast<float>(i->total_download+1)
|
||||
<< " flags: "
|
||||
<< static_cast<const char*>((i->flags & peer_info::interesting)?"I":"_")
|
||||
<< static_cast<const char*>((i->flags & peer_info::choked)?"C":"_")
|
||||
<< static_cast<const char*>((i->flags & peer_info::remote_interested)?"i":"_")
|
||||
<< static_cast<const char*>((i->flags & peer_info::remote_choked)?"c":"_") << "\n";
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
i->get_download_queue(queue);
|
||||
for (std::vector<partial_piece_info>::iterator i = queue.begin();
|
||||
i != queue.end();
|
||||
|
@ -273,7 +283,9 @@ int main(int argc, char* argv[])
|
|||
}
|
||||
std::cout << "\n";
|
||||
}
|
||||
*/
|
||||
std::cout << "___________________________________\n";
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -87,7 +87,7 @@ namespace libtorrent
|
|||
// this is the constructor where the we are teh active part. The peer_conenction
|
||||
// should handshake and verify that the other end has the correct id
|
||||
peer_connection(
|
||||
detail::session_impl* ses
|
||||
detail::session_impl& ses
|
||||
, selector& sel
|
||||
, torrent* t
|
||||
, boost::shared_ptr<libtorrent::socket> s
|
||||
|
@ -96,7 +96,7 @@ namespace libtorrent
|
|||
// with this constructor we have been contacted and we still don't know which torrent the
|
||||
// connection belongs to
|
||||
peer_connection(
|
||||
detail::session_impl* ses
|
||||
detail::session_impl& ses
|
||||
, selector& sel
|
||||
, boost::shared_ptr<libtorrent::socket> s);
|
||||
|
||||
|
@ -156,12 +156,7 @@ namespace libtorrent
|
|||
const stat& statistics() const { return m_statistics; }
|
||||
|
||||
// is called once every second by the main loop
|
||||
void second_tick()
|
||||
{
|
||||
m_statistics.second_tick();
|
||||
m_send_quota_left = m_send_quota;
|
||||
if (m_send_quota > 0) send_buffer_updated();
|
||||
}
|
||||
void second_tick();
|
||||
|
||||
boost::shared_ptr<libtorrent::socket> get_socket() const { return m_socket; }
|
||||
|
||||
|
@ -201,6 +196,9 @@ namespace libtorrent
|
|||
int trust_points() const
|
||||
{ return m_trust_points; }
|
||||
|
||||
int send_quota_limit() const
|
||||
{ return m_send_quota_limit; }
|
||||
|
||||
#ifndef NDEBUG
|
||||
boost::shared_ptr<logger> m_logger;
|
||||
#endif
|
||||
|
@ -250,13 +248,16 @@ namespace libtorrent
|
|||
std::vector<char> m_recv_buffer;
|
||||
|
||||
// this is the buffer where data that is
|
||||
// to be sent is stored until
|
||||
// to be sent is stored until it gets
|
||||
// consumed by send()
|
||||
std::vector<char> m_send_buffer;
|
||||
|
||||
// timeouts
|
||||
boost::posix_time::ptime m_last_receive;
|
||||
boost::posix_time::ptime m_last_sent;
|
||||
|
||||
// the selector is used to add and remove this
|
||||
// peer's socket from the writability monitor list.
|
||||
selector& m_selector;
|
||||
boost::shared_ptr<libtorrent::socket> m_socket;
|
||||
|
||||
|
@ -268,12 +269,14 @@ namespace libtorrent
|
|||
torrent* m_torrent;
|
||||
|
||||
// this is set to false until the peer_id
|
||||
// is received from the other end. Or is
|
||||
// true if the conenction was actively
|
||||
// opened from our side.
|
||||
// is received from the other end. Or it is
|
||||
// true from the start if the conenction
|
||||
// was actively opened from our side.
|
||||
bool m_attached_to_torrent;
|
||||
|
||||
detail::session_impl* m_ses;
|
||||
// a back reference to the session
|
||||
// the peer belongs to.
|
||||
detail::session_impl& m_ses;
|
||||
// is true if it was we that connected to the peer
|
||||
// and false if we got an incomming connection
|
||||
bool m_active;
|
||||
|
@ -335,6 +338,12 @@ namespace libtorrent
|
|||
int m_send_quota;
|
||||
int m_send_quota_left;
|
||||
|
||||
// this is the maximum send quota we should give
|
||||
// this peer given the current download rate
|
||||
// and the current share ratio with this peer.
|
||||
// this limit will maintain a 1:1 share ratio.
|
||||
int m_send_quota_limit;
|
||||
|
||||
// for every valid piece we receive where this
|
||||
// peer was one of the participants, we increase
|
||||
// this value. For every invalid piece we receive
|
||||
|
|
|
@ -47,8 +47,12 @@ namespace libtorrent
|
|||
stat()
|
||||
: m_downloaded(0)
|
||||
, m_uploaded(0)
|
||||
, m_downloaded_protocol(0)
|
||||
, m_uploaded_protocol(0)
|
||||
, m_total_download(0)
|
||||
, m_total_upload(0)
|
||||
, m_total_download_protocol(0)
|
||||
, m_total_upload_protocol(0)
|
||||
, m_peak_downloaded_per_second(0)
|
||||
, m_peak_uploaded_per_second(0)
|
||||
, m_mean_download_per_second(0)
|
||||
|
@ -58,18 +62,44 @@ namespace libtorrent
|
|||
std::fill(m_upload_per_second_history, m_upload_per_second_history+history, 0);
|
||||
}
|
||||
|
||||
void operator+=(const stat& s)
|
||||
{
|
||||
m_downloaded += s.m_downloaded;
|
||||
m_total_download += s.m_downloaded;
|
||||
m_downloaded_protocol += s.m_downloaded_protocol;
|
||||
m_total_download_protocol += s.m_downloaded_protocol;
|
||||
|
||||
m_uploaded += s.m_uploaded;
|
||||
m_total_upload += s.m_uploaded;
|
||||
m_uploaded_protocol += s.m_uploaded_protocol;
|
||||
m_total_upload_protocol += s.m_uploaded_protocol;
|
||||
}
|
||||
|
||||
// TODO: these function should take two arguments
|
||||
// to be able to count both total data sent and also
|
||||
// count only the actual payload (not counting the
|
||||
// protocol chatter)
|
||||
void received_bytes(int num_bytes)
|
||||
{ m_downloaded += num_bytes; m_total_download += num_bytes; }
|
||||
void sent_bytes(int num_bytes)
|
||||
{ m_uploaded += num_bytes; m_total_upload += num_bytes; }
|
||||
void received_bytes(int bytes_payload, int bytes_protocol)
|
||||
{
|
||||
m_downloaded += bytes_payload;
|
||||
m_total_download += bytes_payload;
|
||||
|
||||
m_downloaded_protocol += bytes_protocol;
|
||||
m_total_download_protocol += bytes_protocol;
|
||||
}
|
||||
void sent_bytes(int bytes_payload, int bytes_protocol)
|
||||
{
|
||||
m_uploaded += bytes_payload;
|
||||
m_total_upload += bytes_payload;
|
||||
|
||||
m_uploaded_protocol += bytes_protocol;
|
||||
m_total_upload_protocol += bytes_protocol;
|
||||
}
|
||||
|
||||
// should be called once every second
|
||||
void second_tick();
|
||||
|
||||
// only counts the payload data!
|
||||
float upload_rate() const { return m_mean_upload_per_second; }
|
||||
float download_rate() const { return m_mean_download_per_second; }
|
||||
|
||||
|
@ -81,19 +111,34 @@ namespace libtorrent
|
|||
|
||||
private:
|
||||
|
||||
|
||||
|
||||
// history of download/upload speeds a few seconds back
|
||||
unsigned int m_download_per_second_history[history];
|
||||
unsigned int m_upload_per_second_history[history];
|
||||
|
||||
// the accumulators we are adding the downloads/upploads
|
||||
// to this second
|
||||
// to this second. This only counts the actual payload
|
||||
// and ignores the bytes sent as protocol chatter.
|
||||
unsigned int m_downloaded;
|
||||
unsigned int m_uploaded;
|
||||
|
||||
// the accumulators we are adding the downloads/upploads
|
||||
// to this second. This only counts the protocol
|
||||
// chatter and ignores the actual payload
|
||||
unsigned int m_downloaded_protocol;
|
||||
unsigned int m_uploaded_protocol;
|
||||
|
||||
// total download/upload counters
|
||||
// only counting payload data
|
||||
unsigned int m_total_download;
|
||||
unsigned int m_total_upload;
|
||||
|
||||
// total download/upload counters
|
||||
// only counting protocol chatter
|
||||
unsigned int m_total_download_protocol;
|
||||
unsigned int m_total_upload_protocol;
|
||||
|
||||
// peak mean download/upload rates
|
||||
unsigned int m_peak_downloaded_per_second;
|
||||
unsigned int m_peak_uploaded_per_second;
|
||||
|
|
|
@ -236,14 +236,20 @@ namespace libtorrent
|
|||
|
||||
piece_manager(
|
||||
const torrent_info& info
|
||||
, const boost::filesystem::path& path);
|
||||
, const boost::filesystem::path& path);
|
||||
|
||||
void check_pieces(boost::mutex& mutex, detail::piece_checker_data& data);
|
||||
void check_pieces(
|
||||
boost::mutex& mutex
|
||||
, detail::piece_checker_data& data
|
||||
, std::vector<bool>& pieces);
|
||||
|
||||
void allocate_slots(int num_slots);
|
||||
|
||||
size_type read(char* buf, int piece_index, size_type offset, size_type size);
|
||||
size_type write(const char* buf, int piece_index, size_type offset, size_type size);
|
||||
void write(const char* buf, int piece_index, size_type offset, size_type size);
|
||||
|
||||
const boost::filesystem::path& save_path() const
|
||||
{ return m_save_path; }
|
||||
|
||||
private:
|
||||
|
||||
|
@ -277,6 +283,8 @@ namespace libtorrent
|
|||
// * : the slot is assigned to this piece
|
||||
std::vector<int> m_slot_to_piece;
|
||||
|
||||
boost::filesystem::path m_save_path;
|
||||
|
||||
// synchronization
|
||||
boost::mutex m_locked_pieces_monitor;
|
||||
boost::condition m_unlocked_pieces;
|
||||
|
|
|
@ -50,6 +50,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/policy.hpp"
|
||||
#include "libtorrent/storage.hpp"
|
||||
#include "libtorrent/url_handler.hpp"
|
||||
#include "libtorrent/stat.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
@ -81,7 +82,12 @@ namespace libtorrent
|
|||
{
|
||||
public:
|
||||
|
||||
torrent(detail::session_impl* ses, const torrent_info& torrent_file);
|
||||
typedef entry::integer_type size_type;
|
||||
|
||||
torrent(
|
||||
detail::session_impl& ses
|
||||
, const torrent_info& torrent_file
|
||||
, const boost::filesystem::path& save_path);
|
||||
~torrent() {}
|
||||
|
||||
void abort() { m_abort = true; m_event = event_stopped; }
|
||||
|
@ -101,34 +107,11 @@ namespace libtorrent
|
|||
|
||||
void print(std::ostream& os) const;
|
||||
|
||||
void allocate_files(detail::piece_checker_data* data,
|
||||
boost::mutex& mutex,
|
||||
const boost::filesystem::path& save_path);
|
||||
void check_files(detail::piece_checker_data& data,
|
||||
boost::mutex& mutex);
|
||||
|
||||
void uploaded_bytes(int num_bytes) { assert(num_bytes > 0); m_bytes_uploaded += num_bytes; }
|
||||
void downloaded_bytes(int num_bytes) { assert(num_bytes > 0); m_bytes_downloaded += num_bytes; }
|
||||
|
||||
int bytes_downloaded() const { return m_bytes_downloaded; }
|
||||
int bytes_uploaded() const { return m_bytes_uploaded; }
|
||||
int bytes_left() const
|
||||
{
|
||||
const std::vector<bool>& p = m_storage.pieces();
|
||||
int num_pieces = std::accumulate(p.begin(), p.end(), 0);
|
||||
int total_blocks
|
||||
= (m_torrent_file.total_size()+m_block_size-1)/m_block_size;
|
||||
int blocks_per_piece
|
||||
= m_torrent_file.piece_length() / m_block_size;
|
||||
int unverified_blocks = m_picker.unverified_blocks();
|
||||
int blocks_we_have = num_pieces * blocks_per_piece;
|
||||
const int last_piece = m_torrent_file.num_pieces()-1;
|
||||
if (p[last_piece])
|
||||
{
|
||||
blocks_we_have += m_picker.blocks_in_piece(last_piece)
|
||||
- blocks_per_piece;
|
||||
}
|
||||
return m_torrent_file.total_size()
|
||||
- (blocks_we_have + unverified_blocks) * m_block_size;
|
||||
}
|
||||
stat statistics() const { return m_stat; }
|
||||
size_type bytes_left() const;
|
||||
|
||||
torrent_status status() const;
|
||||
|
||||
|
@ -140,8 +123,8 @@ namespace libtorrent
|
|||
{ return m_torrent_file; }
|
||||
|
||||
policy& get_policy() { return *m_policy; }
|
||||
storage* filesystem() { return &m_storage; }
|
||||
|
||||
piece_manager& filesystem() { return m_storage; }
|
||||
|
||||
// --------------------------------------------
|
||||
// PEER MANAGEMENT
|
||||
|
@ -207,7 +190,8 @@ namespace libtorrent
|
|||
// PIECE MANAGEMENT
|
||||
|
||||
// returns true if we have downloaded the given piece
|
||||
bool have_piece(unsigned int index) const { return m_storage.have_piece(index); }
|
||||
bool have_piece(unsigned int index) const
|
||||
{ return m_have_pieces[index]; }
|
||||
|
||||
// when we get a have- or bitfield- messages, this is called for every
|
||||
// piece a peer has gained.
|
||||
|
@ -234,11 +218,26 @@ namespace libtorrent
|
|||
|
||||
piece_picker& picker() { return m_picker; }
|
||||
|
||||
|
||||
bool verify_piece(int piece_index);
|
||||
|
||||
// this is called from the peer_connection
|
||||
// each time a piece has failed the hash
|
||||
// test
|
||||
void piece_failed(int index);
|
||||
|
||||
float priority() const
|
||||
{ return m_priority; }
|
||||
|
||||
void set_priority(float p)
|
||||
{
|
||||
assert(p >= 0.f && p <= 0.f);
|
||||
m_priority = p;
|
||||
}
|
||||
|
||||
boost::filesystem::path save_path() const
|
||||
{ return m_storage.save_path(); }
|
||||
|
||||
// DEBUG
|
||||
#ifndef NDEBUG
|
||||
logger* spawn_logger(const char* title);
|
||||
|
@ -273,11 +272,6 @@ namespace libtorrent
|
|||
|
||||
void parse_response(const entry& e, std::vector<peer>& peer_list);
|
||||
|
||||
// TODO: Replace with stat-object
|
||||
// total amount of bytes uploaded, downloaded
|
||||
entry::integer_type m_bytes_uploaded;
|
||||
entry::integer_type m_bytes_downloaded;
|
||||
|
||||
torrent_info m_torrent_file;
|
||||
|
||||
piece_manager m_storage;
|
||||
|
@ -294,11 +288,17 @@ namespace libtorrent
|
|||
|
||||
std::vector<peer_connection*> m_connections;
|
||||
|
||||
// this is the upload and download statistics for the whole torrent.
|
||||
// it's updated from all its peers once every second.
|
||||
libtorrent::stat m_stat;
|
||||
|
||||
// -----------------------------
|
||||
|
||||
boost::shared_ptr<policy> m_policy;
|
||||
|
||||
detail::session_impl* m_ses;
|
||||
// a back reference to the session
|
||||
// this torrent belongs to.
|
||||
detail::session_impl& m_ses;
|
||||
|
||||
piece_picker m_picker;
|
||||
|
||||
|
@ -310,6 +310,19 @@ namespace libtorrent
|
|||
// second, and when it reaches 10, the policy::pulse()
|
||||
// is called and the time scaler is reset to 0.
|
||||
int m_time_scaler;
|
||||
|
||||
// this is the priority of this torrent. It is used
|
||||
// to weight the assigned upload bandwidth between peers
|
||||
// it should be within the range [0, 1]
|
||||
float m_priority;
|
||||
|
||||
// the bitmask that says which pieces we have
|
||||
std::vector<bool> m_have_pieces;
|
||||
|
||||
// the number of pieces we have. The same as
|
||||
// std::accumulate(m_have_pieces.begin(),
|
||||
// m_have_pieces.end(), 0)
|
||||
int m_num_pieces;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -78,6 +78,8 @@ namespace libtorrent
|
|||
// transferred this session!
|
||||
std::size_t total_download;
|
||||
std::size_t total_upload;
|
||||
float download_rate;
|
||||
float upload_rate;
|
||||
std::vector<bool> pieces;
|
||||
|
||||
// the number of bytes of the file we have
|
||||
|
@ -100,12 +102,12 @@ namespace libtorrent
|
|||
friend class session;
|
||||
torrent_handle(): m_ses(0) {}
|
||||
|
||||
void get_peer_info(std::vector<peer_info>& v);
|
||||
torrent_status status();
|
||||
void get_download_queue(std::vector<partial_piece_info>& queue);
|
||||
void get_peer_info(std::vector<peer_info>& v) const;
|
||||
torrent_status status() const;
|
||||
void get_download_queue(std::vector<partial_piece_info>& queue) const;
|
||||
|
||||
const torrent_info& get_torrent_info();
|
||||
bool is_valid();
|
||||
const torrent_info& get_torrent_info() const;
|
||||
bool is_valid() const;
|
||||
|
||||
// TODO: add force reannounce
|
||||
|
||||
|
@ -113,6 +115,20 @@ namespace libtorrent
|
|||
// to finish all pieces currently in the pipeline, and then
|
||||
// abort the torrent.
|
||||
|
||||
boost::filesystem::path save_path() const;
|
||||
|
||||
const sha1_hash& info_hash() const
|
||||
{ return m_info_hash; }
|
||||
|
||||
bool operator==(const torrent_handle& h) const
|
||||
{ return m_info_hash == h.m_info_hash; }
|
||||
|
||||
bool operator!=(const torrent_handle& h) const
|
||||
{ return m_info_hash != h.m_info_hash; }
|
||||
|
||||
bool operator<(const torrent_handle& h) const
|
||||
{ return m_info_hash < h.m_info_hash; }
|
||||
|
||||
private:
|
||||
|
||||
torrent_handle(detail::session_impl* s,
|
||||
|
|
|
@ -72,7 +72,7 @@ namespace
|
|||
}
|
||||
|
||||
libtorrent::peer_connection::peer_connection(
|
||||
detail::session_impl* ses
|
||||
detail::session_impl& ses
|
||||
, selector& sel
|
||||
, torrent* t
|
||||
, boost::shared_ptr<libtorrent::socket> s
|
||||
|
@ -97,12 +97,14 @@ libtorrent::peer_connection::peer_connection(
|
|||
, m_choked(true)
|
||||
, m_send_quota(-1)
|
||||
, m_send_quota_left(-1)
|
||||
, m_send_quota_limit(100)
|
||||
, m_trust_points(0)
|
||||
{
|
||||
assert(!m_socket->is_blocking());
|
||||
assert(m_torrent != 0);
|
||||
|
||||
#ifndef NDEBUG
|
||||
m_logger = m_ses->create_log(s->sender().as_string().c_str());
|
||||
m_logger = m_ses.create_log(s->sender().as_string().c_str());
|
||||
#endif
|
||||
|
||||
send_handshake();
|
||||
|
@ -119,7 +121,7 @@ libtorrent::peer_connection::peer_connection(
|
|||
}
|
||||
|
||||
libtorrent::peer_connection::peer_connection(
|
||||
detail::session_impl* ses
|
||||
detail::session_impl& ses
|
||||
, selector& sel
|
||||
, boost::shared_ptr<libtorrent::socket> s)
|
||||
: m_state(read_protocol_length)
|
||||
|
@ -142,11 +144,13 @@ libtorrent::peer_connection::peer_connection(
|
|||
, m_choked(true)
|
||||
, m_send_quota(-1)
|
||||
, m_send_quota_left(-1)
|
||||
, m_send_quota_limit(100)
|
||||
, m_trust_points(0)
|
||||
{
|
||||
assert(!m_socket->is_blocking());
|
||||
|
||||
#ifndef NDEBUG
|
||||
m_logger = m_ses->create_log(s->sender().as_string().c_str());
|
||||
m_logger = m_ses.create_log(s->sender().as_string().c_str());
|
||||
#endif
|
||||
|
||||
// we are not attached to any torrent yet.
|
||||
|
@ -170,13 +174,15 @@ libtorrent::peer_connection::~peer_connection()
|
|||
|
||||
void libtorrent::peer_connection::set_send_quota(int num_bytes)
|
||||
{
|
||||
assert(num_bytes <= m_send_quota_limit);
|
||||
assert(num_bytes >= 0);
|
||||
if (num_bytes > m_send_quota_limit) num_bytes = m_send_quota_limit;
|
||||
|
||||
m_send_quota = num_bytes;
|
||||
m_send_quota_left = num_bytes;
|
||||
send_buffer_updated();
|
||||
}
|
||||
|
||||
|
||||
void libtorrent::peer_connection::send_handshake()
|
||||
{
|
||||
assert(m_send_buffer.size() == 0);
|
||||
|
@ -214,13 +220,14 @@ void libtorrent::peer_connection::send_handshake()
|
|||
|
||||
// peer id
|
||||
std::copy(
|
||||
m_ses->get_peer_id().begin()
|
||||
, m_ses->get_peer_id().end()
|
||||
m_ses.get_peer_id().begin()
|
||||
, m_ses.get_peer_id().end()
|
||||
, m_send_buffer.begin() + pos);
|
||||
|
||||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " ==> HANDSHAKE\n";
|
||||
#endif
|
||||
m_statistics.sent_bytes(0, m_send_buffer.size());
|
||||
|
||||
send_buffer_updated();
|
||||
}
|
||||
|
@ -236,6 +243,12 @@ void libtorrent::peer_connection::dispatch_message()
|
|||
|
||||
// *************** CHOKE ***************
|
||||
case msg_choke:
|
||||
|
||||
if (m_packet_size != 5)
|
||||
throw protocol_error("'choke' message size != 5");
|
||||
|
||||
m_statistics.received_bytes(0, m_packet_size);
|
||||
|
||||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " <== CHOKE\n";
|
||||
#endif
|
||||
|
@ -260,6 +273,11 @@ void libtorrent::peer_connection::dispatch_message()
|
|||
|
||||
// *************** UNCHOKE ***************
|
||||
case msg_unchoke:
|
||||
if (m_packet_size != 1)
|
||||
throw protocol_error("'unchoke' message size != 1");
|
||||
|
||||
m_statistics.received_bytes(0, m_packet_size);
|
||||
|
||||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " <== UNCHOKE\n";
|
||||
#endif
|
||||
|
@ -270,6 +288,11 @@ void libtorrent::peer_connection::dispatch_message()
|
|||
|
||||
// *************** INTERESTED ***************
|
||||
case msg_interested:
|
||||
if (m_packet_size != 1)
|
||||
throw protocol_error("'interested' message size != 1");
|
||||
|
||||
m_statistics.received_bytes(0, m_packet_size);
|
||||
|
||||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " <== INTERESTED\n";
|
||||
#endif
|
||||
|
@ -280,6 +303,11 @@ void libtorrent::peer_connection::dispatch_message()
|
|||
|
||||
// *************** NOT INTERESTED ***************
|
||||
case msg_not_interested:
|
||||
if (m_packet_size != 1)
|
||||
throw protocol_error("'not interested' message size != 1");
|
||||
|
||||
m_statistics.received_bytes(0, m_packet_size);
|
||||
|
||||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " <== NOT_INTERESTED\n";
|
||||
#endif
|
||||
|
@ -292,6 +320,11 @@ void libtorrent::peer_connection::dispatch_message()
|
|||
// *************** HAVE ***************
|
||||
case msg_have:
|
||||
{
|
||||
if (m_packet_size != 5)
|
||||
throw protocol_error("'have' message size != 5");
|
||||
|
||||
m_statistics.received_bytes(0, m_packet_size);
|
||||
|
||||
std::size_t index = read_int(&m_recv_buffer[1]);
|
||||
// if we got an invalid message, abort
|
||||
if (index >= m_have_piece.size())
|
||||
|
@ -325,6 +358,8 @@ void libtorrent::peer_connection::dispatch_message()
|
|||
if (m_packet_size - 1 != (m_have_piece.size() + 7) / 8)
|
||||
throw protocol_error("bitfield with invalid size");
|
||||
|
||||
m_statistics.received_bytes(0, m_packet_size);
|
||||
|
||||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " <== BITFIELD\n";
|
||||
#endif
|
||||
|
@ -361,6 +396,11 @@ void libtorrent::peer_connection::dispatch_message()
|
|||
// *************** REQUEST ***************
|
||||
case msg_request:
|
||||
{
|
||||
if (m_packet_size != 13)
|
||||
throw protocol_error("'request' message size != 13");
|
||||
|
||||
m_statistics.received_bytes(0, m_packet_size);
|
||||
|
||||
peer_request r;
|
||||
r.piece = read_int(&m_recv_buffer[1]);
|
||||
r.start = read_int(&m_recv_buffer[5]);
|
||||
|
@ -440,7 +480,8 @@ void libtorrent::peer_connection::dispatch_message()
|
|||
(*m_logger) << m_socket->sender().as_string() << " <== PIECE [ piece: " << index << " | s: " << offset << " | l: " << len << " ]\n";
|
||||
#endif
|
||||
|
||||
m_torrent->downloaded_bytes(len);
|
||||
assert(m_packet_size > len);
|
||||
m_statistics.received_bytes(len, m_packet_size - len);
|
||||
|
||||
piece_picker& picker = m_torrent->picker();
|
||||
piece_block block_finished(index, offset / m_torrent->block_size());
|
||||
|
@ -465,9 +506,7 @@ void libtorrent::peer_connection::dispatch_message()
|
|||
|
||||
if (picker.is_finished(block_finished)) break;
|
||||
|
||||
m_receiving_piece.open(m_torrent->filesystem(), index, piece_file::out, offset);
|
||||
m_receiving_piece.write(&m_recv_buffer[9], len);
|
||||
m_receiving_piece.close();
|
||||
m_torrent->filesystem().write(&m_recv_buffer[9], index, offset, len);
|
||||
|
||||
picker.mark_as_finished(block_finished, m_peer_id);
|
||||
|
||||
|
@ -476,9 +515,7 @@ void libtorrent::peer_connection::dispatch_message()
|
|||
// did we just finish the piece?
|
||||
if (picker.is_piece_finished(index))
|
||||
{
|
||||
m_receiving_piece.open(m_torrent->filesystem(), index, piece_file::in);
|
||||
bool verified = m_torrent->filesystem()->verify_piece(m_receiving_piece);
|
||||
m_receiving_piece.close();
|
||||
bool verified = m_torrent->verify_piece(index);
|
||||
if (verified)
|
||||
{
|
||||
m_torrent->announce_piece(index);
|
||||
|
@ -496,6 +533,10 @@ void libtorrent::peer_connection::dispatch_message()
|
|||
// *************** CANCEL ***************
|
||||
case msg_cancel:
|
||||
{
|
||||
if (m_packet_size != 13)
|
||||
throw protocol_error("'cancel' message size != 13");
|
||||
m_statistics.received_bytes(0, m_packet_size);
|
||||
|
||||
peer_request r;
|
||||
r.piece = read_int(&m_recv_buffer[1]);
|
||||
r.start = read_int(&m_recv_buffer[5]);
|
||||
|
@ -550,7 +591,7 @@ void libtorrent::peer_connection::cancel_block(piece_block block)
|
|||
m_send_buffer.resize(start_offset + 17);
|
||||
|
||||
std::copy(buf, buf + 5, m_send_buffer.begin()+start_offset);
|
||||
start_offset +=5;
|
||||
start_offset += 5;
|
||||
|
||||
// index
|
||||
write_int(block.piece_index, &m_send_buffer[start_offset]);
|
||||
|
@ -567,6 +608,7 @@ void libtorrent::peer_connection::cancel_block(piece_block block)
|
|||
(*m_logger) << m_socket->sender().as_string() << " ==> CANCEL [ piece: " << block.piece_index << " | s: " << block_offset << " | l: " << block_size << " | " << block.block_index << " ]\n";
|
||||
#endif
|
||||
assert(start_offset == m_send_buffer.size());
|
||||
m_statistics.sent_bytes(0, 17);
|
||||
|
||||
send_buffer_updated();
|
||||
}
|
||||
|
@ -614,6 +656,7 @@ void libtorrent::peer_connection::request_block(piece_block block)
|
|||
(*m_logger) << m_socket->sender().as_string() << " ==> REQUEST [ piece: " << block.piece_index << " | s: " << block_offset << " | l: " << block_size << " | " << block.block_index << " ]\n";
|
||||
#endif
|
||||
assert(start_offset == m_send_buffer.size());
|
||||
m_statistics.sent_bytes(0, 17);
|
||||
|
||||
send_buffer_updated();
|
||||
}
|
||||
|
@ -634,6 +677,7 @@ void libtorrent::peer_connection::send_bitfield()
|
|||
if (m_torrent->have_piece(i))
|
||||
m_send_buffer[old_size + 5 + (i>>3)] |= 1 << (7 - (i&7));
|
||||
}
|
||||
m_statistics.sent_bytes(0, packet_size);
|
||||
send_buffer_updated();
|
||||
}
|
||||
|
||||
|
@ -646,6 +690,7 @@ void libtorrent::peer_connection::choke()
|
|||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " ==> CHOKE\n";
|
||||
#endif
|
||||
m_statistics.sent_bytes(0, 5);
|
||||
send_buffer_updated();
|
||||
}
|
||||
|
||||
|
@ -658,6 +703,7 @@ void libtorrent::peer_connection::unchoke()
|
|||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " ==> UNCHOKE\n";
|
||||
#endif
|
||||
m_statistics.sent_bytes(0, 5);
|
||||
send_buffer_updated();
|
||||
}
|
||||
|
||||
|
@ -670,6 +716,7 @@ void libtorrent::peer_connection::interested()
|
|||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " ==> INTERESTED\n";
|
||||
#endif
|
||||
m_statistics.sent_bytes(0, 5);
|
||||
send_buffer_updated();
|
||||
}
|
||||
|
||||
|
@ -682,20 +729,49 @@ void libtorrent::peer_connection::not_interested()
|
|||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " ==> NOT_INTERESTED\n";
|
||||
#endif
|
||||
m_statistics.sent_bytes(0, 5);
|
||||
send_buffer_updated();
|
||||
}
|
||||
|
||||
void libtorrent::peer_connection::send_have(int index)
|
||||
{
|
||||
char msg[9] = {0,0,0,5,msg_have};
|
||||
const int packet_size = 9;
|
||||
char msg[packet_size] = {0,0,0,5,msg_have};
|
||||
write_int(index, msg+5);
|
||||
m_send_buffer.insert(m_send_buffer.end(), msg, msg+9);
|
||||
m_send_buffer.insert(m_send_buffer.end(), msg, msg + packet_size);
|
||||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " ==> HAVE [ piece: " << index << " ]\n";
|
||||
#endif
|
||||
m_statistics.sent_bytes(0, packet_size);
|
||||
send_buffer_updated();
|
||||
}
|
||||
|
||||
void libtorrent::peer_connection::second_tick()
|
||||
{
|
||||
m_statistics.second_tick();
|
||||
m_send_quota_left = m_send_quota;
|
||||
if (m_send_quota > 0) send_buffer_updated();
|
||||
|
||||
// If the client sends more data
|
||||
// we send it data faster, otherwise, slower.
|
||||
// It will also depend on how much data the
|
||||
// client has sent us. This is the mean to
|
||||
// maintain a 1:1 share ratio with all peers.
|
||||
|
||||
// TODO: make sure the rate is able to rise if
|
||||
// both peers uses this technique! It could be
|
||||
// enough to just have a constant positive bias
|
||||
// of the send_quota_limit
|
||||
int bias = (static_cast<int>(m_statistics.total_download())
|
||||
- static_cast<int>(m_statistics.total_upload())) / 1024;
|
||||
|
||||
// the maximum send_quota given our download rate from this peer
|
||||
int m_send_quota_limit = m_statistics.download_rate() + bias;
|
||||
if (m_send_quota_limit < 500) m_send_quota_limit = 500;
|
||||
|
||||
// TODO: temporary
|
||||
m_send_quota_limit = 1024*1024;
|
||||
}
|
||||
|
||||
// --------------------------
|
||||
// RECEIVE DATA
|
||||
|
@ -731,7 +807,6 @@ void libtorrent::peer_connection::receive_data()
|
|||
|
||||
if (received > 0)
|
||||
{
|
||||
m_statistics.received_bytes(received);
|
||||
m_last_receive = boost::posix_time::second_clock::local_time();
|
||||
|
||||
m_recv_pos += received;
|
||||
|
@ -741,6 +816,8 @@ void libtorrent::peer_connection::receive_data()
|
|||
switch(m_state)
|
||||
{
|
||||
case read_protocol_length:
|
||||
m_statistics.received_bytes(0, received);
|
||||
|
||||
m_packet_size = reinterpret_cast<unsigned char&>(m_recv_buffer[0]);
|
||||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " protocol length: " << m_packet_size << "\n";
|
||||
|
@ -761,6 +838,7 @@ void libtorrent::peer_connection::receive_data()
|
|||
|
||||
case read_protocol_string:
|
||||
{
|
||||
m_statistics.received_bytes(0, received);
|
||||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " protocol: '" << std::string(m_recv_buffer.begin(), m_recv_buffer.end()) << "'\n";
|
||||
#endif
|
||||
|
@ -784,6 +862,7 @@ void libtorrent::peer_connection::receive_data()
|
|||
|
||||
case read_info_hash:
|
||||
{
|
||||
m_statistics.received_bytes(0, received);
|
||||
// ok, now we have got enough of the handshake. Is this connection
|
||||
// attached to a torrent?
|
||||
|
||||
|
@ -798,7 +877,7 @@ void libtorrent::peer_connection::receive_data()
|
|||
sha1_hash info_hash;
|
||||
std::copy(m_recv_buffer.begin()+8, m_recv_buffer.begin() + 28, (char*)info_hash.begin());
|
||||
|
||||
m_torrent = m_ses->find_torrent(info_hash);
|
||||
m_torrent = m_ses.find_torrent(info_hash);
|
||||
if (m_torrent == 0)
|
||||
{
|
||||
// we couldn't find the torrent!
|
||||
|
@ -843,6 +922,7 @@ void libtorrent::peer_connection::receive_data()
|
|||
|
||||
case read_peer_id:
|
||||
{
|
||||
m_statistics.received_bytes(0, received);
|
||||
if (m_active)
|
||||
{
|
||||
// verify peer_id
|
||||
|
@ -887,6 +967,8 @@ void libtorrent::peer_connection::receive_data()
|
|||
|
||||
|
||||
case read_packet_size:
|
||||
m_statistics.received_bytes(0, received);
|
||||
|
||||
// convert from big endian to native byte order
|
||||
m_packet_size = read_int(&m_recv_buffer[0]);
|
||||
// don't accept packets larger than 1 MB
|
||||
|
@ -916,8 +998,6 @@ void libtorrent::peer_connection::receive_data()
|
|||
|
||||
case read_packet:
|
||||
|
||||
// TODO: dispatch should throw instead of returning status
|
||||
// and instead of throwing network_error, throw protocol_error
|
||||
dispatch_message();
|
||||
|
||||
m_state = read_packet_size;
|
||||
|
@ -974,18 +1054,8 @@ void libtorrent::peer_connection::send_data()
|
|||
throw network_error(0);
|
||||
}
|
||||
|
||||
m_sending_piece.open(
|
||||
m_torrent->filesystem()
|
||||
, r.piece
|
||||
, piece_file::in
|
||||
, r.start);
|
||||
#ifndef NDEBUG
|
||||
assert(m_torrent->filesystem()->verify_piece(m_sending_piece) && "internal error");
|
||||
m_sending_piece.open(
|
||||
m_torrent->filesystem()
|
||||
, r.piece
|
||||
, piece_file::in
|
||||
, r.start);
|
||||
assert(m_torrent->verify_piece(r.piece) && "internal error");
|
||||
#endif
|
||||
const int send_buffer_offset = m_send_buffer.size();
|
||||
const int packet_size = 4 + 5 + 4 + r.length;
|
||||
|
@ -995,14 +1065,16 @@ void libtorrent::peer_connection::send_data()
|
|||
write_int(r.piece, &m_send_buffer[send_buffer_offset+5]);
|
||||
write_int(r.start, &m_send_buffer[send_buffer_offset+9]);
|
||||
|
||||
assert(r.start == m_sending_piece.tell());
|
||||
|
||||
m_sending_piece.read(&m_send_buffer[send_buffer_offset+13], r.length);
|
||||
m_torrent->filesystem().read(
|
||||
&m_send_buffer[send_buffer_offset+13]
|
||||
, r.piece
|
||||
, r.start
|
||||
, r.length);
|
||||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " ==> PIECE [ piece: " << r.piece << " | s: " << r.start << " | l: " << r.length << " ]\n";
|
||||
#endif
|
||||
// let the torrent keep track of how much we have uploaded
|
||||
m_torrent->uploaded_bytes(r.length);
|
||||
m_statistics.sent_bytes(r.length, packet_size - r.length);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1053,7 +1125,6 @@ void libtorrent::peer_connection::send_data()
|
|||
|
||||
if (sent > 0)
|
||||
{
|
||||
m_statistics.sent_bytes(sent);
|
||||
if (m_send_quota_left != -1)
|
||||
{
|
||||
assert(m_send_quota_left >= sent);
|
||||
|
@ -1106,6 +1177,7 @@ void libtorrent::peer_connection::keep_alive()
|
|||
char noop[] = {0,0,0,0};
|
||||
m_send_buffer.insert(m_send_buffer.end(), noop, noop+4);
|
||||
m_last_sent = boost::posix_time::second_clock::local_time();
|
||||
m_statistics.sent_bytes(0, 4);
|
||||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " ==> NOP\n";
|
||||
#endif
|
||||
|
|
|
@ -238,7 +238,7 @@ namespace libtorrent
|
|||
c->choke();
|
||||
}
|
||||
else if (uploaded - downloaded <= m_torrent->block_size()
|
||||
&& c->is_choked() && c->is_peer_interested())
|
||||
&& c->is_choked() && c->is_interesting())
|
||||
{
|
||||
// TODO: if we're not interested in this peer
|
||||
// we should only unchoke it if it' its turn
|
||||
|
@ -352,6 +352,7 @@ namespace libtorrent
|
|||
{
|
||||
// if we're interested in the peer, we unchoke it
|
||||
// and hopes it will unchoke us too
|
||||
if (c.is_interesting) c.unchoke();
|
||||
}
|
||||
|
||||
void policy::not_interested(peer_connection& c)
|
||||
|
|
|
@ -60,6 +60,57 @@ namespace std
|
|||
};
|
||||
#endif
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
// adjusts the upload rates of every peer connection
|
||||
// to make sure the sum of all send quotas equals
|
||||
// the given upload_limit. An upload limit of -1 means
|
||||
// unlimited upload rate, but the rates of each peer
|
||||
// has to be set anyway, since it depends on the download
|
||||
// rate from the peer.
|
||||
void control_upload_rates(
|
||||
int upload_limit
|
||||
, libtorrent::detail::session_impl::connection_map connections)
|
||||
{
|
||||
using namespace libtorrent;
|
||||
|
||||
if (connections.empty()) return;
|
||||
|
||||
assert(upload_limit != 0);
|
||||
|
||||
if (upload_limit == -1)
|
||||
{
|
||||
for (detail::session_impl::connection_map::iterator i = connections.begin();
|
||||
i != connections.end();
|
||||
++i)
|
||||
{
|
||||
// there's no limit, set the quota to max
|
||||
// allowed
|
||||
peer_connection& p = *i->second;
|
||||
p.set_send_quota(p.send_quota_limit());
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: IMPLEMENT!
|
||||
assert(false);
|
||||
|
||||
|
||||
#ifndef NDEBUG
|
||||
int sum = 0;
|
||||
for (detail::session_impl::connection_map::iterator i = connections.begin();
|
||||
i != connections.end();
|
||||
++i)
|
||||
{
|
||||
peer_connection& p = *i->second;
|
||||
sum += p.send_quota();
|
||||
}
|
||||
assert(sum == upload_limit);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
namespace detail
|
||||
|
@ -93,7 +144,8 @@ namespace libtorrent
|
|||
|
||||
try
|
||||
{
|
||||
t->torrent_ptr->allocate_files(t, m_mutex, t->save_path);
|
||||
assert(t != 0);
|
||||
t->torrent_ptr->check_files(*t, m_mutex);
|
||||
// lock the session to add the new torrent
|
||||
|
||||
boost::mutex::scoped_lock l(m_mutex);
|
||||
|
@ -278,7 +330,7 @@ namespace libtorrent
|
|||
// TODO: filter ip:s
|
||||
|
||||
boost::shared_ptr<peer_connection> c(
|
||||
new peer_connection(this, m_selector, s));
|
||||
new peer_connection(*this, m_selector, s));
|
||||
|
||||
if (m_upload_rate != -1) c->set_send_quota(0);
|
||||
m_connections.insert(std::make_pair(s, c));
|
||||
|
@ -299,7 +351,7 @@ namespace libtorrent
|
|||
// (*m_logger) << "readable: " << p->first->sender().as_string() << "\n";
|
||||
p->second->receive_data();
|
||||
}
|
||||
catch(std::exception&)
|
||||
catch(std::exception& e)
|
||||
{
|
||||
// the connection wants to disconnect for some reason, remove it
|
||||
// from the connection-list
|
||||
|
@ -335,7 +387,6 @@ namespace libtorrent
|
|||
{
|
||||
assert(m_selector.is_writability_monitored(p->first));
|
||||
assert(p->second->has_data());
|
||||
// (*m_logger) << "writable: " << p->first->sender().as_string() << "\n";
|
||||
p->second->send_data();
|
||||
}
|
||||
catch(std::exception&)
|
||||
|
@ -390,17 +441,8 @@ namespace libtorrent
|
|||
// This should probably be done by accumulating the
|
||||
// left-over bandwidth to next second. Since the
|
||||
// the sockets consumes its data in rather big chunks.
|
||||
if (m_upload_rate != -1 && !m_connections.empty())
|
||||
{
|
||||
assert(m_upload_rate >= 0);
|
||||
int share = m_upload_rate / m_connections.size();
|
||||
for (connection_map::iterator i = m_connections.begin();
|
||||
i != m_connections.end();
|
||||
++i)
|
||||
{
|
||||
i->second->set_send_quota(share);
|
||||
}
|
||||
}
|
||||
|
||||
control_upload_rates(m_upload_rate, m_connections);
|
||||
|
||||
// do the second_tick() on each connection
|
||||
// this will update their statistics (download and upload speeds)
|
||||
|
@ -409,8 +451,6 @@ namespace libtorrent
|
|||
for (connection_map::iterator i = m_connections.begin();
|
||||
i != m_connections.end();)
|
||||
{
|
||||
i->second->second_tick();
|
||||
|
||||
connection_map::iterator j = i;
|
||||
++i;
|
||||
// if this socket has timed out
|
||||
|
@ -477,7 +517,7 @@ namespace libtorrent
|
|||
m_tracker_manager.tick();
|
||||
boost::xtime t;
|
||||
boost::xtime_get(&t, boost::TIME_UTC);
|
||||
t.nsec += 1000000;
|
||||
t.nsec += 100000000;
|
||||
boost::thread::sleep(t);
|
||||
}
|
||||
|
||||
|
@ -583,7 +623,7 @@ namespace libtorrent
|
|||
// create the torrent and the data associated with
|
||||
// the checker thread and store it before starting
|
||||
// the thread
|
||||
boost::shared_ptr<torrent> torrent_ptr(new torrent(&m_impl, ti));
|
||||
boost::shared_ptr<torrent> torrent_ptr(new torrent(m_impl, ti, save_path));
|
||||
|
||||
detail::piece_checker_data d;
|
||||
d.torrent_ptr = torrent_ptr;
|
||||
|
|
|
@ -51,10 +51,12 @@ void libtorrent::stat::second_tick()
|
|||
m_upload_per_second_history+history-1,
|
||||
m_upload_per_second_history+1);
|
||||
|
||||
m_download_per_second_history[0] = m_downloaded;
|
||||
m_upload_per_second_history[0] = m_uploaded;
|
||||
m_download_per_second_history[0] = m_downloaded + m_downloaded_protocol;
|
||||
m_upload_per_second_history[0] = m_uploaded + m_uploaded_protocol;
|
||||
m_downloaded = 0;
|
||||
m_uploaded = 0;
|
||||
m_downloaded_protocol = 0;
|
||||
m_uploaded_protocol = 0;
|
||||
|
||||
m_mean_download_per_second
|
||||
= std::accumulate(m_download_per_second_history,
|
||||
|
|
104
src/storage.cpp
104
src/storage.cpp
|
@ -50,6 +50,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/torrent.hpp"
|
||||
#include "libtorrent/hasher.hpp"
|
||||
#include "libtorrent/session.hpp"
|
||||
#include "libtorrent/peer_id.hpp"
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define for if (false) {} else for
|
||||
|
@ -479,8 +480,8 @@ namespace {
|
|||
*/
|
||||
struct lazy_hash
|
||||
{
|
||||
mutable sha1_hash digest;
|
||||
mutable hasher h;
|
||||
mutable libtorrent::sha1_hash digest;
|
||||
mutable libtorrent::hasher h;
|
||||
mutable const char* data;
|
||||
std::size_t size;
|
||||
|
||||
|
@ -489,7 +490,7 @@ namespace {
|
|||
, size(size_)
|
||||
{}
|
||||
|
||||
const sha1_hash& get() const
|
||||
const libtorrent::sha1_hash& get() const
|
||||
{
|
||||
if (data)
|
||||
{
|
||||
|
@ -1286,7 +1287,9 @@ namespace libtorrent {
|
|||
storage::storage(const torrent_info& info, const fs::path& path)
|
||||
: m_info(info)
|
||||
, m_save_path(path)
|
||||
{}
|
||||
{
|
||||
assert(info.begin_files() != info.end_files());
|
||||
}
|
||||
|
||||
storage::size_type storage::read(
|
||||
char* buf
|
||||
|
@ -1294,13 +1297,13 @@ namespace libtorrent {
|
|||
, size_type offset
|
||||
, size_type size)
|
||||
{
|
||||
size_type start = slot * m_info->piece_length() + offset;
|
||||
size_type start = slot * m_info.piece_length() + offset;
|
||||
|
||||
// find the file iterator and file offset
|
||||
size_type file_offset = start;
|
||||
std::vector<file>::const_iterator file_iter;
|
||||
|
||||
for (file_iter = m_info->begin_files();;)
|
||||
for (file_iter = m_info.begin_files();;)
|
||||
{
|
||||
if (file_offset < file_iter->size)
|
||||
break;
|
||||
|
@ -1311,7 +1314,7 @@ namespace libtorrent {
|
|||
|
||||
fs::ifstream in(
|
||||
m_save_path / file_iter->path / file_iter->filename
|
||||
, std::ios_base::binary
|
||||
, std::ios_base::binary
|
||||
);
|
||||
|
||||
assert(file_offset < file_iter->size);
|
||||
|
@ -1319,7 +1322,7 @@ namespace libtorrent {
|
|||
in.seekg(std::ios_base::beg, file_offset);
|
||||
|
||||
size_type left_to_read = size;
|
||||
size_type slot_size = m_info->piece_size(slot);
|
||||
size_type slot_size = m_info.piece_size(slot);
|
||||
|
||||
if (offset + left_to_read > slot_size)
|
||||
left_to_read = slot_size - offset;
|
||||
|
@ -1363,13 +1366,13 @@ namespace libtorrent {
|
|||
|
||||
void storage::write(const char* buf, int slot, size_type offset, size_type size)
|
||||
{
|
||||
size_type start = slot * m_info->piece_length() + offset;
|
||||
size_type start = slot * m_info.piece_length() + offset;
|
||||
|
||||
// find the file iterator and file offset
|
||||
size_type file_offset = start;
|
||||
std::vector<file>::const_iterator file_iter;
|
||||
|
||||
for (file_iter = m_info->begin_files();;)
|
||||
for (file_iter = m_info.begin_files();;)
|
||||
{
|
||||
if (file_offset < file_iter->size)
|
||||
break;
|
||||
|
@ -1388,7 +1391,7 @@ namespace libtorrent {
|
|||
out.seekp(std::ios_base::beg, file_offset);
|
||||
|
||||
size_type left_to_write = size;
|
||||
size_type slot_size = m_info->piece_size(slot);
|
||||
size_type slot_size = m_info.piece_size(slot);
|
||||
|
||||
if (offset + left_to_write > slot_size)
|
||||
left_to_write = slot_size - offset;
|
||||
|
@ -1422,7 +1425,7 @@ namespace libtorrent {
|
|||
{
|
||||
++file_iter;
|
||||
|
||||
assert(file_iter != m_info->end_files());
|
||||
assert(file_iter != m_info.end_files());
|
||||
|
||||
fs::path path = m_save_path / file_iter->path / file_iter->filename;
|
||||
|
||||
|
@ -1436,50 +1439,46 @@ namespace libtorrent {
|
|||
|
||||
piece_manager::piece_manager(
|
||||
const torrent_info& info
|
||||
, const fs::path& save_path)
|
||||
, const fs::path& save_path)
|
||||
: m_storage(info, save_path)
|
||||
, m_info(info)
|
||||
, m_save_path(save_path)
|
||||
{
|
||||
}
|
||||
|
||||
size_type piece_manager::read(char* buf, int piece_index, size_type offset, size_type size)
|
||||
piece_manager::size_type piece_manager::read(
|
||||
char* buf
|
||||
, int piece_index
|
||||
, piece_manager::size_type offset
|
||||
, piece_manager::size_type size)
|
||||
{
|
||||
assert(m_piece_to_slot[piece_index] >= 0);
|
||||
int slot = m_piece_to_slot[piece_index];
|
||||
return m_storage.read(buf, slot, offset, size);
|
||||
}
|
||||
|
||||
void piece_manager::write(const char* buf, int piece_index, size_type offset, size_type size)
|
||||
void piece_manager::write(
|
||||
const char* buf
|
||||
, int piece_index
|
||||
, piece_manager::size_type offset
|
||||
, piece_manager::size_type size)
|
||||
{
|
||||
int slot = slot_for_piece(piece_index);
|
||||
m_storage.write(buf, slot, offset, size);
|
||||
}
|
||||
|
||||
void piece_manager::check_pieces(boost::mutex& mutex, detail::piece_checker_data& data)
|
||||
void piece_manager::check_pieces(
|
||||
boost::mutex& mutex
|
||||
, detail::piece_checker_data& data
|
||||
, std::vector<bool>& pieces)
|
||||
{
|
||||
// synchronization ------------------------------------------------------
|
||||
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
// free up some memory
|
||||
std::vector<bool>(
|
||||
m_info.num_pieces(), false
|
||||
).swap(m_have_piece);
|
||||
|
||||
std::vector<entry::integer_type>(
|
||||
m_info.num_pieces(), -1
|
||||
).swap(m_allocated_pieces);
|
||||
|
||||
std::vector<bool>(
|
||||
m_info.num_pieces(), false
|
||||
).swap(m_locked_pieces);
|
||||
|
||||
std::vector<int>(
|
||||
m_info.num_pieces(), -1
|
||||
).swap(m_slot_to_piece);
|
||||
|
||||
std::vector<entry::integer_type>().swap(m_free_blocks);
|
||||
std::vector<entry::integer_type>().swap(m_free_pieces);
|
||||
m_piece_to_slot.resize(m_info.num_pieces(), -1);
|
||||
m_slot_to_piece.resize(m_info.num_pieces(), -1);
|
||||
m_locked_pieces.resize(m_info.num_pieces(), false);
|
||||
|
||||
m_bytes_left = m_info.total_size();
|
||||
|
||||
|
@ -1503,7 +1502,7 @@ namespace libtorrent {
|
|||
|
||||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
data->progress = 0.f;
|
||||
data.progress = 0.f;
|
||||
}
|
||||
|
||||
for (torrent_info::file_iterator file_iter = m_info.begin_files(),
|
||||
|
@ -1513,8 +1512,8 @@ namespace libtorrent {
|
|||
{
|
||||
boost::mutex::scoped_lock lock(mutex);
|
||||
|
||||
data->progress = (float)current_piece / m_info.num_pieces();
|
||||
if (data->abort)
|
||||
data.progress = (float)current_piece / m_info.num_pieces();
|
||||
if (data.abort)
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1615,19 +1614,19 @@ namespace libtorrent {
|
|||
|
||||
for (int i = 0; i < m_info.num_pieces(); ++i)
|
||||
{
|
||||
if (m_have_piece[i])
|
||||
if (pieces[i])
|
||||
continue;
|
||||
|
||||
const sha1_hash& hash = digest[
|
||||
i == m_info.num_pieces() - 1]->get();
|
||||
|
||||
if (equal_hash()(hash, m_info.hash_for_piece(i)))
|
||||
if (hash == m_info.hash_for_piece(i))
|
||||
{
|
||||
m_bytes_left -= m_info.piece_size(i);
|
||||
|
||||
m_piece_to_slot[i] = current_piece;
|
||||
m_slot_to_piece[current_piece] = i;
|
||||
m_have_piece[i] = true;
|
||||
pieces[i] = true;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
|
@ -1665,9 +1664,9 @@ namespace libtorrent {
|
|||
std::cout << " num pieces: " << m_info.num_pieces() << "\n";
|
||||
|
||||
std::cout << " have_pieces: ";
|
||||
print_bitmask(m_have_piece);
|
||||
print_bitmask(pieces);
|
||||
std::cout << "\n";
|
||||
std::cout << std::count(m_have_piece.begin(), m_have_piece.end(), true) << "\n";
|
||||
std::cout << std::count(pieces.begin(), pieces.end(), true) << "\n";
|
||||
|
||||
check_invariant();
|
||||
}
|
||||
|
@ -1696,11 +1695,11 @@ namespace libtorrent {
|
|||
assert(!m_free_slots.empty());
|
||||
}
|
||||
|
||||
std::vector<entry::integer_type>::iterator iter(
|
||||
std::vector<int>::iterator iter(
|
||||
std::find(
|
||||
m_free_slots.begin()
|
||||
, m_free_slots.end()
|
||||
, piece_index));
|
||||
, m_free_slots.end()
|
||||
, piece_index));
|
||||
|
||||
if (iter == m_free_slots.end())
|
||||
{
|
||||
|
@ -1720,7 +1719,7 @@ namespace libtorrent {
|
|||
}
|
||||
|
||||
slot_index = *iter;
|
||||
m_free_pieces.erase(iter);
|
||||
m_free_slots.erase(iter);
|
||||
|
||||
assert(m_slot_to_piece[slot_index] == -2);
|
||||
|
||||
|
@ -1770,7 +1769,7 @@ namespace libtorrent {
|
|||
|
||||
// int last_piece_index = -1;
|
||||
|
||||
for (int i = 0; i < num; ++i, ++iter)
|
||||
for (int i = 0; i < num_slots; ++i, ++iter)
|
||||
{
|
||||
if (iter == end_iter)
|
||||
break;
|
||||
|
@ -1841,7 +1840,6 @@ namespace libtorrent {
|
|||
pos = 0;
|
||||
}
|
||||
*/
|
||||
m_slot_to_piece[piece_pos / piece_size] = -2;
|
||||
}
|
||||
|
||||
m_unallocated_slots.erase(m_unallocated_slots.begin(), iter);
|
||||
|
@ -1852,15 +1850,15 @@ namespace libtorrent {
|
|||
*/
|
||||
}
|
||||
|
||||
void storage::check_invariant() const
|
||||
void piece_manager::check_invariant() const
|
||||
{
|
||||
// synchronization ------------------------------------------------------
|
||||
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
||||
// ----------------------------------------------------------------------
|
||||
|
||||
for (int i = 0; i < m_info.num_pieces(); ++i)
|
||||
{
|
||||
if (m_allocated_pieces[i] != m_info.piece_length() * i)
|
||||
{
|
||||
if (m_piece_to_slot[i] != i)
|
||||
assert(m_slot_to_piece[i] < 0);
|
||||
}
|
||||
}
|
||||
|
@ -1868,5 +1866,3 @@ namespace libtorrent {
|
|||
|
||||
} // namespace libtorrent
|
||||
|
||||
#endif
|
||||
|
||||
|
|
125
src/torrent.cpp
125
src/torrent.cpp
|
@ -143,13 +143,15 @@ namespace
|
|||
namespace libtorrent
|
||||
{
|
||||
|
||||
torrent::torrent(detail::session_impl* ses, const torrent_info& torrent_file)
|
||||
torrent::torrent(
|
||||
detail::session_impl& ses
|
||||
, const torrent_info& torrent_file
|
||||
, const boost::filesystem::path& save_path)
|
||||
: m_block_size(calculate_block_size(torrent_file))
|
||||
, m_abort(false)
|
||||
, m_event(event_started)
|
||||
, m_bytes_uploaded(0)
|
||||
, m_bytes_downloaded(0)
|
||||
, m_torrent_file(torrent_file)
|
||||
, m_storage(m_torrent_file, save_path)
|
||||
, m_next_request(boost::posix_time::second_clock::local_time())
|
||||
, m_duration(1800)
|
||||
, m_policy(new policy(this))
|
||||
|
@ -159,7 +161,11 @@ namespace libtorrent
|
|||
, m_last_working_tracker(0)
|
||||
, m_currently_trying_tracker(0)
|
||||
, m_time_scaler(0)
|
||||
, m_priority(.5)
|
||||
, m_num_pieces(0)
|
||||
{
|
||||
assert(torrent_file.begin_files() != torrent_file.end_files());
|
||||
m_have_pieces.resize(torrent_file.num_pieces(), false);
|
||||
}
|
||||
|
||||
void torrent::tracker_response(const entry& e)
|
||||
|
@ -199,15 +205,15 @@ namespace libtorrent
|
|||
++i)
|
||||
{
|
||||
// don't make connections to ourself
|
||||
if (i->id == m_ses->get_peer_id())
|
||||
if (i->id == m_ses.get_peer_id())
|
||||
continue;
|
||||
|
||||
address a(i->ip, i->port);
|
||||
|
||||
// if we aleady have a connection to the person, don't make another one
|
||||
if (std::find_if(m_ses->m_connections.begin(),
|
||||
m_ses->m_connections.end(),
|
||||
find_peer(i->id, this)) != m_ses->m_connections.end())
|
||||
if (std::find_if(m_ses.m_connections.begin(),
|
||||
m_ses.m_connections.end(),
|
||||
find_peer(i->id, this)) != m_ses.m_connections.end())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
@ -240,6 +246,21 @@ namespace libtorrent
|
|||
!= m_connections.end();
|
||||
}
|
||||
|
||||
torrent::size_type torrent::bytes_left() const
|
||||
{
|
||||
size_type have_bytes = m_num_pieces * m_torrent_file.piece_length();
|
||||
int last_piece = m_torrent_file.num_pieces()-1;
|
||||
if (m_have_pieces[last_piece])
|
||||
{
|
||||
have_bytes -= m_torrent_file.piece_length()
|
||||
- m_torrent_file.piece_size(last_piece);
|
||||
}
|
||||
|
||||
return m_torrent_file.total_size()
|
||||
- have_bytes;
|
||||
}
|
||||
|
||||
|
||||
void torrent::piece_failed(int index)
|
||||
{
|
||||
std::vector<peer_id> downloaders;
|
||||
|
@ -320,19 +341,19 @@ namespace libtorrent
|
|||
request += escape_string(reinterpret_cast<const char*>(m_torrent_file.info_hash().begin()), 20);
|
||||
|
||||
request += "&peer_id=";
|
||||
request += escape_string(reinterpret_cast<const char*>(m_ses->get_peer_id().begin()), 20);
|
||||
request += escape_string(reinterpret_cast<const char*>(m_ses.get_peer_id().begin()), 20);
|
||||
|
||||
request += "&port=";
|
||||
request += boost::lexical_cast<std::string>(port);
|
||||
|
||||
request += "&uploaded=";
|
||||
request += boost::lexical_cast<std::string>(m_bytes_uploaded);
|
||||
request += boost::lexical_cast<std::string>(m_stat.total_upload());
|
||||
|
||||
request += "&downloaded=";
|
||||
request += boost::lexical_cast<std::string>(m_bytes_downloaded);
|
||||
request += boost::lexical_cast<std::string>(m_stat.total_download());
|
||||
|
||||
request += "&left=";
|
||||
request += boost::lexical_cast<std::string>(m_storage.bytes_left());
|
||||
request += boost::lexical_cast<std::string>(bytes_left());
|
||||
|
||||
if (m_event != event_none)
|
||||
{
|
||||
|
@ -409,13 +430,13 @@ namespace libtorrent
|
|||
s->connect(a);
|
||||
boost::shared_ptr<peer_connection> c(new peer_connection(
|
||||
m_ses
|
||||
, m_ses->m_selector
|
||||
, m_ses.m_selector
|
||||
, this
|
||||
, s
|
||||
, id));
|
||||
if (m_ses->m_upload_rate != -1) c->set_send_quota(0);
|
||||
if (m_ses.m_upload_rate != -1) c->set_send_quota(0);
|
||||
detail::session_impl::connection_map::iterator p =
|
||||
m_ses->m_connections.insert(std::make_pair(s, c)).first;
|
||||
m_ses.m_connections.insert(std::make_pair(s, c)).first;
|
||||
|
||||
// add the newly connected peer to this torrent's peer list
|
||||
assert(std::find(m_connections.begin()
|
||||
|
@ -425,8 +446,8 @@ namespace libtorrent
|
|||
|
||||
m_connections.push_back(boost::get_pointer(p->second));
|
||||
|
||||
m_ses->m_selector.monitor_readability(s);
|
||||
m_ses->m_selector.monitor_errors(s);
|
||||
m_ses.m_selector.monitor_readability(s);
|
||||
m_ses.m_selector.monitor_errors(s);
|
||||
// std::cout << "connecting to: " << a.as_string() << ":" << a.port() << "\n";
|
||||
return c;
|
||||
}
|
||||
|
@ -436,16 +457,16 @@ namespace libtorrent
|
|||
assert(std::find(m_connections.begin(), m_connections.end(), p) == m_connections.end());
|
||||
m_connections.push_back(p);
|
||||
detail::session_impl::connection_map::iterator i
|
||||
= m_ses->m_connections.find(p->get_socket());
|
||||
assert(i != m_ses->m_connections.end());
|
||||
= m_ses.m_connections.find(p->get_socket());
|
||||
assert(i != m_ses.m_connections.end());
|
||||
|
||||
if (!m_policy->new_connection(i->second)) throw network_error(0);
|
||||
}
|
||||
|
||||
void torrent::close_all_connections()
|
||||
{
|
||||
for (detail::session_impl::connection_map::iterator i = m_ses->m_connections.begin();
|
||||
i != m_ses->m_connections.end();)
|
||||
for (detail::session_impl::connection_map::iterator i = m_ses.m_connections.begin();
|
||||
i != m_ses.m_connections.end();)
|
||||
{
|
||||
if (i->second->associated_torrent() == this)
|
||||
{
|
||||
|
@ -456,7 +477,7 @@ namespace libtorrent
|
|||
assert(std::find(m_connections.begin(), m_connections.end(), pc) != m_connections.end());
|
||||
detail::session_impl::connection_map::iterator j = i;
|
||||
++i;
|
||||
m_ses->m_connections.erase(j);
|
||||
m_ses.m_connections.erase(j);
|
||||
assert(m_connections.size() + 1 == num_connections);
|
||||
assert(std::find(m_connections.begin(), m_connections.end(), pc) == m_connections.end());
|
||||
}
|
||||
|
@ -487,12 +508,11 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
void torrent::allocate_files(detail::piece_checker_data* data,
|
||||
boost::mutex& mutex,
|
||||
const boost::filesystem::path& save_path)
|
||||
void torrent::check_files(detail::piece_checker_data& data,
|
||||
boost::mutex& mutex)
|
||||
{
|
||||
m_storage.initialize_pieces(this, save_path, data, mutex);
|
||||
m_picker.files_checked(m_storage.pieces());
|
||||
m_storage.check_pieces(mutex, data, m_have_pieces);
|
||||
m_picker.files_checked(m_have_pieces);
|
||||
#ifndef NDEBUG
|
||||
m_picker.integrity_check(this);
|
||||
#endif
|
||||
|
@ -506,14 +526,48 @@ namespace libtorrent
|
|||
m_time_scaler = 0;
|
||||
m_policy->pulse();
|
||||
}
|
||||
|
||||
for (std::vector<peer_connection*>::iterator i = m_connections.begin();
|
||||
i != m_connections.end();
|
||||
++i)
|
||||
{
|
||||
peer_connection* p = (*i);
|
||||
const stat& s = p->statistics();
|
||||
m_stat += s;
|
||||
p->second_tick();
|
||||
}
|
||||
|
||||
m_stat.second_tick();
|
||||
}
|
||||
|
||||
bool torrent::verify_piece(int piece_index)
|
||||
{
|
||||
size_type size = m_torrent_file.piece_size(piece_index);
|
||||
std::vector<char> buffer(size);
|
||||
m_storage.read(&buffer[0], piece_index, size, 0);
|
||||
|
||||
hasher h;
|
||||
h.update(&buffer[0], size);
|
||||
sha1_hash digest = h.final();
|
||||
|
||||
if (m_torrent_file.hash_for_piece(piece_index) != digest)
|
||||
return false;
|
||||
|
||||
if (!m_have_pieces[piece_index])
|
||||
m_num_pieces++;
|
||||
m_have_pieces[piece_index] = true;
|
||||
|
||||
assert(std::accumulate(m_have_pieces.begin(), m_have_pieces.end(), 0)
|
||||
== m_num_pieces);
|
||||
return true;
|
||||
}
|
||||
|
||||
torrent_status torrent::status() const
|
||||
{
|
||||
torrent_status st;
|
||||
|
||||
const std::vector<bool>& p = m_storage.pieces();
|
||||
int num_pieces = std::accumulate(p.begin(), p.end(), 0);
|
||||
const std::vector<bool>& p = m_have_pieces;
|
||||
assert(std::accumulate(p.begin(), p.end(), 0) == m_num_pieces);
|
||||
|
||||
int total_blocks
|
||||
= (m_torrent_file.total_size()+m_block_size-1)/m_block_size;
|
||||
|
@ -522,7 +576,7 @@ namespace libtorrent
|
|||
|
||||
int unverified_blocks = m_picker.unverified_blocks();
|
||||
|
||||
int blocks_we_have = num_pieces * blocks_per_piece;
|
||||
int blocks_we_have = m_num_pieces * blocks_per_piece;
|
||||
const int last_piece = m_torrent_file.num_pieces()-1;
|
||||
if (p[last_piece])
|
||||
{
|
||||
|
@ -530,8 +584,10 @@ namespace libtorrent
|
|||
- blocks_per_piece;
|
||||
}
|
||||
|
||||
st.total_download = m_bytes_downloaded;
|
||||
st.total_upload = m_bytes_uploaded;
|
||||
st.total_download = m_stat.total_download();
|
||||
st.total_upload = m_stat.total_upload();
|
||||
st.download_rate = m_stat.download_rate();
|
||||
st.upload_rate = m_stat.upload_rate();
|
||||
st.progress = (blocks_we_have + unverified_blocks)
|
||||
/ static_cast<float>(total_blocks);
|
||||
|
||||
|
@ -540,10 +596,11 @@ namespace libtorrent
|
|||
|
||||
// TODO: this is not accurate because it assumes the last
|
||||
// block is m_block_size bytes
|
||||
// TODO: st.pieces could be a const pointer maybe?
|
||||
st.total_done = (blocks_we_have + unverified_blocks) * m_block_size;
|
||||
st.pieces = m_storage.pieces();
|
||||
st.pieces = m_have_pieces;
|
||||
|
||||
if (num_pieces == p.size())
|
||||
if (m_num_pieces == p.size())
|
||||
st.state = torrent_status::seeding;
|
||||
else
|
||||
st.state = torrent_status::downloading;
|
||||
|
@ -554,7 +611,7 @@ namespace libtorrent
|
|||
#ifndef NDEBUG
|
||||
void torrent::debug_log(const std::string& line)
|
||||
{
|
||||
(*m_ses->m_logger) << line << "\n";
|
||||
(*m_ses.m_logger) << line << "\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -63,7 +63,7 @@ namespace std
|
|||
namespace libtorrent
|
||||
{
|
||||
|
||||
torrent_status torrent_handle::status()
|
||||
torrent_status torrent_handle::status() const
|
||||
{
|
||||
if (m_ses == 0) throw invalid_handle();
|
||||
|
||||
|
@ -83,6 +83,8 @@ namespace libtorrent
|
|||
torrent_status st;
|
||||
st.total_download = 0;
|
||||
st.total_upload = 0;
|
||||
st.download_rate = 0.f;
|
||||
st.upload_rate = 0.f;
|
||||
if (d == &m_chk->m_torrents.front())
|
||||
st.state = torrent_status::checking_files;
|
||||
else
|
||||
|
@ -96,11 +98,10 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
m_ses = 0;
|
||||
throw invalid_handle();
|
||||
}
|
||||
|
||||
const torrent_info& torrent_handle::get_torrent_info()
|
||||
const torrent_info& torrent_handle::get_torrent_info() const
|
||||
{
|
||||
if (m_ses == 0) throw invalid_handle();
|
||||
|
||||
|
@ -116,11 +117,10 @@ namespace libtorrent
|
|||
if (d != 0) return d->torrent_ptr->torrent_file();
|
||||
}
|
||||
|
||||
m_ses = 0;
|
||||
throw invalid_handle();
|
||||
}
|
||||
|
||||
bool torrent_handle::is_valid()
|
||||
bool torrent_handle::is_valid() const
|
||||
{
|
||||
if (m_ses == 0) return false;
|
||||
|
||||
|
@ -136,11 +136,44 @@ namespace libtorrent
|
|||
if (d != 0) return true;
|
||||
}
|
||||
|
||||
m_ses = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
void torrent_handle::get_peer_info(std::vector<peer_info>& v)
|
||||
boost::filesystem::path torrent_handle::save_path() const
|
||||
{
|
||||
if (m_ses == 0) throw invalid_handle();
|
||||
|
||||
// copy the path into this local variable before
|
||||
// unlocking and returning. Since we could get really
|
||||
// unlucky and having the path removed after we
|
||||
// have unlocked the data but before the return
|
||||
// value has been copied into the destination
|
||||
boost::filesystem::path ret;
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
||||
torrent* t = m_ses->find_torrent(m_info_hash);
|
||||
if (t != 0)
|
||||
{
|
||||
ret = t->save_path();
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
boost::mutex::scoped_lock l(m_chk->m_mutex);
|
||||
detail::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
|
||||
if (d != 0)
|
||||
{
|
||||
ret = d->save_path;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
throw invalid_handle();
|
||||
}
|
||||
|
||||
void torrent_handle::get_peer_info(std::vector<peer_info>& v) const
|
||||
{
|
||||
v.clear();
|
||||
if (m_ses == 0) throw invalid_handle();
|
||||
|
@ -187,7 +220,7 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
void torrent_handle::get_download_queue(std::vector<partial_piece_info>& queue)
|
||||
void torrent_handle::get_download_queue(std::vector<partial_piece_info>& queue) const
|
||||
{
|
||||
queue.clear();
|
||||
|
||||
|
|
Loading…
Reference in New Issue