From 9d3b60edb739dd93a183b33229d5d03c85499c60 Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Thu, 28 Feb 2008 07:34:07 +0000 Subject: [PATCH] added support to bind outgoing connections to specific ports (might be useful to do traffic shaping) --- ChangeLog | 1 + docs/manual.html | 46 +++++++++++++++++++++--- docs/manual.rst | 7 ++++ examples/client_test.cpp | 9 +++++ include/libtorrent/aux_/session_impl.hpp | 6 ++++ include/libtorrent/session_settings.hpp | 7 ++++ src/policy.cpp | 3 +- src/session_impl.cpp | 20 +++++++++-- src/torrent.cpp | 10 ++++++ 9 files changed, 102 insertions(+), 7 deletions(-) diff --git a/ChangeLog b/ChangeLog index f2de0238e..21d54c108 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * Support to bind outgoing connections to specific ports * Disk cache support. * New, more memory efficient, piece picker with sequential download support (instead of the more complicated sequential download threshold). diff --git a/docs/manual.html b/docs/manual.html index e55cb2aaa..a2594a6e0 100644 --- a/docs/manual.html +++ b/docs/manual.html @@ -1143,7 +1143,7 @@ public: std::vector<std::string> const& url_seeds() const; size_type total_size() const; - size_type piece_length() const; + int piece_length() const; int num_pieces() const; sha1_hash const& info_hash() const; std::string const& name() const; @@ -1158,7 +1158,7 @@ public: void print(std::ostream& os) const; - size_type piece_size(unsigned int index) const; + int piece_size(unsigned int index) const; sha1_hash const& hash_for_piece(unsigned int index) const; }; @@ -1432,8 +1432,8 @@ struct announce_entry
 size_type total_size() const;
-size_type piece_length() const;
-size_type piece_size(unsigned int index) const;
+int piece_length() const;
+int piece_size(unsigned int index) const;
 int num_pieces() const;
 
@@ -2596,6 +2596,14 @@ struct session_settings int send_redundant_have; bool lazy_bitfields; int inactivity_timeout; + int unchoke_interval; + int optimistic_unchoke_multiplier; + address announce_ip; + int num_want; + int initial_picker_threshold; + int allowed_fast_set_size; + int max_outstanding_disk_bytes_per_connection; + int handshake_timeout; bool use_dht_as_fallback; bool free_torrent_hashes; bool upnp_ignore_nonrouters; @@ -2603,6 +2611,7 @@ struct session_settings bool auto_upload_slots; int cache_size; int cache_expiry; + std::pair<int, int> outgoing_ports; };

user_agent this is the client identification to the tracker. @@ -2700,6 +2709,30 @@ from seeding.

inactivity_timeout, if a peer is uninteresting and uninterested for longer than this number of seconds, it will be disconnected. Default is 10 minutes

+

unchoke_interval is the number of seconds between chokes/unchokes. +On this interval, peers are re-evaluated for being choked/unchoked. This +is defined as 30 seconds in the protocol, and it should be significantly +longer than what it takes for TCP to ramp up to it's max rate.

+

optimistic_unchoke_multiplier is the number of unchoke intervals between +each optimistic unchoke interval. On this timer, the currently optimistically +unchoked peer will change.

+

announce_ip is the ip address passed along to trackers as the &ip= parameter. +If left as the default (default constructed), that parameter is ommited.

+

num_want is the number of peers we want from each tracker request. It defines +what is sent as the &num_want= parameter to the tracker.

+

initial_picker_threshold specifies the number of pieces we need before we +switch to rarest first picking. This defaults to 4, which means the 4 first +pieces in any torrent are picked at random, the following pieces are picked +in rarest first order.

+

allowed_fast_set_size is the number of pieces we allow peers to download +from us without being unchoked.

+

max_outstanding_disk_bytes_per_connection is the number of bytes each +connection is allowed to have waiting in the disk I/O queue before it is +throttled back. This limit is meant to stop fast internet connections to +queue up bufferes indefinitely on slow hard-drives or storage.

+

handshake_timeout specifies the number of seconds we allow a peer to +delay responding to a protocol handshake. If no response is received within +this time, the connection is closed.

use_dht_as_fallback determines how the DHT is used. If this is true (which it is by default), the DHT will only be used for torrents where all trackers in its tracker list has failed. Either by an explicit error @@ -2730,6 +2763,11 @@ current number of upload slots, see cache_expiry is the number of seconds from the last cached write to a piece in the write cache, to when it's forcefully flushed to disk. Default is 60 second.

+

outgoing_ports, if set to something other than (0, 0) is a range of ports +used to bind outgoing sockets to. This may be useful for users whose router +allows them to assign QoS classes to traffic based on its local port. It is +a range instead of a single port because of the problems with failing to reconnect +to peers if a previous socket to that peer and port is in TIME_WAIT state.

pe_settings

diff --git a/docs/manual.rst b/docs/manual.rst index d22d1454a..1249f17ee 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -2604,6 +2604,7 @@ that will be sent to the tracker. The user-agent is a good way to identify your bool auto_upload_slots; int cache_size; int cache_expiry; + std::pair outgoing_ports; }; ``user_agent`` this is the client identification to the tracker. @@ -2793,6 +2794,12 @@ It defaults to 128 (= 2 MB). ``cache_expiry`` is the number of seconds from the last cached write to a piece in the write cache, to when it's forcefully flushed to disk. Default is 60 second. +``outgoing_ports``, if set to something other than (0, 0) is a range of ports +used to bind outgoing sockets to. This may be useful for users whose router +allows them to assign QoS classes to traffic based on its local port. It is +a range instead of a single port because of the problems with failing to reconnect +to peers if a previous socket to that peer and port is in ``TIME_WAIT`` state. + pe_settings =========== diff --git a/examples/client_test.cpp b/examples/client_test.cpp index 09769f847..b9d7f1857 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -582,6 +582,8 @@ int main(int ac, char* av[]) std::string proxy_type; int poll_interval; int wait_retry; + int bind_port_start = 0; + int bind_port_end = 0; namespace po = boost::program_options; try @@ -643,6 +645,10 @@ int main(int ac, char* av[]) "proxy. The string should be given in the form: :") ("proxy-type", po::value(&proxy_type)->default_value("socks5") , "Sets the type of proxy to use [socks5 | http] ") + ("bind-port-start", po::value(&bind_port_start)->default_value(0) + , "The lower port number that outgoing connections will be bound to") + ("bind-port-end", po::value(&bind_port_end)->default_value(0) + , "The upper port number that outgoing connections will be bound to") ; po::positional_options_description p; @@ -735,6 +741,9 @@ int main(int ac, char* av[]) settings.user_agent = "client_test/" LIBTORRENT_VERSION; settings.urlseed_wait_retry = wait_retry; + settings.outgoing_ports.first = bind_port_start; + settings.outgoing_ports.second = bind_port_end; + std::deque events; ptime next_dir_scan = time_now(); diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index 4a75687a7..2607b0356 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -375,6 +375,8 @@ namespace libtorrent void stop_natpmp(); void stop_upnp(); + int next_port(); + // handles delayed alerts alert_manager m_alerts; @@ -551,6 +553,10 @@ namespace libtorrent void second_tick(asio::error_code const& e); ptime m_last_tick; + // when outgoing_ports is configured, this is the + // port we'll bind the next outgoing socket to + int m_next_port; + #ifndef TORRENT_DISABLE_DHT boost::intrusive_ptr m_dht; dht_settings m_dht_settings; diff --git a/include/libtorrent/session_settings.hpp b/include/libtorrent/session_settings.hpp index 55b332f45..5087a0f25 100644 --- a/include/libtorrent/session_settings.hpp +++ b/include/libtorrent/session_settings.hpp @@ -126,6 +126,7 @@ namespace libtorrent , auto_upload_slots(true) , cache_size(512) , cache_expiry(60) + , outgoing_ports(0,0) {} // this is the user agent that will be sent to the tracker @@ -332,6 +333,12 @@ namespace libtorrent // idle in the cache before it's forcefully flushed // to disk. Default is 60 seconds. int cache_expiry; + + // if != (0, 0), this is the range of ports that + // outgoing connections will be bound to. This + // is useful for users that have routers that + // allow QoS settings based on local port. + std::pair outgoing_ports; }; #ifndef TORRENT_DISABLE_DHT diff --git a/src/policy.cpp b/src/policy.cpp index 1023b5388..16c81a149 100755 --- a/src/policy.cpp +++ b/src/policy.cpp @@ -585,7 +585,8 @@ namespace libtorrent #if defined TORRENT_LOGGING || defined TORRENT_VERBOSE_LOGGING if (candidate != m_peers.end()) { - (*m_torrent->session().m_logger) << "*** FOUND CONNECTION CANDIDATE [" + (*m_torrent->session().m_logger) << time_now_string() + << " *** FOUND CONNECTION CANDIDATE [" " ip: " << candidate->second.ip << " d: " << min_cidr_distance << " external: " << external_ip << diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 3d3392b6a..8dd0a3f8a 100755 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -1138,6 +1138,22 @@ namespace detail m_key = key; } + int session_impl::next_port() + { + std::pair const& out_ports = m_settings.outgoing_ports; + if (m_next_port < out_ports.first || m_next_port > out_ports.second) + m_next_port = out_ports.first; + + int port = m_next_port; + ++m_next_port; + if (m_next_port > out_ports.second) m_next_port = out_ports.first; +#if defined TORRENT_LOGGING + (*m_logger) << time_now_string() << " *** BINDING OUTGOING CONNECTION [ " + "port: " << port << " ]\n"; +#endif + return port; + } + void session_impl::second_tick(asio::error_code const& e) try { session_impl::mutex_t::scoped_lock l(m_mutex); @@ -1149,10 +1165,10 @@ namespace detail if (e) { -#if defined(TORRENT_LOGGING) +#if defined TORRENT_LOGGING (*m_logger) << "*** SECOND TIMER FAILED " << e.message() << "\n"; #endif - abort(); + ::abort(); return; } diff --git a/src/torrent.cpp b/src/torrent.cpp index 7f56a2ab8..5553b9fc0 100755 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -1790,6 +1790,12 @@ namespace libtorrent // the proxy, without requiring CONNECT support s->get().set_no_connect(true); } + + std::pair const& out_ports = m_settings.outgoing_ports; + asio::error_code ec; + if (out_ports.first > 0 && out_ports.second >= out_ports.first) + s->bind(tcp::endpoint(address(), m_ses.next_port()), ec); + boost::intrusive_ptr c(new web_peer_connection( m_ses, shared_from_this(), s, a, url, 0)); @@ -2087,6 +2093,10 @@ namespace libtorrent bool ret = instantiate_connection(m_ses.m_io_service, m_ses.peer_proxy(), *s); TORRENT_ASSERT(ret); + std::pair const& out_ports = m_ses.settings().outgoing_ports; + asio::error_code ec; + if (out_ports.first > 0 && out_ports.second >= out_ports.first) + s->bind(tcp::endpoint(address(), m_ses.next_port()), ec); boost::intrusive_ptr c(new bt_peer_connection( m_ses, shared_from_this(), s, a, peerinfo));