added support for http seeds (BEP 17)

This commit is contained in:
Arvid Norberg 2008-12-30 03:54:07 +00:00
parent 96a771ef8b
commit e5d3755afb
17 changed files with 890 additions and 91 deletions

View File

@ -22,6 +22,7 @@ set(sources
peer_connection
bt_peer_connection
web_peer_connection
http_seed_connection
instantiate_connection
natpmp
piece_picker

View File

@ -1,3 +1,4 @@
* added support for BEP 17 http seeds
* added read_piece() to read pieces from torrent storage
* added option for udp tracker preference
* added super seeding

View File

@ -321,6 +321,7 @@ SOURCES =
peer_connection
bt_peer_connection
web_peer_connection
http_seed_connection
instantiate_connection
natpmp
piece_picker

View File

@ -41,8 +41,8 @@ following features:
* supports local peer discovery (multicasts for peers on the same local network)
* adjusts the length of the request queue depending on download rate.
* has an adjustable read and write disk cache for improved disk throughput.
* multitracker extension support (supports both the `specification by John Hoffman`__
and the uTorrent interpretation).
* multitracker extension support (supports both strict `BEP 12`_ and the
uTorrent interpretation).
* tracker scrapes
* supports both sparse files and compact file allocation (where pieces
are kept consolidated on disk)
@ -51,12 +51,12 @@ following features:
* fast resume support, a way to get rid of the costly piece check at the
start of a resumed torrent. Saves the storage state, piece_picker state
as well as all local peers in a separate fast-resume file.
* `HTTP seeding`_, as `specified by Michael Burford of GetRight`__.
* `HTTP seeding`_, as specified in `BEP 17`_ and `BEP 19`_.
* piece picking on block-level (as opposed to piece-level).
This means it can download parts of the same piece from different peers.
It will also prefer to download whole pieces from single peers if the
download speed is high enough from that particular peer.
* supports the `udp-tracker protocol`_ by Olaf van der Spek.
* supports `BEP 15`_ the udp-tracker protocol.
* queues torrents for file check, instead of checking all of them in parallel.
* supports http proxies and basic proxy authentication
* gzipped tracker-responses
@ -80,7 +80,10 @@ following features:
.. _`DHT extensions`: dht_extensions.html
__ http://home.elp.rr.com/tur/multitracker-spec.txt
__ http://www.getright.com/seedtorrent.html
.. _`BEP 12`: http://bittorrent.org/beps/bep_0012.html
.. _`BEP 15`: http://bittorrent.org/beps/bep_0015.html
.. _`BEP 17`: http://bittorrent.org/beps/bep_0017.html
.. _`BEP 19`: http://bittorrent.org/beps/bep_0019.html
.. _`extension protocol`: extension_protocol.html
.. _`udp-tracker protocol`: udp_tracker_protocol.html

View File

@ -1,7 +1,7 @@
# this makefile assumes that you have docutils and rst2pdf installed
WEB_PATH = ~/Documents/rasterbar/web/products/libtorrent
DOCUTILS = ~/docutils
DOCUTILS = ~/docutils-0.5
TARGETS = index \
udp_tracker_protocol \

View File

@ -1269,6 +1269,9 @@ The ``torrent_info`` has the following synopsis::
bool priv() const;
std::vector<std::string> const& url_seeds() const;
void add_url_seed(std::string const& url);
std::vector<std::string> const& http_seeds() const;
void add_http_seed(std::string const& url);
size_type total_size() const;
int piece_length() const;
@ -1473,17 +1476,20 @@ The input range is assumed to be valid within the torrent. ``file_offset``
must refer to a valid file, i.e. it cannot be >= ``num_files()``.
url_seeds() add_url_seed()
--------------------------
url_seeds() add_url_seed() http_seeds() add_http_seed()
-------------------------------------------------------
::
std::vector<std::string> const& url_seeds() const;
void add_url_seed(std::string const& url);
std::vector<std::string> const& http_seeds() const;
void add_http_seed(std::string const& url);
If there are any url-seeds in this torrent, ``url_seeds()`` will return a
vector of those urls. If you're creating a torrent file, ``add_url_seed()``
adds one url to the list of url-seeds. Currently, the only transport protocol
If there are any url-seeds or http seeds in this torrent, ``url_seeds()``
and ``http_seeds()`` will return a vector of those urls.
``add_url_seed()`` and ``add_http_seed()`` adds one url to the list of
url/http seeds. Currently, the only transport protocol
supported for the url is http.
See `HTTP seeding`_ for more information.
@ -1687,6 +1693,10 @@ Its declaration looks like this::
void remove_url_seed(std::string const& url);
std::set<std::string> url_seeds() const;
void add_http_seed(std::string const& url);
void remove_http_seed(std::string const& url);
std::set<std::string> http_seeds() const;
void set_ratio(float ratio) const;
void set_max_uploads(int max_uploads) const;
void set_max_connections(int max_connections) const;
@ -2225,6 +2235,19 @@ automatically from the list.
See `HTTP seeding`_ for more information.
add_http_seed() remove_http_seed() http_seeds()
-----------------------------------------------
::
void add_http_seed(std::string const& url);
void remove_http_seed(std::string const& url);
std::set<std::string> http_seeds() const;
These functions are identical as the ``*_url_seed()`` variants, but they
operate on BEP 17 web seeds instead of BEP 19.
See `HTTP seeding`_ for more information.
queue_position() queue_position_up() queue_position_down() queue_position_top() queue_position_bottom()
-------------------------------------------------------------------------------------------------------
@ -5514,17 +5537,23 @@ Don't have metadata:
HTTP seeding
------------
The HTTP seed extension implements `this specification`__.
There are two kinds of HTTP seeding. One with that assumes a smart
(and polite) client and one that assumes a smart server. These
are specified in `BEP 19`_ and `BEP 17`_ respectively.
The libtorrent implementation assumes that, if the URL ends with a slash
libtorrent supports both. In the libtorrent source code and API,
BEP 19 urls are typically referred to as *url seeds* and BEP 17
urls are typically referred to as *HTTP seeds*.
The libtorrent implementation of `BEP 19`_ assumes that, if the URL ends with a slash
('/'), the filename should be appended to it in order to request pieces from
that file. The way this works is that if the torrent is a single-file torrent,
only that filename is appended. If the torrent is a multi-file torrent, the
torrent's name '/' the file name is appended. This is the same directory
structure that libtorrent will download torrents into.
__ http://www.getright.com/seedtorrent.html
.. _`BEP 17`: http://bittorrent.org/beps/bep_0017.html
.. _`BEP 19`: http://bittorrent.org/beps/bep_0019.html
filename checks
===============
@ -5544,7 +5573,7 @@ __ http://www.boost.org/libs/filesystem/doc/index.htm
acknowledgments
===============
Written by Arvid Norberg. Copyright |copy| 2003-2006
Written by Arvid Norberg. Copyright |copy| 2003-2008
Contributions by Magnus Jonsson, Daniel Wallin and Cory Nelson

View File

@ -0,0 +1,171 @@
/*
Copyright (c) 2008, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TORRENT_HTTP_SEED_CONNECTION_HPP_INCLUDED
#define TORRENT_HTTP_SEED_CONNECTION_HPP_INCLUDED
#include <ctime>
#include <algorithm>
#include <vector>
#include <deque>
#include <string>
#include "libtorrent/debug.hpp"
#ifdef _MSC_VER
#pragma warning(push, 1)
#endif
#include <boost/smart_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/noncopyable.hpp>
#include <boost/array.hpp>
#include <boost/optional.hpp>
#include <boost/cstdint.hpp>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include "libtorrent/buffer.hpp"
#include "libtorrent/peer_connection.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/peer_id.hpp"
#include "libtorrent/storage.hpp"
#include "libtorrent/stat.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/torrent_handle.hpp"
#include "libtorrent/torrent.hpp"
#include "libtorrent/peer_request.hpp"
#include "libtorrent/piece_block_progress.hpp"
#include "libtorrent/config.hpp"
// parse_url
#include "libtorrent/tracker_manager.hpp"
#include "libtorrent/http_parser.hpp"
namespace libtorrent
{
class torrent;
namespace detail
{
struct session_impl;
}
class TORRENT_EXPORT http_seed_connection
: public peer_connection
{
friend class invariant_access;
public:
// this is the constructor where the we are the active part.
// The peer_conenction should handshake and verify that the
// other end has the correct id
http_seed_connection(
aux::session_impl& ses
, boost::weak_ptr<torrent> t
, boost::shared_ptr<socket_type> s
, tcp::endpoint const& remote
, std::string const& url
, policy::peer* peerinfo);
~http_seed_connection();
// called from the main loop when this connection has any
// work to do.
void on_sent(error_code const& error
, std::size_t bytes_transferred);
void on_receive(error_code const& error
, std::size_t bytes_transferred);
std::string const& url() const { return m_url; }
virtual void get_specific_peer_info(peer_info& p) const;
virtual bool in_handshake() const;
// the following functions appends messages
// to the send buffer
void write_choke() {}
void write_unchoke() {}
void write_interested() {}
void write_not_interested() {}
void write_request(peer_request const& r);
void write_cancel(peer_request const& r)
{ incoming_reject_request(r); }
void write_have(int index) {}
void write_piece(peer_request const& r, disk_buffer_holder& buffer) { TORRENT_ASSERT(false); }
void write_keepalive() {}
void on_connected();
void write_reject_request(peer_request const&) {}
void write_allow_fast(int) {}
#ifdef TORRENT_DEBUG
void check_invariant() const;
#endif
private:
// returns the block currently being
// downloaded. And the progress of that
// block. If the peer isn't downloading
// a piece for the moment, the boost::optional
// will be invalid.
boost::optional<piece_block_progress> downloading_piece_progress() const;
// this has one entry per bittorrent request
std::deque<peer_request> m_requests;
std::string m_server_string;
http_parser m_parser;
std::string m_auth;
std::string m_host;
int m_port;
std::string m_path;
std::string m_url;
// the first request will contain a little bit more data
// than subsequent ones, things that aren't critical are left
// out to save bandwidth.
bool m_first_request;
// the number of bytes left to receive of the response we're
// currently parsing
int m_response_left;
// the number of bytes in the start of the receive buffer
// that's http header
int m_body_start;
};
}
#endif // TORRENT_WEB_PEER_CONNECTION_HPP_INCLUDED

View File

@ -175,7 +175,8 @@ namespace libtorrent
enum
{
standard_bittorrent = 0,
web_seed = 1
web_seed = 1,
http_seed = 2
};
int connection_type;

View File

@ -90,6 +90,24 @@ namespace libtorrent
struct piece_checker_data;
}
struct web_seed_entry
{
std::string url;
// http seeds are different from url seeds in the
// protocol they use. http seeds follows the original
// http seed spec. by John Hoffman
enum type_t { url_seed, http_seed} type;
web_seed_entry(std::string const& url_, type_t type_)
: url(url_), type(type_) {}
bool operator==(web_seed_entry const& e) const
{ return url == e.url && type == e.type; }
bool operator<(web_seed_entry const& e) const
{ return url < e.url && type < e.type; }
};
namespace fs = boost::filesystem;
// a torrent is a class that holds information
@ -281,7 +299,7 @@ namespace libtorrent
void use_interface(const char* net_interface);
tcp::endpoint const& get_interface() const { return m_net_interface; }
void connect_to_url_seed(std::string const& url);
void connect_to_url_seed(web_seed_entry const& url);
bool connect_to_peer(policy::peer* peerinfo);
void set_ratio(float ratio)
@ -325,17 +343,19 @@ namespace libtorrent
// add or remove a url that will be attempted for
// finding the file(s) in this torrent.
void add_url_seed(std::string const& url)
{ m_web_seeds.insert(url); }
void add_web_seed(std::string const& url, web_seed_entry::type_t type)
{ m_web_seeds.insert(web_seed_entry(url, type)); }
void remove_url_seed(std::string const& url)
{ m_web_seeds.erase(url); }
void remove_web_seed(std::string const& url, web_seed_entry::type_t type)
{ m_web_seeds.erase(web_seed_entry(url, type)); }
void retry_url_seed(std::string const& url);
void retry_web_seed(std::string const& url, web_seed_entry::type_t type, int retry = 0);
std::set<std::string> url_seeds() const
std::set<web_seed_entry> web_seeds() const
{ return m_web_seeds; }
std::set<std::string> web_seeds(web_seed_entry::type_t type) const;
bool free_upload_slots() const
{ return m_num_uploads < m_max_uploads; }
@ -531,12 +551,12 @@ namespace libtorrent
// this is the asio callback that is called when a name
// lookup for a WEB SEED is completed.
void on_name_lookup(error_code const& e, tcp::resolver::iterator i
, std::string url, tcp::endpoint proxy);
, web_seed_entry 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(error_code const& e, tcp::resolver::iterator i
, std::string url);
, web_seed_entry url);
// this is called when the torrent has finished. i.e.
// all the pieces we have not filtered have been downloaded.
@ -755,15 +775,15 @@ namespace libtorrent
// The list of web seeds in this torrent. Seeds
// with fatal errors are removed from the set
std::set<std::string> m_web_seeds;
std::set<web_seed_entry> m_web_seeds;
// a list of web seeds that have failed and are
// waiting to be retried
std::map<std::string, ptime> m_web_seeds_next_retry;
std::map<web_seed_entry, ptime> m_web_seeds_next_retry;
// urls of the web seeds that we are currently
// resolving the address for
std::set<std::string> m_resolving_web_seeds;
std::set<web_seed_entry> m_resolving_web_seeds;
#ifndef TORRENT_DISABLE_EXTENSIONS
typedef std::list<boost::shared_ptr<torrent_plugin> > extension_list_t;

View File

@ -341,6 +341,10 @@ namespace libtorrent
void remove_url_seed(std::string const& url) const;
std::set<std::string> url_seeds() const;
void add_http_seed(std::string const& url) const;
void remove_http_seed(std::string const& url) const;
std::set<std::string> http_seeds() const;
#ifndef TORRENT_DISABLE_EXTENSIONS
void add_extension(boost::function<boost::shared_ptr<torrent_plugin>(torrent*, void*)> const& ext
, void* userdata = 0);

View File

@ -197,6 +197,11 @@ namespace libtorrent
void add_url_seed(std::string const& url)
{ m_url_seeds.push_back(url); }
std::vector<std::string> const& http_seeds() const
{ return m_http_seeds; }
void add_http_seed(std::string const& url)
{ m_http_seeds.push_back(url); }
size_type total_size() const { return m_files.total_size(); }
int piece_length() const { return m_files.piece_length(); }
int num_pieces() const { return m_files.num_pieces(); }
@ -296,6 +301,7 @@ namespace libtorrent
// the urls to the trackers
std::vector<announce_entry> m_urls;
std::vector<std::string> m_url_seeds;
std::vector<std::string> m_http_seeds;
nodes_t m_nodes;
// the hash that identifies this torrent

View File

@ -15,8 +15,9 @@ endif
libtorrent_rasterbar_la_SOURCES = entry.cpp escape_string.cpp \
lazy_bdecode.cpp assert.cpp enum_net.cpp broadcast_socket.cpp \
peer_connection.cpp bt_peer_connection.cpp web_peer_connection.cpp \
natpmp.cpp piece_picker.cpp policy.cpp session.cpp session_impl.cpp sha1.cpp \
stat.cpp storage.cpp torrent.cpp torrent_handle.cpp pe_crypto.cpp \
http_seed_connection.cpp natpmp.cpp piece_picker.cpp policy.cpp \
session.cpp session_impl.cpp sha1.cpp stat.cpp storage.cpp torrent.cpp \
torrent_handle.cpp pe_crypto.cpp \
torrent_info.cpp tracker_manager.cpp http_connection.cpp \
http_tracker_connection.cpp udp_tracker_connection.cpp \
alert.cpp identify_client.cpp ip_filter.cpp file.cpp metadata_transfer.cpp \
@ -58,6 +59,7 @@ $(top_srcdir)/include/libtorrent/fingerprint.hpp \
$(top_srcdir)/include/libtorrent/gzip.hpp \
$(top_srcdir)/include/libtorrent/hasher.hpp \
$(top_srcdir)/include/libtorrent/http_connection.hpp \
$(top_srcdir)/include/libtorrent/http_seed_connection.hpp \
$(top_srcdir)/include/libtorrent/http_stream.hpp \
$(top_srcdir)/include/libtorrent/http_parser.hpp \
$(top_srcdir)/include/libtorrent/session_settings.hpp \

View File

@ -0,0 +1,477 @@
/*
Copyright (c) 2008, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "libtorrent/pch.hpp"
#include <vector>
#include <iostream>
#include <iomanip>
#include <limits>
#include <boost/bind.hpp>
#include <sstream>
#include "libtorrent/http_seed_connection.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/identify_client.hpp"
#include "libtorrent/entry.hpp"
#include "libtorrent/bencode.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/invariant_check.hpp"
#include "libtorrent/io.hpp"
#include "libtorrent/version.hpp"
#include "libtorrent/aux_/session_impl.hpp"
#include "libtorrent/parse_url.hpp"
using boost::bind;
using boost::shared_ptr;
using libtorrent::aux::session_impl;
namespace libtorrent
{
http_seed_connection::http_seed_connection(
session_impl& ses
, boost::weak_ptr<torrent> t
, boost::shared_ptr<socket_type> s
, tcp::endpoint const& remote
, std::string const& url
, policy::peer* peerinfo)
: peer_connection(ses, t, s, remote, peerinfo)
, m_url(url)
, m_first_request(true)
, m_response_left(0)
, m_body_start(0)
{
INVARIANT_CHECK;
// we want large blocks as well, so
// we can request more bytes at once
request_large_blocks(true);
set_upload_only(true);
prefer_whole_pieces(1);
// we only want left-over bandwidth
set_priority(0);
shared_ptr<torrent> tor = t.lock();
TORRENT_ASSERT(tor);
int blocks_per_piece = tor->torrent_file().piece_length() / tor->block_size();
// multiply with the blocks per piece since that many requests are
// merged into one http request
m_max_out_request_queue = ses.settings().urlseed_pipeline_size
* blocks_per_piece;
// since this is a web seed, change the timeout
// according to the settings.
set_timeout(ses.settings().urlseed_timeout);
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << "*** http_seed_connection\n";
#endif
std::string protocol;
char const* error;
boost::tie(protocol, m_auth, m_host, m_port, m_path, error)
= parse_url_components(url);
TORRENT_ASSERT(error == 0);
if (!m_auth.empty())
m_auth = base64encode(m_auth);
m_server_string = "HTTP seed @ ";
m_server_string += m_host;
}
http_seed_connection::~http_seed_connection()
{}
boost::optional<piece_block_progress>
http_seed_connection::downloading_piece_progress() const
{
if (m_requests.empty())
return boost::optional<piece_block_progress>();
boost::shared_ptr<torrent> t = associated_torrent().lock();
TORRENT_ASSERT(t);
piece_block_progress ret;
peer_request const& pr = m_requests.front();
ret.piece_index = pr.piece;
if (!m_parser.header_finished())
{
ret.bytes_downloaded = 0;
}
else
{
int receive_buffer_size = receive_buffer().left() - m_parser.body_start();
TORRENT_ASSERT(receive_buffer_size < t->block_size());
ret.bytes_downloaded = t->block_size() - receive_buffer_size;
}
ret.block_index = (pr.start + ret.bytes_downloaded) / t->block_size();
ret.full_block_bytes = t->block_size();
const int last_piece = t->torrent_file().num_pieces() - 1;
if (ret.piece_index == last_piece && ret.block_index
== t->torrent_file().piece_size(last_piece) / t->block_size())
ret.full_block_bytes = t->torrent_file().piece_size(last_piece) % t->block_size();
return ret;
}
void http_seed_connection::on_connected()
{
boost::shared_ptr<torrent> t = associated_torrent().lock();
TORRENT_ASSERT(t);
// this is always a seed
incoming_have_all();
// it is always possible to request pieces
incoming_unchoke();
reset_recv_buffer(t->block_size() + 1024);
}
void http_seed_connection::write_request(peer_request const& r)
{
INVARIANT_CHECK;
boost::shared_ptr<torrent> t = associated_torrent().lock();
TORRENT_ASSERT(t);
TORRENT_ASSERT(t->valid_metadata());
// http_seeds don't support requesting more than one piece
// at a time
TORRENT_ASSERT(r.length <= t->torrent_file().piece_size(r.piece));
std::string request;
request.reserve(400);
int size = r.length;
const int block_size = t->block_size();
const int piece_size = t->torrent_file().piece_length();
peer_request pr;
while (size > 0)
{
int request_offset = r.start + r.length - size;
pr.start = request_offset % piece_size;
pr.length = (std::min)(block_size, size);
pr.piece = r.piece + request_offset / piece_size;
m_requests.push_back(pr);
size -= pr.length;
}
proxy_settings const& ps = m_ses.web_seed_proxy();
bool using_proxy = ps.type == proxy_settings::http
|| ps.type == proxy_settings::http_pw;
request += "GET ";
request += using_proxy ? m_url : m_path;
request += "?info_hash=";
request += escape_string((char const*)&t->torrent_file().info_hash()[0], 20);
request += "&piece=";
request += boost::lexical_cast<std::string>(r.piece);
// if we're requesting less than an entire piece we need to
// add ranges
if (r.start > 0 || r.length != t->torrent_file().piece_size(r.piece))
{
request += "&ranges=";
request += boost::lexical_cast<std::string>(r.start);
request += "-";
// TODO: are ranges inclusive?
request += boost::lexical_cast<std::string>(r.start + r.length);
}
request += " HTTP/1.1\r\n";
request += "Host: ";
request += m_host;
if (m_first_request)
{
request += "\r\nUser-Agent: ";
request += m_ses.settings().user_agent;
}
if (!m_auth.empty())
{
request += "\r\nAuthorization: Basic ";
request += m_auth;
}
if (ps.type == proxy_settings::http_pw)
{
request += "\r\nProxy-Authorization: Basic ";
request += base64encode(ps.username + ":" + ps.password);
}
if (using_proxy)
{
request += "\r\nProxy-Connection: keep-alive";
}
if (m_first_request || using_proxy)
request += "\r\nConnection: keep-alive";
request += "\r\n\r\n";
m_first_request = false;
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << request << "\n";
#endif
send_buffer(request.c_str(), request.size(), message_type_request);
}
// --------------------------
// RECEIVE DATA
// --------------------------
void http_seed_connection::on_receive(error_code const& error
, std::size_t bytes_transferred)
{
INVARIANT_CHECK;
if (error)
{
#ifdef TORRENT_VERBOSE_LOGGING
(*m_logger) << "*** http_seed_connection error: "
<< error.message() << "\n";
#endif
return;
}
boost::shared_ptr<torrent> t = associated_torrent().lock();
TORRENT_ASSERT(t);
incoming_piece_fragment();
for (;;)
{
buffer::const_interval recv_buffer = receive_buffer();
if (bytes_transferred == 0) break;
TORRENT_ASSERT(recv_buffer.left() > 0);
TORRENT_ASSERT(!m_requests.empty());
if (m_requests.empty())
{
disconnect("unexpected HTTP response", 2);
return;
}
peer_request front_request = m_requests.front();
int payload = 0;
int protocol = 0;
bool header_finished = m_parser.header_finished();
if (!header_finished)
{
bool error = false;
boost::tie(payload, protocol) = m_parser.incoming(recv_buffer, error);
m_statistics.received_bytes(0, protocol);
bytes_transferred -= protocol;
if (payload > front_request.length) payload = front_request.length;
if (error)
{
disconnect("failed to parse HTTP response", 2);
return;
}
TORRENT_ASSERT(recv_buffer.left() == 0 || *recv_buffer.begin == 'H');
TORRENT_ASSERT(recv_buffer.left() <= packet_size());
// this means the entire status line hasn't been received yet
if (m_parser.status_code() == -1)
{
TORRENT_ASSERT(payload == 0);
TORRENT_ASSERT(bytes_transferred == 0);
break;
}
// if the status code is not one of the accepted ones, abort
if (m_parser.status_code() != 200 // OK
&& m_parser.status_code() != 503
&& !(m_parser.status_code() >= 300 // redirect
&& m_parser.status_code() < 400))
{
t->remove_web_seed(m_url, web_seed_entry::http_seed);
std::string error_msg = boost::lexical_cast<std::string>(m_parser.status_code())
+ " " + m_parser.message();
if (m_ses.m_alerts.should_post<url_seed_alert>())
{
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
m_ses.m_alerts.post_alert(url_seed_alert(t->get_handle(), url()
, error_msg));
}
disconnect(error_msg.c_str(), 1);
return;
}
if (!m_parser.header_finished())
{
TORRENT_ASSERT(payload == 0);
TORRENT_ASSERT(bytes_transferred == 0);
break;
}
}
// 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("location");
if (location.empty())
{
// we should not try this server again.
t->remove_web_seed(m_url, web_seed_entry::http_seed);
disconnect("got HTTP redirection status without location header", 2);
return;
}
// add the redirected url and remove the current one
t->add_web_seed(location, web_seed_entry::http_seed);
t->remove_web_seed(m_url, web_seed_entry::http_seed);
std::stringstream msg;
msg << "redirecting to \"" << location << "\"";
disconnect(msg.str().c_str());
return;
}
std::string const& server_version = m_parser.header("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 += ")";
}
m_response_left = atol(m_parser.header("content-length").c_str());
if (m_response_left == -1)
{
// we should not try this server again.
t->remove_web_seed(m_url, web_seed_entry::http_seed);
disconnect("no content-length in HTTP response", 2);
return;
}
if (payload > m_response_left) payload = m_response_left;
m_body_start = m_parser.body_start();
m_response_left -= payload;
m_statistics.received_bytes(payload, 0);
}
else
{
payload = bytes_transferred;
if (payload > m_response_left) payload = m_response_left;
if (payload > front_request.length) payload = front_request.length;
m_statistics.received_bytes(payload, 0);
m_response_left -= payload;
}
recv_buffer.begin += m_body_start;
if (m_parser.status_code() == 503)
{
if (!m_parser.finished()) return;
int retry_time = atol(std::string(recv_buffer.begin, recv_buffer.end).c_str());
if (retry_time <= 0) retry_time = 0;
#ifdef TORRENT_VERBOSE_LOGGING
else
{
(*m_logger) << time_now_string() << ": retrying in " << retry_time << " seconds\n";
}
#endif
// temporarily unavailable, retry later
t->retry_web_seed(m_url, web_seed_entry::http_seed, retry_time);
t->remove_web_seed(m_url, web_seed_entry::http_seed);
disconnect("503 retrying later", 1);
return;
}
// we only received the header, no data
if (recv_buffer.left() == 0) break;
if (recv_buffer.left() < front_request.length) break;
m_requests.pop_front();
incoming_piece(front_request, recv_buffer.begin);
if (associated_torrent().expired()) return;
cut_receive_buffer(m_body_start + front_request.length, t->block_size() + 1024);
bytes_transferred -= payload;
m_body_start = 0;
if (m_response_left > 0) continue;
TORRENT_ASSERT(m_response_left == 0);
m_parser.reset();
}
}
void http_seed_connection::get_specific_peer_info(peer_info& p) const
{
if (is_interesting()) p.flags |= peer_info::interesting;
if (is_choked()) p.flags |= peer_info::choked;
p.flags |= peer_info::local_connection;
if (!is_connecting() && m_server_string.empty())
p.flags |= peer_info::handshake;
if (is_connecting() && !is_queued()) p.flags |= peer_info::connecting;
if (is_queued()) p.flags |= peer_info::queued;
p.client = m_server_string;
p.connection_type = peer_info::http_seed;
}
bool http_seed_connection::in_handshake() const
{
return m_server_string.empty();
}
void http_seed_connection::on_sent(error_code const& error
, std::size_t bytes_transferred)
{
INVARIANT_CHECK;
if (error) return;
m_statistics.sent_bytes(0, bytes_transferred);
}
#ifdef TORRENT_DEBUG
void http_seed_connection::check_invariant() const
{
/*
TORRENT_ASSERT(m_num_pieces == std::count(
m_have_piece.begin()
, m_have_piece.end()
, true));
*/ }
#endif
}

