fixed problems in the network layer that made web seeds fail some times. prepared for proxy support in peer connections. worked on the http seeding. added support for web seeds in make_torrent tool

This commit is contained in:
Arvid Norberg 2007-02-12 05:46:29 +00:00
parent e324cfc519
commit 98b92e3f02
15 changed files with 356 additions and 187 deletions

View File

@ -1,3 +1,6 @@
* added support for HTTP redirection support for web seeds.
* fixed race condition when accessing a torrent that was checking its
fast resume data.
* fixed a bug in the DHT which could be triggered if the network was * fixed a bug in the DHT which could be triggered if the network was
dropped or extremely rare cases. dropped or extremely rare cases.
* if the download rate is limited, web seeds will now only use left-over * if the download rate is limited, web seeds will now only use left-over

View File

@ -860,7 +860,9 @@ int main(int ac, char* av[])
out << state_str[s.state] << " "; out << state_str[s.state] << " ";
} }
h.get_peer_info(peers); if ((print_downloads && s.state != torrent_status::seeding)
|| print_peers)
h.get_peer_info(peers);
if (s.state != torrent_status::seeding) if (s.state != torrent_status::seeding)
{ {

View File

@ -77,10 +77,11 @@ int main(int argc, char* argv[])
path::default_name_check(no_check); path::default_name_check(no_check);
if (argc != 4) if (argc != 4 && argc != 5)
{ {
std::cerr << "usage: make_torrent <output torrent-file> " std::cerr << "usage: make_torrent <output torrent-file> "
"<announce url> <file or directory to create torrent from>\n"; "<announce url> <file or directory to create torrent from> "
"[url-seed]\n";
return 1; return 1;
} }
@ -113,6 +114,9 @@ int main(int argc, char* argv[])
t.set_creator(creator_str); t.set_creator(creator_str);
if (argc == 5)
t.add_url_seed(argv[4]);
// create the torrent and print it to out // create the torrent and print it to out
entry e = t.create_torrent(); entry e = t.create_torrent();
libtorrent::bencode(std::ostream_iterator<char>(out), e); libtorrent::bencode(std::ostream_iterator<char>(out), e);

View File

@ -359,8 +359,6 @@ namespace libtorrent
// open files by this session. // open files by this session.
file_pool m_files; file_pool m_files;
// does the actual disconnections
// that are queued up in m_disconnect_peer
void second_tick(asio::error_code const& e); void second_tick(asio::error_code const& e);
boost::posix_time::ptime m_last_tick; boost::posix_time::ptime m_last_tick;

View File

@ -77,6 +77,7 @@ namespace libtorrent
bool finished() const { return m_finished; } bool finished() const { return m_finished; }
boost::tuple<int, int> incoming(buffer::const_interval recv_buffer); boost::tuple<int, int> incoming(buffer::const_interval recv_buffer);
int body_start() const { return m_body_start_pos; } int body_start() const { return m_body_start_pos; }
int content_length() const { return m_content_length; }
void reset(); void reset();
private: private:

View File

@ -117,7 +117,8 @@ namespace libtorrent
aux::session_impl& ses aux::session_impl& ses
, boost::weak_ptr<torrent> t , boost::weak_ptr<torrent> t
, boost::shared_ptr<stream_socket> s , boost::shared_ptr<stream_socket> s
, tcp::endpoint const& remote); , tcp::endpoint const& remote
, tcp::endpoint const& proxy);
// with this constructor we have been contacted and we still don't // with this constructor we have been contacted and we still don't
// know which torrent the connection belongs to // know which torrent the connection belongs to
@ -204,13 +205,11 @@ namespace libtorrent
boost::shared_ptr<stream_socket> get_socket() const { return m_socket; } boost::shared_ptr<stream_socket> get_socket() const { return m_socket; }
tcp::endpoint const& remote() const { return m_remote; } tcp::endpoint const& remote() const { return m_remote; }
tcp::endpoint const& proxy() const { return m_remote_proxy; }
std::vector<bool> const& get_bitfield() const; std::vector<bool> const& get_bitfield() const;
// this will cause this peer_connection to be disconnected. // this will cause this peer_connection to be disconnected.
// what it does is that it puts a reference to it in
// m_ses.m_disconnect_peer list, which will be scanned in the
// mainloop to disconnect peers.
void disconnect(); void disconnect();
bool is_disconnecting() const { return m_disconnecting; } bool is_disconnecting() const { return m_disconnecting; }
@ -382,7 +381,7 @@ namespace libtorrent
bool packet_finished() const bool packet_finished() const
{ {
assert(m_recv_pos <= m_packet_size); assert(m_recv_pos <= m_packet_size);
return m_packet_size == m_recv_pos; return m_packet_size <= m_recv_pos;
} }
void setup_receive(); void setup_receive();
@ -475,7 +474,13 @@ namespace libtorrent
boost::posix_time::ptime m_last_sent; boost::posix_time::ptime m_last_sent;
boost::shared_ptr<stream_socket> m_socket; boost::shared_ptr<stream_socket> m_socket;
// this is the peer we're actually talking to
// it may not necessarily be the peer we're
// connected to, in case we use a proxy
tcp::endpoint m_remote; tcp::endpoint m_remote;
// if we use a proxy, this is the address to it
tcp::endpoint m_remote_proxy;
// this is the torrent this connection is // this is the torrent this connection is
// associated with. If the connection is an // associated with. If the connection is an

