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
dropped or extremely rare cases.
* 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] << " ";
}
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)
{

View File

@ -77,10 +77,11 @@ int main(int argc, char* argv[])
path::default_name_check(no_check);
if (argc != 4)
if (argc != 4 && argc != 5)
{
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;
}
@ -113,6 +114,9 @@ int main(int argc, char* argv[])
t.set_creator(creator_str);
if (argc == 5)
t.add_url_seed(argv[4]);
// create the torrent and print it to out
entry e = t.create_torrent();
libtorrent::bencode(std::ostream_iterator<char>(out), e);

View File

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

View File

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

View File

@ -117,7 +117,8 @@ namespace libtorrent
aux::session_impl& ses
, boost::weak_ptr<torrent> t
, 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
// know which torrent the connection belongs to
@ -204,13 +205,11 @@ namespace libtorrent
boost::shared_ptr<stream_socket> get_socket() const { return m_socket; }
tcp::endpoint const& remote() const { return m_remote; }
tcp::endpoint const& proxy() const { return m_remote_proxy; }
std::vector<bool> const& get_bitfield() const;
// 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();
bool is_disconnecting() const { return m_disconnecting; }
@ -382,7 +381,7 @@ namespace libtorrent
bool packet_finished() const
{
assert(m_recv_pos <= m_packet_size);
return m_packet_size == m_recv_pos;
return m_packet_size <= m_recv_pos;
}
void setup_receive();
@ -475,7 +474,13 @@ namespace libtorrent
boost::posix_time::ptime m_last_sent;
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;
// if we use a proxy, this is the address to it
tcp::endpoint m_remote_proxy;
// this is the torrent this connection is
// 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
// lookup for a web seed is completed.
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);
// this is called when the torrent has finished. i.e.

View File

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

View File

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

View File

@ -198,6 +198,20 @@ namespace libtorrent
}
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
++pos;

View File

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

View File

@ -75,7 +75,8 @@ namespace libtorrent
session_impl& ses
, boost::weak_ptr<torrent> tor
, shared_ptr<stream_socket> s
, tcp::endpoint const& remote)
, tcp::endpoint const& remote
, tcp::endpoint const& proxy)
:
#ifndef NDEBUG
m_last_choke(boost::posix_time::second_clock::universal_time()
@ -94,6 +95,7 @@ namespace libtorrent
, m_last_sent(second_clock::universal_time())
, m_socket(s)
, m_remote(remote)
, m_remote_proxy(proxy)
, m_torrent(tor)
, m_active(true)
, m_peer_interested(false)
@ -593,7 +595,7 @@ namespace libtorrent
// clear the request queue if the client isn't interested
m_requests.clear();
setup_send();
// setup_send();
#ifdef TORRENT_VERBOSE_LOGGING
using namespace boost::posix_time;
@ -701,8 +703,9 @@ namespace libtorrent
return;
}
// build a vector of all pieces
std::vector<int> piece_list;
// let the torrent know which pieces the
// peer has
bool interesting = false;
for (int i = 0; i < (int)m_have_piece.size(); ++i)
{
bool have = bitfield[i];
@ -710,7 +713,10 @@ namespace libtorrent
{
m_have_piece[i] = true;
++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])
{
@ -721,23 +727,7 @@ namespace libtorrent
}
}
// let the torrent know which pieces the
// 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())
if (m_num_pieces == int(m_have_piece.size()))
{
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << " *** THIS IS A SEED ***\n";
@ -1018,6 +1008,7 @@ namespace libtorrent
if (picker.is_finished(block_finished))
{
t->received_redundant_data(t->block_size());
pol.block_finished(*this, block_finished);
send_block_requests();
return;
}
@ -1190,6 +1181,9 @@ namespace libtorrent
assert(it != m_request_queue.end());
if (it == m_request_queue.end()) return;
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
// sent yet, so we don't have to send a cancel.
return;
@ -1199,8 +1193,6 @@ namespace libtorrent
m_download_queue.erase(it);
}
send_block_requests();
int block_offset = block.block_index * t->block_size();
int block_size
= std::min((int)t->torrent_file().piece_size(block.piece_index)-block_offset,
@ -1215,6 +1207,9 @@ namespace libtorrent
write_cancel(r);
m_policy->block_finished(*this, block);
send_block_requests();
#ifdef TORRENT_VERBOSE_LOGGING
using namespace boost::posix_time;
(*m_logger) << to_simple_string(second_clock::universal_time())
@ -1481,7 +1476,7 @@ namespace libtorrent
assert(packet_size > 0);
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());
assert(m_recv_pos >= size);
@ -1492,7 +1487,7 @@ namespace libtorrent
#endif
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)
@ -1762,7 +1757,8 @@ namespace libtorrent
(*m_logger) << "req bandwidth [ " << upload_channel << " ]\n";
#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;
}
return;
@ -1775,7 +1771,7 @@ namespace libtorrent
int sending_buffer = (m_current_send_buffer + 1) & 1;
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.
std::swap(m_current_send_buffer, sending_buffer);
m_write_pos = 0;
@ -1846,6 +1842,11 @@ namespace libtorrent
void peer_connection::reset_recv_buffer(int packet_size)
{
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_packet_size = 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_recv_pos += bytes_transferred;
// 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);
assert(m_recv_pos <= int(m_recv_buffer.size()));
{
INVARIANT_CHECK;
@ -1930,9 +1924,6 @@ namespace libtorrent
assert(m_packet_size > 0);
// do the reset immediately
reset.fire();
setup_receive();
}
catch (file_error& e)
@ -2002,8 +1993,16 @@ namespace libtorrent
assert(m_connecting);
m_socket->open(asio::ip::tcp::v4());
m_socket->bind(t->get_interface());
m_socket->async_connect(m_remote
, bind(&peer_connection::on_connection_complete, self(), _1));
if (m_remote_proxy != tcp::endpoint())
{
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))
{
@ -2189,6 +2188,11 @@ namespace libtorrent
// TODO: the timeout should be called by an event
INVARIANT_CHECK;
#ifndef NDEBUG
// allow step debugging without timing out
return false;
#endif
using namespace boost::posix_time;
ptime now(second_clock::universal_time());

View File

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

View File

@ -1106,9 +1106,7 @@ namespace libtorrent
m_event = tracker_request::none;
req.url = m_trackers[m_currently_trying_tracker].url;
assert(m_connections_quota.given > 0);
req.num_want = std::max(
(m_connections_quota.given
- m_policy->num_peers()), 10);
req.num_want = std::max(m_connections_quota.given - num_peers(), 10);
// if we are aborting. we don't want any new peers
if (req.event == tracker_request::stopped)
req.num_want = 0;
@ -1173,19 +1171,20 @@ namespace libtorrent
(*m_ses.m_logger) << now << " resolving: " << url << "\n";
#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);
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));
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
{
@ -1193,11 +1192,162 @@ namespace libtorrent
tcp::resolver::query q(m_ses.settings().proxy_ip
, boost::lexical_cast<std::string>(m_ses.settings().proxy_port));
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
{
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)
{
INVARIANT_CHECK;
@ -1745,9 +1806,8 @@ namespace libtorrent
m_connections.erase(ci);
throw;
}
#ifndef NDEBUG
assert(p->remote() == p->get_socket()->remote_endpoint());
#endif
assert((p->proxy() == tcp::endpoint() && p->remote() == p->get_socket()->remote_endpoint())
|| p->proxy() == p->get_socket()->remote_endpoint());
#ifndef NDEBUG
m_policy->check_invariant();
@ -2247,6 +2307,10 @@ namespace libtorrent
// let the stats fade out to 0
m_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;
}

