experimental support for filtering pieces (filter from downloading that is)

This commit is contained in:
Arvid Norberg 2005-05-25 10:01:01 +00:00
parent 9707b6aeb0
commit 2fabb2bf80
17 changed files with 376 additions and 211 deletions

View File

@ -193,7 +193,7 @@ Boost.Filesystem, Boost.Date_time and various other boost libraries as well as z
<ul class="simple"> <ul class="simple">
<li>Windows 2000 vc7.1</li> <li>Windows 2000 vc7.1</li>
<li>Linux x86 GCC 3.0.4, GCC 3.2.3, GCC 3.4.2</li> <li>Linux x86 GCC 3.0.4, GCC 3.2.3, GCC 3.4.2</li>
<li>MacOS X, GCC 3.3</li> <li>MacOS X, (Apple's) GCC 3.3, (Apple's) GCC 4.0</li>
<li>SunOS 5.8 GCC 3.1</li> <li>SunOS 5.8 GCC 3.1</li>
<li>Cygwin GCC 3.3.3</li> <li>Cygwin GCC 3.3.3</li>
</ul> </ul>
@ -887,6 +887,10 @@ struct torrent_handle
bool is_paused() const; bool is_paused() const;
bool is_seed() const; bool is_seed() const;
void filter_piece(int index, bool filter);
bool is_piece_filtered(int index) const;
std::vector&lt;bool&gt; filtered_pieces() const;
int num_complete() const; int num_complete() const;
int num_incomplete() const; int num_incomplete() const;
@ -905,8 +909,9 @@ struct torrent_handle
<p>The default constructor will initialize the handle to an invalid state. Which means you cannot <p>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 perform any operation on it, unless you first assign it a valid handle. If you try to perform
any operation on an uninitialized handle, it will throw <tt class="docutils literal"><span class="pre">invalid_handle</span></tt>.</p> any operation on an uninitialized handle, it will throw <tt class="docutils literal"><span class="pre">invalid_handle</span></tt>.</p>
<p><strong>TODO: document trackers() and replace_trackers()</strong> <p><strong>TODO: document trackers() and replace_trackers()</strong></p>
<strong>TODO: document how to create a .torrent</strong></p> <p><strong>TODO: document how to create a .torrent</strong></p>
<p><strong>TODO: document filter_piece(), is_piece_filtered() and filtered_pieces()</strong></p>
<div class="section" id="save-path"> <div class="section" id="save-path">
<h2><a name="save-path">save_path()</a></h2> <h2><a name="save-path">save_path()</a></h2>
<blockquote> <blockquote>
@ -1340,6 +1345,8 @@ struct peer_info
address ip; address ip;
float up_speed; float up_speed;
float down_speed; float down_speed;
float payload_up_speed;
float payload_down_speed;
size_type total_download; size_type total_download;
size_type total_upload; size_type total_upload;
peer_id id; peer_id id;
@ -1393,8 +1400,10 @@ us.</td>
</table> </table>
<p>The <tt class="docutils literal"><span class="pre">ip</span></tt> field is the IP-address to this peer. Its type is a wrapper around the <p>The <tt class="docutils literal"><span class="pre">ip</span></tt> field is the IP-address to this peer. Its type is a wrapper around the
actual address and the port number. See <a class="reference" href="#address">address</a> class.</p> actual address and the port number. See <a class="reference" href="#address">address</a> class.</p>
<p><tt class="docutils literal"><span class="pre">up_speed</span></tt> and <tt class="docutils literal"><span class="pre">down_speed</span></tt> is the current upload and download speed <p><tt class="docutils literal"><span class="pre">up_speed</span></tt> and <tt class="docutils literal"><span class="pre">down_speed</span></tt> contains the current upload and download speed
we have to and from this peer. These figures are updated aproximately once every second.</p> we have to and from this peer (including any protocol messages). The transfer rates
of payload data only are found in <tt class="docutils literal"><span class="pre">payload_up_speed</span></tt> and <tt class="docutils literal"><span class="pre">payload_down_speed</span></tt>.
These figures are updated aproximately once every second.</p>
<p><tt class="docutils literal"><span class="pre">total_download</span></tt> and <tt class="docutils literal"><span class="pre">total_upload</span></tt> are the total number of bytes downloaded <p><tt class="docutils literal"><span class="pre">total_download</span></tt> and <tt class="docutils literal"><span class="pre">total_upload</span></tt> are the total number of bytes downloaded
from and uploaded to this peer. These numbers do not include the protocol chatter, but only from and uploaded to this peer. These numbers do not include the protocol chatter, but only
the payload data.</p> the payload data.</p>

View File

@ -70,7 +70,7 @@ libtorrent has been successfully compiled and tested on:
* Windows 2000 vc7.1 * Windows 2000 vc7.1
* Linux x86 GCC 3.0.4, GCC 3.2.3, GCC 3.4.2 * Linux x86 GCC 3.0.4, GCC 3.2.3, GCC 3.4.2
* MacOS X, GCC 3.3 * MacOS X, (Apple's) GCC 3.3, (Apple's) GCC 4.0
* SunOS 5.8 GCC 3.1 * SunOS 5.8 GCC 3.1
* Cygwin GCC 3.3.3 * Cygwin GCC 3.3.3
@ -816,6 +816,10 @@ Its declaration looks like this::
bool is_paused() const; bool is_paused() const;
bool is_seed() const; bool is_seed() const;
void filter_piece(int index, bool filter);
bool is_piece_filtered(int index) const;
std::vector<bool> filtered_pieces() const;
int num_complete() const; int num_complete() const;
int num_incomplete() const; int num_incomplete() const;
@ -836,8 +840,11 @@ perform any operation on it, unless you first assign it a valid handle. If you t
any operation on an uninitialized handle, it will throw ``invalid_handle``. any operation on an uninitialized handle, it will throw ``invalid_handle``.
**TODO: document trackers() and replace_trackers()** **TODO: document trackers() and replace_trackers()**
**TODO: document how to create a .torrent** **TODO: document how to create a .torrent**
**TODO: document filter_piece(), is_piece_filtered() and filtered_pieces()**
save_path() save_path()
----------- -----------
@ -1301,6 +1308,8 @@ It contains the following fields::
address ip; address ip;
float up_speed; float up_speed;
float down_speed; float down_speed;
float payload_up_speed;
float payload_down_speed;
size_type total_download; size_type total_download;
size_type total_upload; size_type total_upload;
peer_id id; peer_id id;
@ -1346,8 +1355,10 @@ __ http://nolar.com/azureus/extended.htm
The ``ip`` field is the IP-address to this peer. Its type is a wrapper around the The ``ip`` field is the IP-address to this peer. Its type is a wrapper around the
actual address and the port number. See address_ class. actual address and the port number. See address_ class.
``up_speed`` and ``down_speed`` is the current upload and download speed ``up_speed`` and ``down_speed`` contains the current upload and download speed
we have to and from this peer. These figures are updated aproximately once every second. we have to and from this peer (including any protocol messages). The transfer rates
of payload data only are found in ``payload_up_speed`` and ``payload_down_speed``.
These figures are updated aproximately once every second.
``total_download`` and ``total_upload`` are the total number of bytes downloaded ``total_download`` and ``total_upload`` are the total number of bytes downloaded
from and uploaded to this peer. These numbers do not include the protocol chatter, but only from and uploaded to this peer. These numbers do not include the protocol chatter, but only

