diff --git a/ChangeLog b/ChangeLog index 705718480..0d1ac55f0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,4 @@ + * improved support for multi-homed clients * added feature to not count downloaded bytes from web seeds in stats * added alert for incoming local service discovery messages * added option to set file priorities when adding torrents diff --git a/docs/manual.rst b/docs/manual.rst index dd0188d1f..d450fc76e 100644 --- a/docs/manual.rst +++ b/docs/manual.rst @@ -2744,8 +2744,10 @@ use_interface() ``use_interface()`` sets the network interface this torrent will use when it opens outgoing connections. By default, it uses the same interface as the session_ uses to listen on. The -parameter must be a string containing an ip-address (either an IPv4 or IPv6 address). If -the string does not conform to this format and exception is thrown. +parameter must be a string containing one or more, comma separated, ip-address (either an +IPv4 or IPv6 address). When specifying multiple interfaces, the torrent will round-robin +which interface to use for each outgoing conneciton. This is useful for clients that are +multi-homed. info_hash() @@ -3485,6 +3487,8 @@ It contains the following fields:: float progress; int progress_ppm; + + tcp::endpoint local_endpoint; }; The ``flags`` attribute tells you in which state the peer is. It is set to @@ -3710,6 +3714,11 @@ floating point operations are diabled, instead use ``progress_ppm``. ``progress_ppm`` indicates the download progress of the peer in the range [0, 1000000] (parts per million). +``local_endpoint`` is the IP and port pair the socket is bound to locally. i.e. the IP +address of the interface it's going out over. This may be useful for multi-homed +clients with multiple interfaces to the internet. + + session customization ===================== diff --git a/examples/client_test.cpp b/examples/client_test.cpp index e4464c61b..6d64077de 100644 --- a/examples/client_test.cpp +++ b/examples/client_test.cpp @@ -329,7 +329,7 @@ int peer_index(libtorrent::tcp::endpoint addr, std::vector const& peers) { using namespace libtorrent; - if (print_ip) out += "IP "; + if (print_ip) out += "IP "; #ifndef TORRENT_DISABLE_GEO_IP if (print_as) out += "AS "; #endif @@ -355,7 +355,8 @@ void print_peer_info(std::string& out, std::vector const& if (print_ip) { error_code ec; - snprintf(str, sizeof(str), "%-22s:%-5d ", i->ip.address().to_string(ec).c_str(), i->ip.port()); + snprintf(str, sizeof(str), "%-22s %22s ", print_endpoint(i->ip).c_str() + , print_endpoint(i->local_endpoint).c_str()); out += str; } @@ -511,6 +512,7 @@ int torrent_upload_limit = 0; int torrent_download_limit = 0; std::string monitor_dir; std::string bind_to_interface = ""; +std::string outgoing_interface = ""; int poll_interval = 5; int max_connections_per_torrent = 50; @@ -573,6 +575,7 @@ void add_torrent(libtorrent::session& ses h.set_ratio(preferred_ratio); h.set_upload_limit(torrent_upload_limit); h.set_download_limit(torrent_download_limit); + h.use_interface(outgoing_interface.c_str()); #ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES h.resolve_countries(true); #endif @@ -752,6 +755,8 @@ int main(int argc, char* argv[]) " -m sets the .torrent monitor directory\n" " -b sets IP of the interface to bind the\n" " listen socket to\n" + " -I sets the IP of the interface to bind\n" + " outgoing peer connections to\n" " -w sets the retry time for failed web seeds\n" " -t sets the scan interval of the monitor dir\n" " -x loads an emule IP-filter file\n" @@ -956,6 +961,7 @@ int main(int argc, char* argv[]) #endif } break; + case 'I': outgoing_interface = arg; break; } ++i; // skip the argument } @@ -999,6 +1005,7 @@ int main(int argc, char* argv[]) h.set_ratio(preferred_ratio); h.set_upload_limit(torrent_upload_limit); h.set_download_limit(torrent_download_limit); + h.use_interface(outgoing_interface.c_str()); } for (std::vector::iterator i = torrents.begin() @@ -1026,6 +1033,7 @@ int main(int argc, char* argv[]) h.set_ratio(preferred_ratio); h.set_upload_limit(torrent_upload_limit); h.set_download_limit(torrent_download_limit); + h.use_interface(outgoing_interface.c_str()); continue; } diff --git a/include/libtorrent/peer_info.hpp b/include/libtorrent/peer_info.hpp index de59c9d0e..00750d08e 100644 --- a/include/libtorrent/peer_info.hpp +++ b/include/libtorrent/peer_info.hpp @@ -216,6 +216,8 @@ namespace libtorrent int progress_ppm; // [0, 1000000] int estimated_reciprocation_rate; + + tcp::endpoint local_endpoint; }; struct TORRENT_EXPORT peer_list_entry diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp index 434fecf4d..2ae20d86b 100644 --- a/include/libtorrent/torrent.hpp +++ b/include/libtorrent/torrent.hpp @@ -309,7 +309,7 @@ namespace libtorrent void file_progress(std::vector& fp, int flags = 0) const; void use_interface(std::string net_interface); - tcp::endpoint get_interface() const { return m_net_interface; } + tcp::endpoint get_interface() const; void connect_to_url_seed(std::list::iterator url); bool connect_to_peer(policy::peer* peerinfo); @@ -939,9 +939,10 @@ namespace libtorrent std::string m_username; std::string m_password; - // the network interface all outgoing connections - // are opened through - union_endpoint m_net_interface; + // the network interfaces outgoing connections + // are opened through. If there is more then one, + // they are used in a round-robin fasion + std::vector m_net_interfaces; std::string m_save_path; @@ -1208,6 +1209,9 @@ namespace libtorrent // the number of seconds since the last byte was uploaded // from this torrent boost::uint16_t m_last_upload; + + // round-robin index into m_interfaces + mutable boost::uint8_t m_interface_index; }; } diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 52e705469..b4f7a0bcf 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -3471,6 +3471,9 @@ namespace libtorrent int upload_capacity = m_ses.upload_rate_limit(); if (upload_capacity == 0) upload_capacity = (std::max)(20000, m_ses.m_peak_up_rate + 10000); + + error_code ec; + p.local_endpoint = get_socket()->local_endpoint(ec); } // allocates a disk buffer of size 'disk_buffer_size' and replaces the diff --git a/src/torrent.cpp b/src/torrent.cpp index c96ccb6f6..bb5e8bbe9 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -77,6 +77,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/broadcast_socket.hpp" #include "libtorrent/kademlia/dht_tracker.hpp" #include "libtorrent/peer_info.hpp" +#include "libtorrent/enum_net.hpp" #if TORRENT_USE_IOSTREAM #include @@ -226,7 +227,7 @@ namespace libtorrent PRINT_OFFSETOF(torrent, m_time_critical_pieces) PRINT_OFFSETOF(torrent, m_username) PRINT_OFFSETOF(torrent, m_password) - PRINT_OFFSETOF(torrent, m_net_interface) + PRINT_OFFSETOF(torrent, m_net_interfaces) PRINT_OFFSETOF(torrent, m_save_path) PRINT_OFFSETOF(torrent, m_verified) PRINT_OFFSETOF(torrent, m_error) @@ -323,7 +324,6 @@ namespace libtorrent , m_tracker_timer(ses.m_io_service) , m_ses(ses) , m_trackers(m_torrent_file->trackers()) - , m_net_interface(tcp::endpoint(net_interface.address(), 0)) , m_save_path(complete(p.save_path)) , m_storage_constructor(p.storage) , m_ratio(0.f) @@ -381,7 +381,10 @@ namespace libtorrent , m_last_scrape(0) , m_last_download(0) , m_last_upload(0) + , m_interface_index(0) { + m_net_interfaces.push_back(net_interface); + if (p.file_priorities) m_file_priority = *p.file_priorities; @@ -1269,14 +1272,30 @@ namespace libtorrent files_checked(); } - void torrent::use_interface(std::string net_interface) + void torrent::use_interface(std::string net_interfaces) { INVARIANT_CHECK; + m_net_interfaces.clear(); - error_code ec; - address a(address::from_string(net_interface.c_str(), ec)); - if (ec) return; - m_net_interface = tcp::endpoint(a, 0); + char* str = &net_interfaces[0]; + + while (str) + { + char* space = strchr(str, ','); + if (space) *space++ = 0; + error_code ec; + address a(address::from_string(str, ec)); + str = space; + if (ec) continue; + m_net_interfaces.push_back(tcp::endpoint(a, 0)); + } + } + + tcp::endpoint torrent::get_interface() const + { + if (m_net_interfaces.empty()) return tcp::endpoint(address_v4(), 0); + if (m_interface_index >= m_net_interfaces.size()) m_interface_index = 0; + return m_net_interfaces[m_interface_index++]; } void torrent::on_tracker_announce_disp(boost::weak_ptr p