View File

@ -365,6 +365,11 @@ namespace libtorrent
// this is the asio callback that is called when a name // this is the asio callback that is called when a name
// lookup for a web seed is completed. // lookup for a web seed is completed.
void on_name_lookup(asio::error_code const& e, tcp::resolver::iterator i void on_name_lookup(asio::error_code const& e, tcp::resolver::iterator i
, std::string url, tcp::endpoint proxy);
// this is the asio callback that is called when a name
// lookup for a proxy for a web seed is completed.
void on_proxy_name_lookup(asio::error_code const& e, tcp::resolver::iterator i
, std::string url); , std::string url);
// this is called when the torrent has finished. i.e. // this is called when the torrent has finished. i.e.

View File

@ -98,6 +98,7 @@ namespace libtorrent
, boost::weak_ptr<torrent> t , boost::weak_ptr<torrent> t
, boost::shared_ptr<stream_socket> s , boost::shared_ptr<stream_socket> s
, tcp::endpoint const& remote , tcp::endpoint const& remote
, tcp::endpoint const& proxy
, std::string const& url); , std::string const& url);
~web_peer_connection(); ~web_peer_connection();

View File

@ -79,7 +79,7 @@ namespace libtorrent
, boost::weak_ptr<torrent> tor , boost::weak_ptr<torrent> tor
, shared_ptr<stream_socket> s , shared_ptr<stream_socket> s
, tcp::endpoint const& remote) , tcp::endpoint const& remote)
: peer_connection(ses, tor, s, remote) : peer_connection(ses, tor, s, remote, tcp::endpoint())
, m_state(read_protocol_length) , m_state(read_protocol_length)
#ifndef TORRENT_DISABLE_EXTENSIONS #ifndef TORRENT_DISABLE_EXTENSIONS
, m_supports_extensions(false) , m_supports_extensions(false)
@ -310,7 +310,7 @@ namespace libtorrent
buffer::const_interval recv_buffer = receive_buffer(); buffer::const_interval recv_buffer = receive_buffer();
// are we currently receiving a 'piece' message? // are we currently receiving a 'piece' message?
if (m_state != read_packet if (m_state != read_packet
|| (recv_buffer.end - recv_buffer.begin) < 9 || recv_buffer.left() < 9
|| recv_buffer[0] != msg_piece) || recv_buffer[0] != msg_piece)
return boost::optional<piece_block_progress>(); return boost::optional<piece_block_progress>();
@ -328,7 +328,7 @@ namespace libtorrent
p.piece_index = r.piece; p.piece_index = r.piece;
p.block_index = r.start / t->block_size(); p.block_index = r.start / t->block_size();
p.bytes_downloaded = recv_buffer.end - recv_buffer.begin - 9; p.bytes_downloaded = recv_buffer.left() - 9;
p.full_block_bytes = r.length; p.full_block_bytes = r.length;
return boost::optional<piece_block_progress>(p); return boost::optional<piece_block_progress>(p);

View File

@ -198,6 +198,20 @@ namespace libtorrent
} }
catch(boost::bad_lexical_cast&) {} catch(boost::bad_lexical_cast&) {}
} }
else if (name == "content-range")
{
std::stringstream range_str(value);
char dummy;
std::string bytes;
size_type range_start, range_end;
range_str >> bytes >> range_start >> dummy >> range_end;
if (!range_str || range_end < range_start)
{
throw std::runtime_error("invalid content-range in HTTP response: " + range_str.str());
}
// the http range is inclusive
m_content_length = range_end - range_start + 1;
}
// TODO: make sure we don't step outside of the buffer // TODO: make sure we don't step outside of the buffer
++pos; ++pos;

View File

@ -386,6 +386,9 @@ void rpc_manager::reply_with_ping(msg& m, msg const& reply_to)
} }
catch (std::exception& e) catch (std::exception& e)
{ {
#ifndef NDEBUG
std::cerr << e.what() << "\n";
#endif
assert(false); assert(false);
} }
} }

View File

@ -75,7 +75,8 @@ namespace libtorrent
session_impl& ses session_impl& ses
, boost::weak_ptr<torrent> tor , boost::weak_ptr<torrent> tor
, shared_ptr<stream_socket> s , shared_ptr<stream_socket> s
, tcp::endpoint const& remote) , tcp::endpoint const& remote
, tcp::endpoint const& proxy)
: :
#ifndef NDEBUG #ifndef NDEBUG
m_last_choke(boost::posix_time::second_clock::universal_time() m_last_choke(boost::posix_time::second_clock::universal_time()
@ -94,6 +95,7 @@ namespace libtorrent
, m_last_sent(second_clock::universal_time()) , m_last_sent(second_clock::universal_time())
, m_socket(s) , m_socket(s)
, m_remote(remote) , m_remote(remote)
, m_remote_proxy(proxy)
, m_torrent(tor) , m_torrent(tor)
, m_active(true) , m_active(true)
, m_peer_interested(false) , m_peer_interested(false)
@ -593,7 +595,7 @@ namespace libtorrent
// clear the request queue if the client isn't interested // clear the request queue if the client isn't interested
m_requests.clear(); m_requests.clear();
setup_send(); // setup_send();
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
using namespace boost::posix_time; using namespace boost::posix_time;
@ -701,8 +703,9 @@ namespace libtorrent
return; return;
} }
// build a vector of all pieces // let the torrent know which pieces the
std::vector<int> piece_list; // peer has
bool interesting = false;
for (int i = 0; i < (int)m_have_piece.size(); ++i) for (int i = 0; i < (int)m_have_piece.size(); ++i)
{ {
bool have = bitfield[i]; bool have = bitfield[i];
@ -710,7 +713,10 @@ namespace libtorrent
{ {
m_have_piece[i] = true; m_have_piece[i] = true;
++m_num_pieces; ++m_num_pieces;
piece_list.push_back(i); t->peer_has(i);
if (!t->have_piece(i)
&& !t->picker().is_filtered(i))
interesting = true;
} }
else if (!have && m_have_piece[i]) else if (!have && m_have_piece[i])
{ {
@ -721,23 +727,7 @@ namespace libtorrent
} }
} }
// let the torrent know which pieces the if (m_num_pieces == int(m_have_piece.size()))
// peer has, in a shuffled order
bool interesting = false;
if (!t->is_seed())
{
for (std::vector<int>::reverse_iterator i = piece_list.rbegin();
i != piece_list.rend(); ++i)
{
int index = *i;
t->peer_has(index);
if (!t->have_piece(index)
&& !t->picker().is_filtered(index))
interesting = true;
}
}
if (piece_list.size() == m_have_piece.size())
{ {
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << " *** THIS IS A SEED ***\n"; (*m_logger) << " *** THIS IS A SEED ***\n";
@ -1018,6 +1008,7 @@ namespace libtorrent
if (picker.is_finished(block_finished)) if (picker.is_finished(block_finished))
{ {
t->received_redundant_data(t->block_size()); t->received_redundant_data(t->block_size());
pol.block_finished(*this, block_finished);
send_block_requests(); send_block_requests();
return; return;
} }
@ -1190,6 +1181,9 @@ namespace libtorrent
assert(it != m_request_queue.end()); assert(it != m_request_queue.end());
if (it == m_request_queue.end()) return; if (it == m_request_queue.end()) return;
m_request_queue.erase(it); m_request_queue.erase(it);
m_policy->block_finished(*this, block);
send_block_requests();
// since we found it in the request queue, it means it hasn't been // since we found it in the request queue, it means it hasn't been
// sent yet, so we don't have to send a cancel. // sent yet, so we don't have to send a cancel.
return; return;
@ -1199,8 +1193,6 @@ namespace libtorrent
m_download_queue.erase(it); m_download_queue.erase(it);
} }
send_block_requests();
int block_offset = block.block_index * t->block_size(); int block_offset = block.block_index * t->block_size();
int block_size int block_size
= std::min((int)t->torrent_file().piece_size(block.piece_index)-block_offset, = std::min((int)t->torrent_file().piece_size(block.piece_index)-block_offset,
@ -1215,6 +1207,9 @@ namespace libtorrent
write_cancel(r); write_cancel(r);
m_policy->block_finished(*this, block);
send_block_requests();
#ifdef TORRENT_VERBOSE_LOGGING #ifdef TORRENT_VERBOSE_LOGGING
using namespace boost::posix_time; using namespace boost::posix_time;
(*m_logger) << to_simple_string(second_clock::universal_time()) (*m_logger) << to_simple_string(second_clock::universal_time())
@ -1481,7 +1476,7 @@ namespace libtorrent
assert(packet_size > 0); assert(packet_size > 0);
assert((int)m_recv_buffer.size() >= size); assert((int)m_recv_buffer.size() >= size);
// TODO: replace with memmov
std::copy(m_recv_buffer.begin() + size, m_recv_buffer.begin() + m_recv_pos, m_recv_buffer.begin()); std::copy(m_recv_buffer.begin() + size, m_recv_buffer.begin() + m_recv_pos, m_recv_buffer.begin());
assert(m_recv_pos >= size); assert(m_recv_pos >= size);
@ -1492,7 +1487,7 @@ namespace libtorrent
#endif #endif
m_packet_size = packet_size; m_packet_size = packet_size;
m_recv_buffer.resize(m_packet_size); if (m_packet_size >= m_recv_pos) m_recv_buffer.resize(m_packet_size);
} }
void peer_connection::second_tick(float tick_interval) void peer_connection::second_tick(float tick_interval)
@ -1762,7 +1757,8 @@ namespace libtorrent
(*m_logger) << "req bandwidth [ " << upload_channel << " ]\n"; (*m_logger) << "req bandwidth [ " << upload_channel << " ]\n";
#endif #endif
t->request_bandwidth(upload_channel, self(), m_non_prioritized); // the upload queue should not have non-prioritized peers
t->request_bandwidth(upload_channel, self(), /*m_non_prioritized*/ false);
m_writing = true; m_writing = true;
} }
return; return;
@ -1775,7 +1771,7 @@ namespace libtorrent
int sending_buffer = (m_current_send_buffer + 1) & 1; int sending_buffer = (m_current_send_buffer + 1) & 1;
if (m_send_buffer[sending_buffer].empty()) if (m_send_buffer[sending_buffer].empty())
{ {
// thise means we have to swap buffer, because there's no // this means we have to swap buffer, because there's no
// previous buffer we're still waiting for. // previous buffer we're still waiting for.
std::swap(m_current_send_buffer, sending_buffer); std::swap(m_current_send_buffer, sending_buffer);
m_write_pos = 0; m_write_pos = 0;
@ -1846,6 +1842,11 @@ namespace libtorrent
void peer_connection::reset_recv_buffer(int packet_size) void peer_connection::reset_recv_buffer(int packet_size)
{ {
assert(packet_size > 0); assert(packet_size > 0);
if (m_recv_pos > m_packet_size)
{
cut_receive_buffer(m_packet_size, packet_size);
return;
}
m_recv_pos = 0; m_recv_pos = 0;
m_packet_size = packet_size; m_packet_size = packet_size;
if (int(m_recv_buffer.size()) < m_packet_size) if (int(m_recv_buffer.size()) < m_packet_size)
@ -1914,14 +1915,7 @@ namespace libtorrent
m_last_receive = second_clock::universal_time(); m_last_receive = second_clock::universal_time();
m_recv_pos += bytes_transferred; m_recv_pos += bytes_transferred;
assert(m_recv_pos <= int(m_recv_buffer.size()));
// this will reset the m_recv_pos to 0 if the
// entire packet was received
// it is important that this is done before
// setup_receive() is called. Therefore, fire() is
// called before setup_receive().
assert(m_recv_pos <= m_packet_size);
set_to_zero<int> reset(m_recv_pos, m_recv_pos == m_packet_size);
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
@ -1930,9 +1924,6 @@ namespace libtorrent
assert(m_packet_size > 0); assert(m_packet_size > 0);
// do the reset immediately
reset.fire();
setup_receive(); setup_receive();
} }
catch (file_error& e) catch (file_error& e)
@ -2002,8 +1993,16 @@ namespace libtorrent
assert(m_connecting); assert(m_connecting);
m_socket->open(asio::ip::tcp::v4()); m_socket->open(asio::ip::tcp::v4());
m_socket->bind(t->get_interface()); m_socket->bind(t->get_interface());
m_socket->async_connect(m_remote if (m_remote_proxy != tcp::endpoint())
, bind(&peer_connection::on_connection_complete, self(), _1)); {
m_socket->async_connect(m_remote_proxy
, bind(&peer_connection::on_connection_complete, self(), _1));
}
else
{
m_socket->async_connect(m_remote
, bind(&peer_connection::on_connection_complete, self(), _1));
}
if (t->alerts().should_post(alert::debug)) if (t->alerts().should_post(alert::debug))
{ {
@ -2189,6 +2188,11 @@ namespace libtorrent
// TODO: the timeout should be called by an event // TODO: the timeout should be called by an event
INVARIANT_CHECK; INVARIANT_CHECK;
#ifndef NDEBUG
// allow step debugging without timing out
return false;
#endif
using namespace boost::posix_time; using namespace boost::posix_time;
ptime now(second_clock::universal_time()); ptime now(second_clock::universal_time());

View File

@ -79,6 +79,7 @@ namespace
- (int)c.download_queue().size() - (int)c.download_queue().size()
- (int)c.request_queue().size(); - (int)c.request_queue().size();
assert(c.desired_queue_size() > 0);
// if our request queue is already full, we // if our request queue is already full, we
// don't have to make any new requests yet // don't have to make any new requests yet
if (num_requests <= 0) return; if (num_requests <= 0) return;
@ -99,7 +100,8 @@ namespace
// the number of blocks we want, but it will try to make the picked // the number of blocks we want, but it will try to make the picked
// blocks be from whole pieces, possibly by returning more blocks // blocks be from whole pieces, possibly by returning more blocks
// than we requested. // than we requested.
assert(c.remote() == c.get_socket()->remote_endpoint()); assert((c.proxy() == tcp::endpoint() && c.remote() == c.get_socket()->remote_endpoint())
|| c.proxy() == c.get_socket()->remote_endpoint());
// picks the interesting pieces from this peer // picks the interesting pieces from this peer
// the integer is the number of pieces that // the integer is the number of pieces that
@ -248,7 +250,8 @@ namespace
// the one we interrupted may need to request a new piece. // the one we interrupted may need to request a new piece.
// make sure it doesn't take over a block from the peer // make sure it doesn't take over a block from the peer
// that just took over its block // that just took over its block (that would cause an
// infinite recursion)
ignore.push_back(&c); ignore.push_back(&c);
request_a_block(t, *peer, ignore); request_a_block(t, *peer, ignore);
num_requests--; num_requests--;
@ -891,9 +894,9 @@ namespace libtorrent
// TODO: only allow _one_ connection to use this // TODO: only allow _one_ connection to use this
// override at a time // override at a time
#ifndef NDEBUG assert((c.proxy() == tcp::endpoint() && c.remote() == c.get_socket()->remote_endpoint())
assert(c.remote() == c.get_socket()->remote_endpoint()); || c.proxy() == c.get_socket()->remote_endpoint());
#endif
if (m_torrent->num_peers() >= m_torrent->m_connections_quota.given if (m_torrent->num_peers() >= m_torrent->m_connections_quota.given
&& c.remote().address() != m_torrent->current_tracker().address()) && c.remote().address() != m_torrent->current_tracker().address())
{ {
@ -954,9 +957,9 @@ namespace libtorrent
// we don't have ny info about this peer. // we don't have ny info about this peer.
// add a new entry // add a new entry
#ifndef NDEBUG assert((c.proxy() == tcp::endpoint() && c.remote() == c.get_socket()->remote_endpoint())
assert(c.remote() == c.get_socket()->remote_endpoint()); || c.proxy() == c.get_socket()->remote_endpoint());
#endif
peer p(c.remote(), peer::not_connectable); peer p(c.remote(), peer::not_connectable);
m_peers.push_back(p); m_peers.push_back(p);
i = m_peers.end()-1; i = m_peers.end()-1;
@ -1334,9 +1337,9 @@ namespace libtorrent
bool policy::has_connection(const peer_connection* c) bool policy::has_connection(const peer_connection* c)
{ {
assert(c); assert(c);
#ifndef NDEBUG assert((c->proxy() == tcp::endpoint() && c->remote() == c->get_socket()->remote_endpoint())
assert(c->remote() == c->get_socket()->remote_endpoint()); || c->proxy() == c->get_socket()->remote_endpoint());
#endif
return std::find_if( return std::find_if(
m_peers.begin() m_peers.begin()
, m_peers.end() , m_peers.end()

View File

@ -1106,9 +1106,7 @@ namespace libtorrent
m_event = tracker_request::none; m_event = tracker_request::none;
req.url = m_trackers[m_currently_trying_tracker].url; req.url = m_trackers[m_currently_trying_tracker].url;
assert(m_connections_quota.given > 0); assert(m_connections_quota.given > 0);
req.num_want = std::max( req.num_want = std::max(m_connections_quota.given - num_peers(), 10);
(m_connections_quota.given
- m_policy->num_peers()), 10);
// if we are aborting. we don't want any new peers // if we are aborting. we don't want any new peers
if (req.event == tracker_request::stopped) if (req.event == tracker_request::stopped)
req.num_want = 0; req.num_want = 0;
@ -1173,19 +1171,20 @@ namespace libtorrent
(*m_ses.m_logger) << now << " resolving: " << url << "\n"; (*m_ses.m_logger) << now << " resolving: " << url << "\n";
#endif #endif
std::string protocol;
std::string hostname;
int port;
std::string path;
boost::tie(protocol, hostname, port, path)
= parse_url_components(url);
m_resolving_web_seeds.insert(url); m_resolving_web_seeds.insert(url);
if (m_ses.settings().proxy_ip.empty()) if (m_ses.settings().proxy_ip.empty())
{ {
std::string protocol;
std::string hostname;
int port;
std::string path;
boost::tie(protocol, hostname, port, path)
= parse_url_components(url);
tcp::resolver::query q(hostname, boost::lexical_cast<std::string>(port)); tcp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
m_host_resolver.async_resolve(q, m_ses.m_strand.wrap( m_host_resolver.async_resolve(q, m_ses.m_strand.wrap(
bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url))); bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url
, tcp::endpoint())));
} }
else else
{ {
@ -1193,11 +1192,162 @@ namespace libtorrent
tcp::resolver::query q(m_ses.settings().proxy_ip tcp::resolver::query q(m_ses.settings().proxy_ip
, boost::lexical_cast<std::string>(m_ses.settings().proxy_port)); , boost::lexical_cast<std::string>(m_ses.settings().proxy_port));
m_host_resolver.async_resolve(q, m_ses.m_strand.wrap( m_host_resolver.async_resolve(q, m_ses.m_strand.wrap(
bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url))); bind(&torrent::on_proxy_name_lookup, shared_from_this(), _1, _2, url)));
} }
} }
void torrent::on_proxy_name_lookup(asio::error_code const& e, tcp::resolver::iterator host
, std::string url) try
{
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
INVARIANT_CHECK;
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
std::string now(to_simple_string(second_clock::universal_time()));
(*m_ses.m_logger) << now << " completed resolve proxy hostname for: " << url << "\n";
#endif
if (e || host == tcp::resolver::iterator())
{
if (m_ses.m_alerts.should_post(alert::warning))
{
std::stringstream msg;
msg << "HTTP seed proxy hostname lookup failed: " << e.message();
m_ses.m_alerts.post_alert(
url_seed_alert(get_handle(), url, msg.str()));
}
// the name lookup failed for the http host. Don't try
// this host again
remove_url_seed(url);
return;
}
if (m_ses.is_aborted()) return;
tcp::endpoint a(host->endpoint());
if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
{
// TODO: post alert: "proxy at " + a.address().to_string() + " (" + hostname + ") blocked by ip filter");
return;
}
std::string protocol;
std::string hostname;
int port;
std::string path;
boost::tie(protocol, hostname, port, path)
= parse_url_components(url);
tcp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
m_host_resolver.async_resolve(q, m_ses.m_strand.wrap(
bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url, a)));
}
catch (std::exception& exc)
{
assert(false);
};
void torrent::on_name_lookup(asio::error_code const& e, tcp::resolver::iterator host
, std::string url, tcp::endpoint proxy) try
{
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
INVARIANT_CHECK;
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
std::string now(to_simple_string(second_clock::universal_time()));
(*m_ses.m_logger) << now << " completed resolve: " << url << "\n";
#endif
std::set<std::string>::iterator i = m_resolving_web_seeds.find(url);
if (i != m_resolving_web_seeds.end()) m_resolving_web_seeds.erase(i);
if (e || host == tcp::resolver::iterator())
{
if (m_ses.m_alerts.should_post(alert::warning))
{
std::stringstream msg;
msg << "HTTP seed hostname lookup failed: " << e.message();
m_ses.m_alerts.post_alert(
url_seed_alert(get_handle(), url, msg.str()));
}
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << url << "\n";
#endif
// the name lookup failed for the http host. Don't try
// this host again
remove_url_seed(url);
return;
}
if (m_ses.is_aborted()) return;
tcp::endpoint a(host->endpoint());
if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
{
// TODO: post alert: "web seed at " + a.address().to_string() + " blocked by ip filter");
return;
}
peer_iterator conn = m_connections.find(a);
if (conn != m_connections.end())
{
if (dynamic_cast<web_peer_connection*>(conn->second) == 0
|| conn->second->is_disconnecting()) conn->second->disconnect();
else return;
}
boost::shared_ptr<stream_socket> s(new stream_socket(m_ses.m_io_service));
boost::intrusive_ptr<peer_connection> c(new web_peer_connection(
m_ses, shared_from_this(), s, a, proxy, url));
#ifndef NDEBUG
c->m_in_constructor = false;
#endif
try
{
m_ses.m_connection_queue.push_back(c);
assert(m_connections.find(a) == m_connections.end());
#ifndef NDEBUG
m_policy->check_invariant();
#endif
// add the newly connected peer to this torrent's peer list
m_connections.insert(
std::make_pair(a, boost::get_pointer(c)));
#ifndef NDEBUG
m_policy->check_invariant();
#endif
m_ses.process_connection_queue();
}
catch (std::exception& e)
{
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << e.what() << "\n";
#endif
// TODO: post an error alert!
std::map<tcp::endpoint, peer_connection*>::iterator i = m_connections.find(a);
if (i != m_connections.end()) m_connections.erase(i);
m_ses.connection_failed(s, a, e.what());
c->disconnect();
}
}
catch (std::exception& exc)
{
assert(false);
};
void torrent::resolve_peer_country(boost::intrusive_ptr<peer_connection> const& p) const void torrent::resolve_peer_country(boost::intrusive_ptr<peer_connection> const& p) const
{ {
if (m_resolving_country if (m_resolving_country
@ -1512,95 +1662,6 @@ namespace libtorrent
} }
} }
void torrent::on_name_lookup(asio::error_code const& e, tcp::resolver::iterator host
, std::string url) try
{
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
INVARIANT_CHECK;
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
std::string now(to_simple_string(second_clock::universal_time()));
(*m_ses.m_logger) << now << " completed resolve: " << url << "\n";
#endif
std::set<std::string>::iterator i = m_resolving_web_seeds.find(url);
if (i != m_resolving_web_seeds.end()) m_resolving_web_seeds.erase(i);
if (e || host == tcp::resolver::iterator())
{
if (m_ses.m_alerts.should_post(alert::warning))
{
std::stringstream msg;
msg << "HTTP seed hostname lookup failed: " << e.message();
m_ses.m_alerts.post_alert(
url_seed_alert(get_handle(), url, msg.str()));
}
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << url << "\n";
#endif
// the name lookup failed for the http host. Don't try
// this host again
remove_url_seed(url);
return;
}
if (m_ses.is_aborted()) return;
tcp::endpoint a(host->endpoint());
if (m_ses.m_ip_filter.access(a.address()) & ip_filter::blocked)
{
// TODO: post alert: "web seed at " + a.address().to_string() + " blocked by ip filter");
return;
}
boost::shared_ptr<stream_socket> s(new stream_socket(m_ses.m_io_service));
boost::intrusive_ptr<peer_connection> c(new web_peer_connection(
m_ses, shared_from_this(), s, a, url));
#ifndef NDEBUG
c->m_in_constructor = false;
#endif
try
{
m_ses.m_connection_queue.push_back(c);
assert(m_connections.find(a) == m_connections.end());
#ifndef NDEBUG
m_policy->check_invariant();
#endif
// add the newly connected peer to this torrent's peer list
m_connections.insert(
std::make_pair(a, boost::get_pointer(c)));
#ifndef NDEBUG
m_policy->check_invariant();
#endif
m_ses.process_connection_queue();
}
catch (std::exception& e)
{
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
(*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << e.what() << "\n";
#endif
// TODO: post an error alert!
std::map<tcp::endpoint, peer_connection*>::iterator i = m_connections.find(a);
if (i != m_connections.end()) m_connections.erase(i);
m_ses.connection_failed(s, a, e.what());
c->disconnect();
}
}
catch (std::exception& exc)
{
assert(false);
};
peer_connection& torrent::connect_to_peer(const tcp::endpoint& a) peer_connection& torrent::connect_to_peer(const tcp::endpoint& a)
{ {
INVARIANT_CHECK; INVARIANT_CHECK;
@ -1745,9 +1806,8 @@ namespace libtorrent
m_connections.erase(ci); m_connections.erase(ci);
throw; throw;
} }
#ifndef NDEBUG assert((p->proxy() == tcp::endpoint() && p->remote() == p->get_socket()->remote_endpoint())
assert(p->remote() == p->get_socket()->remote_endpoint()); || p->proxy() == p->get_socket()->remote_endpoint());
#endif
#ifndef NDEBUG #ifndef NDEBUG
m_policy->check_invariant(); m_policy->check_invariant();
@ -2247,6 +2307,10 @@ namespace libtorrent
// let the stats fade out to 0 // let the stats fade out to 0
m_stat.second_tick(tick_interval); m_stat.second_tick(tick_interval);
m_web_stat.second_tick(tick_interval); m_web_stat.second_tick(tick_interval);
m_connections_quota.min = 0;
m_connections_quota.max = 0;
m_uploads_quota.min = 0;
m_uploads_quota.max = 0;
return; return;
} }

