forked from premiere/premiere-libtorrent
made udp and http tracker connections build without exception support
This commit is contained in:
parent
010d5631a4
commit
07d1fe84c3
|
@ -157,7 +157,7 @@ namespace libtorrent
|
|||
virtual void on_timeout();
|
||||
|
||||
void parse(const entry& e);
|
||||
peer_entry extract_peer_info(const entry& e);
|
||||
bool extract_peer_info(const entry& e, peer_entry& ret);
|
||||
|
||||
tracker_manager& m_man;
|
||||
http_parser m_parser;
|
||||
|
|
|
@ -203,11 +203,7 @@ namespace libtorrent
|
|||
|
||||
if (name == "content-length")
|
||||
{
|
||||
try
|
||||
{
|
||||
m_content_length = boost::lexical_cast<int>(value);
|
||||
}
|
||||
catch(boost::bad_lexical_cast&) {}
|
||||
m_content_length = atoi(value.c_str());
|
||||
}
|
||||
else if (name == "content-range")
|
||||
{
|
||||
|
@ -505,7 +501,8 @@ namespace libtorrent
|
|||
void http_tracker_connection::on_timeout()
|
||||
{
|
||||
m_timed_out = true;
|
||||
m_socket.close();
|
||||
asio::error_code ec;
|
||||
m_socket.close(ec);
|
||||
m_name_lookup.cancel();
|
||||
if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
|
||||
m_connection_ticket = -1;
|
||||
|
@ -530,7 +527,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
void http_tracker_connection::name_lookup(asio::error_code const& error
|
||||
, tcp::resolver::iterator i) try
|
||||
, tcp::resolver::iterator i)
|
||||
{
|
||||
boost::shared_ptr<request_callback> cb = requester();
|
||||
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING)
|
||||
|
@ -588,16 +585,23 @@ namespace libtorrent
|
|||
m_socket.get<http_stream>().set_no_connect(true);
|
||||
}
|
||||
|
||||
m_socket.open(target_address.protocol());
|
||||
m_socket.bind(tcp::endpoint(bind_interface(), 0));
|
||||
asio::error_code ec;
|
||||
m_socket.open(target_address.protocol(), ec);
|
||||
if (ec)
|
||||
{
|
||||
fail(-1, ec.message().c_str());
|
||||
return;
|
||||
}
|
||||
m_socket.bind(tcp::endpoint(bind_interface(), 0), ec);
|
||||
if (ec)
|
||||
{
|
||||
fail(-1, ec.message().c_str());
|
||||
return;
|
||||
}
|
||||
m_cc.enqueue(bind(&http_tracker_connection::connect, self(), _1, target_address)
|
||||
, bind(&http_tracker_connection::on_timeout, self())
|
||||
, seconds(m_settings.tracker_receive_timeout));
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
fail(-1, e.what());
|
||||
};
|
||||
|
||||
void http_tracker_connection::connect(int ticket, tcp::endpoint target_address)
|
||||
{
|
||||
|
@ -605,7 +609,7 @@ namespace libtorrent
|
|||
m_socket.async_connect(target_address, bind(&http_tracker_connection::connected, self(), _1));
|
||||
}
|
||||
|
||||
void http_tracker_connection::connected(asio::error_code const& error) try
|
||||
void http_tracker_connection::connected(asio::error_code const& error)
|
||||
{
|
||||
if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
|
||||
m_connection_ticket = -1;
|
||||
|
@ -627,12 +631,8 @@ namespace libtorrent
|
|||
, m_send_buffer.size()), bind(&http_tracker_connection::sent
|
||||
, self(), _1));
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
fail(-1, e.what());
|
||||
}
|
||||
|
||||
void http_tracker_connection::sent(asio::error_code const& error) try
|
||||
void http_tracker_connection::sent(asio::error_code const& error)
|
||||
{
|
||||
if (error == asio::error::operation_aborted) return;
|
||||
if (m_timed_out) return;
|
||||
|
@ -652,14 +652,9 @@ namespace libtorrent
|
|||
, m_buffer.size() - m_recv_pos), bind(&http_tracker_connection::receive
|
||||
, self(), _1, _2));
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
fail(-1, e.what());
|
||||
}; // msvc 7.1 seems to require this semi-colon
|
||||
|
||||
|
||||
void http_tracker_connection::receive(asio::error_code const& error
|
||||
, std::size_t bytes_transferred) try
|
||||
, std::size_t bytes_transferred)
|
||||
{
|
||||
if (error == asio::error::operation_aborted) return;
|
||||
if (m_timed_out) return;
|
||||
|
@ -738,10 +733,6 @@ namespace libtorrent
|
|||
, m_buffer.size() - m_recv_pos), bind(&http_tracker_connection::receive
|
||||
, self(), _1, _2));
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
fail(-1, e.what());
|
||||
};
|
||||
|
||||
void http_tracker_connection::on_response()
|
||||
{
|
||||
|
@ -828,15 +819,15 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
// handle tracker response
|
||||
try
|
||||
entry e = bdecode(buf.begin, buf.end);
|
||||
|
||||
if (e.type() != entry::undefined_t)
|
||||
{
|
||||
entry e = bdecode(buf.begin, buf.end);
|
||||
parse(e);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
else
|
||||
{
|
||||
std::string error_str(e.what());
|
||||
error_str += ": \"";
|
||||
std::string error_str("invalid bencoding of tracker response: \"");
|
||||
for (char const* i = buf.begin, *end(buf.end); i != end; ++i)
|
||||
{
|
||||
if (std::isprint(*i)) error_str += *i;
|
||||
|
@ -845,25 +836,25 @@ namespace libtorrent
|
|||
error_str += "\"";
|
||||
fail(m_parser.status_code(), error_str.c_str());
|
||||
}
|
||||
#ifndef NDEBUG
|
||||
catch (...)
|
||||
{
|
||||
TORRENT_ASSERT(false);
|
||||
}
|
||||
#endif
|
||||
close();
|
||||
}
|
||||
|
||||
peer_entry http_tracker_connection::extract_peer_info(const entry& info)
|
||||
bool http_tracker_connection::extract_peer_info(const entry& info, peer_entry& ret)
|
||||
{
|
||||
peer_entry ret;
|
||||
|
||||
// extract peer id (if any)
|
||||
if (info.type() != entry::dictionary_t)
|
||||
{
|
||||
fail(-1, "invalid response from tracker (invalid peer entry)");
|
||||
return false;
|
||||
}
|
||||
entry const* i = info.find_key("peer id");
|
||||
if (i != 0)
|
||||
{
|
||||
if (i->string().length() != 20)
|
||||
throw std::runtime_error("invalid response from tracker");
|
||||
if (i->type() != entry::string_t || i->string().length() != 20)
|
||||
{
|
||||
fail(-1, "invalid response from tracker (invalid peer id)");
|
||||
return false;
|
||||
}
|
||||
std::copy(i->string().begin(), i->string().end(), ret.pid.begin());
|
||||
}
|
||||
else
|
||||
|
@ -874,15 +865,23 @@ namespace libtorrent
|
|||
|
||||
// extract ip
|
||||
i = info.find_key("ip");
|
||||
if (i == 0) throw std::runtime_error("invalid response from tracker");
|
||||
if (i == 0 || i->type() != entry::string_t)
|
||||
{
|
||||
fail(-1, "invalid response from tracker");
|
||||
return false;
|
||||
}
|
||||
ret.ip = i->string();
|
||||
|
||||
// extract port
|
||||
i = info.find_key("port");
|
||||
if (i == 0) throw std::runtime_error("invalid response from tracker");
|
||||
if (i == 0 || i->type() != entry::int_t)
|
||||
{
|
||||
fail(-1, "invalid response from tracker");
|
||||
return false;
|
||||
}
|
||||
ret.port = (unsigned short)i->integer();
|
||||
|
||||
return ret;
|
||||
return true;
|
||||
}
|
||||
|
||||
void http_tracker_connection::parse(entry const& e)
|
||||
|
@ -890,118 +889,133 @@ namespace libtorrent
|
|||
boost::shared_ptr<request_callback> cb = requester();
|
||||
if (!cb) return;
|
||||
|
||||
try
|
||||
// parse the response
|
||||
entry const* failure = e.find_key("failure reason");
|
||||
if (failure && failure->type() == entry::string_t)
|
||||
{
|
||||
// parse the response
|
||||
try
|
||||
fail(m_parser.status_code(), failure->string().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
entry const* warning = e.find_key("warning message");
|
||||
if (warning && warning->type() == entry::string_t)
|
||||
{
|
||||
cb->tracker_warning(warning->string());
|
||||
}
|
||||
|
||||
std::vector<peer_entry> peer_list;
|
||||
|
||||
if (tracker_req().kind == tracker_request::scrape_request)
|
||||
{
|
||||
std::string ih;
|
||||
std::copy(tracker_req().info_hash.begin(), tracker_req().info_hash.end()
|
||||
, std::back_inserter(ih));
|
||||
|
||||
entry const* files = e.find_key("files");
|
||||
if (files == 0 || files->type() != entry::dictionary_t)
|
||||
{
|
||||
entry const& failure = e["failure reason"];
|
||||
|
||||
fail(m_parser.status_code(), failure.string().c_str());
|
||||
return;
|
||||
}
|
||||
catch (type_error const&) {}
|
||||
|
||||
try
|
||||
{
|
||||
entry const& warning = e["warning message"];
|
||||
cb->tracker_warning(warning.string());
|
||||
}
|
||||
catch(type_error const&) {}
|
||||
|
||||
if (tracker_req().kind == tracker_request::scrape_request)
|
||||
{
|
||||
std::string ih;
|
||||
std::copy(tracker_req().info_hash.begin(), tracker_req().info_hash.end()
|
||||
, std::back_inserter(ih));
|
||||
entry scrape_data = e["files"][ih];
|
||||
|
||||
int complete = -1;
|
||||
int incomplete = -1;
|
||||
int downloaded = -1;
|
||||
|
||||
entry const* complete_ent = scrape_data.find_key("complete");
|
||||
if (complete_ent && complete_ent->type() == entry::int_t)
|
||||
complete = complete_ent->integer();
|
||||
|
||||
entry const* incomplete_ent = scrape_data.find_key("incomplete");
|
||||
if (incomplete_ent && incomplete_ent->type() == entry::int_t)
|
||||
incomplete = incomplete_ent->integer();
|
||||
|
||||
entry const* downloaded_ent = scrape_data.find_key("downloaded");
|
||||
if (downloaded_ent && downloaded_ent->type() == entry::int_t)
|
||||
downloaded = downloaded_ent->integer();
|
||||
|
||||
cb->tracker_scrape_response(tracker_req(), complete
|
||||
, incomplete, downloaded);
|
||||
fail(-1, "invalid or missing 'files' entry in scrape response");
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<peer_entry> peer_list;
|
||||
int interval = (int)e["interval"].integer();
|
||||
|
||||
if (e["peers"].type() == entry::string_t)
|
||||
entry const* scrape_data = e.find_key(ih.c_str());
|
||||
if (scrape_data == 0 || scrape_data->type() != entry::dictionary_t)
|
||||
{
|
||||
std::string const& peers = e["peers"].string();
|
||||
for (std::string::const_iterator i = peers.begin();
|
||||
i != peers.end();)
|
||||
{
|
||||
if (std::distance(i, peers.end()) < 6) break;
|
||||
|
||||
peer_entry p;
|
||||
p.pid.clear();
|
||||
p.ip = detail::read_v4_address(i).to_string();
|
||||
p.port = detail::read_uint16(i);
|
||||
peer_list.push_back(p);
|
||||
}
|
||||
fail(-1, "missing or invalid info-hash entry in scrape response");
|
||||
return;
|
||||
}
|
||||
else
|
||||
entry const* complete = scrape_data->find_key("complete");
|
||||
entry const* incomplete = scrape_data->find_key("incomplete");
|
||||
entry const* downloaded = scrape_data->find_key("downloaded");
|
||||
if (complete == 0 || incomplete == 0 || downloaded == 0
|
||||
|| complete->type() != entry::int_t
|
||||
|| incomplete->type() != entry::int_t
|
||||
|| downloaded->type() != entry::int_t)
|
||||
{
|
||||
entry::list_type const& l = e["peers"].list();
|
||||
for(entry::list_type::const_iterator i = l.begin(); i != l.end(); ++i)
|
||||
{
|
||||
peer_entry p = extract_peer_info(*i);
|
||||
peer_list.push_back(p);
|
||||
}
|
||||
fail(-1, "missing 'complete' or 'incomplete' entries in scrape response");
|
||||
return;
|
||||
}
|
||||
|
||||
if (entry const* ipv6_peers = e.find_key("peers6"))
|
||||
{
|
||||
std::string const& peers = ipv6_peers->string();
|
||||
for (std::string::const_iterator i = peers.begin();
|
||||
i != peers.end();)
|
||||
{
|
||||
if (std::distance(i, peers.end()) < 18) break;
|
||||
|
||||
peer_entry p;
|
||||
p.pid.clear();
|
||||
p.ip = detail::read_v6_address(i).to_string();
|
||||
p.port = detail::read_uint16(i);
|
||||
peer_list.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
// look for optional scrape info
|
||||
int complete = -1;
|
||||
int incomplete = -1;
|
||||
|
||||
try { complete = e["complete"].integer(); }
|
||||
catch(type_error&) {}
|
||||
|
||||
try { incomplete = e["incomplete"].integer(); }
|
||||
catch(type_error&) {}
|
||||
|
||||
cb->tracker_response(tracker_req(), peer_list, interval, complete
|
||||
, incomplete);
|
||||
cb->tracker_scrape_response(tracker_req(), complete->integer()
|
||||
, incomplete->integer(), downloaded->integer());
|
||||
return;
|
||||
}
|
||||
catch(type_error& e)
|
||||
|
||||
entry const* interval = e.find_key("interval");
|
||||
if (interval == 0 || interval->type() != entry::int_t)
|
||||
{
|
||||
cb->tracker_request_error(tracker_req(), m_parser.status_code(), e.what());
|
||||
fail(-1, "missing or invalid 'interval' entry in tracker response");
|
||||
return;
|
||||
}
|
||||
catch(std::runtime_error& e)
|
||||
|
||||
entry const* peers_ent = e.find_key("peers");
|
||||
if (peers_ent == 0)
|
||||
{
|
||||
cb->tracker_request_error(tracker_req(), m_parser.status_code(), e.what());
|
||||
fail(-1, "missing 'peers' entry in tracker response");
|
||||
return;
|
||||
}
|
||||
|
||||
if (peers_ent->type() == entry::string_t)
|
||||
{
|
||||
std::string const& peers = peers_ent->string();
|
||||
for (std::string::const_iterator i = peers.begin();
|
||||
i != peers.end();)
|
||||
{
|
||||
if (std::distance(i, peers.end()) < 6) break;
|
||||
|
||||
peer_entry p;
|
||||
p.pid.clear();
|
||||
p.ip = detail::read_v4_address(i).to_string();
|
||||
p.port = detail::read_uint16(i);
|
||||
peer_list.push_back(p);
|
||||
}
|
||||
}
|
||||
else if (peers_ent->type() == entry::list_t)
|
||||
{
|
||||
entry::list_type const& l = peers_ent->list();
|
||||
for(entry::list_type::const_iterator i = l.begin(); i != l.end(); ++i)
|
||||
{
|
||||
peer_entry p;
|
||||
if (!extract_peer_info(*i, p)) return;
|
||||
peer_list.push_back(p);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fail(-1, "invalid 'peers' entry in tracker response");
|
||||
return;
|
||||
}
|
||||
|
||||
entry const* ipv6_peers = e.find_key("peers6");
|
||||
if (ipv6_peers && ipv6_peers->type() == entry::string_t)
|
||||
{
|
||||
std::string const& peers = ipv6_peers->string();
|
||||
for (std::string::const_iterator i = peers.begin();
|
||||
i != peers.end();)
|
||||
{
|
||||
if (std::distance(i, peers.end()) < 18) break;
|
||||
|
||||
peer_entry p;
|
||||
p.pid.clear();
|
||||
p.ip = detail::read_v6_address(i).to_string();
|
||||
p.port = detail::read_uint16(i);
|
||||
peer_list.push_back(p);
|
||||
}
|
||||
}
|
||||
|
||||
// look for optional scrape info
|
||||
int complete = -1;
|
||||
int incomplete = -1;
|
||||
|
||||
entry const* complete_ent = e.find_key("complete");
|
||||
if (complete_ent && complete_ent->type() == entry::int_t)
|
||||
complete = complete_ent->integer();
|
||||
|
||||
entry const* incomplete_ent = e.find_key("incomplete");
|
||||
if (incomplete_ent && incomplete_ent->type() == entry::int_t)
|
||||
incomplete = incomplete_ent->integer();
|
||||
|
||||
cb->tracker_response(tracker_req(), peer_list, interval->integer(), complete
|
||||
, incomplete);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ namespace libtorrent
|
|||
}
|
||||
|
||||
void udp_tracker_connection::name_lookup(asio::error_code const& error
|
||||
, udp::resolver::iterator i) try
|
||||
, udp::resolver::iterator i)
|
||||
{
|
||||
if (error == asio::error::operation_aborted) return;
|
||||
if (!m_socket.is_open()) return; // the operation was aborted
|
||||
|
@ -146,15 +146,27 @@ namespace libtorrent
|
|||
|
||||
if (cb) cb->m_tracker_address = tcp::endpoint(target_address.address(), target_address.port());
|
||||
m_target = target_address;
|
||||
m_socket.open(target_address.protocol());
|
||||
m_socket.bind(udp::endpoint(bind_interface(), 0));
|
||||
m_socket.connect(target_address);
|
||||
asio::error_code ec;
|
||||
m_socket.open(target_address.protocol(), ec);
|
||||
if (ec)
|
||||
{
|
||||
fail(-1, ec.message().c_str());
|
||||
return;
|
||||
}
|
||||
m_socket.bind(udp::endpoint(bind_interface(), 0), ec);
|
||||
if (ec)
|
||||
{
|
||||
fail(-1, ec.message().c_str());
|
||||
return;
|
||||
}
|
||||
m_socket.connect(target_address, ec);
|
||||
if (ec)
|
||||
{
|
||||
fail(-1, ec.message().c_str());
|
||||
return;
|
||||
}
|
||||
send_udp_connect();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
fail(-1, e.what());
|
||||
};
|
||||
|
||||
void udp_tracker_connection::on_timeout()
|
||||
{
|
||||
|
@ -198,15 +210,21 @@ namespace libtorrent
|
|||
// transaction_id
|
||||
detail::write_int32(m_transaction_id, ptr);
|
||||
|
||||
m_socket.send(asio::buffer((void*)send_buf, 16), 0);
|
||||
asio::error_code ec;
|
||||
m_socket.send(asio::buffer((void*)send_buf, 16), 0, ec);
|
||||
++m_attempts;
|
||||
if (ec)
|
||||
{
|
||||
fail(-1, ec.message().c_str());
|
||||
return;
|
||||
}
|
||||
m_buffer.resize(udp_buffer_size);
|
||||
m_socket.async_receive_from(asio::buffer(m_buffer), m_sender
|
||||
, boost::bind(&udp_tracker_connection::connect_response, self(), _1, _2));
|
||||
}
|
||||
|
||||
void udp_tracker_connection::connect_response(asio::error_code const& error
|
||||
, std::size_t bytes_transferred) try
|
||||
, std::size_t bytes_transferred)
|
||||
{
|
||||
if (error == asio::error::operation_aborted) return;
|
||||
if (!m_socket.is_open()) return; // the operation was aborted
|
||||
|
@ -275,8 +293,9 @@ namespace libtorrent
|
|||
boost::shared_ptr<request_callback> cb = requester();
|
||||
if (cb)
|
||||
{
|
||||
cb->debug_log("<== UDP_TRACKER_CONNECT_RESPONSE ["
|
||||
+ lexical_cast<std::string>(m_connection_id) + "]");
|
||||
std::stringstream msg;
|
||||
msg << "<== UDP_TRACKER_CONNECT_RESPONSE [" << m_connection_id << "]";
|
||||
cb->debug_log(msg.str());
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -285,10 +304,6 @@ namespace libtorrent
|
|||
else if (tracker_req().kind == tracker_request::scrape_request)
|
||||
send_udp_scrape();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
fail(-1, e.what());
|
||||
}
|
||||
|
||||
void udp_tracker_connection::send_udp_announce()
|
||||
{
|
||||
|
@ -343,8 +358,14 @@ namespace libtorrent
|
|||
}
|
||||
#endif
|
||||
|
||||
m_socket.send(asio::buffer(buf), 0);
|
||||
asio::error_code ec;
|
||||
m_socket.send(asio::buffer(buf), 0, ec);
|
||||
++m_attempts;
|
||||
if (ec)
|
||||
{
|
||||
fail(-1, ec.message().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
m_socket.async_receive_from(asio::buffer(m_buffer), m_sender
|
||||
, bind(&udp_tracker_connection::announce_response, self(), _1, _2));
|
||||
|
@ -369,15 +390,21 @@ namespace libtorrent
|
|||
// info_hash
|
||||
std::copy(tracker_req().info_hash.begin(), tracker_req().info_hash.end(), out);
|
||||
|
||||
m_socket.send(asio::buffer(&buf[0], buf.size()), 0);
|
||||
asio::error_code ec;
|
||||
m_socket.send(asio::buffer(&buf[0], buf.size()), 0, ec);
|
||||
++m_attempts;
|
||||
if (ec)
|
||||
{
|
||||
fail(-1, ec.message().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
m_socket.async_receive_from(asio::buffer(m_buffer), m_sender
|
||||
, bind(&udp_tracker_connection::scrape_response, self(), _1, _2));
|
||||
}
|
||||
|
||||
void udp_tracker_connection::announce_response(asio::error_code const& error
|
||||
, std::size_t bytes_transferred) try
|
||||
, std::size_t bytes_transferred)
|
||||
{
|
||||
if (error == asio::error::operation_aborted) return;
|
||||
if (!m_socket.is_open()) return; // the operation was aborted
|
||||
|
@ -480,15 +507,10 @@ namespace libtorrent
|
|||
|
||||
m_man.remove_request(this);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
fail(-1, e.what());
|
||||
}; // msvc 7.1 seems to require this
|
||||
|
||||
void udp_tracker_connection::scrape_response(asio::error_code const& error
|
||||
, std::size_t bytes_transferred) try
|
||||
, std::size_t bytes_transferred)
|
||||
{
|
||||
if (error == asio::error::operation_aborted) return;
|
||||
if (!m_socket.is_open()) return; // the operation was aborted
|
||||
|
@ -554,7 +576,6 @@ namespace libtorrent
|
|||
boost::shared_ptr<request_callback> cb = requester();
|
||||
if (!cb)
|
||||
{
|
||||
m_man.remove_request(this);
|
||||
close();
|
||||
return;
|
||||
}
|
||||
|
@ -565,10 +586,5 @@ namespace libtorrent
|
|||
m_man.remove_request(this);
|
||||
close();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
fail(-1, e.what());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue