made udp and http tracker connections build without exception support

This commit is contained in:
Arvid Norberg 2007-12-30 01:57:57 +00:00
parent 010d5631a4
commit 07d1fe84c3
3 changed files with 208 additions and 178 deletions

View File

@ -157,7 +157,7 @@ namespace libtorrent
virtual void on_timeout(); virtual void on_timeout();
void parse(const entry& e); 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; tracker_manager& m_man;
http_parser m_parser; http_parser m_parser;

View File

@ -203,11 +203,7 @@ namespace libtorrent
if (name == "content-length") if (name == "content-length")
{ {
try m_content_length = atoi(value.c_str());
{
m_content_length = boost::lexical_cast<int>(value);
}
catch(boost::bad_lexical_cast&) {}
} }
else if (name == "content-range") else if (name == "content-range")
{ {
@ -505,7 +501,8 @@ namespace libtorrent
void http_tracker_connection::on_timeout() void http_tracker_connection::on_timeout()
{ {
m_timed_out = true; m_timed_out = true;
m_socket.close(); asio::error_code ec;
m_socket.close(ec);
m_name_lookup.cancel(); m_name_lookup.cancel();
if (m_connection_ticket > -1) m_cc.done(m_connection_ticket); if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
m_connection_ticket = -1; m_connection_ticket = -1;
@ -530,7 +527,7 @@ namespace libtorrent
} }
void http_tracker_connection::name_lookup(asio::error_code const& error 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(); boost::shared_ptr<request_callback> cb = requester();
#if defined(TORRENT_VERBOSE_LOGGING) || defined(TORRENT_LOGGING) #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.get<http_stream>().set_no_connect(true);
} }
m_socket.open(target_address.protocol()); asio::error_code ec;
m_socket.bind(tcp::endpoint(bind_interface(), 0)); 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) m_cc.enqueue(bind(&http_tracker_connection::connect, self(), _1, target_address)
, bind(&http_tracker_connection::on_timeout, self()) , bind(&http_tracker_connection::on_timeout, self())
, seconds(m_settings.tracker_receive_timeout)); , 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) 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)); 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); if (m_connection_ticket > -1) m_cc.done(m_connection_ticket);
m_connection_ticket = -1; m_connection_ticket = -1;
@ -627,12 +631,8 @@ namespace libtorrent
, m_send_buffer.size()), bind(&http_tracker_connection::sent , m_send_buffer.size()), bind(&http_tracker_connection::sent
, self(), _1)); , 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 (error == asio::error::operation_aborted) return;
if (m_timed_out) return; if (m_timed_out) return;
@ -652,14 +652,9 @@ namespace libtorrent
, m_buffer.size() - m_recv_pos), bind(&http_tracker_connection::receive , m_buffer.size() - m_recv_pos), bind(&http_tracker_connection::receive
, self(), _1, _2)); , 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 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 (error == asio::error::operation_aborted) return;
if (m_timed_out) return; if (m_timed_out) return;
@ -738,10 +733,6 @@ namespace libtorrent
, m_buffer.size() - m_recv_pos), bind(&http_tracker_connection::receive , m_buffer.size() - m_recv_pos), bind(&http_tracker_connection::receive
, self(), _1, _2)); , self(), _1, _2));
} }
catch (std::exception& e)
{
fail(-1, e.what());
};
void http_tracker_connection::on_response() void http_tracker_connection::on_response()
{ {
@ -828,15 +819,15 @@ namespace libtorrent
} }
// handle tracker response // 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); parse(e);
} }
catch (std::exception& e) else
{ {
std::string error_str(e.what()); std::string error_str("invalid bencoding of tracker response: \"");
error_str += ": \"";
for (char const* i = buf.begin, *end(buf.end); i != end; ++i) for (char const* i = buf.begin, *end(buf.end); i != end; ++i)
{ {
if (std::isprint(*i)) error_str += *i; if (std::isprint(*i)) error_str += *i;
@ -845,25 +836,25 @@ namespace libtorrent
error_str += "\""; error_str += "\"";
fail(m_parser.status_code(), error_str.c_str()); fail(m_parser.status_code(), error_str.c_str());
} }
#ifndef NDEBUG
catch (...)
{
TORRENT_ASSERT(false);
}
#endif
close(); 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) // 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"); entry const* i = info.find_key("peer id");
if (i != 0) if (i != 0)
{ {
if (i->string().length() != 20) if (i->type() != entry::string_t || i->string().length() != 20)
throw std::runtime_error("invalid response from tracker"); {
fail(-1, "invalid response from tracker (invalid peer id)");
return false;
}
std::copy(i->string().begin(), i->string().end(), ret.pid.begin()); std::copy(i->string().begin(), i->string().end(), ret.pid.begin());
} }
else else
@ -874,15 +865,23 @@ namespace libtorrent
// extract ip // extract ip
i = info.find_key("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(); ret.ip = i->string();
// extract port // extract port
i = info.find_key("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(); ret.port = (unsigned short)i->integer();
return ret; return true;
} }
void http_tracker_connection::parse(entry const& e) void http_tracker_connection::parse(entry const& e)
@ -890,118 +889,133 @@ namespace libtorrent
boost::shared_ptr<request_callback> cb = requester(); boost::shared_ptr<request_callback> cb = requester();
if (!cb) return; 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 fail(m_parser.status_code(), failure->string().c_str());
try 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(-1, "invalid or missing 'files' entry in scrape response");
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);
return; return;
} }
std::vector<peer_entry> peer_list; entry const* scrape_data = e.find_key(ih.c_str());
int interval = (int)e["interval"].integer(); if (scrape_data == 0 || scrape_data->type() != entry::dictionary_t)
if (e["peers"].type() == entry::string_t)
{ {
std::string const& peers = e["peers"].string(); fail(-1, "missing or invalid info-hash entry in scrape response");
for (std::string::const_iterator i = peers.begin(); return;
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 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(); fail(-1, "missing 'complete' or 'incomplete' entries in scrape response");
for(entry::list_type::const_iterator i = l.begin(); i != l.end(); ++i) return;
{
peer_entry p = extract_peer_info(*i);
peer_list.push_back(p);
}
} }
cb->tracker_scrape_response(tracker_req(), complete->integer()
if (entry const* ipv6_peers = e.find_key("peers6")) , incomplete->integer(), downloaded->integer());
{ return;
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);
} }
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);
} }
} }