View File

@ -60,8 +60,9 @@ namespace libtorrent
, boost::weak_ptr<torrent> t
, boost::shared_ptr<stream_socket> s
, tcp::endpoint const& remote
, tcp::endpoint const& proxy
, std::string const& url)
: peer_connection(ses, t, s, remote)
: peer_connection(ses, t, s, remote, proxy)
, m_url(url)
, m_first_request(true)
{
@ -136,7 +137,7 @@ namespace libtorrent
// it is always possible to request pieces
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)
@ -291,15 +292,25 @@ namespace libtorrent
for (;;)
{
buffer::const_interval recv_buffer = receive_buffer();
int payload;
int protocol;
bool header_finished = m_parser.header_finished();
boost::tie(payload, protocol) = m_parser.incoming(recv_buffer);
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 (m_parser.status_code() != 206
&& m_parser.status_code() != 200
&& m_parser.status_code() != -1)
// if the status code is not one of the accepted ones, abort
if (m_parser.status_code() != 206 // partial content
&& m_parser.status_code() != 200 // OK
&& m_parser.status_code() < 300 // redirect
&& m_parser.status_code() >= 400)
{
// we should not try this server again.
t->remove_url_seed(m_url);
@ -309,18 +320,63 @@ namespace libtorrent
if (!m_parser.header_finished()) break;
buffer::const_interval http_body = m_parser.get_body();
std::string server_version = m_parser.header<std::string>("server");
if (!server_version.empty())
// we just completed reading the header
if (!header_finished)
{
m_server_string = "URL seed @ ";
m_server_string += m_host;
m_server_string += " (";
m_server_string += server_version;
m_server_string += ")";
if (m_parser.status_code() >= 300 && m_parser.status_code() < 400)
{
// this means we got a redirection request
// look for the location header
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_end;
if (m_parser.status_code() == 206)
@ -366,14 +422,14 @@ namespace libtorrent
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
// http_body.begin is now in sync with the request at the front
// of the request queue
assert(in_range.start - int(m_piece.size()) <= front_request.start);
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
// 1. the middle of a block or the ending of a block
// 2. a number of whole blocks
@ -417,6 +473,10 @@ namespace libtorrent
{
peer_request r = m_requests.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);
http_body.begin += r.length;
}
@ -442,7 +502,9 @@ namespace libtorrent
m_file_requests.pop_front();
assert(http_body.left() == 0);
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;
}
break;