http_connection now supports connecting to all IPs a hostname resolves to, as fallbacks
This commit is contained in:
parent
282f30c7e7
commit
c5d61667b3
|
@ -39,6 +39,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <boost/enable_shared_from_this.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <string>
|
||||
|
||||
#include "libtorrent/socket.hpp"
|
||||
|
@ -91,6 +92,7 @@ struct http_connection : boost::enable_shared_from_this<http_connection>, boost:
|
|||
, m_cc(cc)
|
||||
, m_ssl(false)
|
||||
, m_priority(0)
|
||||
, m_abort(false)
|
||||
{
|
||||
TORRENT_ASSERT(!m_handler.empty());
|
||||
}
|
||||
|
@ -123,10 +125,10 @@ private:
|
|||
|
||||
void on_resolve(error_code const& e
|
||||
, tcp::resolver::iterator i);
|
||||
void queue_connect();
|
||||
void connect(int ticket, tcp::endpoint target_address);
|
||||
void on_connect_timeout();
|
||||
void on_connect(error_code const& e
|
||||
/* , tcp::resolver::iterator i*/);
|
||||
void on_connect(error_code const& e);
|
||||
void on_write(error_code const& e);
|
||||
void on_read(error_code const& e, std::size_t bytes_transferred);
|
||||
static void on_timeout(boost::weak_ptr<http_connection> p
|
||||
|
@ -160,6 +162,8 @@ private:
|
|||
std::string m_port;
|
||||
std::string m_url;
|
||||
|
||||
std::list<tcp::endpoint> m_endpoints;
|
||||
|
||||
// the current download limit, in bytes per second
|
||||
// 0 is unlimited.
|
||||
int m_rate_limit;
|
||||
|
@ -196,6 +200,8 @@ private:
|
|||
// the priority we have in the connection queue.
|
||||
// 0 is normal, 1 is high
|
||||
int m_priority;
|
||||
|
||||
bool m_abort;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -41,6 +41,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include <boost/bind.hpp>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
|
||||
using boost::bind;
|
||||
|
||||
|
@ -198,11 +199,19 @@ void http_connection::start(std::string const& hostname, std::string const& port
|
|||
|
||||
void http_connection::on_connect_timeout()
|
||||
{
|
||||
TORRENT_ASSERT(m_connection_ticket >= 0);
|
||||
if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
|
||||
m_connection_ticket = -1;
|
||||
|
||||
callback(asio::error::timed_out);
|
||||
close();
|
||||
if (!m_endpoints.empty())
|
||||
{
|
||||
m_sock.close();
|
||||
}
|
||||
else
|
||||
{
|
||||
callback(asio::error::timed_out);
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
void http_connection::on_timeout(boost::weak_ptr<http_connection> p
|
||||
|
@ -210,15 +219,23 @@ void http_connection::on_timeout(boost::weak_ptr<http_connection> p
|
|||
{
|
||||
boost::shared_ptr<http_connection> c = p.lock();
|
||||
if (!c) return;
|
||||
if (c->m_connection_ticket > -1) c->m_cc.done(c->m_connection_ticket);
|
||||
c->m_connection_ticket = -1;
|
||||
|
||||
if (e == asio::error::operation_aborted) return;
|
||||
|
||||
if (c->m_last_receive + c->m_timeout < time_now())
|
||||
{
|
||||
c->callback(asio::error::timed_out);
|
||||
c->close();
|
||||
if (c->m_connection_ticket > -1 && !c->m_endpoints.empty())
|
||||
{
|
||||
c->m_sock.close();
|
||||
error_code ec;
|
||||
c->m_timer.expires_at(c->m_last_receive + c->m_timeout, ec);
|
||||
c->m_timer.async_wait(bind(&http_connection::on_timeout, p, _1));
|
||||
}
|
||||
else
|
||||
{
|
||||
c->callback(asio::error::timed_out);
|
||||
c->close();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -236,11 +253,8 @@ void http_connection::close()
|
|||
m_sock.close(ec);
|
||||
m_hostname.clear();
|
||||
m_port.clear();
|
||||
|
||||
if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
|
||||
m_connection_ticket = -1;
|
||||
|
||||
m_handler.clear();
|
||||
m_abort = true;
|
||||
}
|
||||
|
||||
void http_connection::on_resolve(error_code const& e
|
||||
|
@ -254,21 +268,26 @@ void http_connection::on_resolve(error_code const& e
|
|||
}
|
||||
TORRENT_ASSERT(i != tcp::resolver::iterator());
|
||||
|
||||
// look for an address that has the same kind as the one
|
||||
// we're binding to. To make sure a tracker get our
|
||||
// correct listening address.
|
||||
tcp::resolver::iterator target = i;
|
||||
tcp::resolver::iterator end;
|
||||
tcp::endpoint target_address = *i;
|
||||
for (; target != end && target->endpoint().address().is_v4()
|
||||
!= m_bind_addr.is_v4(); ++target);
|
||||
std::transform(i, tcp::resolver::iterator(), std::back_inserter(m_endpoints)
|
||||
, boost::bind(&tcp::resolver::iterator::value_type::endpoint, _1));
|
||||
|
||||
if (target != end)
|
||||
{
|
||||
target_address = *target;
|
||||
}
|
||||
|
||||
m_cc.enqueue(bind(&http_connection::connect, shared_from_this(), _1, target_address)
|
||||
// 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
|
||||
m_endpoints.sort(
|
||||
(bind(&address::is_v4, bind(&tcp::endpoint::address, _1)) == m_bind_addr.is_v4())
|
||||
> (bind(&address::is_v4, bind(&tcp::endpoint::address, _2)) == m_bind_addr.is_v4()));
|
||||
|
||||
queue_connect();
|
||||
}
|
||||
|
||||
void http_connection::queue_connect()
|
||||
{
|
||||
TORRENT_ASSERT(!m_endpoints.empty());
|
||||
tcp::endpoint target = m_endpoints.front();
|
||||
m_endpoints.pop_front();
|
||||
|
||||
m_cc.enqueue(bind(&http_connection::connect, shared_from_this(), _1, target)
|
||||
, bind(&http_connection::on_connect_timeout, shared_from_this())
|
||||
, m_timeout, m_priority);
|
||||
}
|
||||
|
@ -277,28 +296,28 @@ void http_connection::connect(int ticket, tcp::endpoint target_address)
|
|||
{
|
||||
m_connection_ticket = ticket;
|
||||
m_sock.async_connect(target_address, boost::bind(&http_connection::on_connect
|
||||
, shared_from_this(), _1/*, ++i*/));
|
||||
, shared_from_this(), _1));
|
||||
}
|
||||
|
||||
void http_connection::on_connect(error_code const& e
|
||||
/*, tcp::resolver::iterator i*/)
|
||||
void http_connection::on_connect(error_code const& e)
|
||||
{
|
||||
TORRENT_ASSERT(m_connection_ticket >= 0);
|
||||
m_cc.done(m_connection_ticket);
|
||||
|
||||
m_last_receive = time_now();
|
||||
if (!e)
|
||||
{
|
||||
m_last_receive = time_now();
|
||||
if (m_connect_handler) m_connect_handler(*this);
|
||||
async_write(m_sock, asio::buffer(sendbuffer)
|
||||
, bind(&http_connection::on_write, shared_from_this(), _1));
|
||||
}
|
||||
/* else if (i != tcp::resolver::iterator())
|
||||
else if (!m_endpoints.empty() && !m_abort)
|
||||
{
|
||||
// The connection failed. Try the next endpoint in the list.
|
||||
m_sock.close();
|
||||
m_cc.enqueue(bind(&http_connection::connect, shared_from_this(), _1, *i)
|
||||
, bind(&http_connection::on_connect_timeout, shared_from_this())
|
||||
, m_timeout, m_priority);
|
||||
queue_connect();
|
||||
}
|
||||
*/ else
|
||||
else
|
||||
{
|
||||
callback(e);
|
||||
close();
|
||||
|
|
|
@ -76,7 +76,7 @@ void run_test(std::string const& url, int size, int status, int connected
|
|||
|
||||
boost::shared_ptr<http_connection> h(new http_connection(ios, cq
|
||||
, &::http_handler, true, &::http_connect_handler));
|
||||
h->get(url, seconds(30), 0, &ps);
|
||||
h->get(url, seconds(5), 0, &ps);
|
||||
ios.reset();
|
||||
ios.run();
|
||||
|
||||
|
@ -104,6 +104,9 @@ void run_suite(std::string const& protocol, proxy_settings const& ps)
|
|||
<< " proxy **********************\n" << std::endl;
|
||||
|
||||
typedef boost::optional<error_code> err;
|
||||
// this requires the hosts file to be modified
|
||||
// run_test(protocol + "://test.dns.ts:8001/test_file", 3216, 200, 1, error_code(), ps);
|
||||
|
||||
run_test(protocol + "://127.0.0.1:8001/relative/redirect", 3216, 200, 2, error_code(), ps);
|
||||
run_test(protocol + "://127.0.0.1:8001/redirect", 3216, 200, 2, error_code(), ps);
|
||||
run_test(protocol + "://127.0.0.1:8001/infinite_redirect", 0, 301, 6, error_code(), ps);
|
||||
|
|
Loading…
Reference in New Issue