added the ability to limit the number of half-open tcp connections

This commit is contained in:
Arvid Norberg 2005-11-02 16:28:39 +00:00
parent 3f36dd0395
commit bcbe165aee
15 changed files with 351 additions and 154 deletions

View File

@ -1,3 +1,8 @@
* added the ability to limit the number of simultaneous half-open
TCP connections. Flags in peer_info has been added.
release 0.9.1
* strings that are invalid utf-8 strings are now decoded with the
local codepage on windows
* added the ability to build libtorrent both as a shared library

View File

@ -1,41 +1,14 @@
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Rasterbar Software | Products | libtorrent</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" type="text/css" href="../../css/base.css" />
<link rel="stylesheet" type="text/css" href="../../css/rst.css" />
<style type="text/css">
/* Hides from IE-mac \*/
* html pre { height: 1%; }
/* End hide from IE-mac */
</style>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.3.8: http://docutils.sourceforge.net/" />
<title>libtorrent manual</title>
<meta name="author" content="Arvid Norberg, arvid&#64;rasterbar.com" />
<link rel="stylesheet" href="style.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="headerNav">
<ul>
<li class="first"><a href="/">Home</a></li>
<li><a href="../../products.html">Products</a></li>
<li><a href="../../contact.html">Contact</a></li>
<!-- <li><a href="/about.html">About</a></li> -->
</ul>
</div>
<div id="header">
<h1><span>Rasterbar Software</span></h1>
<h2><span>Software developement and consulting</span></h2>
<span>
</span>
</div>
<div id="main">
<div class="document" id="libtorrent-manual">
<h1 class="title">libtorrent manual</h1>
<table class="docinfo" frame="void" rules="none">
@ -1800,7 +1773,9 @@ struct peer_info
remote_interested = 0x4,
remote_choked = 0x8,
supports_extensions = 0x10,
local_connection = 0x20
local_connection = 0x20,
connecting = 0x40,
queued = 0x80
};
unsigned int flags;
address ip;
@ -1858,6 +1833,15 @@ listen port open, and that port is the same as in the
peer connection was opened by this peer connecting to
us.</td>
</tr>
<tr><td><tt class="docutils literal"><span class="pre">connecting</span></tt></td>
<td>The connection is in a half-open state (i.e. it is
being connected).</td>
</tr>
<tr><td><tt class="docutils literal"><span class="pre">queued</span></tt></td>
<td>The connection is currently queued for a connection
attempt. This may happen if there is a limit set on
the number of half-open TCP connections.</td>
</tr>
</tbody>
</table>
<p>The <tt class="docutils literal"><span class="pre">ip</span></tt> field is the IP-address to this peer. Its type is a wrapper around the
@ -3266,13 +3250,5 @@ scripts.</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>
</div>
</div>
<div id="footer">
<span>Copyright &copy; 2005 Rasterbar Software.</span>
</div>
</div>
</body>
</html>

View File

@ -1744,7 +1744,9 @@ It contains the following fields::
remote_interested = 0x4,
remote_choked = 0x8,
supports_extensions = 0x10,
local_connection = 0x20
local_connection = 0x20,
connecting = 0x40,
queued = 0x80
};
unsigned int flags;
address ip;
@ -1792,6 +1794,13 @@ any combination of the enums above. The following table describes each flag:
| | peer connection was opened by this peer connecting to |
| | us. |
+-------------------------+-------------------------------------------------------+
| ``connecting`` | The connection is in a half-open state (i.e. it is |
| | being connected). |
+-------------------------+-------------------------------------------------------+
| ``queued`` | The connection is currently queued for a connection |
| | attempt. This may happen if there is a limit set on |
| | the number of half-open TCP connections. |
+-------------------------+-------------------------------------------------------+
__ extension_protocol.html

View File

@ -1,41 +1,14 @@
<!DOCTYPE html PUBLIC
"-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>Rasterbar Software | Products | libtorrent</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<link rel="stylesheet" type="text/css" href="../../css/base.css" />
<link rel="stylesheet" type="text/css" href="../../css/rst.css" />
<style type="text/css">
/* Hides from IE-mac \*/
* html pre { height: 1%; }
/* End hide from IE-mac */
</style>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="generator" content="Docutils 0.3.8: http://docutils.sourceforge.net/" />
<title>Bittorrent udp-tracker protocol extension</title>
<meta name="author" content="Arvid Norberg, arvid&#64;rasterbar.com" />
<link rel="stylesheet" href="style.css" type="text/css" />
</head>
<body>
<div id="container">
<div id="headerNav">
<ul>
<li class="first"><a href="/">Home</a></li>
<li><a href="../../products.html">Products</a></li>
<li><a href="../../contact.html">Contact</a></li>
<!-- <li><a href="/about.html">About</a></li> -->
</ul>
</div>
<div id="header">
<h1><span>Rasterbar Software</span></h1>
<h2><span>Software developement and consulting</span></h2>
<span>
</span>
</div>
<div id="main">
<div class="document" id="bittorrent-udp-tracker-protocol-extension">
<h1 class="title">Bittorrent udp-tracker protocol extension</h1>
<table class="docinfo" frame="void" rules="none">
@ -529,13 +502,5 @@ from the 20 bytes hash calculated.</td>
<p>Protocol designed by Olaf van der Spek</p>
</div>
</div>
</div>
<div id="footer">
<span>Copyright &copy; 2005 Rasterbar Software.</span>
</div>
</div>
</body>
</html>

View File

@ -273,7 +273,18 @@ void print_peer_info(std::ostream& out, std::vector<libtorrent::peer_info> const
out << progress_bar(0.f, 15);
}
out << " " << identify_client(i->id) << "\n";
if (i->flags & peer_info::connecting)
{
out << esc("31") << " connecting to peer" << esc("0") << "\n";
}
else if (i->flags & peer_info::queued)
{
out << esc("33") << " queued" << esc("0") << "\n";
}
else
{
out << " " << identify_client(i->id) << "\n";
}
}
}
@ -403,6 +414,7 @@ int main(int ac, char* av[])
float preferred_ratio;
int download_limit;
int upload_limit;
int half_open_limit;
std::string save_path_str;
std::string log_level;
std::string ip_filter_file;
@ -447,6 +459,8 @@ int main(int ac, char* av[])
("poll-interval,t", po::value<int>(&poll_interval)->default_value(2)
, "if a directory is being monitored, this is the interval (given "
"in seconds) between two refreshes of the directory listing")
("half-open-limit,a", po::value<int>(&half_open_limit)->default_value(-1)
, "Sets the maximum number of simultaneous half-open tcp connections")
;
po::positional_options_description p;
@ -466,6 +480,7 @@ int main(int ac, char* av[])
if (download_limit <= 0) download_limit = -1;
if (upload_limit <= 0) upload_limit = -1;
if (poll_interval < 2) poll_interval = 2;
if (half_open_limit < 1) half_open_limit = -1;
if (!monitor_dir.empty() && !exists(monitor_dir))
{
std::cerr << "The monitor directory doesn't exist: " << monitor_dir.string() << std::endl;
@ -501,6 +516,7 @@ int main(int ac, char* av[])
handles_t handles;
session ses;
ses.set_max_half_open_connections(half_open_limit);
ses.set_download_rate_limit(download_limit);
ses.set_upload_rate_limit(upload_limit);
ses.listen_on(std::make_pair(listen_port, listen_port + 10));
@ -662,7 +678,7 @@ int main(int ac, char* av[])
if (torrent_finished_alert* p = dynamic_cast<torrent_finished_alert*>(a.get()))
{
// limit the bandwidth for all seeding torrents
p->handle.set_max_connections(10);
p->handle.set_max_connections(60);
//p->handle.set_max_uploads(5);
//p->handle.set_upload_limit(10000);
@ -755,7 +771,8 @@ int main(int ac, char* av[])
out << "info-hash: " << h.info_hash() << "\n";
boost::posix_time::time_duration t = s.next_announce;
out << "next announce: " << esc("37") << boost::posix_time::to_simple_string(t) << esc("0") << "\n";
out << "next announce: " << esc("37") <<
boost::posix_time::to_simple_string(t) << esc("0") << "\n";
out << "tracker: " << s.current_tracker << "\n";
}

View File

@ -86,7 +86,9 @@ namespace libtorrent
protocol_error(const std::string& msg): std::runtime_error(msg) {};
};
class TORRENT_EXPORT peer_connection: public boost::noncopyable
class TORRENT_EXPORT peer_connection
: public boost::noncopyable
, public boost::enable_shared_from_this<peer_connection>
{
friend class invariant_access;
public:
@ -98,7 +100,8 @@ namespace libtorrent
detail::session_impl& ses
, selector& sel
, torrent* t
, boost::shared_ptr<libtorrent::socket> s);
, boost::shared_ptr<libtorrent::socket> s
, address const& remote);
// with this constructor we have been contacted and we still don't
// know which torrent the connection belongs to
@ -123,7 +126,7 @@ namespace libtorrent
// work to do.
void send_data();
void receive_data();
// tells if this connection has data it want to send
// and has enough upload bandwidth quota left to send it.
bool can_write() const;
@ -171,6 +174,7 @@ namespace libtorrent
void second_tick();
boost::shared_ptr<libtorrent::socket> get_socket() const { return m_socket; }
address const& remote() const { return m_remote; }
const peer_id& get_peer_id() const { return m_peer_id; }
const std::vector<bool>& get_bitfield() const;
@ -182,6 +186,27 @@ namespace libtorrent
void disconnect();
bool is_disconnecting() const { return m_disconnecting; }
// this is called when the connection attempt has succeeded
// and the peer_connection is supposed to set m_connecting
// to false, and stop monitor writability
void connection_complete();
// returns true if this connection is still waiting to
// finish the connection attempt
bool is_connecting() const { return m_connecting; }
// returns true if the socket of this peer hasn't been
// attempted to connect yet (i.e. it's queued for
// connection attempt).
bool is_queued() const { return m_queued; }
// called when it's time for this peer_conncetion to actually
// initiate the tcp connection. This may be postponed until
// the library isn't using up the limitation of half-open
// tcp connections.
void connect();
// This is called for every peer right after the upload
// bandwidth has been distributed among them
// It will reset the used bandwidth to 0 and
@ -376,6 +401,7 @@ namespace libtorrent
// peer's socket from the writability monitor list.
selector& m_selector;
boost::shared_ptr<libtorrent::socket> m_socket;
address m_remote;
// this is the torrent this connection is
// associated with. If the connection is an
@ -529,8 +555,9 @@ namespace libtorrent
// this was the request we sent
std::pair<int, int> m_last_metadata_request;
// this is true until this socket has received
// data for the first time. While connecting
// this is true until this socket has become
// writable for the first time (i.e. the
// connection completed). While connecting
// the timeout will not be triggered. This is
// because windows XP SP2 may delay connection
// attempts, which means that the connection
@ -538,6 +565,11 @@ namespace libtorrent
// time out is reached.
bool m_connecting;
// This is true until connect is called on the
// peer_connection's socket. It is false on incoming
// connections.
bool m_queued;
// the number of bytes of metadata we have received
// so far from this per, only counting the current
// request. Any previously finished requests

View File

@ -51,7 +51,9 @@ namespace libtorrent
remote_interested = 0x4,
remote_choked = 0x8,
supports_extensions = 0x10,
local_connection = 0x20
local_connection = 0x20,
connecting = 0x40,
queued = 0x80
};
unsigned int flags;
address ip;

View File

@ -172,8 +172,11 @@ namespace libtorrent
friend class invariant_access;
// TODO: maybe this should be changed to a sorted vector
// using lower_bound?
typedef std::map<boost::shared_ptr<socket>, boost::shared_ptr<peer_connection> > connection_map;
typedef std::map<boost::shared_ptr<socket>, boost::shared_ptr<peer_connection> >
connection_map;
typedef std::map<sha1_hash, boost::shared_ptr<torrent> > torrent_map;
typedef std::deque<boost::shared_ptr<peer_connection> >
connection_queue;
session_impl(
std::pair<int, int> listen_port_range
@ -193,16 +196,31 @@ namespace libtorrent
tracker_manager m_tracker_manager;
torrent_map m_torrents;
// this will see if there are any pending connection attempts
// and in that case initiate new connections until the limit
// is reached.
void process_connection_queue();
// this maps sockets to their peer_connection
// object. It is the complete list of all connected
// peers.
connection_map m_connections;
// this is a list of half-open tcp connections
// (only outgoing connections)
connection_map m_half_open;
// this is a queue of pending outgoing connections. If the
// list of half-open connections is full (given the global
// limit), new outgoing connections are put on this queue,
// waiting for one slot in the half-open queue to open up.
connection_queue m_connection_queue;
// this is a list of iterators into the m_connections map
// that should be disconnected as soon as possible.
// It is used to delay disconnections to avoid troubles
// in loops that iterate over them.
std::vector<connection_map::iterator> m_disconnect_peer;
std::vector<boost::shared_ptr<peer_connection> > m_disconnect_peer;
// filters incomming connections
ip_filter m_ip_filter;
@ -253,6 +271,9 @@ namespace libtorrent
int m_download_rate;
int m_max_uploads;
int m_max_connections;
// the number of simultaneous half-open tcp
// connections libtorrent will have.
int m_half_open_limit;
// statistics gathered from all torrents.
stat m_stat;
@ -379,6 +400,7 @@ namespace libtorrent
void set_download_rate_limit(int bytes_per_second);
void set_max_uploads(int limit);
void set_max_connections(int limit);
void set_max_half_open_connections(int limit);
std::auto_ptr<alert> pop_alert();
void set_severity_level(alert::severity_t s);

View File

@ -133,7 +133,7 @@ namespace libtorrent
void set_blocking(bool blocking);
bool is_blocking() { return m_blocking; }
const address& sender() const { return m_sender; }
const address& sender() const { assert(m_sender != address()); return m_sender; }
address name() const;
void listen(libtorrent::address const& iface, int queue);

View File

@ -176,6 +176,7 @@ namespace libtorrent
torrent_status status() const;
void use_interface(const char* net_interface);
address const& interface() const { return m_net_interface; }
peer_connection& connect_to_peer(const address& a);
void set_ratio(float ratio)

View File

@ -77,7 +77,8 @@ namespace libtorrent
detail::session_impl& ses
, selector& sel
, torrent* t
, boost::shared_ptr<libtorrent::socket> s)
, boost::shared_ptr<libtorrent::socket> s
, address const& remote)
:
#ifndef NDEBUG
m_last_choke(boost::posix_time::second_clock::universal_time()
@ -92,11 +93,12 @@ namespace libtorrent
, m_last_sent(second_clock::universal_time())
, m_selector(sel)
, m_socket(s)
, m_remote(remote)
, m_torrent(t)
, m_attached_to_torrent(true)
, m_ses(ses)
, m_active(true)
, m_writability_monitored(false)
, m_writability_monitored(true)
, m_readability_monitored(true)
, m_peer_interested(false)
, m_peer_choked(true)
@ -119,9 +121,11 @@ namespace libtorrent
boost::gregorian::date(1970, boost::date_time::Jan, 1)
, boost::posix_time::seconds(0))
, m_waiting_metadata_request(false)
, m_connecting(false)
, m_connecting(true)
, m_queued(true)
, m_metadata_progress(0)
{
m_selector.monitor_writability(m_socket);
INVARIANT_CHECK;
// these numbers are used the first second of connection.
@ -158,8 +162,8 @@ namespace libtorrent
assert(m_torrent != 0);
#ifdef TORRENT_VERBOSE_LOGGING
m_logger = m_ses.create_log(s->sender().as_string() + "_"
+ boost::lexical_cast<std::string>(s->sender().port));
m_logger = m_ses.create_log(m_remote.as_string() + "_"
+ boost::lexical_cast<std::string>(m_remote.port));
(*m_logger) << "*** OUTGOING CONNECTION\n";
#endif
@ -202,6 +206,7 @@ namespace libtorrent
, m_last_sent(second_clock::universal_time())
, m_selector(sel)
, m_socket(s)
, m_remote(s->sender())
, m_torrent(0)
, m_attached_to_torrent(false)
, m_ses(ses)
@ -230,7 +235,8 @@ namespace libtorrent
boost::gregorian::date(1970, boost::date_time::Jan, 1)
, boost::posix_time::seconds(0))
, m_waiting_metadata_request(false)
, m_connecting(true)
, m_connecting(false)
, m_queued(false)
, m_metadata_progress(0)
{
INVARIANT_CHECK;
@ -274,8 +280,9 @@ namespace libtorrent
std::fill(m_peer_id.begin(), m_peer_id.end(), 0);
#ifdef TORRENT_VERBOSE_LOGGING
m_logger = m_ses.create_log(s->sender().as_string() + "_"
+ boost::lexical_cast<std::string>(s->sender().port));
assert(m_socket->sender() == remote());
m_logger = m_ses.create_log(remote().as_string() + "_"
+ boost::lexical_cast<std::string>(remote().port));
(*m_logger) << "*** INCOMING CONNECTION\n";
#endif
@ -374,7 +381,7 @@ namespace libtorrent
if (m_torrent)
{
torrent::peer_iterator i = m_torrent->m_connections.find(
get_socket()->sender());
remote());
assert(i == m_torrent->m_connections.end());
}
}
@ -939,7 +946,7 @@ namespace libtorrent
m_torrent->alerts().post_alert(invalid_request_alert(
r
, m_torrent->get_handle()
, m_socket->sender()
, m_remote
, m_peer_id
, "peer sent an illegal request, ignoring"));
}
@ -1058,7 +1065,7 @@ namespace libtorrent
{
m_torrent->alerts().post_alert(
peer_error_alert(
m_socket->sender()
m_remote
, m_peer_id
, "got a block that was not requested"));
}
@ -1077,7 +1084,7 @@ namespace libtorrent
bool was_finished = picker.num_filtered() + m_torrent->num_pieces()
== m_torrent->torrent_file().num_pieces();
picker.mark_as_finished(block_finished, m_socket->sender());
picker.mark_as_finished(block_finished, m_remote);
m_torrent->get_policy().block_finished(*this, block_finished);
@ -1297,7 +1304,7 @@ namespace libtorrent
m_torrent->alerts().post_alert(
chat_message_alert(
m_torrent->get_handle()
, m_socket->sender(), str));
, m_remote, str));
}
}
@ -1435,7 +1442,7 @@ namespace libtorrent
<< "<== LISTEN_PORT [ port: " << port << " ]\n";
#endif
address adr = m_socket->sender();
address adr = m_remote;
adr.port = port;
m_torrent->get_policy().peer_from_tracker(adr, m_peer_id);
}
@ -1450,14 +1457,17 @@ namespace libtorrent
void peer_connection::disconnect()
{
if (m_disconnecting) return;
detail::session_impl::connection_map::iterator i
= m_ses.m_connections.find(m_socket);
assert((m_ses.m_connections.find(m_socket) != m_ses.m_connections.end())
== !m_connecting);
m_disconnecting = true;
assert(i != m_ses.m_connections.end());
assert(std::find(m_ses.m_disconnect_peer.begin()
, m_ses.m_disconnect_peer.end(), i)
, m_ses.m_disconnect_peer.end(), shared_from_this())
== m_ses.m_disconnect_peer.end());
m_ses.m_disconnect_peer.push_back(i);
m_ses.m_disconnect_peer.push_back(shared_from_this());
}
bool peer_connection::dispatch_message(int received)
@ -1634,7 +1644,7 @@ namespace libtorrent
assert(block.block_index < m_torrent->torrent_file().piece_size(block.piece_index));
assert(!m_torrent->picker().is_downloading(block));
m_torrent->picker().mark_as_downloading(block, m_socket->sender());
m_torrent->picker().mark_as_downloading(block, m_remote);
m_request_queue.push_back(block);
send_block_requests();
}
@ -2141,7 +2151,6 @@ namespace libtorrent
if (received > 0)
{
m_connecting = false;
m_last_receive = second_clock::universal_time();
m_recv_pos += received;
@ -2426,6 +2435,46 @@ namespace libtorrent
return m_dl_bandwidth_quota.left() > 0;
}
void peer_connection::connect()
{
INVARIANT_CHECK;
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_ses.m_logger) << "CONNECT: " << m_remote.as_string() << "\n";
#endif
m_queued = false;
assert(m_connecting);
assert(associated_torrent());
m_socket->connect(m_remote, associated_torrent()->interface());
if (m_torrent->alerts().should_post(alert::debug))
{
m_torrent->alerts().post_alert(peer_error_alert(
m_remote, m_peer_id, "connecting to peer"));
}
}
void peer_connection::connection_complete()
{
INVARIANT_CHECK;
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_ses.m_logger) << "COMPLETED: " << m_remote.as_string() << "\n";
#endif
m_connecting = false;
// this means the connection just succeeded
// assert(!can_write());
// assert(m_writability_monitored);
if (!can_write() && m_writability_monitored)
{
m_writability_monitored = false;
m_selector.remove_writable(m_socket);
}
}
// --------------------------
// SEND DATA
// --------------------------
@ -2435,6 +2484,7 @@ namespace libtorrent
{
INVARIANT_CHECK;
assert(!m_connecting);
assert(!m_disconnecting);
assert(m_socket->is_writable());
assert(can_write());
@ -2585,7 +2635,7 @@ namespace libtorrent
#ifndef NDEBUG
void peer_connection::check_invariant() const
{
assert(can_write() == m_selector.is_writability_monitored(m_socket));
assert((can_write() || m_connecting) == m_selector.is_writability_monitored(m_socket));
/*
assert(m_num_pieces == std::count(

View File

@ -116,8 +116,9 @@ namespace
// the number of blocks we want, but it will try to make the picked
// blocks be from whole pieces, possibly by returning more blocks
// than we requested.
assert(c.remote() == c.get_socket()->sender());
p.pick_pieces(c.get_bitfield(), interesting_pieces
, num_requests, prefer_whole_pieces, c.get_socket()->sender());
, num_requests, prefer_whole_pieces, c.remote());
// this vector is filled with the interesting pieces
// that some other peer is currently downloading
@ -866,14 +867,15 @@ namespace libtorrent
// TODO: only allow _one_ connection to use this
// override at a time
assert(c.remote() == c.get_socket()->sender());
if (m_torrent->num_peers() >= m_torrent->m_connections_quota.given
&& c.get_socket()->sender().ip() != m_torrent->current_tracker().ip())
&& c.remote().ip() != m_torrent->current_tracker().ip())
{
throw protocol_error("too many connections, refusing incoming connection"); // cause a disconnect
}
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
if (c.get_socket()->sender().ip() == m_torrent->current_tracker().ip())
if (c.remote().ip() == m_torrent->current_tracker().ip())
{
m_torrent->debug_log("overriding connection limit for tracker NAT-check");
}
@ -882,7 +884,7 @@ namespace libtorrent
std::vector<peer>::iterator i = std::find_if(
m_peers.begin()
, m_peers.end()
, match_peer_ip(c.get_socket()->sender()));
, match_peer_ip(c.remote()));
if (i == m_peers.end())
{
@ -892,8 +894,10 @@ namespace libtorrent
// we don't have ny info about this peer.
// add a new entry
peer p(c.get_socket()->sender(), peer::not_connectable);
assert(c.remote() == c.get_socket()->sender());
peer p(c.remote(), peer::not_connectable);
m_peers.push_back(p);
check_invariant();
i = m_peers.end()-1;
}
else
@ -909,6 +913,7 @@ namespace libtorrent
i->prev_amount_download = 0;
i->prev_amount_upload = 0;
i->connection = &c;
assert(i->connection);
i->connected = second_clock::universal_time();
m_last_optimistic_disconnect = second_clock::universal_time();
}
@ -939,7 +944,7 @@ namespace libtorrent
m_peers.push_back(p);
// the iterator is invalid
// because of the push_back()
i = m_peers.end()-1;
i = m_peers.end() - 1;
}
else
{
@ -1157,7 +1162,9 @@ namespace libtorrent
{
try
{
assert(!p->connection);
p->connection = &m_torrent->connect_to_peer(p->id);
assert(p->connection);
p->connection->add_stat(p->prev_amount_download, p->prev_amount_upload);
p->prev_amount_download = 0;
p->prev_amount_upload = 0;
@ -1166,8 +1173,11 @@ namespace libtorrent
second_clock::universal_time();
return true;
}
catch (network_error&)
catch (network_error& e)
{
// TODO: This path needs testing!
std::string msg = e.what();
assert(false);
// TODO: remove the peer
// m_peers.erase(std::find(m_peers.begin(), m_peers.end(), p));
}
@ -1253,10 +1263,11 @@ namespace libtorrent
bool policy::has_connection(const peer_connection* c)
{
assert(c);
assert(c->remote() == c->get_socket()->sender());
return std::find_if(
m_peers.begin()
, m_peers.end()
, match_peer_ip(c->get_socket()->sender())) != m_peers.end();
, match_peer_ip(c->remote())) != m_peers.end();
}
void policy::check_invariant() const
@ -1264,10 +1275,17 @@ namespace libtorrent
if (m_torrent->is_aborted()) return;
int actual_unchoked = 0;
int connected_peers = 0;
int total_connections = 0;
int nonempty_connections = 0;
for (std::vector<peer>::const_iterator i = m_peers.begin();
i != m_peers.end(); ++i)
{
++total_connections;
if (!i->connection) continue;
++nonempty_connections;
if (!i->connection->is_disconnecting())
++connected_peers;
if (!i->connection->is_choked()) ++actual_unchoked;
@ -1291,6 +1309,7 @@ namespace libtorrent
// When there's an outgoing connection, it will first
// be added to the torrent and then to the policy.
// that's why the two second cases are in there.
assert(connected_peers == num_torrent_peers
|| (connected_peers == num_torrent_peers + 1
&& connected_peers > 0)

View File

@ -393,6 +393,7 @@ namespace libtorrent { namespace detail
, m_download_rate(-1)
, m_max_uploads(-1)
, m_max_connections(-1)
, m_half_open_limit(-1)
, m_incoming_connection(false)
{
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
@ -441,7 +442,34 @@ namespace libtorrent { namespace detail
{
while (!m_disconnect_peer.empty())
{
m_connections.erase(m_disconnect_peer.back());
boost::shared_ptr<peer_connection>& p = m_disconnect_peer.back();
assert(p->is_disconnecting());
if (p->is_connecting())
{
// Since this peer is still connecting, will not be
// in the list of completed connections.
connection_map::iterator i = m_half_open.find(p->get_socket());
if (i == m_half_open.end())
{
// this connection is not in the half-open list, so it
// has to be in the queue, waiting to be connected.
connection_queue::iterator j = std::find(
m_connection_queue.begin(), m_connection_queue.end(), p);
assert(j != m_connection_queue.end());
if (j != m_connection_queue.end()) m_connection_queue.erase(j);
}
else
{
m_half_open.erase(i);
}
}
else
{
connection_map::iterator i = m_connections.find(p->get_socket());
assert(i != m_connections.end());
if (i != m_connections.end()) m_connections.erase(i);
}
m_disconnect_peer.pop_back();
}
}
@ -514,6 +542,21 @@ namespace libtorrent { namespace detail
}
}
void session_impl::process_connection_queue()
{
while (!m_connection_queue.empty())
{
if ((int)m_half_open.size() >= m_half_open_limit
&& m_half_open_limit > 0)
return;
connection_queue::value_type& c = m_connection_queue.front();
m_half_open.insert(std::make_pair(c->get_socket(), c));
assert(c->associated_torrent());
c->connect();
m_connection_queue.pop_front();
}
}
void session_impl::operator()()
{
@ -605,7 +648,24 @@ namespace libtorrent { namespace detail
// the connection may have been disconnected in the receive phase
if (p == m_connections.end())
{
m_selector.remove(*i);
// if we didn't find the socket among the
// connected connections, look among the
// half-open connections to see if some of
// them have finished.
p = m_half_open.find(*i);
if (p == m_half_open.end())
{
m_selector.remove(*i);
}
else
{
p->second->connection_complete();
assert(!p->second->is_connecting());
m_connections.insert(*p);
m_half_open.erase(p);
process_connection_queue();
}
}
else
{
@ -703,6 +763,7 @@ namespace libtorrent { namespace detail
boost::shared_ptr<peer_connection> c(
new peer_connection(*this, m_selector, s));
assert(!c->is_connecting());
m_connections.insert(std::make_pair(s, c));
m_selector.monitor_readability(s);
m_selector.monitor_errors(s);
@ -773,6 +834,9 @@ namespace libtorrent { namespace detail
i != error_clients.end(); ++i)
{
connection_map::iterator p = m_connections.find(*i);
m_selector.remove(*i);
// the connection may have been disconnected in the receive or send phase
if (p != m_connections.end())
{
if (m_alerts.should_post(alert::debug))
@ -783,12 +847,7 @@ namespace libtorrent { namespace detail
, p->second->id()
, "connection closed"));
}
}
m_selector.remove(*i);
// the connection may have been disconnected in the receive or send phase
if (p != m_connections.end())
{
#if defined(TORRENT_VERBOSE_LOGGING)
(*p->second->m_logger) << "*** CONNECTION EXCEPTION\n";
#endif
@ -809,6 +868,32 @@ namespace libtorrent { namespace detail
assert(m_listen_socket.unique());
m_listen_socket.reset();
}
else
{
// the error was not in one of the connected
// conenctions. Look among the half-open ones.
p = m_half_open.find(*i);
if (p != m_half_open.end())
{
if (m_alerts.should_post(alert::debug))
{
m_alerts.post_alert(
peer_error_alert(
p->first->sender()
, p->second->id()
, "connection attempt failed"));
// TODO: TEMP!
#warning TEMP!
std::ofstream log("connect.log", std::ios::app);
log << boost::posix_time::microsec_clock::universal_time() << " FAILED: "
<< (*i)->sender().as_string() << std::endl;
p->second->set_failed();
m_half_open.erase(p);
}
}
}
}
#ifndef NDEBUG
@ -1003,17 +1088,25 @@ namespace libtorrent { namespace detail
{
assert(place);
for (connection_map::iterator i = m_half_open.begin();
i != m_half_open.end(); ++i)
{
assert(i->second->is_connecting());
}
for (connection_map::iterator i = m_connections.begin();
i != m_connections.end(); ++i)
{
assert(i->second);
if (i->second->can_write() != m_selector.is_writability_monitored(i->first)
if (i->second->is_connecting()
|| i->second->can_write() != m_selector.is_writability_monitored(i->first)
|| i->second->can_read() != m_selector.is_readability_monitored(i->first))
{
std::ofstream error_log("error.log", std::ios_base::app);
boost::shared_ptr<peer_connection> p = i->second;
error_log << "selector::is_writability_monitored() " << m_selector.is_writability_monitored(i->first) << "\n";
error_log << "selector::is_readability_monitored() " << m_selector.is_readability_monitored(i->first) << "\n";
error_log << "peer_connection::is_connecting() " << p->is_connecting() << "\n";
error_log << "peer_connection::can_write() " << p->can_write() << "\n";
error_log << "peer_connection::can_read() " << p->can_read() << "\n";
error_log << "peer_connection::ul_quota_left " << p->m_ul_bandwidth_quota.left() << "\n";
@ -1406,6 +1499,13 @@ namespace libtorrent
m_impl.m_max_connections = limit;
}
void session::set_max_half_open_connections(int limit)
{
assert(limit > 0 || limit == -1);
boost::mutex::scoped_lock l(m_impl.m_mutex);
m_impl.m_half_open_limit = limit;
}
void session::set_upload_rate_limit(int bytes_per_second)
{
assert(bytes_per_second > 0 || bytes_per_second == -1);

View File

@ -857,7 +857,7 @@ namespace libtorrent
{
assert(p != 0);
peer_iterator i = m_connections.find(p->get_socket()->sender());
peer_iterator i = m_connections.find(p->remote());
assert(i != m_connections.end());
if (ready_for_connections())
@ -903,25 +903,20 @@ namespace libtorrent
peer_connection& torrent::connect_to_peer(const address& a)
{
boost::shared_ptr<socket> s(new socket(socket::tcp, false));
s->connect(a, m_net_interface);
boost::shared_ptr<peer_connection> c(new peer_connection(
m_ses, m_ses.m_selector, this, s));
m_ses, m_ses.m_selector, this, s, a));
detail::session_impl::connection_map::iterator p =
m_ses.m_connections.insert(std::make_pair(s, c)).first;
m_ses.m_connection_queue.push_back(c);
// add the newly connected peer to this torrent's peer list
assert(m_connections.find(p->second->get_socket()->sender())
== m_connections.end());
assert(m_connections.find(a) == m_connections.end());
#ifndef NDEBUG
m_policy->check_invariant();
#endif
// add the newly connected peer to this torrent's peer list
m_connections.insert(
std::make_pair(
p->second->get_socket()->sender()
, boost::get_pointer(p->second)));
std::make_pair(a, boost::get_pointer(c)));
#ifndef NDEBUG
m_policy->check_invariant();
@ -929,13 +924,14 @@ namespace libtorrent
m_ses.m_selector.monitor_readability(s);
m_ses.m_selector.monitor_errors(s);
m_ses.process_connection_queue();
return *c;
}
void torrent::attach_peer(peer_connection* p)
{
assert(p != 0);
assert(m_connections.find(p->get_socket()->sender()) == m_connections.end());
assert(m_connections.find(p->remote()) == m_connections.end());
assert(!p->is_local());
detail::session_impl::connection_map::iterator i
@ -950,7 +946,8 @@ namespace libtorrent
// connection list.
m_policy->new_connection(*i->second);
m_connections.insert(std::make_pair(p->get_socket()->sender(), p));
assert(p->remote() == p->get_socket()->sender());
m_connections.insert(std::make_pair(p->remote(), p));
#ifndef NDEBUG
m_policy->check_invariant();

View File

@ -450,7 +450,7 @@ namespace libtorrent
// but still connectable
if (!i->second->is_local()) continue;
address ip = i->second->get_socket()->sender();
address ip = i->second->remote();
entry peer(entry::dictionary_t);
peer["ip"] = ip.as_string();
peer["port"] = ip.port;
@ -578,7 +578,7 @@ namespace libtorrent
p.payload_down_speed = statistics.download_payload_rate();
p.payload_up_speed = statistics.upload_payload_rate();
p.id = peer->get_peer_id();
p.ip = peer->get_socket()->sender();
p.ip = peer->remote();
p.total_download = statistics.total_payload_download();
p.total_upload = statistics.total_payload_upload();
@ -621,7 +621,9 @@ namespace libtorrent
if (peer->has_peer_choked()) p.flags |= peer_info::remote_choked;
if (peer->support_extensions()) p.flags |= peer_info::supports_extensions;
if (peer->is_local()) p.flags |= peer_info::local_connection;
if (peer->is_connecting() && !peer->is_queued()) p.flags |= peer_info::connecting;
if (peer->is_queued()) p.flags |= peer_info::queued;
p.pieces = peer->get_bitfield();
p.seed = peer->is_seed();
}