*** empty log message ***

This commit is contained in:
Arvid Norberg 2003-12-07 05:53:04 +00:00
parent b62f8f1a85
commit 5f9ae41e86
14 changed files with 569 additions and 232 deletions

View File

@ -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
----------

View File

@ -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";
}
}
}

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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;
};
}

View File

@ -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,

View File

@ -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

View File

@ -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)

View File

@ -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;

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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();