diff --git a/ChangeLog b/ChangeLog
index 20331c068..ed03f4213 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,4 @@
+ * improved IPv6 support by announcing twice when necessary
* added feature to set a separate global rate limit for local peers
* added preset settings for low memory environments and seed machines
min_memory_usage() and high_performance_seeder()
diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp
index 7f658630b..c40a1f13c 100644
--- a/include/libtorrent/aux_/session_impl.hpp
+++ b/include/libtorrent/aux_/session_impl.hpp
@@ -719,6 +719,7 @@ namespace libtorrent
void tracker_response(tracker_request const&
, libtorrent::address const& tracker_ip
+ , std::list
const& ip_list
, std::vector& peers
, int interval
, int complete
@@ -737,7 +738,7 @@ namespace libtorrent
to_hex((const char*)&i->pid[0], 20, pid);
if (i->pid.is_all_zeros()) pid[0] = 0;
- snprintf(tmp, 200, " %16s %5d %s\n", i->ip.c_str(), i->port, pid);
+ snprintf(tmp, 200, " %-16s %-5d %s\n", i->ip.c_str(), i->port, pid);
s += tmp;
}
snprintf(tmp, 200, "external ip: %s\n", print_address(external_ip).c_str());
diff --git a/include/libtorrent/http_connection.hpp b/include/libtorrent/http_connection.hpp
index fb88d0649..9bf9727c5 100644
--- a/include/libtorrent/http_connection.hpp
+++ b/include/libtorrent/http_connection.hpp
@@ -122,6 +122,8 @@ struct http_connection : boost::enable_shared_from_this, boost:
#else
socket_type const& socket() const { return m_sock; }
#endif
+
+ std::list const& endpoints() const { return m_endpoints; }
private:
diff --git a/include/libtorrent/http_tracker_connection.hpp b/include/libtorrent/http_tracker_connection.hpp
index d94637d54..47d7a1ac4 100644
--- a/include/libtorrent/http_tracker_connection.hpp
+++ b/include/libtorrent/http_tracker_connection.hpp
@@ -70,7 +70,6 @@ namespace libtorrent
, connection_queue& cc
, tracker_manager& man
, tracker_request const& req
- , address bind_infc
, boost::weak_ptr c
, aux::session_impl const& ses
, proxy_settings const& ps
@@ -97,7 +96,6 @@ namespace libtorrent
tracker_manager& m_man;
boost::shared_ptr m_tracker_connection;
aux::session_impl const& m_ses;
- address m_bind_iface;
address m_tracker_ip;
proxy_settings const& m_ps;
connection_queue& m_cc;
diff --git a/include/libtorrent/torrent.hpp b/include/libtorrent/torrent.hpp
index 31fad4605..ba2fa5dee 100644
--- a/include/libtorrent/torrent.hpp
+++ b/include/libtorrent/torrent.hpp
@@ -363,6 +363,7 @@ namespace libtorrent
virtual void tracker_response(
tracker_request const& r
, address const& tracker_ip
+ , std::list const& ip_list
, std::vector& e, int interval
, int complete, int incomplete, address const& external_ip);
virtual void tracker_request_timed_out(
@@ -390,7 +391,8 @@ namespace libtorrent
void force_tracker_request(ptime);
void scrape_tracker();
void announce_with_tracker(tracker_request::event_t e
- = tracker_request::none);
+ = tracker_request::none
+ , address const& bind_interface = address_v4::any());
ptime const& last_scrape() const { return m_last_scrape; }
// sets the username and password that will be sent to
diff --git a/include/libtorrent/tracker_manager.hpp b/include/libtorrent/tracker_manager.hpp
index d76aea6c6..c8155b7bb 100644
--- a/include/libtorrent/tracker_manager.hpp
+++ b/include/libtorrent/tracker_manager.hpp
@@ -110,6 +110,7 @@ namespace libtorrent
int num_want;
std::string ipv6;
std::string ipv4;
+ address bind_ip;
};
struct TORRENT_EXPORT request_callback
@@ -124,6 +125,7 @@ namespace libtorrent
virtual void tracker_response(
tracker_request const& req
, address const& tracker_ip
+ , std::list const& ip_list
, std::vector& peers
, int interval
, int complete
@@ -187,7 +189,6 @@ namespace libtorrent
tracker_connection(tracker_manager& man
, tracker_request const& req
, io_service& ios
- , address bind_interface
, boost::weak_ptr r);
boost::shared_ptr requester();
@@ -199,14 +200,13 @@ namespace libtorrent
void fail_timeout();
virtual void start() = 0;
virtual void close();
- address const& bind_interface() const { return m_bind_interface; }
+ address const& bind_interface() const { return m_req.bind_ip; }
void sent_bytes(int bytes);
void received_bytes(int bytes);
protected:
boost::weak_ptr m_requester;
private:
- address m_bind_interface;
tracker_manager& m_man;
const tracker_request m_req;
};
@@ -226,7 +226,6 @@ namespace libtorrent
, connection_queue& cc
, tracker_request r
, std::string const& auth
- , address bind_infc
, boost::weak_ptr c
= boost::weak_ptr());
void abort_all_requests(bool all = false);
diff --git a/include/libtorrent/udp_tracker_connection.hpp b/include/libtorrent/udp_tracker_connection.hpp
index 114e414f2..f0a777a1a 100644
--- a/include/libtorrent/udp_tracker_connection.hpp
+++ b/include/libtorrent/udp_tracker_connection.hpp
@@ -71,7 +71,6 @@ namespace libtorrent
, connection_queue& cc
, tracker_manager& man
, tracker_request const& req
- , address bind_infc
, boost::weak_ptr c
, aux::session_impl const& ses
, proxy_settings const& ps);
@@ -112,6 +111,7 @@ namespace libtorrent
udp::resolver m_name_lookup;
udp_socket m_socket;
udp::endpoint m_target;
+ std::list m_endpoints;
int m_transaction_id;
boost::int64_t m_connection_id;
diff --git a/src/http_connection.cpp b/src/http_connection.cpp
index cf35eb5dd..4be7d1150 100644
--- a/src/http_connection.cpp
+++ b/src/http_connection.cpp
@@ -298,8 +298,10 @@ void http_connection::on_resolve(error_code const& e
// sort the endpoints so that the ones with the same IP version as our
// bound listen socket are first. So that when contacting a tracker,
// we'll talk to it from the same IP that we're listening on
- std::partition(m_endpoints.begin(), m_endpoints.end()
- , boost::bind(&address::is_v4, boost::bind(&tcp::endpoint::address, _1)) == m_bind_addr.is_v4());
+ if (m_bind_addr != address_v4::any())
+ std::partition(m_endpoints.begin(), m_endpoints.end()
+ , boost::bind(&address::is_v4, boost::bind(&tcp::endpoint::address, _1))
+ == m_bind_addr.is_v4());
#endif
queue_connect();
diff --git a/src/http_tracker_connection.cpp b/src/http_tracker_connection.cpp
index 1796228ea..80adecab4 100644
--- a/src/http_tracker_connection.cpp
+++ b/src/http_tracker_connection.cpp
@@ -70,15 +70,13 @@ namespace libtorrent
, connection_queue& cc
, tracker_manager& man
, tracker_request const& req
- , address bind_infc
, boost::weak_ptr c
, aux::session_impl const& ses
, proxy_settings const& ps
, std::string const& auth)
- : tracker_connection(man, req, ios, bind_infc, c)
+ : tracker_connection(man, req, ios, c)
, m_man(man)
, m_ses(ses)
- , m_bind_iface(bind_infc)
, m_ps(ps)
, m_cc(cc)
, m_ios(ios)
@@ -173,7 +171,7 @@ namespace libtorrent
:settings.tracker_completion_timeout;
m_tracker_connection->get(url, seconds(timeout)
- , 1, &m_ps, 5, settings.user_agent, m_bind_iface);
+ , 1, &m_ps, 5, settings.user_agent, bind_interface());
// the url + 100 estimated header size
sent_bytes(url.size() + 100);
@@ -476,8 +474,14 @@ namespace libtorrent
if (incomplete_ent && incomplete_ent->type() == entry::int_t)
incomplete = int(incomplete_ent->integer());
- cb->tracker_response(tracker_req(), m_tracker_ip, peer_list, interval->integer(), complete
- , incomplete, external_ip);
+ std::list ip_list;
+ std::transform(m_tracker_connection->endpoints().begin()
+ , m_tracker_connection->endpoints().end()
+ , std::back_inserter(ip_list)
+ , boost::bind(&tcp::endpoint::address, _1));
+
+ cb->tracker_response(tracker_req(), m_tracker_ip, ip_list, peer_list
+ , interval->integer(), complete, incomplete, external_ip);
}
}
diff --git a/src/torrent.cpp b/src/torrent.cpp
index a5478a24c..03c3e3b08 100644
--- a/src/torrent.cpp
+++ b/src/torrent.cpp
@@ -1054,7 +1054,8 @@ namespace libtorrent
#endif
- void torrent::announce_with_tracker(tracker_request::event_t e)
+ void torrent::announce_with_tracker(tracker_request::event_t e
+ , address const& bind_interface)
{
INVARIANT_CHECK;
@@ -1106,6 +1107,9 @@ namespace libtorrent
if (!ae.complete_sent && is_seed()) req.event = tracker_request::completed;
}
+ if (!is_any(bind_interface)) req.bind_ip = bind_interface;
+ else req.bind_ip = m_ses.m_listen_interface.address();
+
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
(*m_ses.m_logger) << time_now_string() << " ==> TACKER REQUEST " << req.url
<< " event=" << (req.event==tracker_request::stopped?"stopped"
@@ -1115,13 +1119,12 @@ namespace libtorrent
{
boost::shared_ptr tl(new aux::tracker_logger(m_ses));
m_ses.m_tracker_manager.queue_request(m_ses.m_io_service, m_ses.m_half_open, req
- , tracker_login(), m_ses.m_listen_interface.address(), tl);
+ , tracker_login(), tl);
}
else
#endif
m_ses.m_tracker_manager.queue_request(m_ses.m_io_service, m_ses.m_half_open, req
- , tracker_login(), m_ses.m_listen_interface.address()
- , m_abort?boost::shared_ptr():shared_from_this());
+ , tracker_login() , m_abort?boost::shared_ptr():shared_from_this());
ae.updating = true;
if (m_ses.m_alerts.should_post())
@@ -1146,8 +1149,9 @@ namespace libtorrent
req.info_hash = m_torrent_file->info_hash();
req.kind = tracker_request::scrape_request;
req.url = m_trackers[i].url;
+ req.bind_ip = m_ses.m_listen_interface.address();
m_ses.m_tracker_manager.queue_request(m_ses.m_io_service, m_ses.m_half_open, req
- , tracker_login(), m_ses.m_listen_interface.address(), shared_from_this());
+ , tracker_login(), shared_from_this());
m_last_scrape = time_now();
}
@@ -1182,7 +1186,8 @@ namespace libtorrent
void torrent::tracker_response(
tracker_request const& r
- , address const& tracker_ip
+ , address const& tracker_ip // this is the IP we connected to
+ , std::list const& tracker_ips // these are all the IPs it resolved to
, std::vector& peer_list
, int interval
, int complete
@@ -1237,6 +1242,10 @@ namespace libtorrent
s << "\n";
}
s << "external ip: " << external_ip << "\n";
+ s << "tracker ips: ";
+ std::copy(tracker_ips.begin(), tracker_ips.end(), std::ostream_iterator(s, " "));
+ s << "\n";
+ s << "we connected to: " << tracker_ip << "\n";
debug_log(s.str());
#endif
// for each of the peers we got from the tracker
@@ -1273,6 +1282,41 @@ namespace libtorrent
get_handle(), peer_list.size(), r.url));
}
m_got_tracker_response = true;
+
+ // we're listening on an interface type that was not used
+ // when talking to the tracker. If there is a matching interface
+ // type in the tracker IP list, make another tracker request
+ // using that interface
+ // in order to avoid triggering this case over and over, don't
+ // do it if the bind IP for the tracker request that just completed
+ // matches one of the listen interfaces, since that means this
+ // announce was the second one
+ // don't connect twice just to tell it we're stopping
+
+ if (((!is_any(m_ses.m_ipv6_interface.address()) && tracker_ip.is_v4())
+ || (!is_any(m_ses.m_ipv4_interface.address()) && tracker_ip.is_v6()))
+ && r.bind_ip != m_ses.m_ipv4_interface.address()
+ && r.bind_ip != m_ses.m_ipv6_interface.address()
+ && r.event != tracker_request::stopped)
+ {
+ std::list::const_iterator i = std::find_if(tracker_ips.begin()
+ , tracker_ips.end(), boost::bind(&address::is_v4, _1) != tracker_ip.is_v4());
+ if (i != tracker_ips.end())
+ {
+ // the tracker did resolve to a different type if address, so announce
+ // to that as well
+
+ // tell the tracker to bind to the opposite protocol type
+ address bind_interface = tracker_ip.is_v4()
+ ?m_ses.m_ipv6_interface.address()
+ :m_ses.m_ipv4_interface.address();
+ announce_with_tracker(r.event, bind_interface);
+#if (defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING) && TORRENT_USE_IOSTREAM
+ debug_log("announce again using " + print_address(bind_interface)
+ + " as the bind interface");
+#endif
+ }
+ }
}
void torrent::on_peer_name_lookup(error_code const& e, tcp::resolver::iterator host
diff --git a/src/tracker_manager.cpp b/src/tracker_manager.cpp
index 318d2dbb7..40966ed35 100644
--- a/src/tracker_manager.cpp
+++ b/src/tracker_manager.cpp
@@ -133,11 +133,9 @@ namespace libtorrent
tracker_manager& man
, tracker_request const& req
, io_service& ios
- , address bind_interface_
, boost::weak_ptr r)
: timeout_handler(ios)
, m_requester(r)
- , m_bind_interface(bind_interface_)
, m_man(man)
, m_req(req)
{}
@@ -211,7 +209,6 @@ namespace libtorrent
, connection_queue& cc
, tracker_request req
, std::string const& auth
- , address bind_infc
, boost::weak_ptr c)
{
mutex_t::scoped_lock l(m_mutex);
@@ -236,14 +233,14 @@ namespace libtorrent
#endif
{
con = new http_tracker_connection(
- ios, cc, *this, req, bind_infc, c
+ ios, cc, *this, req, c
, m_ses, m_proxy, auth);
}
else if (protocol == "udp")
{
con = new udp_tracker_connection(
- ios, cc, *this, req, bind_infc
- , c, m_ses, m_proxy);
+ ios, cc, *this, req , c, m_ses
+ , m_proxy);
}
else
{
diff --git a/src/udp_tracker_connection.cpp b/src/udp_tracker_connection.cpp
index 26128d771..3a86e1259 100644
--- a/src/udp_tracker_connection.cpp
+++ b/src/udp_tracker_connection.cpp
@@ -75,11 +75,10 @@ namespace libtorrent
, connection_queue& cc
, tracker_manager& man
, tracker_request const& req
- , address bind_infc
, boost::weak_ptr c
, aux::session_impl const& ses
, proxy_settings const& proxy)
- : tracker_connection(man, req, ios, bind_infc, c)
+ : tracker_connection(man, req, ios, c)
, m_man(man)
, m_name_lookup(ios)
, m_socket(ios, boost::bind(&udp_tracker_connection::on_receive, self(), _1, _2, _3, _4), cc)
@@ -143,42 +142,69 @@ namespace libtorrent
// look for an address that has the same kind as the one
// we're listening on. To make sure the tracker get our
// correct listening address.
- udp::resolver::iterator target = i;
- udp::resolver::iterator end;
- udp::endpoint target_address = *i;
- for (; target != end && target->endpoint().address().is_v4()
- != bind_interface().is_v4(); ++target);
- if (target == end)
+
+ std::transform(i, udp::resolver::iterator(), std::back_inserter(m_endpoints)
+ , boost::bind(&udp::resolver::iterator::value_type::endpoint, _1));
+
+ // remove endpoints that are filtered by the IP filter
+ for (std::list::iterator i = m_endpoints.begin();
+ i != m_endpoints.end();)
{
- TORRENT_ASSERT(target_address.address().is_v4() != bind_interface().is_v4());
- if (cb)
- {
- std::string tracker_address_type = target_address.address().is_v4() ? "IPv4" : "IPv6";
- std::string bind_address_type = bind_interface().is_v4() ? "IPv4" : "IPv6";
- cb->tracker_warning(tracker_req(), "the tracker only resolves to an "
- + tracker_address_type + " address, and you're listening on an "
- + bind_address_type + " socket. This may prevent you from receiving incoming connections.");
- }
- }
- else
- {
- target_address = *target;
+ if (m_ses.m_ip_filter.access(i->address()) == ip_filter::blocked)
+ i = m_endpoints.erase(i);
+ else
+ ++i;
}
- if (m_ses.m_ip_filter.access(target_address.address()) & ip_filter::blocked)
+ if (m_endpoints.empty())
{
fail(-1, "blocked by IP filter");
return;
}
- if (cb) cb->m_tracker_address = tcp::endpoint(target_address.address(), target_address.port());
- m_target = target_address;
- error_code ec;
- m_socket.bind(udp::endpoint(bind_interface(), 0), ec);
- if (ec)
+ std::list::iterator iter = m_endpoints.begin();
+ m_target = *iter;
+
+ if (bind_interface() != address_v4::any())
{
- fail(-1, ec.message().c_str());
- return;
+ // find first endpoint that matches our bind interface type
+ for (; iter != m_endpoints.end() && iter->address().is_v4()
+ != bind_interface().is_v4(); ++iter);
+
+ if (iter == m_endpoints.end())
+ {
+ TORRENT_ASSERT(m_target.address().is_v4() != bind_interface().is_v4());
+ if (cb)
+ {
+ char const* tracker_address_type = m_target.address().is_v4() ? "IPv4" : "IPv6";
+ char const* bind_address_type = bind_interface().is_v4() ? "IPv4" : "IPv6";
+ char msg[200];
+ snprintf(msg, sizeof(msg)
+ , "the tracker only resolves to an %s address, and you're "
+ "listening on an %s socket. This may prevent you from receiving "
+ "incoming connections."
+ , tracker_address_type, bind_address_type);
+
+ cb->tracker_warning(tracker_req(), msg);
+ }
+ }
+ else
+ {
+ m_target = *iter;
+ }
+ }
+
+ if (cb) cb->m_tracker_address = tcp::endpoint(m_target.address(), m_target.port());
+
+ if (bind_interface() != address_v4::any())
+ {
+ error_code ec;
+ m_socket.bind(udp::endpoint(bind_interface(), 0), ec);
+ if (ec)
+ {
+ fail(-1, ec.message().c_str());
+ return;
+ }
}
send_udp_connect();
}
@@ -423,8 +449,14 @@ namespace libtorrent
peer_list.push_back(e);
}
- cb->tracker_response(tracker_req(), m_target.address(), peer_list, interval
- , complete, incomplete, address());
+ std::list ip_list;
+ std::transform(m_endpoints.begin()
+ , m_endpoints.end()
+ , std::back_inserter(ip_list)
+ , boost::bind(&udp::endpoint::address, _1));
+
+ cb->tracker_response(tracker_req(), m_target.address(), ip_list
+ , peer_list, interval, complete, incomplete, address());
m_man.remove_request(this);
close();