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:
parent
e324cfc519
commit
98b92e3f02
|
@ -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
|
||||
|
|
|
@ -860,6 +860,8 @@ int main(int ac, char* av[])
|
|||
out << state_str[s.state] << " ";
|
||||
}
|
||||
|
||||
if ((print_downloads && s.state != torrent_status::seeding)
|
||||
|| print_peers)
|
||||
h.get_peer_info(peers);
|
||||
|
||||
if (s.state != torrent_status::seeding)
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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,8 +474,14 @@ 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
|
||||
// incoming conncetion, this is set to zero
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
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());
|
||||
|
|
|
@ -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()
|
||||
|
|
264
src/torrent.cpp
264
src/torrent.cpp
|
@ -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,6 +1171,9 @@ namespace libtorrent
|
|||
(*m_ses.m_logger) << now << " resolving: " << url << "\n";
|
||||
#endif
|
||||
|
||||
m_resolving_web_seeds.insert(url);
|
||||
if (m_ses.settings().proxy_ip.empty())
|
||||
{
|
||||
std::string protocol;
|
||||
std::string hostname;
|
||||
int port;
|
||||
|
@ -1180,12 +1181,10 @@ namespace libtorrent
|
|||
boost::tie(protocol, hostname, port, path)
|
||||
= parse_url_components(url);
|
||||
|
||||
m_resolving_web_seeds.insert(url);
|
||||
if (m_ses.settings().proxy_ip.empty())
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
// 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)
|
||||
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;
|
||||
|
||||
// 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,7 +320,48 @@ namespace libtorrent
|
|||
|
||||
if (!m_parser.header_finished()) break;
|
||||
|
||||
buffer::const_interval http_body = m_parser.get_body();
|
||||
// we just completed reading the header
|
||||
if (!header_finished)
|
||||
{
|
||||
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())
|
||||
|
@ -321,6 +373,10 @@ namespace libtorrent
|
|||
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;
|
||||
|
|
Loading…
Reference in New Issue