View File

@ -69,6 +69,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/peer.hpp"
#include "libtorrent/bt_peer_connection.hpp"
#include "libtorrent/web_peer_connection.hpp"
#include "libtorrent/http_seed_connection.hpp"
#include "libtorrent/peer_id.hpp"
#include "libtorrent/alert.hpp"
#include "libtorrent/identify_client.hpp"
@ -593,8 +594,14 @@ namespace libtorrent
, int((m_torrent_file->total_size()+m_block_size-1)/m_block_size));
std::vector<std::string> const& url_seeds = m_torrent_file->url_seeds();
std::copy(url_seeds.begin(), url_seeds.end(), std::inserter(m_web_seeds
, m_web_seeds.begin()));
for (std::vector<std::string>::const_iterator i = url_seeds.begin()
, end(url_seeds.end()); i != end; ++i)
add_web_seed(*i, web_seed_entry::url_seed);
std::vector<std::string> const& http_seeds = m_torrent_file->http_seeds();
for (std::vector<std::string>::const_iterator i = http_seeds.begin()
, end(http_seeds.end()); i != end; ++i)
add_web_seed(*i, web_seed_entry::http_seed);
set_state(torrent_status::checking_resume_data);
@ -2430,12 +2437,12 @@ namespace libtorrent
}
}
void torrent::connect_to_url_seed(std::string const& url)
void torrent::connect_to_url_seed(web_seed_entry const& web)
{
INVARIANT_CHECK;
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
(*m_ses.m_logger) << time_now_string() << " resolving web seed: " << url << "\n";
(*m_ses.m_logger) << time_now_string() << " resolving web seed: " << web.url << "\n";
#endif
std::string protocol;
@ -2445,7 +2452,7 @@ namespace libtorrent
std::string path;
char const* error;
boost::tie(protocol, auth, hostname, port, path, error)
= parse_url_components(url);
= parse_url_components(web.url);
if (error)
{
@ -2453,7 +2460,7 @@ namespace libtorrent
(*m_ses.m_logger) << time_now_string() << " failed to parse web seed url: " << error << "\n";
#endif
// never try it again
remove_url_seed(url);
m_web_seeds.erase(web);
return;
}
@ -2466,10 +2473,10 @@ namespace libtorrent
if (m_ses.m_alerts.should_post<url_seed_alert>())
{
m_ses.m_alerts.post_alert(
url_seed_alert(get_handle(), url, "unknown protocol"));
url_seed_alert(get_handle(), web.url, "unknown protocol"));
}
// never try it again
remove_url_seed(url);
m_web_seeds.erase(web);
return;
}
@ -2478,10 +2485,10 @@ namespace libtorrent
if (m_ses.m_alerts.should_post<url_seed_alert>())
{
m_ses.m_alerts.post_alert(
url_seed_alert(get_handle(), url, "invalid hostname"));
url_seed_alert(get_handle(), web.url, "invalid hostname"));
}
// never try it again
remove_url_seed(url);
m_web_seeds.erase(web);
return;
}
@ -2490,14 +2497,14 @@ namespace libtorrent
if (m_ses.m_alerts.should_post<url_seed_alert>())
{
m_ses.m_alerts.post_alert(
url_seed_alert(get_handle(), url, "invalid port"));
url_seed_alert(get_handle(), web.url, "invalid port"));
}
// never try it again
remove_url_seed(url);
m_web_seeds.erase(web);
return;
}
m_resolving_web_seeds.insert(url);
m_resolving_web_seeds.insert(web);
proxy_settings const& ps = m_ses.web_seed_proxy();
if (ps.type == proxy_settings::http
|| ps.type == proxy_settings::http_pw)
@ -2506,7 +2513,7 @@ namespace libtorrent
tcp::resolver::query q(ps.hostname
, boost::lexical_cast<std::string>(ps.port));
m_host_resolver.async_resolve(q,
bind(&torrent::on_proxy_name_lookup, shared_from_this(), _1, _2, url));
bind(&torrent::on_proxy_name_lookup, shared_from_this(), _1, _2, web));
}
else
{
@ -2515,30 +2522,30 @@ namespace libtorrent
if (m_ses.m_alerts.should_post<url_seed_alert>())
{
m_ses.m_alerts.post_alert(
url_seed_alert(get_handle(), url, "port blocked by port-filter"));
url_seed_alert(get_handle(), web.url, "port blocked by port-filter"));
}
// never try it again
remove_url_seed(url);
m_web_seeds.erase(web);
return;
}
tcp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
m_host_resolver.async_resolve(q,
bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url
bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, web
, tcp::endpoint()));
}
}
void torrent::on_proxy_name_lookup(error_code const& e, tcp::resolver::iterator host
, std::string url)
, web_seed_entry web)
{
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
INVARIANT_CHECK;
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
(*m_ses.m_logger) << time_now_string() << " completed resolve proxy hostname for: " << url << "\n";
(*m_ses.m_logger) << time_now_string() << " completed resolve proxy hostname for: " << web.url << "\n";
#endif
if (m_abort) return;
@ -2548,12 +2555,12 @@ namespace libtorrent
if (m_ses.m_alerts.should_post<url_seed_alert>())
{
m_ses.m_alerts.post_alert(
url_seed_alert(get_handle(), url, e.message()));
url_seed_alert(get_handle(), web.url, e.message()));
}
// the name lookup failed for the http host. Don't try
// this host again
remove_url_seed(url);
m_web_seeds.erase(web);
return;
}
@ -2566,16 +2573,16 @@ namespace libtorrent
int port;
char const* error;
boost::tie(ignore, ignore, hostname, port, ignore, error)
= parse_url_components(url);
= parse_url_components(web.url);
if (error)
{
if (m_ses.m_alerts.should_post<url_seed_alert>())
{
m_ses.m_alerts.post_alert(
url_seed_alert(get_handle(), url, error));
url_seed_alert(get_handle(), web.url, error));
}
remove_url_seed(url);
m_web_seeds.erase(web);
return;
}
@ -2588,23 +2595,23 @@ namespace libtorrent
tcp::resolver::query q(hostname, boost::lexical_cast<std::string>(port));
m_host_resolver.async_resolve(q,
bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, url, a));
bind(&torrent::on_name_lookup, shared_from_this(), _1, _2, web, a));
}
void torrent::on_name_lookup(error_code const& e, tcp::resolver::iterator host
, std::string url, tcp::endpoint proxy)
, web_seed_entry web, tcp::endpoint proxy)
{
session_impl::mutex_t::scoped_lock l(m_ses.m_mutex);
INVARIANT_CHECK;
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING
(*m_ses.m_logger) << time_now_string() << " completed resolve: " << url << "\n";
(*m_ses.m_logger) << time_now_string() << " completed resolve: " << web.url << "\n";
#endif
if (m_abort) return;
std::set<std::string>::iterator i = m_resolving_web_seeds.find(url);
std::set<web_seed_entry>::iterator i = m_resolving_web_seeds.find(web);
if (i != m_resolving_web_seeds.end()) m_resolving_web_seeds.erase(i);
if (e || host == tcp::resolver::iterator())
@ -2614,15 +2621,15 @@ namespace libtorrent
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()));
url_seed_alert(get_handle(), web.url, msg.str()));
}
#if defined TORRENT_VERBOSE_LOGGING || defined TORRENT_LOGGING || defined TORRENT_ERROR_LOGGING
(*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << url << "\n";
(*m_ses.m_logger) << " ** HOSTNAME LOOKUP FAILED!**: " << web.url << "\n";
#endif
// the name lookup failed for the http host. Don't try
// this host again
remove_url_seed(url);
m_web_seeds.erase(web);
return;
}
@ -2652,8 +2659,17 @@ namespace libtorrent
s->get<http_stream>()->set_no_connect(true);
}
boost::intrusive_ptr<peer_connection> c(new (std::nothrow) web_peer_connection(
m_ses, shared_from_this(), s, a, url, 0));
boost::intrusive_ptr<peer_connection> c;
if (web.type == web_seed_entry::url_seed)
{
c.reset(new (std::nothrow) web_peer_connection(
m_ses, shared_from_this(), s, a, web.url, 0));
}
else if (web.type == web_seed_entry::http_seed)
{
c.reset(new (std::nothrow) http_seed_connection(
m_ses, shared_from_this(), s, a, web.url, 0));
}
if (!c) return;
#ifdef TORRENT_DEBUG
@ -2924,7 +2940,18 @@ namespace libtorrent
{
std::string url = url_list->list_string_value_at(i);
if (url.empty()) continue;
m_web_seeds.insert(url);
add_web_seed(url, web_seed_entry::url_seed);
}
}
lazy_entry const* httpseeds = rd.dict_find_list("httpseeds");
if (httpseeds)
{
for (int i = 0; i < httpseeds->list_size(); ++i)
{
std::string url = httpseeds->list_string_value_at(i);
if (url.empty()) continue;
add_web_seed(url, web_seed_entry::http_seed);
}
}
}
@ -3028,10 +3055,19 @@ namespace libtorrent
if (!m_web_seeds.empty())
{
entry::list_type& url_list = ret["url-list"].list();
for (std::set<std::string>::const_iterator i = m_web_seeds.begin()
for (std::set<web_seed_entry>::const_iterator i = m_web_seeds.begin()
, end(m_web_seeds.end()); i != end; ++i)
{
url_list.push_back(*i);
if (i->type != web_seed_entry::url_seed) continue;
url_list.push_back(i->url);
}
entry::list_type& httpseed_list = ret["httpseeds"].list();
for (std::set<web_seed_entry>::const_iterator i = m_web_seeds.begin()
, end(m_web_seeds.end()); i != end; ++i)
{
if (i->type != web_seed_entry::http_seed) continue;
httpseed_list.push_back(i->url);
}
}
@ -4536,12 +4572,13 @@ namespace libtorrent
// ---- WEB SEEDS ----
ptime now = time_now();
// re-insert urls that are to be retrieds into the m_web_seeds
typedef std::map<std::string, ptime>::iterator iter_t;
typedef std::map<web_seed_entry, ptime>::iterator iter_t;
for (iter_t i = m_web_seeds_next_retry.begin(); i != m_web_seeds_next_retry.end();)
{
iter_t erase_element = i++;
if (erase_element->second <= time_now())
if (erase_element->second <= now)
{
m_web_seeds.insert(erase_element->first);
m_web_seeds_next_retry.erase(erase_element);
@ -4553,23 +4590,23 @@ namespace libtorrent
{
// keep trying web-seeds if there are any
// first find out which web seeds we are connected to
std::set<std::string> web_seeds;
std::set<web_seed_entry> web_seeds;
for (peer_iterator i = m_connections.begin();
i != m_connections.end(); ++i)
{
web_peer_connection* p
= dynamic_cast<web_peer_connection*>(*i);
if (!p) continue;
web_seeds.insert(p->url());
web_peer_connection* p = dynamic_cast<web_peer_connection*>(*i);
if (p) web_seeds.insert(web_seed_entry(p->url(), web_seed_entry::url_seed));
http_seed_connection* s = dynamic_cast<http_seed_connection*>(*i);
if (s) web_seeds.insert(web_seed_entry(s->url(), web_seed_entry::http_seed));
}
for (std::set<std::string>::iterator i = m_resolving_web_seeds.begin()
for (std::set<web_seed_entry>::iterator i = m_resolving_web_seeds.begin()
, end(m_resolving_web_seeds.end()); i != end; ++i)
web_seeds.insert(web_seeds.begin(), *i);
// from the list of available web seeds, subtract the ones we are
// already connected to.
std::vector<std::string> not_connected_web_seeds;
std::vector<web_seed_entry> not_connected_web_seeds;
std::set_difference(m_web_seeds.begin(), m_web_seeds.end(), web_seeds.begin()
, web_seeds.end(), std::back_inserter(not_connected_web_seeds));
@ -4615,10 +4652,22 @@ namespace libtorrent
}
}
void torrent::retry_url_seed(std::string const& url)
std::set<std::string> torrent::web_seeds(web_seed_entry::type_t type) const
{
m_web_seeds_next_retry[url] = time_now()
+ seconds(m_ses.settings().urlseed_wait_retry);
std::set<std::string> ret;
for (std::set<web_seed_entry>::const_iterator i = m_web_seeds.begin()
, end(m_web_seeds.end()); i != end; ++i)
{
if (i->type != type) continue;
ret.insert(i->url);
}
return ret;
}
void torrent::retry_web_seed(std::string const& url, web_seed_entry::type_t type, int retry)
{
if (retry == 0) retry = m_ses.settings().urlseed_wait_retry;
m_web_seeds_next_retry[web_seed_entry(url, type)] = time_now() + seconds(retry);
}
bool torrent::try_connect_peer()

View File

@ -506,20 +506,39 @@ namespace libtorrent
void torrent_handle::add_url_seed(std::string const& url) const
{
INVARIANT_CHECK;
TORRENT_FORWARD(add_url_seed(url));
TORRENT_FORWARD(add_web_seed(url, web_seed_entry::url_seed));
}
void torrent_handle::remove_url_seed(std::string const& url) const
{
INVARIANT_CHECK;
TORRENT_FORWARD(remove_url_seed(url));
TORRENT_FORWARD(remove_web_seed(url, web_seed_entry::url_seed));
}
std::set<std::string> torrent_handle::url_seeds() const
{
INVARIANT_CHECK;
const static std::set<std::string> empty;
TORRENT_FORWARD_RETURN(url_seeds(), empty);
TORRENT_FORWARD_RETURN(web_seeds(web_seed_entry::url_seed), empty);
}
void torrent_handle::add_http_seed(std::string const& url) const
{
INVARIANT_CHECK;
TORRENT_FORWARD(add_web_seed(url, web_seed_entry::http_seed));
}
void torrent_handle::remove_http_seed(std::string const& url) const
{
INVARIANT_CHECK;
TORRENT_FORWARD(remove_web_seed(url, web_seed_entry::http_seed));
}
std::set<std::string> torrent_handle::http_seeds() const
{
INVARIANT_CHECK;
const static std::set<std::string> empty;
TORRENT_FORWARD_RETURN(web_seeds(web_seed_entry::http_seed), empty);
}
void torrent_handle::replace_trackers(

View File

@ -651,6 +651,22 @@ namespace libtorrent
}
}
// if there are any http-seeds, extract them
lazy_entry const* http_seeds = torrent_file.dict_find("httpseeds");
if (http_seeds && http_seeds->type() == lazy_entry::string_t)
{
m_http_seeds.push_back(http_seeds->string_value());
}
else if (http_seeds && http_seeds->type() == lazy_entry::list_t)
{
for (int i = 0, end(http_seeds->list_size()); i < end; ++i)
{
lazy_entry const* url = http_seeds->list_at(i);
if (url->type() != lazy_entry::string_t) continue;
m_http_seeds.push_back(url->string_value());
}
}
m_comment = torrent_file.dict_find_string_value("comment.utf-8");
if (m_comment.empty()) m_comment = torrent_file.dict_find_string_value("comment");

View File

@ -381,9 +381,9 @@ namespace libtorrent
if (m_parser.status_code() == 503)
{
// temporarily unavailable, retry later
t->retry_url_seed(m_url);
t->retry_web_seed(m_url, web_seed_entry::url_seed);
}
t->remove_url_seed(m_url);
t->remove_web_seed(m_url, web_seed_entry::url_seed);
std::string error_msg = boost::lexical_cast<std::string>(m_parser.status_code())
+ " " + m_parser.message();
if (m_ses.m_alerts.should_post<url_seed_alert>())
@ -418,7 +418,7 @@ namespace libtorrent
if (location.empty())
{
// we should not try this server again.
t->remove_url_seed(m_url);
t->remove_web_seed(m_url, web_seed_entry::url_seed);
disconnect("got HTTP redirection status without location header", 2);
return;
}
@ -439,7 +439,7 @@ namespace libtorrent
size_t i = location.rfind(path);
if (i == std::string::npos)
{
t->remove_url_seed(m_url);
t->remove_web_seed(m_url, web_seed_entry::url_seed);
std::stringstream msg;
msg << "got invalid HTTP redirection location (\"" << location << "\") "
"expected it to end with: " << path;
@ -448,8 +448,8 @@ namespace libtorrent
}
location.resize(i);
}
t->add_url_seed(location);
t->remove_url_seed(m_url);
t->add_web_seed(location, web_seed_entry::url_seed);
t->remove_web_seed(m_url, web_seed_entry::url_seed);
std::stringstream msg;
msg << "redirecting to \"" << location << "\"";
disconnect(msg.str().c_str());
@ -487,7 +487,7 @@ namespace libtorrent
if (!range_str)
{
// we should not try this server again.
t->remove_url_seed(m_url);
t->remove_web_seed(m_url, web_seed_entry::url_seed);
std::stringstream msg;
msg << "invalid range in HTTP response: " << range_str.str();
disconnect(msg.str().c_str(), 2);
@ -503,7 +503,7 @@ namespace libtorrent
if (range_end == -1)
{
// we should not try this server again.
t->remove_url_seed(m_url);
t->remove_web_seed(m_url, web_seed_entry::url_seed);
disconnect("no content-length in HTTP response", 2);
return;
}
@ -684,7 +684,6 @@ namespace libtorrent
return m_server_string.empty();
}
// throws exception when the client should be disconnected
void web_peer_connection::on_sent(error_code const& error
, std::size_t bytes_transferred)
{