View File

@ -103,7 +103,7 @@ namespace libtorrent
} }
void udp_tracker_connection::name_lookup(asio::error_code const& error 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 (error == asio::error::operation_aborted) return;
if (!m_socket.is_open()) return; // the operation was aborted 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()); if (cb) cb->m_tracker_address = tcp::endpoint(target_address.address(), target_address.port());
m_target = target_address; m_target = target_address;
m_socket.open(target_address.protocol()); asio::error_code ec;
m_socket.bind(udp::endpoint(bind_interface(), 0)); m_socket.open(target_address.protocol(), ec);
m_socket.connect(target_address); 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(); send_udp_connect();
} }
catch (std::exception& e)
{
fail(-1, e.what());
};
void udp_tracker_connection::on_timeout() void udp_tracker_connection::on_timeout()
{ {
@ -198,15 +210,21 @@ namespace libtorrent
// transaction_id // transaction_id
detail::write_int32(m_transaction_id, ptr); 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; ++m_attempts;
if (ec)
{
fail(-1, ec.message().c_str());
return;
}
m_buffer.resize(udp_buffer_size); m_buffer.resize(udp_buffer_size);
m_socket.async_receive_from(asio::buffer(m_buffer), m_sender m_socket.async_receive_from(asio::buffer(m_buffer), m_sender
, boost::bind(&udp_tracker_connection::connect_response, self(), _1, _2)); , boost::bind(&udp_tracker_connection::connect_response, self(), _1, _2));
} }
void udp_tracker_connection::connect_response(asio::error_code const& error 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 (error == asio::error::operation_aborted) return;
if (!m_socket.is_open()) return; // the operation was aborted if (!m_socket.is_open()) return; // the operation was aborted
@ -275,8 +293,9 @@ namespace libtorrent
boost::shared_ptr<request_callback> cb = requester(); boost::shared_ptr<request_callback> cb = requester();
if (cb) if (cb)
{ {
cb->debug_log("<== UDP_TRACKER_CONNECT_RESPONSE [" std::stringstream msg;
+ lexical_cast<std::string>(m_connection_id) + "]"); msg << "<== UDP_TRACKER_CONNECT_RESPONSE [" << m_connection_id << "]";
cb->debug_log(msg.str());
} }
#endif #endif
@ -285,10 +304,6 @@ namespace libtorrent
else if (tracker_req().kind == tracker_request::scrape_request) else if (tracker_req().kind == tracker_request::scrape_request)
send_udp_scrape(); send_udp_scrape();
} }
catch (std::exception& e)
{
fail(-1, e.what());
}
void udp_tracker_connection::send_udp_announce() void udp_tracker_connection::send_udp_announce()
{ {
@ -343,8 +358,14 @@ namespace libtorrent
} }
#endif #endif
m_socket.send(asio::buffer(buf), 0); asio::error_code ec;
m_socket.send(asio::buffer(buf), 0, ec);
++m_attempts; ++m_attempts;
if (ec)
{
fail(-1, ec.message().c_str());
return;
}
m_socket.async_receive_from(asio::buffer(m_buffer), m_sender m_socket.async_receive_from(asio::buffer(m_buffer), m_sender
, bind(&udp_tracker_connection::announce_response, self(), _1, _2)); , bind(&udp_tracker_connection::announce_response, self(), _1, _2));
@ -369,15 +390,21 @@ namespace libtorrent
// info_hash // info_hash
std::copy(tracker_req().info_hash.begin(), tracker_req().info_hash.end(), out); 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; ++m_attempts;
if (ec)
{
fail(-1, ec.message().c_str());
return;
}
m_socket.async_receive_from(asio::buffer(m_buffer), m_sender m_socket.async_receive_from(asio::buffer(m_buffer), m_sender
, bind(&udp_tracker_connection::scrape_response, self(), _1, _2)); , bind(&udp_tracker_connection::scrape_response, self(), _1, _2));
} }
void udp_tracker_connection::announce_response(asio::error_code const& error 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 (error == asio::error::operation_aborted) return;
if (!m_socket.is_open()) return; // the operation was aborted if (!m_socket.is_open()) return; // the operation was aborted
@ -480,15 +507,10 @@ namespace libtorrent
m_man.remove_request(this); m_man.remove_request(this);
close(); 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 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 (error == asio::error::operation_aborted) return;
if (!m_socket.is_open()) return; // the operation was aborted if (!m_socket.is_open()) return; // the operation was aborted
@ -554,7 +576,6 @@ namespace libtorrent
boost::shared_ptr<request_callback> cb = requester(); boost::shared_ptr<request_callback> cb = requester();
if (!cb) if (!cb)
{ {
m_man.remove_request(this);
close(); close();
return; return;
} }
@ -565,10 +586,5 @@ namespace libtorrent
m_man.remove_request(this); m_man.remove_request(this);
close(); close();
} }
catch (std::exception& e)
{
fail(-1, e.what());
}
} }