*** empty log message ***

This commit is contained in:
Arvid Norberg 2004-01-12 03:05:10 +00:00
parent b9bbf242c6
commit 9e979efb8b
17 changed files with 396 additions and 124 deletions

View File

@ -473,6 +473,7 @@ struct torrent_handle
entry write_resume_data();
void force_reannounce();
void connect_peer(const address& adr) const;
void set_ratio(float ratio);
boost::filsystem::path save_path() const;
@ -498,6 +499,13 @@ torrent. If the peer does not respond, or is not a member of this torrent, it wi
be disconnected. No harm can be done by using this other than an unnecessary connection
attempt is made. If the torrent is uninitialized or in queued or checking mode, this
will throw <a class="reference" href="#invalid-handle">invalid_handle</a>.</p>
<p><tt class="literal"><span class="pre">set_ratio()</span></tt> sets the desired download / upload ratio. If set to 0, it is considered being
infinite. i.e. the client will always upload as much as it can, no matter how much it gets back
in return. With this setting it will work much like the standard clients.</p>
<p>Besides 0, the ration can be set to any number greater than or equal to 1. It means how much to
attempt to upload in return for each download. e.g. if set to 2, the client will try to upload
2 bytes for every byte received. The default setting for this is 0, which will make it work
as a standard client.</p>
<p><tt class="literal"><span class="pre">info_hash()</span></tt> returns the info hash for the torrent.</p>
<p><tt class="literal"><span class="pre">set_max_uploads()</span></tt> sets the maximum number of peers that's unchoked at the same time on this
torrent. If you set this to -1, there will be no limit.</p>
@ -1264,6 +1272,49 @@ not trust the fast-resume data and just do the checking.</p>
</div>
<div class="section" id="file-format">
<h1><a class="toc-backref" href="#id44" name="file-format">file format</a></h1>
<p>The file format is a bencoded dictionary containing the following fields:</p>
<table border class="table">
<colgroup>
<col width="26%" />
<col width="74%" />
</colgroup>
<tbody valign="top">
<tr><td><tt class="literal"><span class="pre">file-format</span></tt></td>
<td>string: &quot;libtorrent resume file&quot;</td>
</tr>
<tr><td><tt class="literal"><span class="pre">file-version</span></tt></td>
<td>integer: 1</td>
</tr>
<tr><td><tt class="literal"><span class="pre">info-hash</span></tt></td>
<td>string, the info hash of the torrent this data is saved for.</td>
</tr>
<tr><td><tt class="literal"><span class="pre">blocks</span> <span class="pre">per</span> <span class="pre">piece</span></tt></td>
<td>integer, the number of blocks per piece. Must be: piece_size
/ (16 * 1024). Clamped to be within the range [1, 128]. It
is the number of blocks per (normal sized) piece. Usually
each piece is 16 * 1024 bytes in size.</td>
</tr>
<tr><td><tt class="literal"><span class="pre">slots</span></tt></td>
<td><p class="first">list of integers. The list mappes slots ti piece indices. It
tells which piece is on which slot. If piece index is -2 it
means it is free, that there's no piece there. If it is -1,
means the slot isn't allocated on disk yet. The pieces have
to meet the following requirements:</p>
<ul class="simple">
<li>if there's a slot at the position of the piece index,
the piece must be located in that slot.</li>
</ul>
<p class="last">TODO: finish</p>
</td>
</tr>
<tr><td><tt class="literal"><span class="pre">peers</span></tt></td>
<td>&nbsp;</td>
</tr>
<tr><td><tt class="literal"><span class="pre">unfinished</span></tt></td>
<td>&nbsp;</td>
</tr>
</tbody>
</table>
<p>TODO: describe the file format</p>
</div>
<div class="section" id="extensions">

View File

@ -471,6 +471,7 @@ Its declaration looks like this::
entry write_resume_data();
void force_reannounce();
void connect_peer(const address& adr) const;
void set_ratio(float ratio);
boost::filsystem::path save_path() const;
@ -500,6 +501,14 @@ be disconnected. No harm can be done by using this other than an unnecessary con
attempt is made. If the torrent is uninitialized or in queued or checking mode, this
will throw invalid_handle_.
``set_ratio()`` sets the desired download / upload ratio. If set to 0, it is considered being
infinite. i.e. the client will always upload as much as it can, no matter how much it gets back
in return. With this setting it will work much like the standard clients.
Besides 0, the ration can be set to any number greater than or equal to 1. It means how much to
attempt to upload in return for each download. e.g. if set to 2, the client will try to upload
2 bytes for every byte received. The default setting for this is 0, which will make it work
as a standard client.
``info_hash()`` returns the info hash for the torrent.
@ -1337,6 +1346,37 @@ not trust the fast-resume data and just do the checking.
file format
===========
The file format is a bencoded dictionary containing the following fields:
+----------------------+--------------------------------------------------------------+
| ``file-format`` | string: "libtorrent resume file" |
+----------------------+--------------------------------------------------------------+
| ``file-version`` | integer: 1 |
+----------------------+--------------------------------------------------------------+
| ``info-hash`` | string, the info hash of the torrent this data is saved for. |
+----------------------+--------------------------------------------------------------+
| ``blocks per piece`` | integer, the number of blocks per piece. Must be: piece_size |
| | / (16 * 1024). Clamped to be within the range [1, 128]. It |
| | is the number of blocks per (normal sized) piece. Usually |
| | each piece is 16 * 1024 bytes in size. |
+----------------------+--------------------------------------------------------------+
| ``slots`` | list of integers. The list mappes slots ti piece indices. It |
| | tells which piece is on which slot. If piece index is -2 it |
| | means it is free, that there's no piece there. If it is -1, |
| | means the slot isn't allocated on disk yet. The pieces have |
| | to meet the following requirements: |
| | |
| | * if there's a slot at the position of the piece index, |
| | the piece must be located in that slot. |
| | |
| | TODO: finish |
+----------------------+--------------------------------------------------------------+
| ``peers`` | |
+----------------------+--------------------------------------------------------------+
| ``unfinished`` | |
+----------------------+--------------------------------------------------------------+
TODO: describe the file format
extensions

View File

@ -147,6 +147,38 @@ std::string to_string(float v, int width)
return s.str();
}
std::string pos_to_string(float v, int width)
{
std::stringstream s;
s.precision(width-1);
s.flags(std::ios_base::right);
s.width(width);
s.fill(' ');
s << fabs(v);
return s.str();
}
std::string ratio(float a, float b)
{
std::stringstream s;
if (a > b)
{
if (b < 0.001f) s << " inf:1";
else s << pos_to_string(a/b, 4) << ":1";
}
else if (a < b)
{
if (a < 0.001f) s << " 1:inf";
else s << "1:" << pos_to_string(b/a, 4);
}
else
{
s << " 1:1";
}
return s.str();
}
std::string add_suffix(float val)
{
const char* prefix[] = {"B", "kB", "MB", "GB", "TB"};
@ -207,6 +239,7 @@ int main(int argc, char* argv[])
entry resume_data;
try
{
// TODO: use a torrent-specific name here
std::ifstream resume_file("test.fastresume", std::ios_base::binary);
resume_file.unsetf(std::ios_base::skipws);
resume_data = bdecode(std::istream_iterator<char>(resume_file)
@ -217,6 +250,7 @@ int main(int argc, char* argv[])
handles.push_back(ses.add_torrent(t, "", resume_data));
handles.back().set_max_uploads(7);
handles.back().set_ratio(1);
}
catch (std::exception& e)
{
@ -235,7 +269,7 @@ int main(int argc, char* argv[])
if (c == 'q')
{
entry data = handles.front().write_resume_data();
// TODO: use a torrent-specific name here
std::ofstream out("test.fastresume", std::ios_base::binary);
out.unsetf(std::ios_base::skipws);
bencode(std::ostream_iterator<char>(out), data);
@ -303,7 +337,7 @@ int main(int argc, char* argv[])
<< "(" << add_suffix(total_down) << ") "
<< "u:" << add_suffix(up) << "/s "
<< "(" << add_suffix(total_up) << ") "
<< "diff: " << add_suffix(total_down - total_up) << "\n";
<< "ratio: " << ratio(total_down, total_up) << "\n";
boost::posix_time::time_duration t = s.next_announce;
out << "next announce: " << boost::posix_time::to_simple_string(t) << "\n";
@ -316,7 +350,7 @@ int main(int argc, char* argv[])
<< "(" << add_suffix(i->total_download) << ") "
<< "u: " << add_suffix(i->up_speed) << "/s "
<< "(" << add_suffix(i->total_upload) << ") "
<< "df: " << add_suffix((int)i->total_download - (int)i->total_upload) << " "
<< "df: " << ratio(i->total_download, i->total_upload) << " "
<< "f: "
<< static_cast<const char*>((i->flags & peer_info::interesting)?"I":"_")
<< static_cast<const char*>((i->flags & peer_info::choked)?"C":"_")

View File

@ -152,49 +152,49 @@ namespace libtorrent
integer_type& integer()
{
if (m_type != int_t) throw type_error("invalid typ requested from entry");
if (m_type != int_t) throw type_error("invalid type requested from entry");
return *reinterpret_cast<integer_type*>(data);
}
const integer_type& integer() const
{
if (m_type != int_t) throw type_error("invalid typ requested from entry");
if (m_type != int_t) throw type_error("invalid type requested from entry");
return *reinterpret_cast<const integer_type*>(data);
}
string_type& string()
{
if (m_type != string_t) throw type_error("invalid typ requested from entry");
if (m_type != string_t) throw type_error("invalid type requested from entry");
return *reinterpret_cast<string_type*>(data);
}
const string_type& string() const
{
if (m_type != string_t) throw type_error("invalid typ requested from entry");
if (m_type != string_t) throw type_error("invalid type requested from entry");
return *reinterpret_cast<const string_type*>(data);
}
list_type& list()
{
if (m_type != list_t) throw type_error("invalid typ requested from entry");
if (m_type != list_t) throw type_error("invalid type requested from entry");
return *reinterpret_cast<list_type*>(data);
}
const list_type& list() const
{
if (m_type != list_t) throw type_error("invalid typ requested from entry");
if (m_type != list_t) throw type_error("invalid type requested from entry");
return *reinterpret_cast<const list_type*>(data);
}
dictionary_type& dict()
{
if (m_type != dictionary_t) throw type_error("invalid typ requested from entry");
if (m_type != dictionary_t) throw type_error("invalid type requested from entry");
return *reinterpret_cast<dictionary_type*>(data);
}
const dictionary_type& dict() const
{
if (m_type != dictionary_t) throw type_error("invalid typ requested from entry");
if (m_type != dictionary_t) throw type_error("invalid type requested from entry");
return *reinterpret_cast<const dictionary_type*>(data);
}

View File

@ -324,12 +324,7 @@ namespace libtorrent
int send_quota_limit() const
{ return m_send_quota_limit; }
int share_diff() const
{
return m_free_upload
+ m_statistics.total_payload_download()
- m_statistics.total_payload_upload();
}
int share_diff() const;
bool support_extensions() const
{ return m_supports_extensions; }

View File

@ -40,6 +40,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/peer.hpp"
#include "libtorrent/piece_picker.hpp"
#include "libtorrent/socket.hpp"
namespace libtorrent
{
@ -104,13 +105,13 @@ namespace libtorrent
struct peer
{
peer(const peer_id& pid);
peer(const peer_id& pid, const address& a);
int total_download() const;
int total_upload() const;
bool operator==(const peer_id& pid) const
{ return id == pid; }
bool operator==(const address& pip) const
{ return ip == pip; }
// the id of the peer. This is needed to store information
// about peers that aren't connected right now. This
@ -118,6 +119,9 @@ namespace libtorrent
// will be saved a limited amount of time
peer_id id;
// the ip/port pair this peer is or was connected on
address ip;
// the time when this peer was optimistically unchoked
// the last time.
boost::posix_time::ptime last_optimistically_unchoked;

View File

@ -118,8 +118,10 @@ namespace libtorrent
void parse_resume_data(
const entry& rd
, const torrent_info& info);
std::vector<int> piece_map;
std::vector<piece_picker::downloading_piece> unfinished_pieces;
std::vector<address> peers;
// is filled in by storage::initialize_pieces()
// and represents the progress. It should be a

View File

@ -95,6 +95,7 @@ namespace libtorrent
, std::vector<bool>& pieces);
void allocate_slots(int num_slots);
void mark_failed(int index);
size_type read(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);

View File

@ -154,6 +154,12 @@ namespace libtorrent
piece_manager& filesystem() { return m_storage; }
void set_ratio(float ratio)
{ m_ratio = ratio; }
float ratio() const
{ return m_ratio; }
// --------------------------------------------
// PEER MANAGEMENT
@ -347,6 +353,11 @@ namespace libtorrent
// true when the first tracker reponse
// is received
bool m_got_tracker_response;
// the upload/download ratio that each peer
// tries to maintain.
// 0 is infinite
float m_ratio;
};
}

View File

@ -146,6 +146,10 @@ namespace libtorrent
// manually connect a peer
void connect_peer(const address& adr) const;
// valid ratios are 0 (infinite ratio) or [ 1.0 , inf )
// the ratio is uploaded / downloaded. less than 1 is not allowed
void set_ratio(float up_down_ratio);
// TODO: add finish_file_allocation, which will force the
// torrent to allocate storage for all pieces.

View File

@ -123,6 +123,7 @@ namespace libtorrent
new (data) dictionary_type;
break;
default:
assert(m_type == undefined_t);
m_type = undefined_t;
}
}
@ -166,6 +167,7 @@ namespace libtorrent
call_destructor(reinterpret_cast<dictionary_type*>(data));
break;
default:
assert(m_type == undefined_t);
break;
}
}

View File

@ -703,6 +703,15 @@ namespace libtorrent
m_extension_messages[i] = f->second.integer();
}
}
#ifndef NDEBUG
(*m_logger) << "supported extensions:\n";
for (entry::dictionary_type::const_iterator i = extensions.begin();
i != extensions.end();
++i)
{
(*m_logger) << i->first << "\n";
}
#endif
}
catch(invalid_encoding& e)
{
@ -1037,6 +1046,20 @@ namespace libtorrent
send_buffer_updated();
}
int peer_connection::share_diff() const
{
float ratio = m_torrent->ratio();
// if we have an infinite ratio, just say we have downloaded
// much more than we have uploaded. And we'll keep uploading.
if (ratio == 0.f) return 99999.f;
return m_free_upload
+ (m_statistics.total_payload_download() * ratio)
- m_statistics.total_payload_upload();
}
void peer_connection::second_tick()
{
m_statistics.second_tick();
@ -1060,6 +1083,7 @@ namespace libtorrent
}
else
{
float ratio = m_torrent->ratio();
// if we have downloaded too much, response with an
// upload rate of 10 kB/s more than we dowlload
// if we have uploaded too much, send with a rate of
@ -1067,16 +1091,21 @@ namespace libtorrent
int bias = 0;
if (diff > -2*m_torrent->block_size())
{
bias = m_statistics.download_rate() / 2;
bias = (m_statistics.download_rate() * ratio) / 2;
if (bias < 10*1024) bias = 10*1024;
}
else
{
bias = -m_statistics.download_rate() / 2;
bias = -(m_statistics.download_rate() * ratio) / 2;
}
m_send_quota_limit = m_statistics.download_rate() + bias;
// the maximum send_quota given our download rate from this peer
if (m_send_quota_limit < 256) m_send_quota_limit = 256;
// if the peer has been choked, send tha current piece
// as fast as possible
if (is_choked()) m_send_quota_limit = -1;
}
}

View File

@ -39,6 +39,10 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/socket.hpp"
#include "libtorrent/peer_connection.hpp"
// TODO: move all alerts to a single header
// session.hpp is included just for the peer_error_alert
#include "libtorrent/session.hpp"
#if defined(_MSC_VER) && _MSC_VER < 1300
# define for if (false) {} else for
#endif
@ -445,7 +449,8 @@ namespace libtorrent
void policy::ban_peer(const peer_connection& c)
{
std::vector<peer>::iterator i = std::find(m_peers.begin(), m_peers.end(), c.get_peer_id());
std::vector<peer>::iterator i =
std::find(m_peers.begin(), m_peers.end(), c.get_socket()->sender());
assert(i != m_peers.end());
i->banned = true;
@ -454,7 +459,7 @@ namespace libtorrent
bool policy::new_connection(peer_connection& c)
{
std::vector<peer>::iterator i
= std::find(m_peers.begin(), m_peers.end(), c.get_peer_id());
= std::find(m_peers.begin(), m_peers.end(), c.get_socket()->sender());
if (i == m_peers.end())
{
using namespace boost::posix_time;
@ -462,7 +467,7 @@ namespace libtorrent
// we don't have ny info about this peer.
// add a new entry
peer p(c.get_peer_id());
peer p(c.get_peer_id(), c.get_socket()->sender());
m_peers.push_back(p);
i = m_peers.end()-1;
}
@ -481,7 +486,8 @@ namespace libtorrent
{
try
{
std::vector<peer>::iterator i = std::find(m_peers.begin(), m_peers.end(), id);
std::vector<peer>::iterator i =
std::find(m_peers.begin(), m_peers.end(), remote);
if (i == m_peers.end())
{
using namespace boost::posix_time;
@ -489,7 +495,7 @@ namespace libtorrent
// we don't have ny info about this peer.
// add a new entry
peer p(id);
peer p(id, remote);
m_peers.push_back(p);
i = m_peers.end()-1;
}
@ -508,8 +514,22 @@ namespace libtorrent
i->connection = &m_torrent->connect_to_peer(remote, id);
}
catch(network_error&) {}
catch(protocol_error&) {}
catch(network_error& e)
{
if (m_torrent->alerts().should_post(alert::debug))
{
m_torrent->alerts().post_alert(
peer_error_alert(id, e.what()));
}
}
catch(protocol_error& e)
{
if (m_torrent->alerts().should_post(alert::debug))
{
m_torrent->alerts().post_alert(
peer_error_alert(id, e.what()));
}
}
}
// this is called when we are choked by a peer
@ -599,7 +619,7 @@ namespace libtorrent
void policy::connection_closed(const peer_connection& c)
{
std::vector<peer>::iterator i
= std::find(m_peers.begin(), m_peers.end(), c.get_peer_id());
= std::find(m_peers.begin(), m_peers.end(), c.get_socket()->sender());
assert(i != m_peers.end());
@ -631,7 +651,8 @@ namespace libtorrent
#ifndef NDEBUG
bool policy::has_connection(const peer_connection* p)
{
return std::find(m_peers.begin(), m_peers.end(), p->get_peer_id()) != m_peers.end();
return std::find(m_peers.begin(), m_peers.end(), p->get_socket()->sender())
!= m_peers.end();
}
void policy::check_invariant()
@ -649,8 +670,11 @@ namespace libtorrent
}
#endif
policy::peer::peer(const peer_id& pid)
policy::peer::peer(
const peer_id& pid
, const address& a)
: id(pid)
, ip(a)
, last_optimistically_unchoked(
boost::gregorian::date(1970,boost::gregorian::Jan,1))
, connected(boost::posix_time::second_clock::local_time())

View File

@ -296,6 +296,15 @@ namespace libtorrent
m_ses->m_torrents.insert(
std::make_pair(t->info_hash, t->torrent_ptr)).first;
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);
}
}
}
catch(const std::exception& e)
@ -891,9 +900,6 @@ namespace libtorrent
// if we don't have any resume data, return
if (resume_data.type() == entry::undefined_t) return;
std::vector<int> tmp_pieces;
std::vector<piece_picker::downloading_piece> tmp_unfinished;
entry rd = resume_data;
try
@ -915,6 +921,7 @@ namespace libtorrent
if (slots.size() > info.num_pieces())
return;
std::vector<int> tmp_pieces;
tmp_pieces.reserve(slots.size());
for (entry::list_type::const_iterator i = slots.begin();
i != slots.end();
@ -931,8 +938,11 @@ namespace libtorrent
if (num_blocks_per_piece > 128 || num_blocks_per_piece < 1)
return;
// the unfinished pieces
const entry::list_type& unfinished = rd.dict()["unfinished"].list();
std::vector<piece_picker::downloading_piece> tmp_unfinished;
tmp_unfinished.reserve(unfinished.size());
for (entry::list_type::const_iterator i = unfinished.begin();
i != unfinished.end();
@ -962,6 +972,21 @@ namespace libtorrent
tmp_unfinished.push_back(p);
}
// the peers
entry::list_type& peer_list = rd.dict()["peers"].list();
std::vector<address> tmp_peers;
tmp_peers.reserve(peer_list.size());
for (entry::list_type::iterator i = peer_list.begin();
i != peer_list.end();
++i)
{
address a(i->dict()["ip"].string(), i->dict()["port"].integer());
tmp_peers.push_back(a);
}
peers.swap(tmp_peers);
piece_map.swap(tmp_pieces);
unfinished_pieces.swap(tmp_unfinished);
}
@ -974,78 +999,4 @@ namespace libtorrent
return;
}
}
/*
void detail::piece_checker_data::parse_resume_data(
const std::vector<char>* rd
, const torrent_info& info)
{
piece_map.clear();
unfinished_pieces.clear();
std::vector<int> tmp_pieces;
std::vector<piece_picker::downloading_piece> tmp_unfinished;
if (rd == 0) return;
const std::vector<char>& data = *rd;
if (data.size() < 20 + 3 * 4) return;
std::vector<char>::const_iterator ptr = data.begin();
sha1_hash info_hash;
for (int i = 0; i < 20; ++i) info_hash[i] = read_uchar(ptr);
if (info.info_hash() != info_hash) return;
int num_slots = detail::read_int(ptr);
if (num_slots < 0) return;
if (data.size() < 20 + (3 + num_slots) * 4) return;
tmp_pieces.reserve(num_slots);
for (int i = 0; i < num_slots; ++i)
{
int index = read_int(ptr);
if (index >= info.num_pieces() || index < -2)
return;
tmp_pieces.push_back(index);
}
int num_blocks_per_piece = read_int(ptr);
if (num_blocks_per_piece > 128 || num_blocks_per_piece < 1)
return;
int num_unfinished = read_int(ptr);
if (num_unfinished < 0) return;
if (data.size() != 20 + (1 + num_slots + 2 + num_unfinished) * 4 + num_unfinished * (num_blocks_per_piece / 8))
return;
tmp_unfinished.reserve(num_unfinished);
for (int i = 0; i < num_unfinished; ++i)
{
piece_picker::downloading_piece p;
p.index = detail::read_int(ptr);
p.finished_blocks.reset();
p.requested_blocks.reset();
if (p.index < 0
|| p.index >= info.num_pieces())
return;
const int num_bitmask_bytes = std::max(num_blocks_per_piece / 8, 1);
for (int j = 0; j < num_bitmask_bytes; ++j)
{
unsigned char bits = read_uchar(ptr);
for (int k = 0; k < 8; ++k)
{
const int bit = j * 8 + k;
if (bits & (1 << k))
p.finished_blocks[bit] = true;
}
}
tmp_unfinished.push_back(p);
}
piece_map.swap(tmp_pieces);
unfinished_pieces.swap(tmp_unfinished);
}
*/
}

View File

@ -359,6 +359,7 @@ namespace libtorrent {
, std::vector<bool>& pieces);
void allocate_slots(int num_slots);
void mark_failed(int index);
size_type read(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);
@ -432,6 +433,10 @@ namespace libtorrent {
void piece_manager::impl::export_piece_map(
std::vector<int>& p) const
{
// synchronization ------------------------------------------------------
boost::recursive_mutex::scoped_lock lock(m_mutex);
// ----------------------------------------------------------------------
p.clear();
std::vector<int>::const_reverse_iterator last;
for (last = m_slot_to_piece.rbegin();
@ -455,8 +460,32 @@ namespace libtorrent {
{
m_pimpl->export_piece_map(p);
}
// TODO: daniel, make sure this function does everything it needs to do
void piece_manager::impl::mark_failed(int index)
{
// synchronization ------------------------------------------------------
boost::recursive_mutex::scoped_lock lock(m_mutex);
// ----------------------------------------------------------------------
assert(index >= 0 && index < m_piece_to_slot.size());
assert(m_piece_to_slot[index] >= 0);
int slot = m_slot_to_piece[m_piece_to_slot[index]];
assert(slot >= 0);
m_slot_to_piece[m_piece_to_slot[index]] = -2;
m_piece_to_slot[index] = -1;
m_free_slots.push_back(slot);
}
void piece_manager::mark_failed(int index)
{
m_pimpl->mark_failed(index);
}
piece_manager::size_type piece_manager::impl::read(
char* buf
, int piece_index

View File

@ -100,11 +100,18 @@ namespace
const entry::dictionary_type& info = e.dict();
// extract peer id
// extract peer id (if any)
entry::dictionary_type::const_iterator i = info.find("peer id");
if (i == info.end()) throw std::runtime_error("invalid response from tracker");
if (i->second.string().length() != 20) throw std::runtime_error("invalid response from tracker");
std::copy(i->second.string().begin(), i->second.string().end(), ret.id.begin());
if (i != info.end())
{
if (i->second.string().length() != 20) throw std::runtime_error("invalid response from tracker");
std::copy(i->second.string().begin(), i->second.string().end(), ret.id.begin());
}
else
{
// if there's no peer_id, just initialize it to a bunch of zeroes
std::fill_n(ret.id.begin(), 20, 0);
}
// extract ip
i = info.find("ip");
@ -146,14 +153,17 @@ namespace
return ret.str();
}
struct find_peer
struct find_peer_by_id
{
find_peer(const peer_id& i, const torrent* t): id(i), tor(t) {}
find_peer_by_id(const peer_id& i, const torrent* t): id(i), tor(t) {}
bool operator()(const detail::session_impl::connection_map::value_type& c) const
{
if (c.second->get_peer_id() != id) return false;
if (tor != c.second->associated_torrent()) return false;
// have a special case for all zeros. We can have any number
// of peers with that id, since it's used to indicate no id.
if (std::count(id.begin(), id.end(), 0) == 20) return false;
return true;
}
@ -161,12 +171,31 @@ namespace
{
if (p->get_peer_id() != id) return false;
if (tor != p->associated_torrent()) return false;
// have a special case for all zeros. We can have any number
// of peers with that id, since it's used to indicate no id.
if (std::count(id.begin(), id.end(), 0) == 20) return false;
return true;
}
const peer_id& id;
const torrent* tor;
};
struct find_peer_by_ip
{
find_peer_by_ip(const address& a, const torrent* t): ip(a), tor(t) {}
bool operator()(const detail::session_impl::connection_map::value_type& c) const
{
if (c.first->sender() != ip) return false;
if (tor != c.second->associated_torrent()) return false;
return true;
}
const address& ip;
const torrent* tor;
};
}
namespace libtorrent
@ -193,6 +222,7 @@ namespace libtorrent
, m_priority(.5)
, m_num_pieces(0)
, m_got_tracker_response(false)
, m_ratio(0.f)
{
assert(torrent_file.begin_files() != torrent_file.end_files());
m_have_pieces.resize(torrent_file.num_pieces(), false);
@ -246,9 +276,18 @@ namespace libtorrent
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_by_id(i->id, this)) != m_ses.m_connections.end())
{
continue;
}
if (std::find_if(
m_ses.m_connections.begin()
, m_ses.m_connections.end()
, find_peer_by_ip(a, this)) != m_ses.m_connections.end())
{
continue;
}
@ -273,12 +312,12 @@ namespace libtorrent
{
assert(std::count_if(m_connections.begin()
, m_connections.end()
, find_peer(id, this)) <= 1);
, find_peer_by_id(id, this)) <= 1);
return std::find_if(
m_connections.begin()
, m_connections.end()
, find_peer(id, this))
, find_peer_by_id(id, this))
!= m_connections.end();
}
@ -342,6 +381,7 @@ namespace libtorrent
// start with redownloading the pieces that the client
// that has sent the least number of pieces
m_picker.restore_piece(index);
m_storage.mark_failed(index);
// TODO: make sure restore_piece() works
assert(m_have_pieces[index] == false);
@ -407,6 +447,10 @@ namespace libtorrent
m_event = event_none;
}
// extension that tells the tracker that
// we don't need any peer_id's in the response
request += "&no_peer_id=1";
return request;
}
@ -495,7 +539,8 @@ namespace libtorrent
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()
assert(std::find(
m_connections.begin()
, m_connections.end()
, boost::get_pointer(p->second))
== m_connections.end());