View File

@ -147,10 +147,10 @@ void clear()
#endif #endif
std::string to_string(float v, int width) std::string to_string(float v, int width, int precision = 4)
{ {
std::stringstream s; std::stringstream s;
s.precision(width-2); s.precision(precision);
s.flags(std::ios_base::right); s.flags(std::ios_base::right);
s.width(width); s.width(width);
s.fill(' '); s.fill(' ');
@ -158,10 +158,10 @@ std::string to_string(float v, int width)
return s.str(); return s.str();
} }
std::string pos_to_string(float v, int width) std::string pos_to_string(float v, int width, int precision = 4)
{ {
std::stringstream s; std::stringstream s;
s.precision(width-1); s.precision(precision);
s.flags(std::ios_base::right); s.flags(std::ios_base::right);
s.width(width); s.width(width);
s.fill(' '); s.fill(' ');
@ -194,12 +194,11 @@ std::string add_suffix(float val)
{ {
const char* prefix[] = {"B", "kB", "MB", "GB", "TB"}; const char* prefix[] = {"B", "kB", "MB", "GB", "TB"};
const int num_prefix = sizeof(prefix) / sizeof(const char*); const int num_prefix = sizeof(prefix) / sizeof(const char*);
int i; for (int i = 0; i < num_prefix; ++i)
for (i = 0; i < num_prefix; ++i)
{ {
if (fabs(val) < 1000.f) if (fabs(val) < 1000.f)
return to_string(val, i==0?7:6) + prefix[i]; return to_string(val, i==0?7:6) + prefix[i];
val /= 1024.f; val /= 1000.f;
} }
return to_string(val, 6) + "PB"; return to_string(val, 6) + "PB";
} }
@ -221,8 +220,7 @@ void print_peer_info(std::ostream& out, std::vector<libtorrent::peer_info> const
out << " down up q r flags client block\n"; out << " down up q r flags client block\n";
for (std::vector<peer_info>::const_iterator i = peers.begin(); for (std::vector<peer_info>::const_iterator i = peers.begin();
i != peers.end(); i != peers.end(); ++i)
++i)
{ {
out.fill(' '); out.fill(' ');
out.width(2); out.width(2);
@ -233,8 +231,8 @@ void print_peer_info(std::ostream& out, std::vector<libtorrent::peer_info> const
// << "ul:" << add_suffix(i->upload_limit) << "/s " // << "ul:" << add_suffix(i->upload_limit) << "/s "
// << "uc:" << add_suffix(i->upload_ceiling) << "/s " // << "uc:" << add_suffix(i->upload_ceiling) << "/s "
// << "df:" << ratio(i->total_download, i->total_upload) << " " // << "df:" << ratio(i->total_download, i->total_upload) << " "
<< to_string(i->download_queue_length, 2) << " " << to_string(i->download_queue_length, 2, 2) << " "
<< to_string(i->upload_queue_length, 2) << " " << to_string(i->upload_queue_length, 2, 2) << " "
<< static_cast<const char*>((i->flags & peer_info::interesting)?"I":"_") << 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::choked)?"C":"_")
<< static_cast<const char*>((i->flags & peer_info::remote_interested)?"i":"_") << static_cast<const char*>((i->flags & peer_info::remote_interested)?"i":"_")
@ -354,8 +352,7 @@ int main(int argc, char* argv[])
if (c == 'q') if (c == 'q')
{ {
for (std::vector<torrent_handle>::iterator i = handles.begin(); for (std::vector<torrent_handle>::iterator i = handles.begin();
i != handles.end(); i != handles.end(); ++i)
++i)
{ {
torrent_handle h = *i; torrent_handle h = *i;
if (!h.get_torrent_info().is_valid()) continue; if (!h.get_torrent_info().is_valid()) continue;
@ -441,8 +438,7 @@ int main(int argc, char* argv[])
std::stringstream out; std::stringstream out;
for (std::vector<torrent_handle>::iterator i = handles.begin(); for (std::vector<torrent_handle>::iterator i = handles.begin();
i != handles.end(); i != handles.end(); ++i)
++i)
{ {
if (!i->is_valid()) if (!i->is_valid())
{ {
@ -515,14 +511,14 @@ int main(int argc, char* argv[])
{ {
out.width(4); out.width(4);
out.fill(' '); out.fill(' ');
out << i->piece_index << ": |"; out << i->piece_index << ": [";
for (int j = 0; j < i->blocks_in_piece; ++j) for (int j = 0; j < i->blocks_in_piece; ++j)
{ {
if (i->finished_blocks[j]) out << "#"; if (i->finished_blocks[j]) out << "#";
else if (i->requested_blocks[j]) out << "+"; else if (i->requested_blocks[j]) out << "+";
else out << "."; else out << "-";
} }
out << "|\n"; out << "]\n";
} }
out << "___________________________________\n"; out << "___________________________________\n";

View File

@ -101,12 +101,8 @@ namespace libtorrent
template <class OutIt> template <class OutIt>
void write_string(OutIt& out, const std::string& val) void write_string(OutIt& out, const std::string& val)
{ {
std::string::const_iterator end = val.begin()+val.length(); std::string::const_iterator end = val.begin() + val.length();
for (std::string::const_iterator i = val.begin(); i != end; ++i) std::copy(val.begin(), end, out);
{
*out = *i;
++out;
}
} }
template <class OutIt> template <class OutIt>
@ -115,6 +111,13 @@ namespace libtorrent
write_string(out, boost::lexical_cast<std::string>(val)); write_string(out, boost::lexical_cast<std::string>(val));
} }
template <class OutIt>
void write_char(OutIt& out, char c)
{
*out = c;
++out;
}
template <class InIt> template <class InIt>
std::string read_until(InIt& in, InIt end, char end_token) std::string read_until(InIt& in, InIt end, char end_token)
{ {
@ -130,7 +133,7 @@ namespace libtorrent
} }
template<class InIt> template<class InIt>
std::string read_string(InIt& in, InIt end, int len) std::string read_string(InIt& in, InIt end, int len)
{ {
assert(len >= 0); assert(len >= 0);
std::string ret; std::string ret;
@ -149,35 +152,34 @@ namespace libtorrent
switch(e.type()) switch(e.type())
{ {
case entry::int_t: case entry::int_t:
*out = 'i'; ++out; write_char(out, 'i');
write_integer(out, e.integer()); write_integer(out, e.integer());
*out = 'e'; ++out; write_char(out, 'e');
break; break;
case entry::string_t: case entry::string_t:
write_integer(out, e.string().length()); write_integer(out, e.string().length());
*out = ':'; ++out; write_char(out, ':');
write_string(out, e.string()); write_string(out, e.string());
break; break;
case entry::list_t: case entry::list_t:
*out = 'l'; ++out; write_char(out, 'l');
for (entry::list_type::const_iterator i = e.list().begin(); i != e.list().end(); ++i) for (entry::list_type::const_iterator i = e.list().begin(); i != e.list().end(); ++i)
bencode_recursive(out, *i); bencode_recursive(out, *i);
*out = 'e'; ++out; write_char(out, 'e');
break; break;
case entry::dictionary_t: case entry::dictionary_t:
*out = 'd'; ++out; write_char(out, 'd');
for (entry::dictionary_type::const_iterator i = e.dict().begin(); for (entry::dictionary_type::const_iterator i = e.dict().begin();
i != e.dict().end(); i != e.dict().end(); ++i)
++i)
{ {
// write key // write key
write_integer(out, i->first.length()); write_integer(out, i->first.length());
*out = ':'; ++out; write_char(out, ':');
write_string(out, i->first); write_string(out, i->first);
// write value // write value
bencode_recursive(out, i->second); bencode_recursive(out, i->second);
} }
*out = 'e'; ++out; write_char(out, 'e');
break; break;
default: default:
throw invalid_encoding(); throw invalid_encoding();

View File

@ -57,7 +57,6 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/socket.hpp" #include "libtorrent/socket.hpp"
#include "libtorrent/peer_id.hpp" #include "libtorrent/peer_id.hpp"
#include "libtorrent/storage.hpp" #include "libtorrent/storage.hpp"
#include "libtorrent/piece_picker.hpp"
#include "libtorrent/stat.hpp" #include "libtorrent/stat.hpp"
#include "libtorrent/debug.hpp" #include "libtorrent/debug.hpp"
#include "libtorrent/alert.hpp" #include "libtorrent/alert.hpp"

View File

@ -56,6 +56,8 @@ namespace libtorrent
address ip; address ip;
float up_speed; float up_speed;
float down_speed; float down_speed;
float payload_up_speed;
float payload_down_speed;
size_type total_download; size_type total_download;
size_type total_upload; size_type total_upload;
peer_id id; peer_id id;

View File

@ -134,6 +134,23 @@ namespace libtorrent
// (i.e. we don't have to maintain a refcount) // (i.e. we don't have to maintain a refcount)
void we_have(int index); void we_have(int index);
// This will mark a piece as unfiltered, and if it was
// previously marked as filtered, it will be considered
// interesting again and be placed in the piece list available
// for downloading.
void mark_as_unfiltered(int index);
// This will mark a piece as filtered. The piece will be
// removed from the list of pieces avalable for downloading
// and hence, will not be downloaded.
void mark_as_filtered(int index);
// returns true if the pieces at 'index' is marked as filtered
bool is_filtered(int index) const;
// fills the bitmask with 1's for pieces that are filtered
void filtered_pieces(std::vector<bool>& mask) const;
// pieces should be the vector that represents the pieces a // pieces should be the vector that represents the pieces a
// client has. It returns a list of all pieces that this client // client has. It returns a list of all pieces that this client
// has and that are interesting to download. It returns them in // has and that are interesting to download. It returns them in
@ -209,6 +226,7 @@ namespace libtorrent
piece_pos(int peer_count_, int index_) piece_pos(int peer_count_, int index_)
: peer_count(peer_count_) : peer_count(peer_count_)
, downloading(0) , downloading(0)
, filtered(0)
, index(index_) , index(index_)
{ {
assert(peer_count_ >= 0); assert(peer_count_ >= 0);
@ -219,9 +237,13 @@ namespace libtorrent
unsigned peer_count : 11; unsigned peer_count : 11;
// is 1 if the piece is marked as being downloaded // is 1 if the piece is marked as being downloaded
unsigned downloading : 1; unsigned downloading : 1;
// is 1 if the piece is filtered (not to be downloaded)
unsigned filtered : 1;
// index in to the piece_info vector // index in to the piece_info vector
unsigned index : 20; unsigned index : 19;
enum { we_have_index = 0x3ffff };
bool operator!=(piece_pos p) bool operator!=(piece_pos p)
{ return index != p.index || peer_count != p.peer_count; } { return index != p.index || peer_count != p.peer_count; }
@ -231,8 +253,13 @@ namespace libtorrent
}; };
void move(bool downloading, int vec_index, int elem_index); void move(bool downloading, bool filtered, int vec_index, int elem_index);
void remove(bool downloading, int vec_index, int elem_index); void remove(bool downloading, bool filtered, int vec_index, int elem_index);
std::vector<std::vector<int> >& pick_piece_info_vector(bool downloading
, bool filtered);
std::vector<std::vector<int> > const& pick_piece_info_vector(
bool downloading, bool filtered) const;
int add_interesting_blocks(const std::vector<int>& piece_list, int add_interesting_blocks(const std::vector<int>& piece_list,
const std::vector<bool>& pieces, const std::vector<bool>& pieces,
@ -252,10 +279,14 @@ namespace libtorrent
// during piece picking // during piece picking
std::vector<std::vector<int> > m_downloading_piece_info; std::vector<std::vector<int> > m_downloading_piece_info;
// this vector has the same structure as m_piece_info
// but only contains pieces we aren't interested in (filtered)
std::vector<std::vector<int> > m_filtered_piece_info;
// this maps indices to number of peers that has this piece and // this maps indices to number of peers that has this piece and
// index into the m_piece_info vectors. // index into the m_piece_info vectors.
// 0xfffff means that we have the piece, so it doesn't // piece_pos::we_have_index means that we have the piece, so it
// exist in the piece_info buckets // doesn't exist in the piece_info buckets
std::vector<piece_pos> m_piece_map; std::vector<piece_pos> m_piece_map;
// each piece that's currently being downloaded // each piece that's currently being downloaded

View File

@ -141,6 +141,10 @@ namespace libtorrent
void resume(); void resume();
bool is_paused() const { return m_paused; } bool is_paused() const { return m_paused; }
void filter_piece(int index, bool download);
bool is_piece_filtered(int index) const;
void filtered_pieces(std::vector<bool>& bitmask) const;
torrent_status status() const; torrent_status status() const;
void use_interface(const char* net_interface); void use_interface(const char* net_interface);

View File

@ -208,6 +208,13 @@ namespace libtorrent
void pause(); void pause();
void resume(); void resume();
// marks the piece with the given index as filtered
// it will not be downloaded
void filter_piece(int index, bool filter);
bool is_piece_filtered(int index) const;
std::vector<bool> filtered_pieces() const;
// set the interface to bind outgoing connections // set the interface to bind outgoing connections
// to. // to.
void use_interface(const char* net_interface); void use_interface(const char* net_interface);

View File

@ -273,7 +273,8 @@ namespace libtorrent
{ {
int index = *i; int index = *i;
m_torrent->peer_has(index); m_torrent->peer_has(index);
if (!m_torrent->have_piece(index)) if (!m_torrent->have_piece(index)
&& m_torrent->picker().is_filtered(index))
interesting = true; interesting = true;
} }
@ -654,7 +655,9 @@ namespace libtorrent
++m_num_pieces; ++m_num_pieces;
m_torrent->peer_has(index); m_torrent->peer_has(index);
if (!m_torrent->have_piece(index) && !is_interesting()) if (!m_torrent->have_piece(index)
&& !is_interesting()
&& !m_torrent->picker().is_filtered(index))
m_torrent->get_policy().peer_is_interesting(*this); m_torrent->get_policy().peer_is_interesting(*this);
} }
@ -729,12 +732,12 @@ namespace libtorrent
// peer has, in a shuffled order // peer has, in a shuffled order
bool interesting = false; bool interesting = false;
for (std::vector<int>::iterator i = piece_list.begin(); for (std::vector<int>::iterator i = piece_list.begin();
i != piece_list.end(); i != piece_list.end(); ++i)
++i)
{ {
int index = *i; int index = *i;
m_torrent->peer_has(index); m_torrent->peer_has(index);
if (!m_torrent->have_piece(index)) if (!m_torrent->have_piece(index)
&& !m_torrent->picker().is_filtered(index))
interesting = true; interesting = true;
} }
@ -1571,7 +1574,14 @@ namespace libtorrent
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
using namespace boost::posix_time; using namespace boost::posix_time;
(*m_logger) << to_simple_string(second_clock::universal_time()) (*m_logger) << to_simple_string(second_clock::universal_time())
<< " ==> BITFIELD\n"; << " ==> BITFIELD ";
for (int i = 0; i < (int)m_have_piece.size(); ++i)
{
if (m_torrent->have_piece(i)) (*m_logger) << "1";
else (*m_logger) << "0";
}
(*m_logger) << "\n";
#endif #endif
const int packet_size = ((int)m_have_piece.size() + 7) / 8 + 5; const int packet_size = ((int)m_have_piece.size() + 7) / 8 + 5;
const int old_size = (int)m_send_buffer.size(); const int old_size = (int)m_send_buffer.size();

View File

@ -57,6 +57,7 @@ namespace libtorrent
piece_picker::piece_picker(int blocks_per_piece, int total_num_blocks) piece_picker::piece_picker(int blocks_per_piece, int total_num_blocks)
: m_piece_info(2) : m_piece_info(2)
, m_downloading_piece_info(2) , m_downloading_piece_info(2)
, m_filtered_piece_info(2)
, m_piece_map((total_num_blocks + blocks_per_piece-1) / blocks_per_piece) , m_piece_map((total_num_blocks + blocks_per_piece-1) / blocks_per_piece)
{ {
assert(blocks_per_piece > 0); assert(blocks_per_piece > 0);
@ -64,7 +65,7 @@ namespace libtorrent
// the piece index is stored in 20 bits, which limits the allowed // the piece index is stored in 20 bits, which limits the allowed
// number of pieces somewhat // number of pieces somewhat
if (m_piece_map.size() >= 0xfffff) throw std::runtime_error("too many pieces in torrent"); if (m_piece_map.size() >= piece_pos::we_have_index) throw std::runtime_error("too many pieces in torrent");
m_blocks_per_piece = blocks_per_piece; m_blocks_per_piece = blocks_per_piece;
m_blocks_in_last_piece = total_num_blocks % blocks_per_piece; m_blocks_in_last_piece = total_num_blocks % blocks_per_piece;
@ -76,7 +77,7 @@ namespace libtorrent
// allocate the piece_map to cover all pieces // allocate the piece_map to cover all pieces
// and make them invalid (as if though we already had every piece) // and make them invalid (as if though we already had every piece)
std::fill(m_piece_map.begin(), m_piece_map.end(), piece_pos(0, 0xfffff)); std::fill(m_piece_map.begin(), m_piece_map.end(), piece_pos(0, piece_pos::we_have_index));
} }
void piece_picker::files_checked( void piece_picker::files_checked(
@ -107,14 +108,18 @@ namespace libtorrent
int index = *i; int index = *i;
assert(index >= 0); assert(index >= 0);
assert(index < (int)m_piece_map.size()); assert(index < (int)m_piece_map.size());
assert(m_piece_map[index].index == 0xfffff); assert(m_piece_map[index].index == piece_pos::we_have_index);
int peer_count = m_piece_map[index].peer_count; int peer_count = m_piece_map[index].peer_count;
assert(peer_count == 0); assert(peer_count == 0);
assert(m_piece_info.size() == 2); assert(m_piece_info.size() == 2);
m_piece_map[index].index = (int)m_piece_info[peer_count].size(); piece_pos& p = m_piece_map[index];
m_piece_info[peer_count].push_back(index); std::vector<std::vector<int> >& dst_vec = pick_piece_info_vector(p.downloading
, p.filtered);
assert((int)dst_vec.size() > peer_count);
p.index = (int)dst_vec[peer_count].size();
dst_vec[peer_count].push_back(index);
} }
// if we have fast resume info // if we have fast resume info
@ -184,14 +189,14 @@ namespace libtorrent
*/ */
} }
if (i->index == 0xfffff) if (i->index == piece_pos::we_have_index)
{ {
assert(t == 0 || t->have_piece(index)); assert(t == 0 || t->have_piece(index));
assert(i->downloading == 0); assert(i->downloading == 0);
// make sure there's no entry // make sure there's no entry
// with this index. (there shouldn't // with this index. (there shouldn't
// be since the piece_map is 0xfffff) // be since the piece_map is piece_pos::we_have_index)
for (std::vector<std::vector<int> >::const_iterator i = m_piece_info.begin(); for (std::vector<std::vector<int> >::const_iterator i = m_piece_info.begin();
i != m_piece_info.end(); ++i) i != m_piece_info.end(); ++i)
{ {
@ -203,8 +208,7 @@ namespace libtorrent
} }
for (std::vector<std::vector<int> >::const_iterator i = m_downloading_piece_info.begin(); for (std::vector<std::vector<int> >::const_iterator i = m_downloading_piece_info.begin();
i != m_downloading_piece_info.end(); i != m_downloading_piece_info.end(); ++i)
++i)
{ {
for (std::vector<int>::const_iterator j = i->begin(); for (std::vector<int>::const_iterator j = i->begin();
j != i->end(); ++j) j != i->end(); ++j)
@ -219,7 +223,7 @@ namespace libtorrent
if (t != 0) if (t != 0)
assert(!t->have_piece(index)); assert(!t->have_piece(index));
const std::vector<std::vector<int> >& c_vec = (i->downloading)?m_downloading_piece_info:m_piece_info; const std::vector<std::vector<int> >& c_vec = pick_piece_info_vector(i->downloading, i->filtered);
assert(i->peer_count < c_vec.size()); assert(i->peer_count < c_vec.size());
const std::vector<int>& vec = c_vec[i->peer_count]; const std::vector<int>& vec = c_vec[i->peer_count];
assert(i->index < vec.size()); assert(i->index < vec.size());
@ -261,11 +265,30 @@ namespace libtorrent
return 1.f; return 1.f;
} }
void piece_picker::move(bool downloading, int peer_count, int elem_index) std::vector<std::vector<int> >& piece_picker::pick_piece_info_vector(
bool downloading, bool filtered)
{
return filtered
?m_filtered_piece_info
:(downloading?m_downloading_piece_info:m_piece_info);
}
std::vector<std::vector<int> > const& piece_picker::pick_piece_info_vector(
bool downloading, bool filtered) const
{
return filtered
?m_filtered_piece_info
:(downloading?m_downloading_piece_info:m_piece_info);
}
// will update the piece with the given properties (downloading, filtered, peer_count, elem_index)
// to place it at the correct position in the vectors.
void piece_picker::move(bool downloading, bool filtered, int peer_count, int elem_index)
{ {
assert(peer_count >= 0); assert(peer_count >= 0);
assert(elem_index >= 0); assert(elem_index >= 0);
std::vector<std::vector<int> >& src_vec = (downloading)?m_downloading_piece_info:m_piece_info; std::vector<std::vector<int> >& src_vec(pick_piece_info_vector(downloading, filtered));
assert((int)src_vec.size() > peer_count); assert((int)src_vec.size() > peer_count);
assert((int)src_vec[peer_count].size() > elem_index); assert((int)src_vec[peer_count].size() > elem_index);
@ -276,7 +299,7 @@ namespace libtorrent
assert(p.downloading != downloading || (int)p.peer_count != peer_count); assert(p.downloading != downloading || (int)p.peer_count != peer_count);
std::vector<std::vector<int> >& dst_vec = (p.downloading)?m_downloading_piece_info:m_piece_info; std::vector<std::vector<int> >& dst_vec(pick_piece_info_vector(p.downloading, p.filtered));
if (dst_vec.size() <= p.peer_count) if (dst_vec.size() <= p.peer_count)
{ {
@ -308,21 +331,20 @@ namespace libtorrent
} }
src_vec[peer_count].pop_back(); src_vec[peer_count].pop_back();
} }
void piece_picker::remove(bool downloading, int peer_count, int elem_index) void piece_picker::remove(bool downloading, bool filtered, int peer_count, int elem_index)
{ {
assert(peer_count >= 0); assert(peer_count >= 0);
assert(elem_index >= 0); assert(elem_index >= 0);
std::vector<std::vector<int> >& src_vec = (downloading)?m_downloading_piece_info:m_piece_info; std::vector<std::vector<int> >& src_vec(pick_piece_info_vector(downloading, filtered));
assert((int)src_vec.size() > peer_count); assert((int)src_vec.size() > peer_count);
assert((int)src_vec[peer_count].size() > elem_index); assert((int)src_vec[peer_count].size() > elem_index);
int index = src_vec[peer_count][elem_index]; int index = src_vec[peer_count][elem_index];
m_piece_map[index].index = 0xfffff; m_piece_map[index].index = piece_pos::we_have_index;
if (downloading) if (downloading)
{ {
@ -360,7 +382,8 @@ namespace libtorrent
m_downloads.erase(i); m_downloads.erase(i);
m_piece_map[index].downloading = 0; m_piece_map[index].downloading = 0;
move(true, m_piece_map[index].peer_count, m_piece_map[index].index); piece_pos& p = m_piece_map[index];
move(true, p.filtered, p.peer_count, p.index);
#ifndef NDEBUG #ifndef NDEBUG
// integrity_check(); // integrity_check();
@ -381,9 +404,10 @@ namespace libtorrent
// if we have the piece, we don't have to move // if we have the piece, we don't have to move
// any entries in the piece_info vector // any entries in the piece_info vector
if (index == 0xfffff) return; if (index == piece_pos::we_have_index) return;
move(m_piece_map[i].downloading, peer_count, index); piece_pos& p = m_piece_map[i];
move(p.downloading, p.filtered, peer_count, index);
#ifndef NDEBUG #ifndef NDEBUG
// integrity_check(); // integrity_check();
@ -407,10 +431,15 @@ namespace libtorrent
if (m_piece_map[i].peer_count > 0) if (m_piece_map[i].peer_count > 0)
m_piece_map[i].peer_count--; m_piece_map[i].peer_count--;
if (index == 0xfffff) return; if (index == piece_pos::we_have_index) return;
move(m_piece_map[i].downloading, peer_count, index); piece_pos& p = m_piece_map[i];
move(p.downloading, p.filtered, peer_count, index);
} }
// this is used to indicate that we succesfully have
// downloaded a piece, and that no further attempts
// to pick that piece should be made. The piece will
// be removed from the available piece list.
void piece_picker::we_have(int index) void piece_picker::we_have(int index)
{ {
assert(index >= 0); assert(index >= 0);
@ -421,16 +450,74 @@ namespace libtorrent
assert(m_piece_map[index].downloading == 1); assert(m_piece_map[index].downloading == 1);
assert(info_index != 0xfffff); assert(info_index != piece_pos::we_have_index);
remove(m_piece_map[index].downloading, peer_count, info_index); piece_pos& p = m_piece_map[index];
remove(p.downloading, p.filtered, peer_count, info_index);
#ifndef NDEBUG #ifndef NDEBUG
// integrity_check(); // integrity_check();
#endif #endif
} }
void piece_picker::pick_pieces(const std::vector<bool>& pieces,
std::vector<piece_block>& interesting_pieces, void piece_picker::mark_as_filtered(int index)
int num_blocks) const {
assert(index >= 0);
assert(index < (int)m_piece_map.size());
piece_pos& p = m_piece_map[index];
if (p.filtered == 1) return;
p.filtered = 1;
if (p.index != piece_pos::we_have_index)
move(p.downloading, false, p.peer_count, p.index);
#ifndef NDEBUG
integrity_check();
#endif
}
// this function can be used for pieces that we don't
// have, but have marked as filtered (so we didn't
// want to download them) but later want to enable for
// downloading, then we call this function and it will
// be inserted in the available piece list again
void piece_picker::mark_as_unfiltered(int index)
{
assert(index >= 0);
assert(index < (int)m_piece_map.size());
piece_pos& p = m_piece_map[index];
if (p.filtered == 0) return;
p.filtered = 0;
if (p.index != piece_pos::we_have_index)
move(p.downloading, true, p.peer_count, p.index);
#ifndef NDEBUG
integrity_check();
#endif
}
bool piece_picker::is_filtered(int index) const
{
assert(index >= 0);
assert(index < (int)m_piece_map.size());
return m_piece_map[index].filtered == 1;
}
void piece_picker::filtered_pieces(std::vector<bool>& mask) const
{
mask.resize(m_piece_map.size());
std::vector<bool>::iterator j = mask.begin();
for (std::vector<piece_pos>::const_iterator i = m_piece_map.begin(),
end(m_piece_map.end()); i != end; ++i, ++j)
{
*j = i->filtered == 1;
}
}
void piece_picker::pick_pieces(const std::vector<bool>& pieces
, std::vector<piece_block>& interesting_pieces
, int num_blocks) const
{ {
assert(num_blocks > 0); assert(num_blocks > 0);
assert(pieces.size() == m_piece_map.size()); assert(pieces.size() == m_piece_map.size());
@ -445,8 +532,10 @@ namespace libtorrent
// parts of them may be free for download as well, the // parts of them may be free for download as well, the
// partially donloaded pieces will be prioritized // partially donloaded pieces will be prioritized
assert(m_piece_info.begin() != m_piece_info.end()); assert(m_piece_info.begin() != m_piece_info.end());
// +1 is to ignore pieces that no peer has. The bucket with index 0 contains
// pieces that 0 other peers has.
std::vector<std::vector<int> >::const_iterator free = m_piece_info.begin()+1; std::vector<std::vector<int> >::const_iterator free = m_piece_info.begin()+1;
assert(m_downloading_piece_info.begin()!=m_downloading_piece_info.end()); assert(m_downloading_piece_info.begin() != m_downloading_piece_info.end());
std::vector<std::vector<int> >::const_iterator partial = m_downloading_piece_info.begin()+1; std::vector<std::vector<int> >::const_iterator partial = m_downloading_piece_info.begin()+1;
while((free != m_piece_info.end()) || (partial != m_downloading_piece_info.end())) while((free != m_piece_info.end()) || (partial != m_downloading_piece_info.end()))
@ -472,10 +561,10 @@ namespace libtorrent
} }
} }
int piece_picker::add_interesting_blocks(const std::vector<int>& piece_list, int piece_picker::add_interesting_blocks(const std::vector<int>& piece_list
const std::vector<bool>& pieces, , const std::vector<bool>& pieces
std::vector<piece_block>& interesting_blocks, , std::vector<piece_block>& interesting_blocks
int num_blocks) const , int num_blocks) const
{ {
assert(num_blocks > 0); assert(num_blocks > 0);
@ -571,7 +660,7 @@ namespace libtorrent
assert(block.piece_index < (int)m_piece_map.size()); assert(block.piece_index < (int)m_piece_map.size());
assert(block.block_index < (int)max_blocks_per_piece); assert(block.block_index < (int)max_blocks_per_piece);
if (m_piece_map[block.piece_index].index == 0xfffff) return true; if (m_piece_map[block.piece_index].index == piece_pos::we_have_index) return true;
if (m_piece_map[block.piece_index].downloading == 0) return false; if (m_piece_map[block.piece_index].downloading == 0) return false;
std::vector<downloading_piece>::const_iterator i std::vector<downloading_piece>::const_iterator i
= std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index)); = std::find_if(m_downloads.begin(), m_downloads.end(), has_index(block.piece_index));
@ -594,7 +683,7 @@ namespace libtorrent
if (p.downloading == 0) if (p.downloading == 0)
{ {
p.downloading = 1; p.downloading = 1;
move(false, p.peer_count, p.index); move(false, p.filtered, p.peer_count, p.index);
downloading_piece dp; downloading_piece dp;
dp.index = block.piece_index; dp.index = block.piece_index;
@ -627,10 +716,12 @@ namespace libtorrent
assert(block.block_index < blocks_in_piece(block.piece_index)); assert(block.block_index < blocks_in_piece(block.piece_index));
piece_pos& p = m_piece_map[block.piece_index]; piece_pos& p = m_piece_map[block.piece_index];
if (p.index == piece_pos::we_have_index) return;
if (p.downloading == 0) if (p.downloading == 0)
{ {
p.downloading = 1; p.downloading = 1;
move(false, p.peer_count, p.index); move(false, p.filtered, p.peer_count, p.index);
downloading_piece dp; downloading_piece dp;
dp.index = block.piece_index; dp.index = block.piece_index;
@ -750,7 +841,8 @@ namespace libtorrent
{ {
m_downloads.erase(i); m_downloads.erase(i);
m_piece_map[block.piece_index].downloading = 0; m_piece_map[block.piece_index].downloading = 0;
move(true, m_piece_map[block.piece_index].peer_count, m_piece_map[block.piece_index].index); piece_pos& p = m_piece_map[block.piece_index];
move(true, p.filtered, p.peer_count, p.index);
} }
#ifndef NDEBUG #ifndef NDEBUG
// integrity_check(); // integrity_check();

View File

@ -124,8 +124,7 @@ namespace
busy_pieces.reserve(10); busy_pieces.reserve(10);
for (std::vector<piece_block>::iterator i = interesting_pieces.begin(); for (std::vector<piece_block>::iterator i = interesting_pieces.begin();
i != interesting_pieces.end(); i != interesting_pieces.end(); ++i)
++i)
{ {
if (p.is_downloading(*i)) if (p.is_downloading(*i))
{ {

View File

@ -136,26 +136,28 @@ namespace libtorrent { namespace detail
// lock the session to add the new torrent // lock the session to add the new torrent
boost::mutex::scoped_lock l(m_mutex); boost::mutex::scoped_lock l(m_mutex);
if (!t->abort) if (t->abort)
{ {
boost::mutex::scoped_lock l(m_ses.m_mutex);
m_ses.m_torrents.insert(std::make_pair(t->info_hash, t->torrent_ptr));
m_torrents.pop_front(); m_torrents.pop_front();
if (t->torrent_ptr->is_seed() && m_ses.m_alerts.should_post(alert::info)) continue;
{
m_ses.m_alerts.post_alert(torrent_finished_alert(
t->torrent_ptr->get_handle()
, "torrent is complete"));
}
peer_id id;
std::fill(id.begin(), id.end(), 0);
for (std::vector<address>::const_iterator i = t->peers.begin();
i != t->peers.end(); ++i)
{
t->torrent_ptr->get_policy().peer_from_tracker(*i, id);
}
} }
boost::mutex::scoped_lock l2(m_ses.m_mutex);
m_ses.m_torrents.insert(std::make_pair(t->info_hash, t->torrent_ptr));
if (t->torrent_ptr->is_seed() && m_ses.m_alerts.should_post(alert::info))
{
m_ses.m_alerts.post_alert(torrent_finished_alert(
t->torrent_ptr->get_handle()
, "torrent is complete"));
}
peer_id id;
std::fill(id.begin(), id.end(), 0);
for (std::vector<address>::const_iterator i = t->peers.begin();
i != t->peers.end(); ++i)
{
t->torrent_ptr->get_policy().peer_from_tracker(*i, id);
}
m_torrents.pop_front();
} }
catch(const std::exception& e) catch(const std::exception& e)
{ {

View File

@ -1119,13 +1119,11 @@ namespace libtorrent
std::vector<char> piece_data(static_cast<int>(m_info.piece_length())); std::vector<char> piece_data(static_cast<int>(m_info.piece_length()));
// this maps a piece hash to piece index. It will be
// build the first time it is used (to save time if it
// isn't needed)
std::multimap<sha1_hash, int> hash_to_piece; std::multimap<sha1_hash, int> hash_to_piece;
// build the hash-map, that maps hashes to pieces // build the hash-map, that maps hashes to pieces
for (int i = 0; i < m_info.num_pieces(); ++i)
{
hash_to_piece.insert(std::make_pair(m_info.hash_for_piece(i), i));
}
for (int current_slot = 0; current_slot < m_info.num_pieces(); ++current_slot) for (int current_slot = 0; current_slot < m_info.num_pieces(); ++current_slot)
{ {
try try
@ -1137,6 +1135,14 @@ namespace libtorrent
, 0 , 0
, static_cast<int>(m_info.piece_size(current_slot))); , static_cast<int>(m_info.piece_size(current_slot)));
if (hash_to_piece.empty())
{
for (int i = 0; i < m_info.num_pieces(); ++i)
{
hash_to_piece.insert(std::make_pair(m_info.hash_for_piece(i), i));
}
}
int piece_index = identify_data( int piece_index = identify_data(
piece_data piece_data
, current_slot , current_slot

View File

@ -555,6 +555,34 @@ namespace libtorrent
return m_username + ":" + m_password; return m_username + ":" + m_password;
} }
void torrent::filter_piece(int index, bool filter)
{
// this call is only valid on torrents with metadata
assert(m_picker.get());
assert(index >= 0);
assert(index < m_torrent_file.num_pieces());
if (filter) m_picker->mark_as_filtered(index);
else m_picker->mark_as_unfiltered(index);
}
bool torrent::is_piece_filtered(int index) const
{
// this call is only valid on torrents with metadata
assert(m_picker.get());
assert(index >= 0);
assert(index < m_torrent_file.num_pieces());
return m_picker->is_filtered(index);
}
void torrent::filtered_pieces(std::vector<bool>& bitmask) const
{
// this call is only valid on torrents with metadata
assert(m_picker.get());
m_picker->filtered_pieces(bitmask);
}
void torrent::replace_trackers(std::vector<announce_entry> const& urls) void torrent::replace_trackers(std::vector<announce_entry> const& urls)
{ {
assert(!urls.empty()); assert(!urls.empty());

View File

@ -76,64 +76,11 @@ namespace libtorrent
{ {
namespace namespace
{ {
#if defined(_MSC_VER) && _MSC_VER < 1300 void throw_invalid_handle()
template<class T>
struct transform_void{ typedef T type; };
template<>
struct transform_void<void> { typedef int type; };
template<class Ret>
struct void_call_wrapper
{ {
template<class F> throw_invalid_handle();
static Ret call(F f, torrent& t)
{
return f(t);
}
};
template<>
struct void_call_wrapper<void>
{
template<class F>
static int call(F f, torrent& t)
{
f(t);
return 0;
}
};
template<class Ret, class F>
transform_void<Ret>::type call_member(
detail::session_impl* ses
, detail::checker_impl* chk
, sha1_hash const& hash
, F f)
{
typedef typename transform_void<Ret>::type ret;
if (ses == 0) throw invalid_handle();
{
boost::mutex::scoped_lock l(ses->m_mutex);
torrent* t = ses->find_torrent(hash);
if (t != 0) return void_call_wrapper<Ret>::call(f, *t);
}
if (chk)
{
boost::mutex::scoped_lock l(chk->m_mutex);
detail::piece_checker_data* d = chk->find_torrent(hash);
if (d != 0) return void_call_wrapper<Ret>::call(f, *d->torrent_ptr);
}
throw invalid_handle();
} }
#else
template<class Ret, class F> template<class Ret, class F>
Ret call_member( Ret call_member(
detail::session_impl* ses detail::session_impl* ses
@ -141,14 +88,7 @@ namespace libtorrent
, sha1_hash const& hash , sha1_hash const& hash
, F f) , F f)
{ {
if (ses == 0) throw invalid_handle(); if (ses == 0) throw_invalid_handle();
{
boost::mutex::scoped_lock l(ses->m_mutex);
torrent* t = ses->find_torrent(hash);
if (t != 0) return f(*t);
}
if (chk) if (chk)
{ {
@ -157,10 +97,15 @@ namespace libtorrent
detail::piece_checker_data* d = chk->find_torrent(hash); detail::piece_checker_data* d = chk->find_torrent(hash);
if (d != 0) return f(*d->torrent_ptr); if (d != 0) return f(*d->torrent_ptr);
} }
throw invalid_handle();
{
boost::mutex::scoped_lock l(ses->m_mutex);
torrent* t = ses->find_torrent(hash);
if (t != 0) return f(*t);
}
throw_invalid_handle();
} }
#endif
} }
#ifndef NDEBUG #ifndef NDEBUG
@ -281,13 +226,7 @@ namespace libtorrent
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
if (m_ses == 0) throw invalid_handle(); if (m_ses == 0) throw_invalid_handle();
{
boost::mutex::scoped_lock l(m_ses->m_mutex);
torrent* t = m_ses->find_torrent(m_info_hash);
if (t != 0) return t->status();
}
if (m_chk) if (m_chk)
{ {
@ -308,9 +247,38 @@ namespace libtorrent
} }
} }
throw invalid_handle(); {
boost::mutex::scoped_lock l(m_ses->m_mutex);
torrent* t = m_ses->find_torrent(m_info_hash);
if (t != 0) return t->status();
}
throw_invalid_handle();
} }
void torrent_handle::filter_piece(int index, bool filter)
{
INVARIANT_CHECK;
call_member<void>(m_ses, m_chk, m_info_hash
, bind(&torrent::filter_piece, _1, index, filter));
}
bool torrent_handle::is_piece_filtered(int index) const
{
INVARIANT_CHECK;
return call_member<bool>(m_ses, m_chk, m_info_hash
, bind(&torrent::is_piece_filtered, _1, index));
}
std::vector<bool> torrent_handle::filtered_pieces() const
{
INVARIANT_CHECK;
std::vector<bool> ret;
call_member<void>(m_ses, m_chk, m_info_hash
, bind(&torrent::filtered_pieces, _1, boost::ref(ret)));
return ret;
}
std::vector<announce_entry> const& torrent_handle::trackers() const std::vector<announce_entry> const& torrent_handle::trackers() const
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
@ -331,7 +299,7 @@ namespace libtorrent
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
if (!has_metadata()) throw invalid_handle(); if (!has_metadata()) throw_invalid_handle();
return call_member<torrent_info const&>(m_ses, m_chk, m_info_hash return call_member<torrent_info const&>(m_ses, m_chk, m_info_hash
, bind(&torrent::torrent_file, _1)); , bind(&torrent::torrent_file, _1));
} }
@ -342,12 +310,6 @@ namespace libtorrent
if (m_ses == 0) return false; if (m_ses == 0) return false;
{
boost::mutex::scoped_lock l(m_ses->m_mutex);
torrent* t = m_ses->find_torrent(m_info_hash);
if (t != 0) return true;
}
if (m_chk) if (m_chk)
{ {
boost::mutex::scoped_lock l(m_chk->m_mutex); boost::mutex::scoped_lock l(m_chk->m_mutex);
@ -355,6 +317,12 @@ namespace libtorrent
if (d != 0) return true; if (d != 0) return true;
} }
{
boost::mutex::scoped_lock l(m_ses->m_mutex);
torrent* t = m_ses->find_torrent(m_info_hash);
if (t != 0) return true;
}
return false; return false;
} }
@ -499,11 +467,11 @@ namespace libtorrent
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
if (m_ses == 0) throw invalid_handle(); if (m_ses == 0) throw_invalid_handle();
boost::mutex::scoped_lock l(m_ses->m_mutex); boost::mutex::scoped_lock l(m_ses->m_mutex);
torrent* t = m_ses->find_torrent(m_info_hash); torrent* t = m_ses->find_torrent(m_info_hash);
if (t == 0) throw invalid_handle(); if (t == 0) throw_invalid_handle();
peer_id id; peer_id id;
std::fill(id.begin(), id.end(), 0); std::fill(id.begin(), id.end(), 0);
@ -515,11 +483,11 @@ namespace libtorrent
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
if (m_ses == 0) throw invalid_handle(); if (m_ses == 0) throw_invalid_handle();
boost::mutex::scoped_lock l(m_ses->m_mutex); boost::mutex::scoped_lock l(m_ses->m_mutex);
torrent* t = m_ses->find_torrent(m_info_hash); torrent* t = m_ses->find_torrent(m_info_hash);
if (t == 0) throw invalid_handle(); if (t == 0) throw_invalid_handle();
using boost::posix_time::second_clock; using boost::posix_time::second_clock;
t->force_tracker_request(second_clock::universal_time() t->force_tracker_request(second_clock::universal_time()
@ -530,11 +498,11 @@ namespace libtorrent
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
if (m_ses == 0) throw invalid_handle(); if (m_ses == 0) throw_invalid_handle();
boost::mutex::scoped_lock l(m_ses->m_mutex); boost::mutex::scoped_lock l(m_ses->m_mutex);
torrent* t = m_ses->find_torrent(m_info_hash); torrent* t = m_ses->find_torrent(m_info_hash);
if (t == 0) throw invalid_handle(); if (t == 0) throw_invalid_handle();
t->force_tracker_request(); t->force_tracker_request();
} }
@ -557,7 +525,7 @@ namespace libtorrent
INVARIANT_CHECK; INVARIANT_CHECK;
v.clear(); v.clear();
if (m_ses == 0) throw invalid_handle(); if (m_ses == 0) throw_invalid_handle();
boost::mutex::scoped_lock l(m_ses->m_mutex); boost::mutex::scoped_lock l(m_ses->m_mutex);
@ -565,8 +533,7 @@ namespace libtorrent
if (t == 0) return; if (t == 0) return;
for (torrent::const_peer_iterator i = t->begin(); for (torrent::const_peer_iterator i = t->begin();
i != t->end(); i != t->end(); ++i)
++i)
{ {
peer_connection* peer = i->second; peer_connection* peer = i->second;
@ -580,6 +547,8 @@ namespace libtorrent
const stat& statistics = peer->statistics(); const stat& statistics = peer->statistics();
p.down_speed = statistics.download_rate(); p.down_speed = statistics.download_rate();
p.up_speed = statistics.upload_rate(); p.up_speed = statistics.upload_rate();
p.payload_down_speed = statistics.download_payload_rate();
p.payload_up_speed = statistics.upload_payload_rate();
p.id = peer->get_peer_id(); p.id = peer->get_peer_id();
p.ip = peer->get_socket()->sender(); p.ip = peer->get_socket()->sender();
@ -632,7 +601,7 @@ namespace libtorrent
bool torrent_handle::send_chat_message(address ip, std::string message) const bool torrent_handle::send_chat_message(address ip, std::string message) const
{ {
if (m_ses == 0) throw invalid_handle(); if (m_ses == 0) throw_invalid_handle();
boost::mutex::scoped_lock l(m_ses->m_mutex); boost::mutex::scoped_lock l(m_ses->m_mutex);
const torrent* t = m_ses->find_torrent(m_info_hash); const torrent* t = m_ses->find_torrent(m_info_hash);
@ -668,7 +637,7 @@ namespace libtorrent
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
if (m_ses == 0) throw invalid_handle(); if (m_ses == 0) throw_invalid_handle();
boost::mutex::scoped_lock l(m_ses->m_mutex); boost::mutex::scoped_lock l(m_ses->m_mutex);
torrent* t = m_ses->find_torrent(m_info_hash); torrent* t = m_ses->find_torrent(m_info_hash);

View File

@ -501,9 +501,7 @@ namespace libtorrent
tracker_connections_t keep_connections; tracker_connections_t keep_connections;
for (tracker_connections_t::const_iterator i = for (tracker_connections_t::const_iterator i =
m_connections.begin(); m_connections.begin(); i != m_connections.end(); ++i)
i != m_connections.end();
++i)
{ {
if (!(*i)->has_requester()) keep_connections.push_back(*i); if (!(*i)->has_requester()) keep_connections.push_back(*i);
} }