forked from premiere/premiere-libtorrent
*** empty log message ***
This commit is contained in:
parent
b9bbf242c6
commit
9e979efb8b
|
@ -473,6 +473,7 @@ struct torrent_handle
|
||||||
entry write_resume_data();
|
entry write_resume_data();
|
||||||
void force_reannounce();
|
void force_reannounce();
|
||||||
void connect_peer(const address& adr) const;
|
void connect_peer(const address& adr) const;
|
||||||
|
void set_ratio(float ratio);
|
||||||
|
|
||||||
boost::filsystem::path save_path() const;
|
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
|
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
|
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>
|
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">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
|
<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>
|
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>
|
||||||
<div class="section" id="file-format">
|
<div class="section" id="file-format">
|
||||||
<h1><a class="toc-backref" href="#id44" name="file-format">file format</a></h1>
|
<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>
|
<p>TODO: describe the file format</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="section" id="extensions">
|
<div class="section" id="extensions">
|
||||||
|
|
|
@ -471,6 +471,7 @@ Its declaration looks like this::
|
||||||
entry write_resume_data();
|
entry write_resume_data();
|
||||||
void force_reannounce();
|
void force_reannounce();
|
||||||
void connect_peer(const address& adr) const;
|
void connect_peer(const address& adr) const;
|
||||||
|
void set_ratio(float ratio);
|
||||||
|
|
||||||
boost::filsystem::path save_path() const;
|
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
|
attempt is made. If the torrent is uninitialized or in queued or checking mode, this
|
||||||
will throw invalid_handle_.
|
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.
|
``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
|
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
|
TODO: describe the file format
|
||||||
|
|
||||||
extensions
|
extensions
|
||||||
|
|
|
@ -147,6 +147,38 @@ std::string to_string(float v, int width)
|
||||||
return s.str();
|
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)
|
std::string add_suffix(float val)
|
||||||
{
|
{
|
||||||
const char* prefix[] = {"B", "kB", "MB", "GB", "TB"};
|
const char* prefix[] = {"B", "kB", "MB", "GB", "TB"};
|
||||||
|
@ -207,6 +239,7 @@ int main(int argc, char* argv[])
|
||||||
entry resume_data;
|
entry resume_data;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
// TODO: use a torrent-specific name here
|
||||||
std::ifstream resume_file("test.fastresume", std::ios_base::binary);
|
std::ifstream resume_file("test.fastresume", std::ios_base::binary);
|
||||||
resume_file.unsetf(std::ios_base::skipws);
|
resume_file.unsetf(std::ios_base::skipws);
|
||||||
resume_data = bdecode(std::istream_iterator<char>(resume_file)
|
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.push_back(ses.add_torrent(t, "", resume_data));
|
||||||
handles.back().set_max_uploads(7);
|
handles.back().set_max_uploads(7);
|
||||||
|
handles.back().set_ratio(1);
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
|
@ -235,7 +269,7 @@ int main(int argc, char* argv[])
|
||||||
if (c == 'q')
|
if (c == 'q')
|
||||||
{
|
{
|
||||||
entry data = handles.front().write_resume_data();
|
entry data = handles.front().write_resume_data();
|
||||||
|
// TODO: use a torrent-specific name here
|
||||||
std::ofstream out("test.fastresume", std::ios_base::binary);
|
std::ofstream out("test.fastresume", std::ios_base::binary);
|
||||||
out.unsetf(std::ios_base::skipws);
|
out.unsetf(std::ios_base::skipws);
|
||||||
bencode(std::ostream_iterator<char>(out), data);
|
bencode(std::ostream_iterator<char>(out), data);
|
||||||
|
@ -303,7 +337,7 @@ int main(int argc, char* argv[])
|
||||||
<< "(" << add_suffix(total_down) << ") "
|
<< "(" << add_suffix(total_down) << ") "
|
||||||
<< "u:" << add_suffix(up) << "/s "
|
<< "u:" << add_suffix(up) << "/s "
|
||||||
<< "(" << add_suffix(total_up) << ") "
|
<< "(" << 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;
|
boost::posix_time::time_duration t = s.next_announce;
|
||||||
out << "next announce: " << boost::posix_time::to_simple_string(t) << "\n";
|
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) << ") "
|
<< "(" << add_suffix(i->total_download) << ") "
|
||||||
<< "u: " << add_suffix(i->up_speed) << "/s "
|
<< "u: " << add_suffix(i->up_speed) << "/s "
|
||||||
<< "(" << add_suffix(i->total_upload) << ") "
|
<< "(" << 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: "
|
<< "f: "
|
||||||
<< 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":"_")
|
||||||
|
|
|
@ -152,49 +152,49 @@ namespace libtorrent
|
||||||
|
|
||||||
integer_type& integer()
|
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);
|
return *reinterpret_cast<integer_type*>(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
const integer_type& integer() const
|
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);
|
return *reinterpret_cast<const integer_type*>(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
string_type& string()
|
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);
|
return *reinterpret_cast<string_type*>(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
const string_type& string() const
|
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);
|
return *reinterpret_cast<const string_type*>(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
list_type& list()
|
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);
|
return *reinterpret_cast<list_type*>(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
const list_type& list() const
|
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);
|
return *reinterpret_cast<const list_type*>(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
dictionary_type& dict()
|
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);
|
return *reinterpret_cast<dictionary_type*>(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
const dictionary_type& dict() const
|
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);
|
return *reinterpret_cast<const dictionary_type*>(data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -324,12 +324,7 @@ namespace libtorrent
|
||||||
int send_quota_limit() const
|
int send_quota_limit() const
|
||||||
{ return m_send_quota_limit; }
|
{ return m_send_quota_limit; }
|
||||||
|
|
||||||
int share_diff() const
|
int share_diff() const;
|
||||||
{
|
|
||||||
return m_free_upload
|
|
||||||
+ m_statistics.total_payload_download()
|
|
||||||
- m_statistics.total_payload_upload();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool support_extensions() const
|
bool support_extensions() const
|
||||||
{ return m_supports_extensions; }
|
{ return m_supports_extensions; }
|
||||||
|
|
|
@ -40,6 +40,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
#include "libtorrent/peer.hpp"
|
#include "libtorrent/peer.hpp"
|
||||||
#include "libtorrent/piece_picker.hpp"
|
#include "libtorrent/piece_picker.hpp"
|
||||||
|
#include "libtorrent/socket.hpp"
|
||||||
|
|
||||||
namespace libtorrent
|
namespace libtorrent
|
||||||
{
|
{
|
||||||
|
@ -104,13 +105,13 @@ namespace libtorrent
|
||||||
|
|
||||||
struct peer
|
struct peer
|
||||||
{
|
{
|
||||||
peer(const peer_id& pid);
|
peer(const peer_id& pid, const address& a);
|
||||||
|
|
||||||
int total_download() const;
|
int total_download() const;
|
||||||
int total_upload() const;
|
int total_upload() const;
|
||||||
|
|
||||||
bool operator==(const peer_id& pid) const
|
bool operator==(const address& pip) const
|
||||||
{ return id == pid; }
|
{ return ip == pip; }
|
||||||
|
|
||||||
// the id of the peer. This is needed to store information
|
// the id of the peer. This is needed to store information
|
||||||
// about peers that aren't connected right now. This
|
// about peers that aren't connected right now. This
|
||||||
|
@ -118,6 +119,9 @@ namespace libtorrent
|
||||||
// will be saved a limited amount of time
|
// will be saved a limited amount of time
|
||||||
peer_id id;
|
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 time when this peer was optimistically unchoked
|
||||||
// the last time.
|
// the last time.
|
||||||
boost::posix_time::ptime last_optimistically_unchoked;
|
boost::posix_time::ptime last_optimistically_unchoked;
|
||||||
|
|
|
@ -118,8 +118,10 @@ namespace libtorrent
|
||||||
void parse_resume_data(
|
void parse_resume_data(
|
||||||
const entry& rd
|
const entry& rd
|
||||||
, const torrent_info& info);
|
, const torrent_info& info);
|
||||||
|
|
||||||
std::vector<int> piece_map;
|
std::vector<int> piece_map;
|
||||||
std::vector<piece_picker::downloading_piece> unfinished_pieces;
|
std::vector<piece_picker::downloading_piece> unfinished_pieces;
|
||||||
|
std::vector<address> peers;
|
||||||
|
|
||||||
// is filled in by storage::initialize_pieces()
|
// is filled in by storage::initialize_pieces()
|
||||||
// and represents the progress. It should be a
|
// and represents the progress. It should be a
|
||||||
|
|
|
@ -95,6 +95,7 @@ namespace libtorrent
|
||||||
, std::vector<bool>& pieces);
|
, std::vector<bool>& pieces);
|
||||||
|
|
||||||
void allocate_slots(int num_slots);
|
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);
|
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);
|
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; }
|
piece_manager& filesystem() { return m_storage; }
|
||||||
|
|
||||||
|
void set_ratio(float ratio)
|
||||||
|
{ m_ratio = ratio; }
|
||||||
|
|
||||||
|
float ratio() const
|
||||||
|
{ return m_ratio; }
|
||||||
|
|
||||||
// --------------------------------------------
|
// --------------------------------------------
|
||||||
// PEER MANAGEMENT
|
// PEER MANAGEMENT
|
||||||
|
|
||||||
|
@ -347,6 +353,11 @@ namespace libtorrent
|
||||||
// true when the first tracker reponse
|
// true when the first tracker reponse
|
||||||
// is received
|
// is received
|
||||||
bool m_got_tracker_response;
|
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
|
// manually connect a peer
|
||||||
void connect_peer(const address& adr) const;
|
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
|
// TODO: add finish_file_allocation, which will force the
|
||||||
// torrent to allocate storage for all pieces.
|
// torrent to allocate storage for all pieces.
|
||||||
|
|
||||||
|
|
|
@ -123,6 +123,7 @@ namespace libtorrent
|
||||||
new (data) dictionary_type;
|
new (data) dictionary_type;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
assert(m_type == undefined_t);
|
||||||
m_type = undefined_t;
|
m_type = undefined_t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -166,6 +167,7 @@ namespace libtorrent
|
||||||
call_destructor(reinterpret_cast<dictionary_type*>(data));
|
call_destructor(reinterpret_cast<dictionary_type*>(data));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
assert(m_type == undefined_t);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -703,6 +703,15 @@ namespace libtorrent
|
||||||
m_extension_messages[i] = f->second.integer();
|
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)
|
catch(invalid_encoding& e)
|
||||||
{
|
{
|
||||||
|
@ -1037,6 +1046,20 @@ namespace libtorrent
|
||||||
send_buffer_updated();
|
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()
|
void peer_connection::second_tick()
|
||||||
{
|
{
|
||||||
m_statistics.second_tick();
|
m_statistics.second_tick();
|
||||||
|
@ -1060,6 +1083,7 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
float ratio = m_torrent->ratio();
|
||||||
// if we have downloaded too much, response with an
|
// if we have downloaded too much, response with an
|
||||||
// upload rate of 10 kB/s more than we dowlload
|
// upload rate of 10 kB/s more than we dowlload
|
||||||
// if we have uploaded too much, send with a rate of
|
// if we have uploaded too much, send with a rate of
|
||||||
|
@ -1067,16 +1091,21 @@ namespace libtorrent
|
||||||
int bias = 0;
|
int bias = 0;
|
||||||
if (diff > -2*m_torrent->block_size())
|
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;
|
if (bias < 10*1024) bias = 10*1024;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
bias = -m_statistics.download_rate() / 2;
|
bias = -(m_statistics.download_rate() * ratio) / 2;
|
||||||
}
|
}
|
||||||
m_send_quota_limit = m_statistics.download_rate() + bias;
|
m_send_quota_limit = m_statistics.download_rate() + bias;
|
||||||
|
|
||||||
// the maximum send_quota given our download rate from this peer
|
// the maximum send_quota given our download rate from this peer
|
||||||
if (m_send_quota_limit < 256) m_send_quota_limit = 256;
|
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/socket.hpp"
|
||||||
#include "libtorrent/peer_connection.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
|
#if defined(_MSC_VER) && _MSC_VER < 1300
|
||||||
# define for if (false) {} else for
|
# define for if (false) {} else for
|
||||||
#endif
|
#endif
|
||||||
|
@ -445,7 +449,8 @@ namespace libtorrent
|
||||||
|
|
||||||
void policy::ban_peer(const peer_connection& c)
|
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());
|
assert(i != m_peers.end());
|
||||||
|
|
||||||
i->banned = true;
|
i->banned = true;
|
||||||
|
@ -454,7 +459,7 @@ namespace libtorrent
|
||||||
bool policy::new_connection(peer_connection& c)
|
bool policy::new_connection(peer_connection& c)
|
||||||
{
|
{
|
||||||
std::vector<peer>::iterator i
|
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())
|
if (i == m_peers.end())
|
||||||
{
|
{
|
||||||
using namespace boost::posix_time;
|
using namespace boost::posix_time;
|
||||||
|
@ -462,7 +467,7 @@ namespace libtorrent
|
||||||
|
|
||||||
// we don't have ny info about this peer.
|
// we don't have ny info about this peer.
|
||||||
// add a new entry
|
// 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);
|
m_peers.push_back(p);
|
||||||
i = m_peers.end()-1;
|
i = m_peers.end()-1;
|
||||||
}
|
}
|
||||||
|
@ -481,7 +486,8 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
try
|
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())
|
if (i == m_peers.end())
|
||||||
{
|
{
|
||||||
using namespace boost::posix_time;
|
using namespace boost::posix_time;
|
||||||
|
@ -489,7 +495,7 @@ namespace libtorrent
|
||||||
|
|
||||||
// we don't have ny info about this peer.
|
// we don't have ny info about this peer.
|
||||||
// add a new entry
|
// add a new entry
|
||||||
peer p(id);
|
peer p(id, remote);
|
||||||
m_peers.push_back(p);
|
m_peers.push_back(p);
|
||||||
i = m_peers.end()-1;
|
i = m_peers.end()-1;
|
||||||
}
|
}
|
||||||
|
@ -508,8 +514,22 @@ namespace libtorrent
|
||||||
i->connection = &m_torrent->connect_to_peer(remote, id);
|
i->connection = &m_torrent->connect_to_peer(remote, id);
|
||||||
|
|
||||||
}
|
}
|
||||||
catch(network_error&) {}
|
catch(network_error& e)
|
||||||
catch(protocol_error&) {}
|
{
|
||||||
|
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
|
// this is called when we are choked by a peer
|
||||||
|
@ -599,7 +619,7 @@ namespace libtorrent
|
||||||
void policy::connection_closed(const peer_connection& c)
|
void policy::connection_closed(const peer_connection& c)
|
||||||
{
|
{
|
||||||
std::vector<peer>::iterator i
|
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());
|
assert(i != m_peers.end());
|
||||||
|
|
||||||
|
@ -631,7 +651,8 @@ namespace libtorrent
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
bool policy::has_connection(const peer_connection* p)
|
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()
|
void policy::check_invariant()
|
||||||
|
@ -649,8 +670,11 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
policy::peer::peer(const peer_id& pid)
|
policy::peer::peer(
|
||||||
|
const peer_id& pid
|
||||||
|
, const address& a)
|
||||||
: id(pid)
|
: id(pid)
|
||||||
|
, ip(a)
|
||||||
, last_optimistically_unchoked(
|
, last_optimistically_unchoked(
|
||||||
boost::gregorian::date(1970,boost::gregorian::Jan,1))
|
boost::gregorian::date(1970,boost::gregorian::Jan,1))
|
||||||
, connected(boost::posix_time::second_clock::local_time())
|
, 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(
|
m_ses->m_torrents.insert(
|
||||||
std::make_pair(t->info_hash, t->torrent_ptr)).first;
|
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)
|
catch(const std::exception& e)
|
||||||
|
@ -891,9 +900,6 @@ namespace libtorrent
|
||||||
// if we don't have any resume data, return
|
// if we don't have any resume data, return
|
||||||
if (resume_data.type() == entry::undefined_t) 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;
|
entry rd = resume_data;
|
||||||
|
|
||||||
try
|
try
|
||||||
|
@ -915,6 +921,7 @@ namespace libtorrent
|
||||||
if (slots.size() > info.num_pieces())
|
if (slots.size() > info.num_pieces())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
std::vector<int> tmp_pieces;
|
||||||
tmp_pieces.reserve(slots.size());
|
tmp_pieces.reserve(slots.size());
|
||||||
for (entry::list_type::const_iterator i = slots.begin();
|
for (entry::list_type::const_iterator i = slots.begin();
|
||||||
i != slots.end();
|
i != slots.end();
|
||||||
|
@ -931,8 +938,11 @@ namespace libtorrent
|
||||||
if (num_blocks_per_piece > 128 || num_blocks_per_piece < 1)
|
if (num_blocks_per_piece > 128 || num_blocks_per_piece < 1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// the unfinished pieces
|
||||||
|
|
||||||
const entry::list_type& unfinished = rd.dict()["unfinished"].list();
|
const entry::list_type& unfinished = rd.dict()["unfinished"].list();
|
||||||
|
|
||||||
|
std::vector<piece_picker::downloading_piece> tmp_unfinished;
|
||||||
tmp_unfinished.reserve(unfinished.size());
|
tmp_unfinished.reserve(unfinished.size());
|
||||||
for (entry::list_type::const_iterator i = unfinished.begin();
|
for (entry::list_type::const_iterator i = unfinished.begin();
|
||||||
i != unfinished.end();
|
i != unfinished.end();
|
||||||
|
@ -962,6 +972,21 @@ namespace libtorrent
|
||||||
tmp_unfinished.push_back(p);
|
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);
|
piece_map.swap(tmp_pieces);
|
||||||
unfinished_pieces.swap(tmp_unfinished);
|
unfinished_pieces.swap(tmp_unfinished);
|
||||||
}
|
}
|
||||||
|
@ -974,78 +999,4 @@ namespace libtorrent
|
||||||
return;
|
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);
|
, std::vector<bool>& pieces);
|
||||||
|
|
||||||
void allocate_slots(int num_slots);
|
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);
|
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);
|
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(
|
void piece_manager::impl::export_piece_map(
|
||||||
std::vector<int>& p) const
|
std::vector<int>& p) const
|
||||||
{
|
{
|
||||||
|
// synchronization ------------------------------------------------------
|
||||||
|
boost::recursive_mutex::scoped_lock lock(m_mutex);
|
||||||
|
// ----------------------------------------------------------------------
|
||||||
|
|
||||||
p.clear();
|
p.clear();
|
||||||
std::vector<int>::const_reverse_iterator last;
|
std::vector<int>::const_reverse_iterator last;
|
||||||
for (last = m_slot_to_piece.rbegin();
|
for (last = m_slot_to_piece.rbegin();
|
||||||
|
@ -456,6 +461,30 @@ namespace libtorrent {
|
||||||
m_pimpl->export_piece_map(p);
|
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(
|
piece_manager::size_type piece_manager::impl::read(
|
||||||
char* buf
|
char* buf
|
||||||
|
|
|
@ -100,11 +100,18 @@ namespace
|
||||||
|
|
||||||
const entry::dictionary_type& info = e.dict();
|
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");
|
entry::dictionary_type::const_iterator i = info.find("peer id");
|
||||||
if (i == info.end()) throw std::runtime_error("invalid response from tracker");
|
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());
|
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
|
// extract ip
|
||||||
i = info.find("ip");
|
i = info.find("ip");
|
||||||
|
@ -146,14 +153,17 @@ namespace
|
||||||
return ret.str();
|
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
|
bool operator()(const detail::session_impl::connection_map::value_type& c) const
|
||||||
{
|
{
|
||||||
if (c.second->get_peer_id() != id) return false;
|
if (c.second->get_peer_id() != id) return false;
|
||||||
if (tor != c.second->associated_torrent()) 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,12 +171,31 @@ namespace
|
||||||
{
|
{
|
||||||
if (p->get_peer_id() != id) return false;
|
if (p->get_peer_id() != id) return false;
|
||||||
if (tor != p->associated_torrent()) 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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const peer_id& id;
|
const peer_id& id;
|
||||||
const torrent* tor;
|
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
|
namespace libtorrent
|
||||||
|
@ -193,6 +222,7 @@ namespace libtorrent
|
||||||
, m_priority(.5)
|
, m_priority(.5)
|
||||||
, m_num_pieces(0)
|
, m_num_pieces(0)
|
||||||
, m_got_tracker_response(false)
|
, m_got_tracker_response(false)
|
||||||
|
, m_ratio(0.f)
|
||||||
{
|
{
|
||||||
assert(torrent_file.begin_files() != torrent_file.end_files());
|
assert(torrent_file.begin_files() != torrent_file.end_files());
|
||||||
m_have_pieces.resize(torrent_file.num_pieces(), false);
|
m_have_pieces.resize(torrent_file.num_pieces(), false);
|
||||||
|
@ -246,9 +276,18 @@ namespace libtorrent
|
||||||
address a(i->ip, i->port);
|
address a(i->ip, i->port);
|
||||||
|
|
||||||
// if we aleady have a connection to the person, don't make another one
|
// if we aleady have a connection to the person, don't make another one
|
||||||
if (std::find_if(m_ses.m_connections.begin(),
|
if (std::find_if(
|
||||||
m_ses.m_connections.end(),
|
m_ses.m_connections.begin()
|
||||||
find_peer(i->id, this)) != m_ses.m_connections.end())
|
, 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;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -273,12 +312,12 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
assert(std::count_if(m_connections.begin()
|
assert(std::count_if(m_connections.begin()
|
||||||
, m_connections.end()
|
, m_connections.end()
|
||||||
, find_peer(id, this)) <= 1);
|
, find_peer_by_id(id, this)) <= 1);
|
||||||
|
|
||||||
return std::find_if(
|
return std::find_if(
|
||||||
m_connections.begin()
|
m_connections.begin()
|
||||||
, m_connections.end()
|
, m_connections.end()
|
||||||
, find_peer(id, this))
|
, find_peer_by_id(id, this))
|
||||||
!= m_connections.end();
|
!= m_connections.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -342,6 +381,7 @@ namespace libtorrent
|
||||||
// start with redownloading the pieces that the client
|
// start with redownloading the pieces that the client
|
||||||
// that has sent the least number of pieces
|
// that has sent the least number of pieces
|
||||||
m_picker.restore_piece(index);
|
m_picker.restore_piece(index);
|
||||||
|
m_storage.mark_failed(index);
|
||||||
|
|
||||||
// TODO: make sure restore_piece() works
|
// TODO: make sure restore_piece() works
|
||||||
assert(m_have_pieces[index] == false);
|
assert(m_have_pieces[index] == false);
|
||||||
|
@ -407,6 +447,10 @@ namespace libtorrent
|
||||||
m_event = event_none;
|
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;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -495,7 +539,8 @@ namespace libtorrent
|
||||||
m_ses.m_connections.insert(std::make_pair(s, c)).first;
|
m_ses.m_connections.insert(std::make_pair(s, c)).first;
|
||||||
|
|
||||||
// add the newly connected peer to this torrent's peer list
|
// 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()
|
, m_connections.end()
|
||||||
, boost::get_pointer(p->second))
|
, boost::get_pointer(p->second))
|
||||||
== m_connections.end());
|
== m_connections.end());
|
||||||
|
|
|
@ -207,7 +207,7 @@ namespace libtorrent
|
||||||
|
|
||||||
// num unfinished pieces
|
// num unfinished pieces
|
||||||
int num_unfinished = q.size();
|
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();
|
entry::list_type& up = ret.dict()["unfinished"].list();
|
||||||
|
|
||||||
// info for each unfinished piece
|
// info for each unfinished piece
|
||||||
|
@ -237,6 +237,27 @@ namespace libtorrent
|
||||||
// push the struct onto the unfinished-piece list
|
// push the struct onto the unfinished-piece list
|
||||||
up.push_back(piece_struct);
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -300,6 +321,35 @@ namespace libtorrent
|
||||||
t->force_tracker_request();
|
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
|
void torrent_handle::get_peer_info(std::vector<peer_info>& v) const
|
||||||
{
|
{
|
||||||
v.clear();
|
v.clear();
|
||||||
|
|
Loading…
Reference in New Issue