View File

@ -207,7 +207,7 @@ namespace libtorrent
// num unfinished pieces
int num_unfinished = q.size();
ret.dict()["unfinished"] = entry(entry::list_t);
ret.dict()["unfinished"] = entry::list_type();
entry::list_type& up = ret.dict()["unfinished"].list();
// info for each unfinished piece
@ -237,6 +237,27 @@ namespace libtorrent
// push the struct onto the unfinished-piece list
up.push_back(piece_struct);
}
// write local peers
ret.dict()["peers"] = entry::list_type();
entry::list_type& peer_list = ret.dict()["peers"].list();
for (torrent::peer_const_iterator i = t->begin();
i != t->end();
++i)
{
// we cannot save remote connection
// since we don't know their listen port
if (!(*i)->is_local()) continue;
address ip = (*i)->get_socket()->sender();
entry::dictionary_type peer;
peer["ip"] = ip.as_string();
peer["port"] = ip.port();
peer_list.push_back(peer);
}
return ret;
}
@ -300,6 +321,35 @@ namespace libtorrent
t->force_tracker_request();
}
void torrent_handle::set_ratio(float ratio)
{
assert(ratio >= 0.f);
if (m_ses == 0) throw invalid_handle();
if (ratio < 1.f && ratio > 0.f)
ratio = 1.f;
{
boost::mutex::scoped_lock l(m_ses->m_mutex);
torrent* t = m_ses->find_torrent(m_info_hash);
if (t != 0)
{
t->set_ratio(ratio);
}
}
if (m_chk)
{
boost::mutex::scoped_lock l(m_chk->m_mutex);
detail::piece_checker_data* d = m_chk->find_torrent(m_info_hash);
if (d != 0)
{
d->torrent_ptr->set_ratio(ratio);
}
}
}
void torrent_handle::get_peer_info(std::vector<peer_info>& v) const
{
v.clear();