improved IPv6 support by announcing twice when necessary

This commit is contained in:
Arvid Norberg 2009-05-15 21:23:41 +00:00
parent ea671933ab
commit 437cb94fd0
12 changed files with 142 additions and 60 deletions

View File

@ -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()

View File

@ -719,6 +719,7 @@ namespace libtorrent
void tracker_response(tracker_request const&
, libtorrent::address const& tracker_ip
, std::list<address> const& ip_list
, std::vector<peer_entry>& 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());

View File

@ -122,6 +122,8 @@ struct http_connection : boost::enable_shared_from_this<http_connection>, boost:
#else
socket_type const& socket() const { return m_sock; }
#endif
std::list<tcp::endpoint> const& endpoints() const { return m_endpoints; }
private:

View File

@ -70,7 +70,6 @@ namespace libtorrent
, connection_queue& cc
, tracker_manager& man
, tracker_request const& req
, address bind_infc
, boost::weak_ptr<request_callback> c
, aux::session_impl const& ses
, proxy_settings const& ps
@ -97,7 +96,6 @@ namespace libtorrent
tracker_manager& m_man;
boost::shared_ptr<http_connection> 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;

View File

@ -363,6 +363,7 @@ namespace libtorrent
virtual void tracker_response(
tracker_request const& r
, address const& tracker_ip
, std::list<address> const& ip_list
, std::vector<peer_entry>& 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

View File

@ -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<address> const& ip_list
, std::vector<peer_entry>& 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<request_callback> r);
boost::shared_ptr<request_callback> 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<request_callback> 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<request_callback> c
= boost::weak_ptr<request_callback>());
void abort_all_requests(bool all = false);

View File

@ -71,7 +71,6 @@ namespace libtorrent
, connection_queue& cc
, tracker_manager& man
, tracker_request const& req
, address bind_infc
, boost::weak_ptr<request_callback> 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<udp::endpoint> m_endpoints;
int m_transaction_id;
boost::int64_t m_connection_id;

View File

@ -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();

View File

@ -70,15 +70,13 @@ namespace libtorrent
, connection_queue& cc
, tracker_manager& man
, tracker_request const& req
, address bind_infc
, boost::weak_ptr<request_callback> 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<address> 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);
}
}

View File

@ -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<aux::tracker_logger> 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<torrent>():shared_from_this());
, tracker_login() , m_abort?boost::shared_ptr<torrent>():shared_from_this());
ae.updating = true;
if (m_ses.m_alerts.should_post<tracker_announce_alert>())
@ -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<address> const& tracker_ips // these are all the IPs it resolved to
, std::vector<peer_entry>& 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<address>(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<address>::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

View File

@ -133,11 +133,9 @@ namespace libtorrent
tracker_manager& man
, tracker_request const& req
, io_service& ios
, address bind_interface_
, boost::weak_ptr<request_callback> 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<request_callback> 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
{

View File

@ -75,11 +75,10 @@ namespace libtorrent
, connection_queue& cc
, tracker_manager& man
, tracker_request const& req
, address bind_infc
, boost::weak_ptr<request_callback> 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<udp::endpoint>::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<udp::endpoint>::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<address> 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();