*** empty log message ***
This commit is contained in:
parent
b9bbf242c6
commit
9e979efb8b
|
@ -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: "libtorrent resume file"</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> </td>
|
||||
</tr>
|
||||
<tr><td><tt class="literal"><span class="pre">unfinished</span></tt></td>
|
||||
<td> </td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>TODO: describe the file format</p>
|
||||
</div>
|
||||
<div class="section" id="extensions">
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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":"_")
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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())
|
||||
|
|
105
src/session.cpp
105
src/session.cpp
|
@ -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);
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue