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