View File

@ -60,8 +60,9 @@ namespace libtorrent
, boost::weak_ptr<torrent> t , boost::weak_ptr<torrent> t
, boost::shared_ptr<stream_socket> s , boost::shared_ptr<stream_socket> s
, tcp::endpoint const& remote , tcp::endpoint const& remote
, tcp::endpoint const& proxy
, std::string const& url) , std::string const& url)
: peer_connection(ses, t, s, remote) : peer_connection(ses, t, s, remote, proxy)
, m_url(url) , m_url(url)
, m_first_request(true) , m_first_request(true)
{ {
@ -136,7 +137,7 @@ namespace libtorrent
// it is always possible to request pieces // it is always possible to request pieces
incoming_unchoke(); incoming_unchoke();
reset_recv_buffer(512*1024+1024); reset_recv_buffer(t->torrent_file().piece_length() + 1024 * 2);
} }
void web_peer_connection::write_request(peer_request const& r) void web_peer_connection::write_request(peer_request const& r)
@ -291,15 +292,25 @@ namespace libtorrent
for (;;) for (;;)
{ {
buffer::const_interval recv_buffer = receive_buffer(); buffer::const_interval recv_buffer = receive_buffer();
int payload; int payload;
int protocol; int protocol;
bool header_finished = m_parser.header_finished();
boost::tie(payload, protocol) = m_parser.incoming(recv_buffer); boost::tie(payload, protocol) = m_parser.incoming(recv_buffer);
m_statistics.received_bytes(payload, protocol); m_statistics.received_bytes(payload, protocol);
assert(recv_buffer.left() <= packet_size());
assert (recv_buffer.left() < packet_size()
|| m_parser.finished());
// this means the entire status line hasn't been received yet
if (m_parser.status_code() == -1) break;
// TODO: maybe all 200 - 299 should be considered successful // if the status code is not one of the accepted ones, abort
if (m_parser.status_code() != 206 if (m_parser.status_code() != 206 // partial content
&& m_parser.status_code() != 200 && m_parser.status_code() != 200 // OK
&& m_parser.status_code() != -1) && m_parser.status_code() < 300 // redirect
&& m_parser.status_code() >= 400)
{ {
// we should not try this server again. // we should not try this server again.
t->remove_url_seed(m_url); t->remove_url_seed(m_url);
@ -309,18 +320,63 @@ namespace libtorrent
if (!m_parser.header_finished()) break; if (!m_parser.header_finished()) break;
buffer::const_interval http_body = m_parser.get_body(); // we just completed reading the header
if (!header_finished)
std::string server_version = m_parser.header<std::string>("server");
if (!server_version.empty())
{ {
m_server_string = "URL seed @ "; if (m_parser.status_code() >= 300 && m_parser.status_code() < 400)
m_server_string += m_host; {
m_server_string += " ("; // this means we got a redirection request
m_server_string += server_version; // look for the location header
m_server_string += ")"; std::string location = m_parser.header<std::string>("location");
if (location.empty())
{
// we should not try this server again.
t->remove_url_seed(m_url);
throw std::runtime_error("got HTTP redirection status without location header");
}
bool single_file_request = false;
if (!m_path.empty() && m_path[m_path.size() - 1] != '/')
single_file_request = true;
// add the redirected url and remove the current one
if (!single_file_request)
{
assert(!m_file_requests.empty());
int file_index = m_file_requests.front();
torrent_info const& info = t->torrent_file();
std::string path = info.file_at(file_index).path.string();
path = escape_path(path.c_str(), path.length());
size_t i = location.rfind(path);
if (i == std::string::npos)
{
t->remove_url_seed(m_url);
throw std::runtime_error("got invalid HTTP redirection location (\"" + location + "\") "
"expected it to end with: " + path);
}
location.resize(i);
}
t->add_url_seed(location);
t->remove_url_seed(m_url);
throw std::runtime_error("redirecting to " + location);
}
std::string server_version = m_parser.header<std::string>("server");
if (!server_version.empty())
{
m_server_string = "URL seed @ ";
m_server_string += m_host;
m_server_string += " (";
m_server_string += server_version;
m_server_string += ")";
}
} }
buffer::const_interval http_body = m_parser.get_body();
size_type range_start; size_type range_start;
size_type range_end; size_type range_end;
if (m_parser.status_code() == 206) if (m_parser.status_code() == 206)
@ -366,14 +422,14 @@ namespace libtorrent
throw std::runtime_error("invalid range in HTTP response"); throw std::runtime_error("invalid range in HTTP response");
} }
front_request = m_requests.front();
// skip the http header and the blocks we've already read. The // skip the http header and the blocks we've already read. The
// http_body.begin is now in sync with the request at the front // http_body.begin is now in sync with the request at the front
// of the request queue // of the request queue
assert(in_range.start - int(m_piece.size()) <= front_request.start); assert(in_range.start - int(m_piece.size()) <= front_request.start);
http_body.begin += front_request.start - in_range.start + int(m_piece.size()); http_body.begin += front_request.start - in_range.start + int(m_piece.size());
front_request = m_requests.front();
// the http response body consists of 3 parts // the http response body consists of 3 parts
// 1. the middle of a block or the ending of a block // 1. the middle of a block or the ending of a block
// 2. a number of whole blocks // 2. a number of whole blocks
@ -417,6 +473,10 @@ namespace libtorrent
{ {
peer_request r = m_requests.front(); peer_request r = m_requests.front();
m_requests.pop_front(); m_requests.pop_front();
assert(http_body.begin == recv_buffer.begin + m_parser.body_start()
+ r.start - in_range.start);
assert(http_body.left() >= r.length);
incoming_piece(r, http_body.begin); incoming_piece(r, http_body.begin);
http_body.begin += r.length; http_body.begin += r.length;
} }
@ -442,7 +502,9 @@ namespace libtorrent
m_file_requests.pop_front(); m_file_requests.pop_front();
assert(http_body.left() == 0); assert(http_body.left() == 0);
m_parser.reset(); m_parser.reset();
cut_receive_buffer(http_body.end - recv_buffer.begin, 512*1024+1024); assert(recv_buffer.end == http_body.end || *http_body.end == 'H');
cut_receive_buffer(http_body.end - recv_buffer.begin
, t->torrent_file().piece_length() + 1024 * 2);
continue; continue;
} }
break; break;