forked from premiere/premiere-libtorrent
factor out parse_tracker_response and add unit tests. make gen_todo cover tests also, and regenerate todo.html
This commit is contained in:
parent
1c915f2e95
commit
2d438e0758
|
@ -1,7 +1,7 @@
|
||||||
import glob
|
import glob
|
||||||
import os
|
import os
|
||||||
|
|
||||||
paths = ['src/*.cpp', 'src/kademlia/*.cpp', 'include/libtorrent/*.hpp', 'include/libtorrent/kademlia/*.hpp', 'include/libtorrent/aux_/*.hpp', 'include/libtorrent/extensions/*.hpp']
|
paths = ['test/*.cpp', 'src/*.cpp', 'src/kademlia/*.cpp', 'include/libtorrent/*.hpp', 'include/libtorrent/kademlia/*.hpp', 'include/libtorrent/aux_/*.hpp', 'include/libtorrent/extensions/*.hpp']
|
||||||
|
|
||||||
os.system('(cd .. ; ctags %s 2>/dev/null)' % ' '.join(paths))
|
os.system('(cd .. ; ctags %s 2>/dev/null)' % ' '.join(paths))
|
||||||
|
|
||||||
|
|
1626
docs/todo.html
1626
docs/todo.html
File diff suppressed because one or more lines are too long
|
@ -95,9 +95,6 @@ namespace libtorrent
|
||||||
|
|
||||||
virtual void on_timeout(error_code const&) {}
|
virtual void on_timeout(error_code const&) {}
|
||||||
|
|
||||||
void parse(int status_code, lazy_entry const& e);
|
|
||||||
bool extract_peer_info(lazy_entry const& e, peer_entry& ret);
|
|
||||||
|
|
||||||
tracker_manager& m_man;
|
tracker_manager& m_man;
|
||||||
boost::shared_ptr<http_connection> m_tracker_connection;
|
boost::shared_ptr<http_connection> m_tracker_connection;
|
||||||
aux::session_impl& m_ses;
|
aux::session_impl& m_ses;
|
||||||
|
@ -109,6 +106,9 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
TORRENT_EXTRA_EXPORT tracker_response parse_tracker_response(
|
||||||
|
char const* data, int size, error_code& ec
|
||||||
|
, bool scrape_request, sha1_hash scrape_ih);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // TORRENT_HTTP_TRACKER_CONNECTION_HPP_INCLUDED
|
#endif // TORRENT_HTTP_TRACKER_CONNECTION_HPP_INCLUDED
|
||||||
|
|
|
@ -237,7 +237,8 @@ namespace libtorrent
|
||||||
// if this is a dictionary, look for a key ``name`` whose value
|
// if this is a dictionary, look for a key ``name`` whose value
|
||||||
// is an int. If such key exist, return a pointer to its value,
|
// is an int. If such key exist, return a pointer to its value,
|
||||||
// otherwise NULL.
|
// otherwise NULL.
|
||||||
boost::int64_t dict_find_int_value(char const* name, boost::int64_t default_val = 0) const;
|
boost::int64_t dict_find_int_value(char const* name
|
||||||
|
, boost::int64_t default_val = 0) const;
|
||||||
lazy_entry const* dict_find_int(char const* name) const;
|
lazy_entry const* dict_find_int(char const* name) const;
|
||||||
|
|
||||||
// these functions require that ``this`` is a dictionary.
|
// these functions require that ``this`` is a dictionary.
|
||||||
|
|
|
@ -150,20 +150,48 @@ namespace libtorrent
|
||||||
, min_interval(120)
|
, min_interval(120)
|
||||||
, complete(-1)
|
, complete(-1)
|
||||||
, incomplete(-1)
|
, incomplete(-1)
|
||||||
|
, downloaders(-1)
|
||||||
, downloaded(-1)
|
, downloaded(-1)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
// peers from the tracker, in various forms
|
||||||
std::vector<peer_entry> peers;
|
std::vector<peer_entry> peers;
|
||||||
std::vector<ipv4_peer_entry> peers4;
|
std::vector<ipv4_peer_entry> peers4;
|
||||||
#if TORRENT_USE_IPV6
|
#if TORRENT_USE_IPV6
|
||||||
std::vector<ipv6_peer_entry> peers6;
|
std::vector<ipv6_peer_entry> peers6;
|
||||||
#endif
|
#endif
|
||||||
|
// our external IP address (if the tracker responded with ti, otherwise
|
||||||
|
// INADDR_ANY)
|
||||||
address external_ip;
|
address external_ip;
|
||||||
|
|
||||||
|
// the tracker id, if it was included in the response, otherwise
|
||||||
|
// an empty string
|
||||||
std::string trackerid;
|
std::string trackerid;
|
||||||
|
|
||||||
|
// if the tracker returned an error, this is set to that error
|
||||||
|
std::string failure_reason;
|
||||||
|
|
||||||
|
// contains a warning message from the tracker, if included in
|
||||||
|
// the response
|
||||||
|
std::string warning_message;
|
||||||
|
|
||||||
|
// re-announce interval, in seconds
|
||||||
int interval;
|
int interval;
|
||||||
|
|
||||||
|
// the lowest force-announce interval
|
||||||
int min_interval;
|
int min_interval;
|
||||||
|
|
||||||
|
// the number of seeds in the swarm
|
||||||
int complete;
|
int complete;
|
||||||
|
|
||||||
|
// the number of downloaders in the swarm
|
||||||
int incomplete;
|
int incomplete;
|
||||||
|
|
||||||
|
// if supported by the tracker, the number of actively downloading peers.
|
||||||
|
// i.e. partial seeds. If not suppored, -1
|
||||||
|
int downloaders;
|
||||||
|
|
||||||
|
// the number of times the torrent has been downloaded
|
||||||
int downloaded;
|
int downloaded;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -328,27 +328,70 @@ namespace libtorrent
|
||||||
received_bytes(size + parser.body_start());
|
received_bytes(size + parser.body_start());
|
||||||
|
|
||||||
// handle tracker response
|
// handle tracker response
|
||||||
lazy_entry e;
|
|
||||||
error_code ecode;
|
error_code ecode;
|
||||||
int res = lazy_bdecode(data, data + size, e, ecode);
|
|
||||||
|
|
||||||
if (res == 0 && e.type() == lazy_entry::dict_t)
|
boost::shared_ptr<request_callback> cb = requester();
|
||||||
|
if (!cb)
|
||||||
{
|
{
|
||||||
parse(parser.status_code(), e);
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
tracker_response resp = parse_tracker_response(data, size, ecode
|
||||||
|
, tracker_req().kind == tracker_request::scrape_request
|
||||||
|
, tracker_req().info_hash);
|
||||||
|
|
||||||
|
if (!resp.warning_message.empty())
|
||||||
|
cb->tracker_warning(tracker_req(), resp.warning_message);
|
||||||
|
|
||||||
|
if (ecode)
|
||||||
|
{
|
||||||
|
fail(ecode, parser.status_code());
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!resp.failure_reason.empty())
|
||||||
|
{
|
||||||
|
fail(error_code(errors::tracker_failure), parser.status_code()
|
||||||
|
, resp.failure_reason.c_str(), resp.interval, resp.min_interval);
|
||||||
|
close();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// do slightly different things for scrape requests
|
||||||
|
if (tracker_req().kind == tracker_request::scrape_request)
|
||||||
|
{
|
||||||
|
cb->tracker_scrape_response(tracker_req(), resp.complete
|
||||||
|
, resp.incomplete, resp.downloaded, resp.downloaders);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fail(ecode, parser.status_code());
|
std::list<address> ip_list;
|
||||||
|
if (m_tracker_connection)
|
||||||
|
{
|
||||||
|
error_code ec;
|
||||||
|
ip_list.push_back(
|
||||||
|
m_tracker_connection->socket().remote_endpoint(ec).address());
|
||||||
|
std::vector<tcp::endpoint> const& epts = m_tracker_connection->endpoints();
|
||||||
|
for (std::vector<tcp::endpoint>::const_iterator i = epts.begin()
|
||||||
|
, end(epts.end()); i != end; ++i)
|
||||||
|
{
|
||||||
|
ip_list.push_back(i->address());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cb->tracker_response(tracker_req(), m_tracker_ip, ip_list, resp);
|
||||||
}
|
}
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool http_tracker_connection::extract_peer_info(lazy_entry const& info, peer_entry& ret)
|
bool extract_peer_info(lazy_entry const& info, peer_entry& ret, error_code& ec)
|
||||||
{
|
{
|
||||||
// extract peer id (if any)
|
// extract peer id (if any)
|
||||||
if (info.type() != lazy_entry::dict_t)
|
if (info.type() != lazy_entry::dict_t)
|
||||||
{
|
{
|
||||||
fail(error_code(errors::invalid_peer_dict));
|
ec.assign(errors::invalid_peer_dict, get_libtorrent_category());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
lazy_entry const* i = info.dict_find_string("peer id");
|
lazy_entry const* i = info.dict_find_string("peer id");
|
||||||
|
@ -366,7 +409,7 @@ namespace libtorrent
|
||||||
i = info.dict_find_string("ip");
|
i = info.dict_find_string("ip");
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
{
|
{
|
||||||
fail(error_code(errors::invalid_tracker_response));
|
ec.assign(errors::invalid_tracker_response, get_libtorrent_category());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ret.hostname = i->string_value();
|
ret.hostname = i->string_value();
|
||||||
|
@ -375,7 +418,7 @@ namespace libtorrent
|
||||||
i = info.dict_find_int("port");
|
i = info.dict_find_int("port");
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
{
|
{
|
||||||
fail(error_code(errors::invalid_tracker_response));
|
ec.assign(errors::invalid_tracker_response, get_libtorrent_category());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ret.port = (unsigned short)i->int_value();
|
ret.port = (unsigned short)i->int_value();
|
||||||
|
@ -383,18 +426,27 @@ namespace libtorrent
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: 2 make this a free function that can be easily unit tested
|
tracker_response parse_tracker_response(char const* data, int size, error_code& ec
|
||||||
void http_tracker_connection::parse(int status_code, lazy_entry const& e)
|
, bool scrape_request, sha1_hash scrape_ih)
|
||||||
{
|
{
|
||||||
boost::shared_ptr<request_callback> cb = requester();
|
tracker_response resp;
|
||||||
if (!cb) return;
|
|
||||||
|
lazy_entry e;
|
||||||
|
int res = lazy_bdecode(data, data + size, e, ec);
|
||||||
|
|
||||||
|
if (ec) return resp;
|
||||||
|
|
||||||
|
if (res != 0 || e.type() != lazy_entry::dict_t)
|
||||||
|
{
|
||||||
|
ec.assign(errors::invalid_tracker_response, get_libtorrent_category());
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
|
|
||||||
int interval = int(e.dict_find_int_value("interval", 0));
|
int interval = int(e.dict_find_int_value("interval", 0));
|
||||||
// if no interval is specified, default to 30 minutes
|
// if no interval is specified, default to 30 minutes
|
||||||
if (interval == 0) interval = 1800;
|
if (interval == 0) interval = 1800;
|
||||||
int min_interval = int(e.dict_find_int_value("min interval", 30));
|
int min_interval = int(e.dict_find_int_value("min interval", 30));
|
||||||
|
|
||||||
tracker_response resp;
|
|
||||||
resp.interval = interval;
|
resp.interval = interval;
|
||||||
resp.min_interval = min_interval;
|
resp.min_interval = min_interval;
|
||||||
|
|
||||||
|
@ -406,44 +458,48 @@ namespace libtorrent
|
||||||
lazy_entry const* failure = e.dict_find_string("failure reason");
|
lazy_entry const* failure = e.dict_find_string("failure reason");
|
||||||
if (failure)
|
if (failure)
|
||||||
{
|
{
|
||||||
fail(error_code(errors::tracker_failure), status_code
|
resp.failure_reason = failure->string_value();
|
||||||
, failure->string_value().c_str(), interval, min_interval);
|
ec.assign(errors::tracker_failure, get_libtorrent_category());
|
||||||
return;
|
return resp;
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_entry const* warning = e.dict_find_string("warning message");
|
lazy_entry const* warning = e.dict_find_string("warning message");
|
||||||
if (warning)
|
if (warning)
|
||||||
cb->tracker_warning(tracker_req(), warning->string_value());
|
resp.warning_message = warning->string_value();
|
||||||
|
|
||||||
if (tracker_req().kind == tracker_request::scrape_request)
|
if (scrape_request)
|
||||||
{
|
{
|
||||||
std::string ih = tracker_req().info_hash.to_string();
|
|
||||||
|
|
||||||
lazy_entry const* files = e.dict_find_dict("files");
|
lazy_entry const* files = e.dict_find_dict("files");
|
||||||
if (files == 0)
|
if (files == 0)
|
||||||
{
|
{
|
||||||
fail(error_code(errors::invalid_files_entry), -1, ""
|
ec.assign(errors::invalid_files_entry, get_libtorrent_category());
|
||||||
, interval, min_interval);
|
return resp;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_entry const* scrape_data = files->dict_find_dict(ih.c_str());
|
// TODO: 4 this is a bug. if the info-hash contains a 0, this will
|
||||||
|
// fail!
|
||||||
|
lazy_entry const* scrape_data = files->dict_find_dict(
|
||||||
|
scrape_ih.to_string().c_str());
|
||||||
|
|
||||||
if (scrape_data == 0)
|
if (scrape_data == 0)
|
||||||
{
|
{
|
||||||
fail(error_code(errors::invalid_hash_entry), -1, ""
|
ec.assign(errors::invalid_hash_entry, get_libtorrent_category());
|
||||||
, interval, min_interval);
|
return resp;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int complete = int(scrape_data->dict_find_int_value("complete", -1));
|
resp.complete = int(scrape_data->dict_find_int_value("complete", -1));
|
||||||
int incomplete = int(scrape_data->dict_find_int_value("incomplete", -1));
|
resp.incomplete = int(scrape_data->dict_find_int_value("incomplete", -1));
|
||||||
int downloaded = int(scrape_data->dict_find_int_value("downloaded", -1));
|
resp.downloaded = int(scrape_data->dict_find_int_value("downloaded", -1));
|
||||||
int downloaders = int(scrape_data->dict_find_int_value("downloaders", -1));
|
resp.downloaders = int(scrape_data->dict_find_int_value("downloaders", -1));
|
||||||
cb->tracker_scrape_response(tracker_req(), complete
|
|
||||||
, incomplete, downloaded, downloaders);
|
return resp;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// look for optional scrape info
|
||||||
|
resp.complete = int(e.dict_find_int_value("complete", -1));
|
||||||
|
resp.incomplete = int(e.dict_find_int_value("incomplete", -1));
|
||||||
|
resp.downloaded = int(e.dict_find_int_value("downloaded", -1));
|
||||||
|
|
||||||
lazy_entry const* peers_ent = e.dict_find("peers");
|
lazy_entry const* peers_ent = e.dict_find("peers");
|
||||||
if (peers_ent && peers_ent->type() == lazy_entry::string_t)
|
if (peers_ent && peers_ent->type() == lazy_entry::string_t)
|
||||||
{
|
{
|
||||||
|
@ -465,12 +521,21 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
int len = peers_ent->list_size();
|
int len = peers_ent->list_size();
|
||||||
resp.peers.reserve(len);
|
resp.peers.reserve(len);
|
||||||
|
error_code parse_error;
|
||||||
for (int i = 0; i < len; ++i)
|
for (int i = 0; i < len; ++i)
|
||||||
{
|
{
|
||||||
peer_entry p;
|
peer_entry p;
|
||||||
if (!extract_peer_info(*peers_ent->list_at(i), p)) return;
|
if (!extract_peer_info(*peers_ent->list_at(i), p, parse_error))
|
||||||
|
continue;
|
||||||
resp.peers.push_back(p);
|
resp.peers.push_back(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// only report an error if all peer entries are invalid
|
||||||
|
if (resp.peers.empty() && parse_error)
|
||||||
|
{
|
||||||
|
ec = parse_error;
|
||||||
|
return resp;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -501,16 +566,15 @@ namespace libtorrent
|
||||||
#else
|
#else
|
||||||
lazy_entry const* ipv6_peers = 0;
|
lazy_entry const* ipv6_peers = 0;
|
||||||
#endif
|
#endif
|
||||||
|
/*
|
||||||
// if we didn't receive any peers. We don't care if we're stopping anyway
|
// if we didn't receive any peers. We don't care if we're stopping anyway
|
||||||
if (peers_ent == 0 && ipv6_peers == 0
|
if (peers_ent == 0 && ipv6_peers == 0
|
||||||
&& tracker_req().event != tracker_request::stopped)
|
&& tracker_req().event != tracker_request::stopped)
|
||||||
{
|
{
|
||||||
fail(error_code(errors::invalid_peers_entry), -1, ""
|
ec.assign(errors::invalid_peers_entry, get_libtorrent_category());
|
||||||
, interval, min_interval);
|
return resp;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
lazy_entry const* ip_ent = e.dict_find_string("external ip");
|
lazy_entry const* ip_ent = e.dict_find_string("external ip");
|
||||||
if (ip_ent)
|
if (ip_ent)
|
||||||
{
|
{
|
||||||
|
@ -523,26 +587,7 @@ namespace libtorrent
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// look for optional scrape info
|
return resp;
|
||||||
resp.complete = int(e.dict_find_int_value("complete", -1));
|
|
||||||
resp.incomplete = int(e.dict_find_int_value("incomplete", -1));
|
|
||||||
resp.downloaded = int(e.dict_find_int_value("downloaded", -1));
|
|
||||||
|
|
||||||
std::list<address> ip_list;
|
|
||||||
if (m_tracker_connection)
|
|
||||||
{
|
|
||||||
error_code ec;
|
|
||||||
ip_list.push_back(m_tracker_connection->socket().remote_endpoint(ec).address());
|
|
||||||
std::vector<tcp::endpoint> const& epts = m_tracker_connection->endpoints();
|
|
||||||
for (std::vector<tcp::endpoint>::const_iterator i = epts.begin()
|
|
||||||
, end(epts.end()); i != end; ++i)
|
|
||||||
{
|
|
||||||
ip_list.push_back(i->address());
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
cb->tracker_response(tracker_req(), m_tracker_ip, ip_list, resp);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,14 +36,176 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#include "libtorrent/alert.hpp"
|
#include "libtorrent/alert.hpp"
|
||||||
#include "libtorrent/session.hpp"
|
#include "libtorrent/session.hpp"
|
||||||
#include "libtorrent/error_code.hpp"
|
#include "libtorrent/error_code.hpp"
|
||||||
|
#include "libtorrent/tracker_manager.hpp"
|
||||||
|
#include "libtorrent/http_tracker_connection.hpp" // for parse_tracker_response
|
||||||
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
namespace lt = libtorrent;
|
namespace lt = libtorrent;
|
||||||
|
|
||||||
|
void test_parse_hostname_peers()
|
||||||
|
{
|
||||||
|
char const response[] = "d5:peersld7:peer id20:aaaaaaaaaaaaaaaaaaaa2:ip13:test_hostname4:porti1000eed7:peer id20:bbbbabaababababababa2:ip12:another_host4:porti1001eeee";
|
||||||
|
error_code ec;
|
||||||
|
tracker_response resp = parse_tracker_response(response, sizeof(response) - 1
|
||||||
|
, ec, false, sha1_hash());
|
||||||
|
|
||||||
|
TEST_EQUAL(ec, error_code());
|
||||||
|
TEST_EQUAL(resp.peers.size(), 2);
|
||||||
|
if (resp.peers.size() == 2)
|
||||||
|
{
|
||||||
|
peer_entry const& e0 = resp.peers[0];
|
||||||
|
peer_entry const& e1 = resp.peers[1];
|
||||||
|
TEST_EQUAL(e0.hostname, "test_hostname");
|
||||||
|
TEST_EQUAL(e0.port, 1000);
|
||||||
|
TEST_EQUAL(e0.pid, peer_id("aaaaaaaaaaaaaaaaaaaa"));
|
||||||
|
|
||||||
|
TEST_EQUAL(e1.hostname, "another_host");
|
||||||
|
TEST_EQUAL(e1.port, 1001);
|
||||||
|
TEST_EQUAL(e1.pid, peer_id("bbbbabaababababababa"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_parse_peers4()
|
||||||
|
{
|
||||||
|
char const response[] = "d5:peers12:\x01\x02\x03\x04\x30\x10"
|
||||||
|
"\x09\x08\x07\x06\x20\x10" "e";
|
||||||
|
error_code ec;
|
||||||
|
tracker_response resp = parse_tracker_response(response, sizeof(response) - 1
|
||||||
|
, ec, false, sha1_hash());
|
||||||
|
|
||||||
|
TEST_EQUAL(ec, error_code());
|
||||||
|
TEST_EQUAL(resp.peers4.size(), 2);
|
||||||
|
if (resp.peers.size() == 2)
|
||||||
|
{
|
||||||
|
ipv4_peer_entry const& e0 = resp.peers4[0];
|
||||||
|
ipv4_peer_entry const& e1 = resp.peers4[1];
|
||||||
|
TEST_CHECK(e0.ip == address_v4::from_string("1.2.3.4").to_bytes());
|
||||||
|
TEST_EQUAL(e0.port, 0x3010);
|
||||||
|
|
||||||
|
TEST_CHECK(e1.ip == address_v4::from_string("9.8.7.6").to_bytes());
|
||||||
|
TEST_EQUAL(e1.port, 0x2010);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_parse_interval()
|
||||||
|
{
|
||||||
|
char const response[] = "d8:intervali1042e12:min intervali10e5:peers0:e";
|
||||||
|
error_code ec;
|
||||||
|
tracker_response resp = parse_tracker_response(response, sizeof(response) - 1
|
||||||
|
, ec, false, sha1_hash());
|
||||||
|
|
||||||
|
TEST_EQUAL(ec, error_code());
|
||||||
|
TEST_EQUAL(resp.peers.size(), 0);
|
||||||
|
TEST_EQUAL(resp.peers4.size(), 0);
|
||||||
|
TEST_EQUAL(resp.interval, 1042);
|
||||||
|
TEST_EQUAL(resp.min_interval, 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_parse_warning()
|
||||||
|
{
|
||||||
|
char const response[] = "d5:peers0:15:warning message12:test messagee";
|
||||||
|
error_code ec;
|
||||||
|
tracker_response resp = parse_tracker_response(response, sizeof(response) - 1
|
||||||
|
, ec, false, sha1_hash());
|
||||||
|
|
||||||
|
TEST_EQUAL(ec, error_code());
|
||||||
|
TEST_EQUAL(resp.peers.size(), 0);
|
||||||
|
TEST_EQUAL(resp.warning_message, "test message");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_parse_failure_reason()
|
||||||
|
{
|
||||||
|
char const response[] = "d5:peers0:14:failure reason12:test messagee";
|
||||||
|
error_code ec;
|
||||||
|
tracker_response resp = parse_tracker_response(response, sizeof(response) - 1
|
||||||
|
, ec, false, sha1_hash());
|
||||||
|
|
||||||
|
TEST_EQUAL(ec, error_code(errors::tracker_failure));
|
||||||
|
TEST_EQUAL(resp.peers.size(), 0);
|
||||||
|
TEST_EQUAL(resp.failure_reason, "test message");
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_parse_scrape_response()
|
||||||
|
{
|
||||||
|
char const response[] = "d5:filesd20:aaaaaaaaaaaaaaaaaaaad8:completei1e10:incompletei2e10:downloadedi3e11:downloadersi6eeee";
|
||||||
|
error_code ec;
|
||||||
|
tracker_response resp = parse_tracker_response(response, sizeof(response) - 1
|
||||||
|
, ec, true, sha1_hash("aaaaaaaaaaaaaaaaaaaa"));
|
||||||
|
|
||||||
|
TEST_EQUAL(ec, error_code());
|
||||||
|
TEST_EQUAL(resp.complete, 1);
|
||||||
|
TEST_EQUAL(resp.incomplete, 2);
|
||||||
|
TEST_EQUAL(resp.downloaded, 3);
|
||||||
|
TEST_EQUAL(resp.downloaders, 6);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_parse_scrape_response_with_zero()
|
||||||
|
{
|
||||||
|
char const response[] = "d5:filesd20:aaa\0aaaaaaaaaaaaaaaad8:completei4e10:incompletei5e10:downloadedi6eeee";
|
||||||
|
error_code ec;
|
||||||
|
tracker_response resp = parse_tracker_response(response, sizeof(response) - 1
|
||||||
|
, ec, true, sha1_hash("aaa\0aaaaaaaaaaaaaaaa"));
|
||||||
|
|
||||||
|
TEST_EQUAL(ec, error_code());
|
||||||
|
TEST_EQUAL(resp.complete, 1);
|
||||||
|
TEST_EQUAL(resp.incomplete, 2);
|
||||||
|
TEST_EQUAL(resp.downloaded, 3);
|
||||||
|
TEST_EQUAL(resp.downloaders, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_parse_external_ip()
|
||||||
|
{
|
||||||
|
char const response[] = "d5:peers0:11:external ip4:\x01\x02\x03\x04" "e";
|
||||||
|
error_code ec;
|
||||||
|
tracker_response resp = parse_tracker_response(response, sizeof(response) - 1
|
||||||
|
, ec, false, sha1_hash());
|
||||||
|
|
||||||
|
TEST_EQUAL(ec, error_code());
|
||||||
|
TEST_EQUAL(resp.peers.size(), 0);
|
||||||
|
TEST_EQUAL(resp.external_ip, address_v4::from_string("1.2.3.4"));
|
||||||
|
}
|
||||||
|
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
void test_parse_external_ip6()
|
||||||
|
{
|
||||||
|
char const response[] = "d5:peers0:11:external ip16:\xf1\x02\x03\x04\0\0\0\0\0\0\0\0\0\0\xff\xff" "e";
|
||||||
|
error_code ec;
|
||||||
|
tracker_response resp = parse_tracker_response(response, sizeof(response) - 1
|
||||||
|
, ec, false, sha1_hash());
|
||||||
|
|
||||||
|
TEST_EQUAL(ec, error_code());
|
||||||
|
TEST_EQUAL(resp.peers.size(), 0);
|
||||||
|
TEST_EQUAL(resp.external_ip, address_v6::from_string("f102:0304::ffff"));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
int test_main()
|
int test_main()
|
||||||
{
|
{
|
||||||
|
test_parse_hostname_peers();
|
||||||
|
test_parse_peers4();
|
||||||
|
test_parse_interval();
|
||||||
|
test_parse_warning();
|
||||||
|
test_parse_failure_reason();
|
||||||
|
test_parse_scrape_response();
|
||||||
|
test_parse_scrape_response_with_zero();
|
||||||
|
test_parse_external_ip();
|
||||||
|
#if TORRENT_USE_IPV6
|
||||||
|
test_parse_external_ip6();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// TODO: test parse peers6
|
||||||
|
// TODO: test parse tracker-id
|
||||||
|
// TODO: test parse failure-reason
|
||||||
|
// TODO: test all failure paths
|
||||||
|
// invalid bencoding
|
||||||
|
// not a dictionary
|
||||||
|
// no files entry in scrape response
|
||||||
|
// no info-hash entry in scrape response
|
||||||
|
// malformed peers in peer list of dictionaries
|
||||||
|
// uneven number of bytes in peers and peers6 string responses
|
||||||
|
|
||||||
int http_port = start_web_server();
|
int http_port = start_web_server();
|
||||||
int udp_port = start_udp_tracker();
|
int udp_port = start_udp_tracker();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue