forked from premiere/premiere-libtorrent
*** empty log message ***
This commit is contained in:
parent
a19ec4afc2
commit
24e4c197c9
|
@ -90,17 +90,19 @@ The current state includes the following features:</p>
|
|||
thread-safe library interface. (i.e. There's no way for the user to cause a deadlock).</li>
|
||||
<li>can limit the upload bandwidth usage</li>
|
||||
<li>piece-wise file allocation</li>
|
||||
<li>upload rate limit, balanced depending on download speed and upload bandwidth</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
<p>Functions that are yet to be implemented:</p>
|
||||
<blockquote>
|
||||
<ul class="simple">
|
||||
<li>optimistic unchoke</li>
|
||||
<li>choke/unchoke algorithm</li>
|
||||
<li>Snubbing</li>
|
||||
<li>more generous optimistic unchoke</li>
|
||||
<li>better choke/unchoke algorithm</li>
|
||||
<li>fast resume</li>
|
||||
<li>number of connections limit</li>
|
||||
<li>better handling of peers that send bad data</li>
|
||||
<li>ip-filters</li>
|
||||
<li>file-level piece priority</li>
|
||||
<li>a good upload speed cap (the one currently used don't balance loads between peers)</li>
|
||||
</ul>
|
||||
</blockquote>
|
||||
<p>libtorrent is portable at least among windows, macosx, and UNIX-systems. It uses boost.thread,
|
||||
|
@ -407,6 +409,8 @@ struct torrent_handle
|
|||
|
||||
boost::filsystem::path save_path() const;
|
||||
|
||||
void set_max_uploads(int max_uploads);
|
||||
|
||||
sha1_hash info_hash() const;
|
||||
|
||||
bool operator==(const torrent_handle&) const;
|
||||
|
@ -416,10 +420,12 @@ struct torrent_handle
|
|||
</pre>
|
||||
<p>The default constructor will initialize the handle to an invalid state. Which means you cannot
|
||||
perform any operation on it, unless you first assign it a valid handle. If you try to perform
|
||||
any operation they will simply return.</p>
|
||||
any operation on an uninitialized handle, it will throw <tt class="literal"><span class="pre">invalid_handle</span></tt>.</p>
|
||||
<p><tt class="literal"><span class="pre">save_path()</span></tt> returns the path that was given to <tt class="literal"><span class="pre">add_torrent()</span></tt> when this torrent
|
||||
was started.</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>
|
||||
<div class="section" id="status">
|
||||
<h3><a class="toc-backref" href="#id15" name="status">status()</a></h3>
|
||||
<p><tt class="literal"><span class="pre">status()</span></tt> will return a structure with information about the status of this
|
||||
|
@ -904,6 +910,7 @@ int main(int argc, char* argv[])
|
|||
<div class="section" id="aknowledgements">
|
||||
<h1><a class="toc-backref" href="#id34" name="aknowledgements">Aknowledgements</a></h1>
|
||||
<p>Written by Arvid Norberg and Daniel Wallin. Copyright (c) 2003</p>
|
||||
<p>Contributions by Magnus Jonsson</p>
|
||||
<p>Project is hosted by sourceforge.</p>
|
||||
<p><a class="reference" href="http://sourceforge.net"><img alt="sf_logo" src="http://sourceforge.net/sflogo.php?group_id=7994" /></a></p>
|
||||
</div>
|
||||
|
|
|
@ -41,18 +41,20 @@ The current state includes the following features:
|
|||
thread-safe library interface. (i.e. There's no way for the user to cause a deadlock).
|
||||
* can limit the upload bandwidth usage
|
||||
* piece-wise file allocation
|
||||
* upload rate limit, balanced depending on download speed and upload bandwidth
|
||||
|
||||
__ http://home.elp.rr.com/tur/multitracker-spec.txt
|
||||
.. _Azureus: http://azureus.sourceforge.net
|
||||
|
||||
Functions that are yet to be implemented:
|
||||
|
||||
* optimistic unchoke
|
||||
* choke/unchoke algorithm
|
||||
* Snubbing
|
||||
* more generous optimistic unchoke
|
||||
* better choke/unchoke algorithm
|
||||
* fast resume
|
||||
* number of connections limit
|
||||
* better handling of peers that send bad data
|
||||
* ip-filters
|
||||
* file-level piece priority
|
||||
* a good upload speed cap (the one currently used don't balance loads between peers)
|
||||
|
||||
libtorrent is portable at least among windows, macosx, and UNIX-systems. It uses boost.thread,
|
||||
boost.filesystem boost.date_time and various other boost libraries and zlib.
|
||||
|
@ -426,6 +428,8 @@ Its declaration looks like this::
|
|||
|
||||
boost::filsystem::path save_path() const;
|
||||
|
||||
void set_max_uploads(int max_uploads);
|
||||
|
||||
sha1_hash info_hash() const;
|
||||
|
||||
bool operator==(const torrent_handle&) const;
|
||||
|
@ -435,13 +439,16 @@ Its declaration looks like this::
|
|||
|
||||
The default constructor will initialize the handle to an invalid state. Which means you cannot
|
||||
perform any operation on it, unless you first assign it a valid handle. If you try to perform
|
||||
any operation they will simply return.
|
||||
any operation on an uninitialized handle, it will throw ``invalid_handle``.
|
||||
|
||||
``save_path()`` returns the path that was given to ``add_torrent()`` when this torrent
|
||||
was started.
|
||||
|
||||
``info_hash()`` returns the info hash for the torrent.
|
||||
|
||||
``set_max_uploads()`` 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.
|
||||
|
||||
status()
|
||||
~~~~~~~~
|
||||
|
||||
|
@ -990,6 +997,8 @@ Aknowledgements
|
|||
|
||||
Written by Arvid Norberg and Daniel Wallin. Copyright (c) 2003
|
||||
|
||||
Contributions by Magnus Jonsson
|
||||
|
||||
Project is hosted by sourceforge.
|
||||
|
||||
|sf_logo|__
|
||||
|
|
|
@ -36,7 +36,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <exception>
|
||||
|
||||
#include <boost/format.hpp>
|
||||
//#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
#include "libtorrent/entry.hpp"
|
||||
#include "libtorrent/bencode.hpp"
|
||||
|
@ -75,7 +75,7 @@ void clear()
|
|||
HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
COORD c = {0, 0};
|
||||
DWORD n;
|
||||
FillConsoleOutputCharacter(h, ' ', 80 * 80, c, &n);
|
||||
FillConsoleOutputCharacter(h, ' ', 120 * 80, c, &n);
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -185,7 +185,7 @@ int main(int argc, char* argv[])
|
|||
session s(6881, "E\x1");
|
||||
|
||||
// limit upload rate to 100 kB/s
|
||||
// s.set_upload_rate_limit(100 * 1024);
|
||||
s.set_upload_rate_limit(100 * 1024);
|
||||
|
||||
s.set_http_settings(settings);
|
||||
for (int i = 0; i < argc-1; ++i)
|
||||
|
@ -198,6 +198,7 @@ int main(int argc, char* argv[])
|
|||
torrent_info t(e);
|
||||
t.print(std::cout);
|
||||
handles.push_back(s.add_torrent(t, ""));
|
||||
handles.back().set_max_uploads(20);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
|
@ -246,15 +247,7 @@ int main(int argc, char* argv[])
|
|||
int total_down = s.total_download;
|
||||
int total_up = s.total_upload;
|
||||
int num_peers = peers.size();
|
||||
/*
|
||||
std::cout << boost::format("%f%% p:%d d:(%s) %s/s u:(%s) %s/s\n")
|
||||
% (s.progress*100)
|
||||
% num_peers
|
||||
% add_suffix(total_down)
|
||||
% add_suffix(down)
|
||||
% add_suffix(total_up)
|
||||
% add_suffix(up);
|
||||
*/
|
||||
|
||||
out.precision(4);
|
||||
out.width(5);
|
||||
out.fill(' ');
|
||||
|
@ -276,8 +269,7 @@ int main(int argc, char* argv[])
|
|||
<< "diff: " << add_suffix(total_down - total_up) << "\n";
|
||||
|
||||
boost::posix_time::time_duration t = s.next_announce;
|
||||
// std::cout << "next announce: " << boost::posix_time::to_simple_string(t) << "\n";
|
||||
out << "next announce: " << t.hours() << ":" << t.minutes() << ":" << t.seconds() << "\n";
|
||||
out << "next announce: " << boost::posix_time::to_simple_string(t) << "\n";
|
||||
|
||||
for (std::vector<peer_info>::iterator i = peers.begin();
|
||||
i != peers.end();
|
||||
|
@ -288,7 +280,7 @@ int main(int argc, char* argv[])
|
|||
<< "u: " << add_suffix(i->up_speed) << "/s "
|
||||
<< "(" << add_suffix(i->total_upload) << ") "
|
||||
<< "df: " << add_suffix((int)i->total_download - (int)i->total_upload) << " "
|
||||
<< "l: " << add_suffix(i->upload_ceiling) << "/s "
|
||||
<< "l: " << add_suffix(i->upload_limit) << "/s "
|
||||
<< "f: "
|
||||
<< static_cast<const char*>((i->flags & peer_info::interesting)?"I":"_")
|
||||
<< static_cast<const char*>((i->flags & peer_info::choked)?"C":"_")
|
||||
|
@ -305,13 +297,12 @@ int main(int argc, char* argv[])
|
|||
if (progress * 20 > j) out << "#";
|
||||
else out << "-";
|
||||
}
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
out << "\n";
|
||||
}
|
||||
|
||||
out << "___________________________________\n";
|
||||
/*
|
||||
|
||||
i->get_download_queue(queue);
|
||||
for (std::vector<partial_piece_info>::iterator i = queue.begin();
|
||||
i != queue.end();
|
||||
|
@ -324,13 +315,13 @@ int main(int argc, char* argv[])
|
|||
{
|
||||
if (i->finished_blocks[j]) out << "#";
|
||||
else if (i->requested_blocks[j]) out << "=";
|
||||
else out << "-";
|
||||
else out << ".";
|
||||
}
|
||||
out << "|\n";
|
||||
}
|
||||
|
||||
out << "___________________________________\n";
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
clear();
|
||||
|
|
|
@ -59,7 +59,17 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
// TODO: maybe there should be some kind of
|
||||
// per-torrent free-upload counter. All free
|
||||
// download we get is put in there and increases
|
||||
// the amount of free upload we give.
|
||||
// the amount of free upload we give. The free upload
|
||||
// could be distributed to the interest peers
|
||||
// depending on amount we have downloaded from
|
||||
// the peer and depending on the share ratio.
|
||||
// there's no point in giving free upload to
|
||||
// peers we can trade with. Maybe the free upload
|
||||
// only should be given to those we are not interested
|
||||
// in?
|
||||
|
||||
// TODO: the interested flag has to be updated when we
|
||||
// get pieces.
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
|
|
@ -36,14 +36,11 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/weak_ptr.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time.hpp>
|
||||
|
||||
#include "libtorrent/peer.hpp"
|
||||
#include "libtorrent/piece_picker.hpp"
|
||||
|
||||
// TODO: should be able to close connections with too low bandwidth to save memory
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
|
@ -63,7 +60,7 @@ namespace libtorrent
|
|||
|
||||
// called when an incoming connection is accepted
|
||||
// return false if the connection closed
|
||||
bool new_connection(const boost::weak_ptr<peer_connection>& c);
|
||||
bool new_connection(peer_connection& c);
|
||||
|
||||
// this is called once for every peer we get from
|
||||
// the tracker
|
||||
|
@ -79,7 +76,7 @@ namespace libtorrent
|
|||
// the peer has got at least one interesting piece
|
||||
void peer_is_interesting(peer_connection& c);
|
||||
|
||||
void piece_finished(peer_connection& c, int index, bool successfully_verified);
|
||||
void piece_finished(int index, bool successfully_verified);
|
||||
|
||||
void block_finished(peer_connection& c, piece_block b);
|
||||
|
||||
|
@ -95,23 +92,22 @@ namespace libtorrent
|
|||
// the peer is not interested in our pieces
|
||||
void not_interested(peer_connection& c);
|
||||
|
||||
void set_max_uploads(int num_unchoked);
|
||||
|
||||
#ifndef NDEBUG
|
||||
bool has_connection(const peer_connection* p);
|
||||
|
||||
void check_invariant();
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
struct peer
|
||||
{
|
||||
peer(const peer_id& pid)
|
||||
: id(pid)
|
||||
, last_optimistically_unchoked(boost::posix_time::second_clock::local_time())
|
||||
, connected(boost::posix_time::second_clock::local_time())
|
||||
, optimistic_unchokes(0)
|
||||
, prev_amount_upload(0)
|
||||
, prev_amount_download(0)
|
||||
, banned(false)
|
||||
{}
|
||||
peer(const peer_id& pid);
|
||||
|
||||
int total_download() const;
|
||||
int total_upload() const;
|
||||
|
||||
bool operator==(const peer_id& pid) const
|
||||
{ return id == pid; }
|
||||
|
@ -130,10 +126,6 @@ namespace libtorrent
|
|||
// or disconnected if it isn't connected right now
|
||||
boost::posix_time::ptime connected;
|
||||
|
||||
// the number of optimistic unchokes this peer has
|
||||
// been given
|
||||
int optimistic_unchokes;
|
||||
|
||||
// this is the accumulated amount of
|
||||
// uploaded and downloaded data to this
|
||||
// peer. It only accounts for what was
|
||||
|
@ -151,9 +143,13 @@ namespace libtorrent
|
|||
|
||||
// if the peer is connected now, this
|
||||
// will refer to a valid peer_connection
|
||||
boost::weak_ptr<peer_connection> connection;
|
||||
peer_connection* connection;
|
||||
};
|
||||
|
||||
bool unchoke_one_peer();
|
||||
peer* find_choke_candidate();
|
||||
peer* find_unchoke_candidate();
|
||||
|
||||
// a functor that identifies peers that have disconnected and that
|
||||
// are too old for still being saved.
|
||||
struct old_disconnected_peer
|
||||
|
@ -162,7 +158,7 @@ namespace libtorrent
|
|||
{
|
||||
using namespace boost::posix_time;
|
||||
|
||||
return p.connection.expired()
|
||||
return p.connection == 0
|
||||
&& second_clock::local_time() - p.connected > seconds(5*60);
|
||||
}
|
||||
};
|
||||
|
@ -173,6 +169,14 @@ namespace libtorrent
|
|||
int m_num_peers;
|
||||
torrent* m_torrent;
|
||||
|
||||
// the total number of unchoked peers at
|
||||
// any given time. If set to -1, it's unlimited.
|
||||
// must be 2 or higher otherwise.
|
||||
int m_max_uploads;
|
||||
|
||||
// the number of unchoked peers
|
||||
// at any given time
|
||||
int m_num_unchoked;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
|
||||
// TODO: remove the dependency of
|
||||
// platform specific headers here.
|
||||
// sockaddr_in is hard to get rid of in a nice way
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <winsock2.h>
|
||||
|
|
|
@ -75,10 +75,6 @@ namespace libtorrent
|
|||
m_total_upload_protocol += s.m_uploaded_protocol;
|
||||
}
|
||||
|
||||
// TODO: these function should take two arguments
|
||||
// to be able to count both total data sent and also
|
||||
// count only the actual payload (not counting the
|
||||
// protocol chatter)
|
||||
void received_bytes(int bytes_payload, int bytes_protocol)
|
||||
{
|
||||
m_downloaded += bytes_payload;
|
||||
|
|
|
@ -63,18 +63,6 @@ namespace libtorrent
|
|||
struct session_impl;
|
||||
}
|
||||
|
||||
// TODO: each torrent should have a status value that
|
||||
// reflects what's happening to it
|
||||
// TODO: There should be a maximum number of peers that
|
||||
// is maintained (if someone disconnects, try to connect to
|
||||
// anotherone). There should also be a candidate slot where a
|
||||
// new peer is tried for one minute, and if it has better ownload
|
||||
// speed than one of the peers currently connected, it will be
|
||||
// replaced to maximize bandwidth usage. It wil also have to
|
||||
// depend on how many and which pieces the peers have.
|
||||
// TODO: In debug mode all pieces that are sent should be checked.
|
||||
|
||||
|
||||
// a torrent is a class that holds information
|
||||
// for a specific download. It updates itself against
|
||||
// the tracker
|
||||
|
@ -88,7 +76,8 @@ namespace libtorrent
|
|||
detail::session_impl& ses
|
||||
, const torrent_info& torrent_file
|
||||
, const boost::filesystem::path& save_path);
|
||||
~torrent() {}
|
||||
|
||||
~torrent();
|
||||
|
||||
void abort() { m_abort = true; m_event = event_stopped; }
|
||||
bool is_aborted() const { return m_abort; }
|
||||
|
@ -115,7 +104,7 @@ namespace libtorrent
|
|||
|
||||
torrent_status status() const;
|
||||
|
||||
boost::weak_ptr<peer_connection> connect_to_peer(
|
||||
peer_connection& connect_to_peer(
|
||||
const address& a
|
||||
, const peer_id& id);
|
||||
|
||||
|
@ -248,6 +237,7 @@ namespace libtorrent
|
|||
|
||||
#ifndef NDEBUG
|
||||
virtual void debug_log(const std::string& line);
|
||||
void check_invariant();
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
|
|
@ -115,8 +115,14 @@ namespace libtorrent
|
|||
// to finish all pieces currently in the pipeline, and then
|
||||
// abort the torrent.
|
||||
|
||||
// TODO: add finish_file_allocation, which will force the
|
||||
// torrent to allocate storage for all pieces.
|
||||
|
||||
boost::filesystem::path save_path() const;
|
||||
|
||||
// -1 means unlimited unchokes
|
||||
void set_max_uploads(int max_uploads);
|
||||
|
||||
const sha1_hash& info_hash() const
|
||||
{ return m_info_hash; }
|
||||
|
||||
|
|
|
@ -174,8 +174,7 @@ libtorrent::peer_connection::~peer_connection()
|
|||
|
||||
void libtorrent::peer_connection::set_send_quota(int num_bytes)
|
||||
{
|
||||
assert(num_bytes <= m_send_quota_limit);
|
||||
assert(num_bytes >= 0);
|
||||
assert(num_bytes <= m_send_quota_limit || m_send_quota_limit == -1);
|
||||
if (num_bytes > m_send_quota_limit) num_bytes = m_send_quota_limit;
|
||||
|
||||
m_send_quota = num_bytes;
|
||||
|
@ -438,12 +437,17 @@ bool libtorrent::peer_connection::dispatch_message(int received)
|
|||
r.piece = read_int(&m_recv_buffer[1]);
|
||||
r.start = read_int(&m_recv_buffer[5]);
|
||||
r.length = read_int(&m_recv_buffer[9]);
|
||||
m_requests.push_back(r);
|
||||
|
||||
if (!m_choked)
|
||||
{
|
||||
m_requests.push_back(r);
|
||||
send_buffer_updated();
|
||||
}
|
||||
else
|
||||
{
|
||||
// ignoring request since we have
|
||||
// choked this peer
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " <== REQUEST [ piece: " << r.piece << " | s: " << r.start << " | l: " << r.length << " ]\n";
|
||||
|
@ -575,7 +579,7 @@ bool libtorrent::peer_connection::dispatch_message(int received)
|
|||
{
|
||||
m_torrent->piece_failed(index);
|
||||
}
|
||||
m_torrent->get_policy().piece_finished(*this, index, verified);
|
||||
m_torrent->get_policy().piece_finished(index, verified);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -688,9 +692,6 @@ void libtorrent::peer_connection::request_block(piece_block block)
|
|||
std::size_t start_offset = m_send_buffer.size();
|
||||
m_send_buffer.resize(start_offset + 17);
|
||||
|
||||
// TODO: add a timeout to disconnect peer if we don't get any piece messages when
|
||||
// we have requested.
|
||||
|
||||
std::copy(buf, buf + 5, m_send_buffer.begin()+start_offset);
|
||||
start_offset +=5;
|
||||
|
||||
|
@ -741,6 +742,7 @@ void libtorrent::peer_connection::choke()
|
|||
#ifndef NDEBUG
|
||||
(*m_logger) << m_socket->sender().as_string() << " ==> CHOKE\n";
|
||||
#endif
|
||||
m_requests.clear();
|
||||
send_buffer_updated();
|
||||
}
|
||||
|
||||
|
@ -804,19 +806,15 @@ void libtorrent::peer_connection::second_tick()
|
|||
// client has sent us. This is the mean to
|
||||
// maintain a 1:1 share ratio with all peers.
|
||||
|
||||
// TODO: make sure the rate is able to rise if
|
||||
// both peers uses this technique! It could be
|
||||
// enough to just have a constant positive bias
|
||||
// of the send_quota_limit
|
||||
int diff = static_cast<int>(m_statistics.total_download())
|
||||
- static_cast<int>(m_statistics.total_upload());
|
||||
|
||||
if (diff > m_torrent->torrent_file().piece_length())
|
||||
if (diff > 2*m_torrent->block_size())
|
||||
{
|
||||
// if we have downloaded more than one piece more
|
||||
// than we have uploaded, have an unlimited
|
||||
// upload rate
|
||||
m_send_quota = -1;
|
||||
m_send_quota_limit = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -824,18 +822,20 @@ void libtorrent::peer_connection::second_tick()
|
|||
// upload rate of 10 kB/s more than we dowlload
|
||||
// if we have uploaded too much, send with a rate of
|
||||
// 10 kB/s less than we receive
|
||||
if (diff > -32*1024)
|
||||
int bias = 0;
|
||||
if (diff > -2*m_torrent->block_size())
|
||||
{
|
||||
m_send_quota_limit = m_statistics.download_rate() * 1.5;
|
||||
bias = m_statistics.download_rate() * .5;
|
||||
if (bias < 10*1024) bias = 10*1024;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_send_quota_limit = m_statistics.download_rate() * .5;
|
||||
bias = -m_statistics.download_rate() * .5;
|
||||
}
|
||||
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 < 500) m_send_quota_limit = 500;
|
||||
if (m_send_quota_limit < 256) m_send_quota_limit = 256;
|
||||
}
|
||||
assert(m_send_quota_limit >= 500 || m_send_quota_limit == -1);
|
||||
}
|
||||
|
||||
// --------------------------
|
||||
|
|
259
src/policy.cpp
259
src/policy.cpp
|
@ -49,7 +49,11 @@ namespace
|
|||
{
|
||||
// we try to maintain 4 requested blocks in the download
|
||||
// queue
|
||||
request_queue = 16
|
||||
request_queue = 16,
|
||||
|
||||
// the amount of free upload allowed before
|
||||
// the peer is choked
|
||||
free_upload_amount = 4 * 16 * 1024
|
||||
};
|
||||
|
||||
|
||||
|
@ -197,18 +201,83 @@ namespace libtorrent
|
|||
void peer_connection::request_piece(int index);
|
||||
const std::vector<int>& peer_connection::download_queue();
|
||||
|
||||
TODO: implement a limit of the number of unchoked peers.
|
||||
|
||||
TODO: implement some kind of limit of the number of sockets
|
||||
opened, to use for systems where a user has a limited number
|
||||
of open file descriptors
|
||||
of open file descriptors. and for windows which has a buggy tcp-stack.
|
||||
*/
|
||||
|
||||
|
||||
policy::policy(torrent* t)
|
||||
: m_num_peers(0)
|
||||
, m_torrent(t)
|
||||
, m_max_uploads(-1)
|
||||
, m_num_unchoked(0)
|
||||
{}
|
||||
// finds the peer that has the worst download rate
|
||||
// and returns it. May return 0 if all peers are
|
||||
// choked.
|
||||
policy::peer* policy::find_choke_candidate()
|
||||
{
|
||||
peer* worst_peer = 0;
|
||||
int min_weight = std::numeric_limits<int>::max();
|
||||
|
||||
for (std::vector<peer>::iterator i = m_peers.begin();
|
||||
i != m_peers.end();
|
||||
++i)
|
||||
{
|
||||
peer_connection* c = i->connection;
|
||||
|
||||
if (c == 0) continue;
|
||||
if (c->is_choked()) continue;
|
||||
// if the peer isn't interested, just choke it
|
||||
if (!c->is_peer_interested())
|
||||
return &(*i);
|
||||
|
||||
int diff = i->total_download()
|
||||
- i->total_upload();
|
||||
|
||||
int weight = c->statistics().download_rate() * 10
|
||||
+ diff
|
||||
+ (c->has_peer_choked()?-10:10)*1024;
|
||||
|
||||
if (weight > min_weight) continue;
|
||||
|
||||
min_weight = weight;
|
||||
worst_peer = &(*i);
|
||||
continue;
|
||||
}
|
||||
return worst_peer;
|
||||
}
|
||||
|
||||
policy::peer* policy::find_unchoke_candidate()
|
||||
{
|
||||
// if all of our peers are unchoked, there's
|
||||
// no left to unchoke
|
||||
if (m_num_unchoked == m_torrent->num_peers())
|
||||
return 0;
|
||||
|
||||
using namespace boost::posix_time;
|
||||
using namespace boost::gregorian;
|
||||
|
||||
peer* unchoke_peer = 0;
|
||||
ptime min_time(date(9999,Jan,1));
|
||||
|
||||
for (std::vector<peer>::iterator i = m_peers.begin();
|
||||
i != m_peers.end();
|
||||
++i)
|
||||
{
|
||||
peer_connection* c = i->connection;
|
||||
if (c == 0) continue;
|
||||
if (!c->is_choked()) continue;
|
||||
if (!c->is_peer_interested()) continue;
|
||||
if (i->total_download() - i->total_upload()
|
||||
< -free_upload_amount) continue;
|
||||
if (i->last_optimistically_unchoked > min_time) continue;
|
||||
|
||||
min_time = i->last_optimistically_unchoked;
|
||||
unchoke_peer = &(*i);
|
||||
}
|
||||
return unchoke_peer;
|
||||
}
|
||||
|
||||
void policy::pulse()
|
||||
{
|
||||
|
@ -221,34 +290,67 @@ namespace libtorrent
|
|||
, old_disconnected_peer())
|
||||
, m_peers.end());
|
||||
|
||||
// choke peers that have leeched too much without giving anything back
|
||||
for (std::vector<peer>::iterator i = m_peers.begin(); i != m_peers.end(); ++i)
|
||||
if (m_max_uploads != -1)
|
||||
{
|
||||
boost::shared_ptr<peer_connection> c = i->connection.lock();
|
||||
if (c.get() == 0) continue;
|
||||
|
||||
int downloaded = i->prev_amount_download + c->statistics().total_download();
|
||||
int uploaded = i->prev_amount_upload + c->statistics().total_upload();
|
||||
|
||||
if (uploaded - downloaded > m_torrent->torrent_file().piece_length()
|
||||
&& !c->is_choked())
|
||||
// make sure we don't have too many
|
||||
// unchoked peers
|
||||
while (m_num_unchoked > m_max_uploads)
|
||||
{
|
||||
// if we have uploaded more than a piece for free, choke peer and
|
||||
// wait until we catch up with our download.
|
||||
c->choke();
|
||||
peer* p = find_choke_candidate();
|
||||
assert(p);
|
||||
p->connection->choke();
|
||||
--m_num_unchoked;
|
||||
}
|
||||
else if (uploaded - downloaded <= m_torrent->block_size()
|
||||
&& c->is_choked() && c->is_interesting())
|
||||
{
|
||||
// TODO: if we're not interested in this peer
|
||||
// we should only unchoke it if it' its turn
|
||||
// to be optimistically unchoked.
|
||||
|
||||
// we have catched up. We have now shared the same amount
|
||||
// to eachother. Unchoke this peer.
|
||||
c->unchoke();
|
||||
// optimistic unchoke. trade the 'worst'
|
||||
// unchoked peer with one of the choked
|
||||
assert(m_num_unchoked <= m_torrent->num_peers());
|
||||
peer* p = find_choke_candidate();
|
||||
if (p)
|
||||
{
|
||||
p->connection->choke();
|
||||
--m_num_unchoked;
|
||||
unchoke_one_peer();
|
||||
}
|
||||
|
||||
// make sure we have enough
|
||||
// unchoked peers
|
||||
while (m_num_unchoked < m_max_uploads && unchoke_one_peer());
|
||||
}
|
||||
else
|
||||
{
|
||||
// choke peers that have leeched too much without giving anything back
|
||||
for (std::vector<peer>::iterator i = m_peers.begin();
|
||||
i != m_peers.end();
|
||||
++i)
|
||||
{
|
||||
peer_connection* c = i->connection;
|
||||
if (c == 0) continue;
|
||||
|
||||
int downloaded = i->total_download();
|
||||
int uploaded = i->total_upload();
|
||||
|
||||
if (downloaded - uploaded < -free_upload_amount
|
||||
&& !c->is_choked())
|
||||
{
|
||||
// if we have uploaded more than a piece for free, choke peer and
|
||||
// wait until we catch up with our download.
|
||||
c->choke();
|
||||
}
|
||||
else if (downloaded - uploaded > -free_upload_amount
|
||||
&& c->is_choked() && c->is_peer_interested())
|
||||
{
|
||||
// we have catched up. We have now shared the same amount
|
||||
// to eachother. Unchoke this peer.
|
||||
c->unchoke();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
check_invariant();
|
||||
#endif
|
||||
}
|
||||
|
||||
void policy::ban_peer(const peer_connection& c)
|
||||
|
@ -259,30 +361,29 @@ namespace libtorrent
|
|||
i->banned = true;
|
||||
}
|
||||
|
||||
bool policy::new_connection(const boost::weak_ptr<peer_connection>& c)
|
||||
bool policy::new_connection(peer_connection& c)
|
||||
{
|
||||
boost::shared_ptr<peer_connection> con = c.lock();
|
||||
assert(con.get() != 0);
|
||||
if (con.get() == 0) return false;
|
||||
|
||||
std::vector<peer>::iterator i
|
||||
= std::find(m_peers.begin(), m_peers.end(), con->get_peer_id());
|
||||
= std::find(m_peers.begin(), m_peers.end(), c.get_peer_id());
|
||||
if (i == m_peers.end())
|
||||
{
|
||||
using namespace boost::posix_time;
|
||||
using namespace boost::gregorian;
|
||||
|
||||
// we don't have ny info about this peer.
|
||||
// add a new entry
|
||||
peer p(con->get_peer_id());
|
||||
peer p(c.get_peer_id());
|
||||
m_peers.push_back(p);
|
||||
i = m_peers.end()-1;
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(i->connection.expired());
|
||||
assert(i->connection == 0);
|
||||
if (i->banned) return false;
|
||||
}
|
||||
|
||||
i->connected = boost::posix_time::second_clock::local_time();
|
||||
i->connection = c;
|
||||
i->connection = &c;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -293,13 +394,16 @@ namespace libtorrent
|
|||
std::vector<peer>::iterator i = std::find(m_peers.begin(), m_peers.end(), id);
|
||||
if (i == m_peers.end())
|
||||
{
|
||||
using namespace boost::posix_time;
|
||||
using namespace boost::gregorian;
|
||||
|
||||
// we don't have ny info about this peer.
|
||||
// add a new entry
|
||||
peer p(id);
|
||||
m_peers.push_back(p);
|
||||
i = m_peers.end()-1;
|
||||
}
|
||||
else if (!i->connection.expired())
|
||||
else if (!i->connection == 0)
|
||||
{
|
||||
// this means we're already connected
|
||||
// to this peer. don't connect to
|
||||
|
@ -310,7 +414,7 @@ namespace libtorrent
|
|||
if (i->banned) return;
|
||||
|
||||
i->connected = boost::posix_time::second_clock::local_time();
|
||||
i->connection = m_torrent->connect_to_peer(remote, id);
|
||||
i->connection = &m_torrent->connect_to_peer(remote, id);
|
||||
|
||||
}
|
||||
catch(network_error&) {}
|
||||
|
@ -324,8 +428,7 @@ namespace libtorrent
|
|||
{
|
||||
}
|
||||
|
||||
// TODO: the peer_connection argument here should be removed.
|
||||
void policy::piece_finished(peer_connection& c, int index, bool successfully_verified)
|
||||
void policy::piece_finished(int index, bool successfully_verified)
|
||||
{
|
||||
// TODO: if verification failed, mark the peers that were involved
|
||||
// in some way
|
||||
|
@ -348,15 +451,33 @@ namespace libtorrent
|
|||
}
|
||||
}
|
||||
|
||||
// called when a peer is interested in us
|
||||
void policy::interested(peer_connection& c)
|
||||
{
|
||||
// if we're interested in the peer, we unchoke it
|
||||
// and hopes it will unchoke us too
|
||||
if (c.is_interesting()) c.unchoke();
|
||||
}
|
||||
/* if (c.is_interesting())
|
||||
{
|
||||
c.unchoke();
|
||||
++m_num_unchoked;
|
||||
}
|
||||
*/ }
|
||||
|
||||
// called when a peer is no longer interested in us
|
||||
void policy::not_interested(peer_connection& c)
|
||||
{
|
||||
c.not_interested();
|
||||
}
|
||||
|
||||
bool policy::unchoke_one_peer()
|
||||
{
|
||||
peer* p = find_unchoke_candidate();
|
||||
if (p == 0) return false;
|
||||
|
||||
p->connection->unchoke();
|
||||
p->last_optimistically_unchoked = boost::posix_time::second_clock::local_time();
|
||||
++m_num_unchoked;
|
||||
return true;
|
||||
}
|
||||
|
||||
// this is called whenever a peer connection is closed
|
||||
|
@ -370,6 +491,18 @@ namespace libtorrent
|
|||
i->connected = boost::posix_time::second_clock::local_time();
|
||||
i->prev_amount_download += c.statistics().total_download();
|
||||
i->prev_amount_upload += c.statistics().total_upload();
|
||||
if (!i->connection->is_choked() && !m_torrent->is_aborted())
|
||||
{
|
||||
--m_num_unchoked;
|
||||
unchoke_one_peer();
|
||||
}
|
||||
i->connection = 0;
|
||||
}
|
||||
|
||||
void policy::set_max_uploads(int max_uploads)
|
||||
{
|
||||
assert(max_uploads > 1 || max_uploads == -1);
|
||||
m_max_uploads = max_uploads;
|
||||
}
|
||||
|
||||
void policy::peer_is_interesting(peer_connection& c)
|
||||
|
@ -384,5 +517,47 @@ namespace libtorrent
|
|||
{
|
||||
return std::find(m_peers.begin(), m_peers.end(), p->get_peer_id()) != m_peers.end();
|
||||
}
|
||||
|
||||
void policy::check_invariant()
|
||||
{
|
||||
assert(m_max_uploads >= 2 || m_max_uploads == -1);
|
||||
int actual_unchoked = 0;
|
||||
for (std::vector<peer>::iterator i = m_peers.begin();
|
||||
i != m_peers.end();
|
||||
++i)
|
||||
{
|
||||
if (!i->connection) continue;
|
||||
if (!i->connection->is_choked()) actual_unchoked++;
|
||||
}
|
||||
assert(actual_unchoked <= m_max_uploads || m_max_uploads == -1);
|
||||
}
|
||||
#endif
|
||||
|
||||
policy::peer::peer(const peer_id& pid)
|
||||
: id(pid)
|
||||
, last_optimistically_unchoked(
|
||||
boost::gregorian::date(1970,boost::gregorian::Jan,1))
|
||||
, connected(boost::posix_time::second_clock::local_time())
|
||||
, prev_amount_upload(0)
|
||||
, prev_amount_download(0)
|
||||
, banned(false)
|
||||
{}
|
||||
|
||||
int policy::peer::total_download() const
|
||||
{
|
||||
if (connection != 0)
|
||||
return connection->statistics().total_download()
|
||||
+ prev_amount_download;
|
||||
else
|
||||
return prev_amount_download;
|
||||
}
|
||||
|
||||
int policy::peer::total_upload() const
|
||||
{
|
||||
if (connection != 0)
|
||||
return connection->statistics().total_upload()
|
||||
+ prev_amount_upload;
|
||||
else
|
||||
return prev_amount_upload;
|
||||
}
|
||||
}
|
||||
|
|
142
src/session.cpp
142
src/session.cpp
|
@ -1,6 +1,6 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2003, Arvid Norberg
|
||||
Copyright (c) 2003, Arvid Norberg, Magnus Jonsson
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
|
@ -63,6 +63,41 @@ namespace std
|
|||
namespace
|
||||
{
|
||||
|
||||
|
||||
// This struct is used by control_upload_rates() below. It keeps
|
||||
// track how much bandwidth has been allocated to each connection
|
||||
// and other relevant information to assist in the allocation process.
|
||||
struct connection_info
|
||||
{
|
||||
libtorrent::peer_connection* p; // which peer_connection this info refers to
|
||||
int allocated_quota; // bandwidth allocated to this peer connection
|
||||
int quota_limit; // bandwidth limit
|
||||
int estimated_upload_capacity; // estimated channel bandwidth
|
||||
|
||||
bool operator < (const connection_info &other) const
|
||||
{
|
||||
return estimated_upload_capacity < other.estimated_upload_capacity;
|
||||
}
|
||||
|
||||
int give(int amount)
|
||||
{
|
||||
|
||||
// if amount > 0, try to add amount to the allocated quota.
|
||||
// if amount < 0, try to subtract abs(amount) from the allocated quota
|
||||
//
|
||||
// Quota will not go above quota_limit or below 0. This means that
|
||||
// not all the amount given or taken may be accepted.
|
||||
//
|
||||
// return value: how much quota was actually added (or subtracted if negative).
|
||||
|
||||
int old_quota=allocated_quota;
|
||||
allocated_quota+=amount;
|
||||
allocated_quota=std::min(allocated_quota,quota_limit);
|
||||
allocated_quota=std::max(0,allocated_quota);
|
||||
return allocated_quota-old_quota;
|
||||
}
|
||||
};
|
||||
|
||||
// adjusts the upload rates of every peer connection
|
||||
// to make sure the sum of all send quotas equals
|
||||
// the given upload_limit. An upload limit of -1 means
|
||||
|
@ -92,21 +127,105 @@ namespace
|
|||
}
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// There's an upload limit, so we need to distribute the available
|
||||
// upload bandwidth among the peer_connections fairly, but not
|
||||
// wastefully.
|
||||
|
||||
// TODO: upload limit support is currently broken
|
||||
assert(false);
|
||||
// For each peer_connection, keep some local data about their
|
||||
// quota limit and estimated upload capacity, and how much quota
|
||||
// has been allocated to them.
|
||||
|
||||
std::vector<connection_info> peer_info;
|
||||
|
||||
for (detail::session_impl::connection_map::iterator i = connections.begin();
|
||||
i != connections.end();
|
||||
++i)
|
||||
{
|
||||
peer_connection& p = *i->second;
|
||||
connection_info pi;
|
||||
|
||||
pi.p=&p;
|
||||
pi.allocated_quota=0; // we haven't given it any bandwith yet
|
||||
pi.quota_limit=p.send_quota_limit();
|
||||
|
||||
pi.estimated_upload_capacity=
|
||||
p.has_data() ? std::max(10,(int)p.statistics().upload_rate()*11/10)
|
||||
// If there's no data to send, upload capacity is practically 0.
|
||||
// Here we set it to 1 though, because otherwise it will not be able
|
||||
// to accept any quota at all, which may upset quota_limit balances.
|
||||
: 1;
|
||||
|
||||
peer_info.push_back(pi);
|
||||
}
|
||||
|
||||
// Sum all peer_connections' quota limit to get the total quota limit.
|
||||
|
||||
int sum_total_of_quota_limits=0;
|
||||
for(int i=0;i<peer_info.size();i++)
|
||||
sum_total_of_quota_limits+=peer_info[i].quota_limit;
|
||||
|
||||
// This is how much total bandwidth that can be distributed.
|
||||
int quota_left_to_distribute=std::min(upload_limit,sum_total_of_quota_limits);
|
||||
|
||||
|
||||
// Sort w.r.t. channel capacitiy, lowest channel capacity first.
|
||||
// Makes it easy to traverse the list in sorted order.
|
||||
std::sort(peer_info.begin(),peer_info.end());
|
||||
|
||||
|
||||
// Distribute quota until there's nothing more to distribute
|
||||
|
||||
while(quota_left_to_distribute!=0)
|
||||
{
|
||||
assert(quota_left_to_distribute>0);
|
||||
|
||||
for(int i=0;i<peer_info.size();i++)
|
||||
{
|
||||
// Traverse the peer list from slowest connection to fastest.
|
||||
|
||||
// In each step, share bandwidth equally between this peer_connection
|
||||
// and the following faster peer_connections.
|
||||
//
|
||||
// Rounds upwards to avoid trying to give 0 bandwidth to someone (may get caught in an endless loop otherwise)
|
||||
|
||||
int num_peers_left_to_share_quota=peer_info.size()-i;
|
||||
int try_to_give_to_this_peer=(quota_left_to_distribute + num_peers_left_to_share_quota-1)/num_peers_left_to_share_quota;
|
||||
|
||||
// But do not allocate more than the estimated upload capacity.
|
||||
try_to_give_to_this_peer=std::min(
|
||||
peer_info[i].estimated_upload_capacity,
|
||||
try_to_give_to_this_peer);
|
||||
|
||||
// Also, when the peer is given quota, it will not accept more than it's quota_limit.
|
||||
int quota_actually_given_to_peer=peer_info[i].give(try_to_give_to_this_peer);
|
||||
|
||||
quota_left_to_distribute-=quota_actually_given_to_peer;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, inform the peers of how much quota they get.
|
||||
|
||||
for(int i=0;i<peer_info.size();i++)
|
||||
peer_info[i].p->set_send_quota(peer_info[i].allocated_quota);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
int sum = 0;
|
||||
{
|
||||
int sum_quota = 0;
|
||||
int sum_quota_limit = 0;
|
||||
for (detail::session_impl::connection_map::iterator i = connections.begin();
|
||||
i != connections.end();
|
||||
++i)
|
||||
{
|
||||
peer_connection& p = *i->second;
|
||||
sum += p.send_quota();
|
||||
sum_quota += p.send_quota();
|
||||
|
||||
sum_quota_limit += p.send_quota_limit();
|
||||
}
|
||||
assert(abs(sum_quota - std::min(upload_limit,sum_quota_limit)) < 10);
|
||||
}
|
||||
assert(sum == upload_limit);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -324,9 +443,6 @@ namespace libtorrent
|
|||
#ifndef NDEBUG
|
||||
(*m_logger) << s->sender().as_string() << " <== INCOMING CONNECTION\n";
|
||||
#endif
|
||||
// TODO: the send buffer size should be controllable from the outside
|
||||
// s->set_send_bufsize(2048);
|
||||
|
||||
// TODO: filter ip:s
|
||||
|
||||
boost::shared_ptr<peer_connection> c(
|
||||
|
@ -485,14 +601,6 @@ namespace libtorrent
|
|||
++i;
|
||||
}
|
||||
// distribute the maximum upload rate among the peers
|
||||
// TODO: implement an intelligent algorithm that
|
||||
// will shift bandwidth from the peers that can't
|
||||
// utilize all their assigned bandwidth to the peers
|
||||
// that actually can maintain the upload rate.
|
||||
// This should probably be done by accumulating the
|
||||
// left-over bandwidth to next second. Since the
|
||||
// the sockets consumes its data in rather big chunks.
|
||||
|
||||
control_upload_rates(m_upload_rate, m_connections);
|
||||
|
||||
|
||||
|
|
|
@ -105,6 +105,10 @@ namespace {
|
|||
|
||||
}
|
||||
|
||||
// TODO: implement fast resume. i.e. the possibility to
|
||||
// supply additional information about which pieces are
|
||||
// assigned to which slots.
|
||||
|
||||
namespace libtorrent {
|
||||
|
||||
struct thread_safe_storage
|
||||
|
@ -608,8 +612,7 @@ namespace libtorrent {
|
|||
|
||||
for (int i = current_slot; i < m_info.num_pieces(); ++i)
|
||||
{
|
||||
if (pieces[i])
|
||||
continue;
|
||||
if (pieces[i] && i != current_slot) continue;
|
||||
|
||||
const sha1_hash& hash = digest[
|
||||
i == m_info.num_pieces() - 1]->get();
|
||||
|
@ -620,11 +623,20 @@ namespace libtorrent {
|
|||
|
||||
if (found_piece != -1)
|
||||
{
|
||||
if (pieces[found_piece])
|
||||
{
|
||||
assert(m_piece_to_slot[found_piece] != -1);
|
||||
m_slot_to_piece[m_piece_to_slot[found_piece]] = -2;
|
||||
m_free_slots.push_back(m_piece_to_slot[found_piece]);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_bytes_left -= m_info.piece_size(found_piece);
|
||||
}
|
||||
|
||||
m_piece_to_slot[found_piece] = current_slot;
|
||||
m_slot_to_piece[current_slot] = found_piece;
|
||||
pieces[found_piece] = true;
|
||||
m_piece_to_slot[found_piece] = current_slot;
|
||||
m_slot_to_piece[current_slot] = found_piece;
|
||||
pieces[found_piece] = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -168,6 +168,11 @@ namespace libtorrent
|
|||
m_have_pieces.resize(torrent_file.num_pieces(), false);
|
||||
}
|
||||
|
||||
torrent::~torrent()
|
||||
{
|
||||
if (m_ses.m_abort) m_abort = true;
|
||||
}
|
||||
|
||||
void torrent::tracker_response(const entry& e)
|
||||
{
|
||||
std::vector<peer> peer_list;
|
||||
|
@ -279,15 +284,14 @@ namespace libtorrent
|
|||
++i)
|
||||
{
|
||||
if (std::find(downloaders.begin(), downloaders.end(), (*i)->get_peer_id())
|
||||
!= downloaders.end())
|
||||
== downloaders.end()) continue;
|
||||
|
||||
(*i)->received_invalid_data();
|
||||
if ((*i)->trust_points() <= -5)
|
||||
{
|
||||
(*i)->received_invalid_data();
|
||||
if ((*i)->trust_points() <= -5)
|
||||
{
|
||||
// we don't trust this peer anymore
|
||||
// ban it.
|
||||
m_policy->ban_peer(*(*i));
|
||||
}
|
||||
// we don't trust this peer anymore
|
||||
// ban it.
|
||||
m_policy->ban_peer(*(*i));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -422,11 +426,9 @@ namespace libtorrent
|
|||
#endif
|
||||
}
|
||||
|
||||
boost::weak_ptr<peer_connection> torrent::connect_to_peer(const address& a, const peer_id& id)
|
||||
peer_connection& torrent::connect_to_peer(const address& a, const peer_id& id)
|
||||
{
|
||||
boost::shared_ptr<socket> s(new socket(socket::tcp, false));
|
||||
// TODO: the send buffer size should be controllable from the outside
|
||||
// s->set_send_bufsize(2048);
|
||||
s->connect(a);
|
||||
boost::shared_ptr<peer_connection> c(new peer_connection(
|
||||
m_ses
|
||||
|
@ -449,7 +451,7 @@ namespace libtorrent
|
|||
m_ses.m_selector.monitor_readability(s);
|
||||
m_ses.m_selector.monitor_errors(s);
|
||||
// std::cout << "connecting to: " << a.as_string() << ":" << a.port() << "\n";
|
||||
return c;
|
||||
return *c;
|
||||
}
|
||||
|
||||
void torrent::attach_peer(peer_connection* p)
|
||||
|
@ -460,7 +462,7 @@ namespace libtorrent
|
|||
= m_ses.m_connections.find(p->get_socket());
|
||||
assert(i != m_ses.m_connections.end());
|
||||
|
||||
if (!m_policy->new_connection(i->second)) throw network_error(0);
|
||||
if (!m_policy->new_connection(*i->second)) throw network_error(0);
|
||||
}
|
||||
|
||||
void torrent::close_all_connections()
|
||||
|
@ -523,6 +525,14 @@ namespace libtorrent
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void torrent::check_invariant()
|
||||
{
|
||||
assert(m_num_pieces
|
||||
== std::count(m_have_pieces.begin(), m_have_pieces.end(), true));
|
||||
}
|
||||
#endif
|
||||
|
||||
void torrent::second_tick()
|
||||
{
|
||||
m_time_scaler++;
|
||||
|
|
|
@ -63,6 +63,35 @@ namespace std
|
|||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
void torrent_handle::set_max_uploads(int max_uploads)
|
||||
{
|
||||
if (m_ses == 0) throw invalid_handle();
|
||||
|
||||
assert(m_chk != 0);
|
||||
{
|
||||
boost::mutex::scoped_lock l(m_ses->m_mutex);
|
||||
torrent* t = m_ses->find_torrent(m_info_hash);
|
||||
if (t != 0)
|
||||
{
|
||||
t->get_policy().set_max_uploads(max_uploads);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
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->get_policy().set_max_uploads(max_uploads);
|
||||
return;
|
||||
}
|
||||
}
|
||||
throw invalid_handle();
|
||||
}
|
||||
|
||||
torrent_status torrent_handle::status() const
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue