add proper error handling to peer connections and session (#1149)

add proper error handling to peer connections and session. i.e. catch exceptions in asio handlers and catch by const reference
This commit is contained in:
Arvid Norberg 2016-09-25 09:50:48 -04:00 committed by GitHub
parent b60fe066e2
commit 97c6a75084
19 changed files with 143 additions and 67 deletions

View File

@ -99,7 +99,7 @@ AX_PTHREAD()
LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$PTHREAD_CFLAGS $CFLAGS"
CC="$PTHREAD_CC"
CXXFLAGS="$CXXFLAGS -ftemplate-depth=128"
CXXFLAGS="$CXXFLAGS -ftemplate-depth=128 -Wno-format-zero-length"
AS_ECHO "Checking for visibility support:"
AC_CACHE_CHECK([for __attribute__((visibility("hidden")))],
@ -166,9 +166,9 @@ AC_ARG_ENABLE(
[logging],
[AS_HELP_STRING(
[--enable-logging],
[enable logging to disk (use value "verbose" to enable verbose peer wire logging or "errors" limit logging to errors ) [default=no]])],
[enable logging support, enabled by alert mask [default=yes]])],
[[ARG_ENABLE_LOGGING=$enableval]],
[[ARG_ENABLE_LOGGING=no]]
[[ARG_ENABLE_LOGGING=yes]]
)
AC_ARG_ENABLE(
@ -190,7 +190,7 @@ AC_ARG_ENABLE(
[dht],
[AS_HELP_STRING(
[--enable-dht],
[enable dht support (use value "logging" to add extra logging) [default=yes]])],
[enable dht support [default=yes]])],
[[ARG_ENABLE_DHT=$enableval]],
[[ARG_ENABLE_DHT=yes]]
)

View File

@ -305,7 +305,7 @@ code to implement a simple bittorrent client::
std::cin >> a;
return 0;
}
catch (std::exception& e)
catch (std::exception const& e)
{
std::cerr << ec.what() << std::endl;
return 1;

View File

@ -1802,7 +1802,7 @@ int main(int argc, char* argv[])
for (std::vector<alert*>::iterator i = alerts.begin()
, end(alerts.end()); i != end; ++i)
{
TORRENT_TRY
try
{
if (!::handle_alert(ses, *i, files, non_files))
{
@ -1812,7 +1812,7 @@ int main(int argc, char* argv[])
events.push_back(event_string);
if (events.size() >= 20) events.pop_front();
}
} TORRENT_CATCH(std::exception& ) {}
} catch (std::exception const&) {}
}
alerts.clear();

View File

@ -377,7 +377,7 @@ int main(int argc, char* argv[])
#ifndef BOOST_NO_EXCEPTIONS
}
catch (std::exception& e)
catch (std::exception const& e)
{
std::fprintf(stderr, "%s\n", e.what());
}

View File

@ -61,6 +61,12 @@ namespace libtorrent { namespace aux
handler_storage(handler_storage const&);
};
struct error_handler_interface
{
virtual void on_exception(std::exception const&) = 0;
virtual void on_error(error_code const&) = 0;
};
// this class is a wrapper for an asio handler object. Its main purpose
// is to pass along additional parameters to the asio handler allocator
// function, as well as providing a distinct type for the handler
@ -69,15 +75,38 @@ namespace libtorrent { namespace aux
struct allocating_handler
{
allocating_handler(
Handler h, handler_storage<Size>& s)
Handler h, handler_storage<Size>& s, error_handler_interface& eh)
: handler(std::move(h))
, storage(s)
, error_handler(eh)
{}
template <class... A>
void operator()(A&&... a) const
{
#ifdef BOOST_NO_EXCEPTIONS
handler(std::forward<A>(a)...);
#else
try
{
handler(std::forward<A>(a)...);
}
catch (system_error const& e)
{
error_handler.on_error(e.code());
}
catch (std::exception const& e)
{
error_handler.on_exception(e);
}
catch (...)
{
// this is pretty bad
TORRENT_ASSERT(false);
std::runtime_error e("unknown exception");
error_handler.on_exception(e);
}
#endif
}
friend void* asio_handler_allocate(
@ -108,6 +137,7 @@ namespace libtorrent { namespace aux
Handler handler;
handler_storage<Size>& storage;
error_handler_interface& error_handler;
};
}

View File

@ -194,6 +194,7 @@ namespace libtorrent
, boost::noncopyable
, uncork_interface
, single_threaded
, aux::error_handler_interface
{
// the size of each allocation that is chained in the send buffer
enum { send_buffer_size_impl = 128 };
@ -249,6 +250,9 @@ namespace libtorrent
bool m_posting_torrent_updates = false;
#endif
void on_exception(std::exception const& e) override;
void on_error(error_code const& ec) override;
void reopen_listen_sockets();
torrent_peer_allocator_interface* get_peer_allocator() override
@ -1099,7 +1103,7 @@ namespace libtorrent
make_tick_handler(Handler const& handler)
{
return aux::allocating_handler<Handler, TORRENT_READ_HANDLER_MAX_SIZE>(
handler, m_tick_handler_storage);
handler, m_tick_handler_storage, *this);
}
// torrents are announced on the local network in a

View File

@ -96,7 +96,10 @@ namespace libtorrent
op_ssl_handshake,
// a connection failed to satisfy the bind interface setting
op_get_interface
op_get_interface,
// the error was unexpected and it is unknown which operation caused it
op_unknown,
};
}

View File

@ -259,11 +259,15 @@ namespace libtorrent
, public disk_observer
, public peer_connection_interface
, public std::enable_shared_from_this<peer_connection>
, public aux::error_handler_interface
{
friend class invariant_access;
friend class torrent;
public:
void on_exception(std::exception const& e) override;
void on_error(error_code const& ec) override;
virtual connection_type type() const = 0;
enum channels
@ -283,14 +287,14 @@ namespace libtorrent
virtual ~peer_connection();
void set_peer_info(torrent_peer* pi)
void set_peer_info(torrent_peer* pi) override
{
TORRENT_ASSERT(m_peer_info == 0 || pi == 0 );
TORRENT_ASSERT(pi != nullptr || m_disconnect_started);
m_peer_info = pi;
}
torrent_peer* peer_info_struct() const
torrent_peer* peer_info_struct() const override
{ return m_peer_info; }
// this is called when the peer object is created, in case
@ -358,7 +362,7 @@ namespace libtorrent
std::uint32_t peer_rank() const;
void fast_reconnect(bool r);
bool fast_reconnect() const { return m_fast_reconnect; }
bool fast_reconnect() const override { return m_fast_reconnect; }
// this is called when we receive a new piece
// (and it has passed the hash check)
@ -391,12 +395,12 @@ namespace libtorrent
void set_upload_only(bool u);
bool upload_only() const { return m_upload_only; }
void set_holepunch_mode();
void set_holepunch_mode() override;
// will send a keep-alive message to the peer
void keep_alive();
peer_id const& pid() const { return m_peer_id; }
peer_id const& pid() const override { return m_peer_id; }
void set_pid(peer_id const& peer_id) { m_peer_id = peer_id; }
bool has_piece(int i) const;
@ -413,7 +417,7 @@ namespace libtorrent
time_duration download_queue_time(int extra_bytes = 0) const;
bool is_interesting() const { return m_interesting; }
bool is_choked() const { return m_choked; }
bool is_choked() const override { return m_choked; }
bool is_peer_interested() const { return m_peer_interested; }
bool has_peer_choked() const { return m_peer_choked; }
@ -423,7 +427,7 @@ namespace libtorrent
void update_interest();
virtual void get_peer_info(peer_info& p) const;
void get_peer_info(peer_info& p) const override;
// returns the torrent this connection is a part of
// may be zero if the connection is an incoming connection
@ -432,8 +436,8 @@ namespace libtorrent
std::weak_ptr<torrent> associated_torrent() const
{ return m_torrent; }
stat const& statistics() const { return m_statistics; }
void add_stat(std::int64_t downloaded, std::int64_t uploaded);
stat const& statistics() const override { return m_statistics; }
void add_stat(std::int64_t downloaded, std::int64_t uploaded) override;
void sent_bytes(int bytes_payload, int bytes_protocol);
void received_bytes(int bytes_payload, int bytes_protocol);
void trancieve_ip_packet(int bytes, bool ipv6);
@ -446,8 +450,8 @@ namespace libtorrent
void timeout_requests();
std::shared_ptr<socket_type> get_socket() const { return m_socket; }
tcp::endpoint const& remote() const { return m_remote; }
tcp::endpoint local_endpoint() const { return m_local; }
tcp::endpoint const& remote() const override { return m_remote; }
tcp::endpoint local_endpoint() const override { return m_local; }
bitfield const& get_bitfield() const;
std::vector<int> const& allowed_fast();
@ -457,13 +461,13 @@ namespace libtorrent
time_point last_received() const { return m_last_receive; }
// this will cause this peer_connection to be disconnected.
virtual void disconnect(error_code const& ec
, operation_t op, int error = 0);
void disconnect(error_code const& ec
, operation_t op, int error = 0) override;
// called when a connect attempt fails (not when an
// established connection fails)
void connect_failed(error_code const& e);
bool is_disconnecting() const { return m_disconnecting; }
bool is_disconnecting() const override { return m_disconnecting; }
// this is called when the connection attempt has succeeded
// and the peer_connection is supposed to set m_connecting
@ -487,7 +491,7 @@ namespace libtorrent
// a connection is local if it was initiated by us.
// if it was an incoming connection, it is remote
bool is_outgoing() const { return m_outgoing; }
bool is_outgoing() const override { return m_outgoing; }
bool received_listen_port() const { return m_received_listen_port; }
void received_listen_port()
@ -496,7 +500,7 @@ namespace libtorrent
bool on_local_network() const;
bool ignore_unchoke_slots() const;
bool failed() const { return m_failed; }
bool failed() const override { return m_failed; }
int desired_queue_size() const
{
@ -525,9 +529,9 @@ namespace libtorrent
int est_reciprocation_rate() const { return m_est_reciprocation_rate; }
#ifndef TORRENT_DISABLE_LOGGING
bool should_log(peer_log_alert::direction_t direction) const;
bool should_log(peer_log_alert::direction_t direction) const override;
void peer_log(peer_log_alert::direction_t direction
, char const* event, char const* fmt, ...) const TORRENT_FORMAT(4,5);
, char const* event, char const* fmt, ...) const override TORRENT_FORMAT(4,5);
void peer_log(peer_log_alert::direction_t direction
, char const* event) const;
@ -608,7 +612,7 @@ namespace libtorrent
void cancel_request(piece_block const& b, bool force = false);
void send_block_requests();
void assign_bandwidth(int channel, int amount);
void assign_bandwidth(int channel, int amount) override;
#if TORRENT_USE_INVARIANT_CHECKS
void check_invariant() const;
@ -677,7 +681,7 @@ namespace libtorrent
// called when the disk write buffer is drained again, and we can
// start downloading payload again
void on_disk();
void on_disk() override;
int num_reading_bytes() const { return m_reading_bytes; }
@ -1181,7 +1185,7 @@ namespace libtorrent
make_read_handler(Handler const& handler)
{
return aux::allocating_handler<Handler, TORRENT_READ_HANDLER_MAX_SIZE>(
handler, m_read_handler_storage
handler, m_read_handler_storage, *this
);
}
@ -1190,7 +1194,7 @@ namespace libtorrent
make_write_handler(Handler const& handler)
{
return aux::allocating_handler<Handler, TORRENT_WRITE_HANDLER_MAX_SIZE>(
handler, m_write_handler_storage
handler, m_write_handler_storage, *this
);
}

View File

@ -1455,6 +1455,7 @@ namespace libtorrent {
"connect",
"ssl_handshake",
"get_interface",
"unknown",
};
if (op < 0 || op >= int(sizeof(names)/sizeof(names[0])))

View File

@ -81,7 +81,7 @@ namespace libtorrent
|| (ip & 0xffff0000) == 0xc0a80000 // 192.168.x.x
|| (ip & 0xffff0000) == 0xa9fe0000 // 169.254.x.x
|| (ip & 0xff000000) == 0x7f000000); // 127.x.x.x
} TORRENT_CATCH(std::exception&) { return false; }
} TORRENT_CATCH(std::exception const&) { return false; }
}
bool is_loopback(address const& addr)
@ -92,7 +92,7 @@ namespace libtorrent
return addr.to_v4() == address_v4::loopback();
else
return addr.to_v6() == address_v6::loopback();
} TORRENT_CATCH(std::exception&) { return false; }
} TORRENT_CATCH(std::exception const&) { return false; }
#else
return addr.to_v4() == address_v4::loopback();
#endif
@ -111,7 +111,7 @@ namespace libtorrent
#else
return addr.to_v4() == address_v4::any();
#endif
} TORRENT_CATCH(std::exception&) { return false; }
} TORRENT_CATCH(std::exception const&) { return false; }
}
bool is_teredo(address const& addr)
@ -122,7 +122,7 @@ namespace libtorrent
std::uint8_t teredo_prefix[] = {0x20, 0x01, 0, 0};
address_v6::bytes_type b = addr.to_v6().to_bytes();
return memcmp(&b[0], teredo_prefix, 4) == 0;
} TORRENT_CATCH(std::exception&) { return false; }
} TORRENT_CATCH(std::exception const&) { return false; }
#else
TORRENT_UNUSED(addr);
return false;
@ -140,7 +140,7 @@ namespace libtorrent
error_code ec;
address::from_string("::1", ec);
return !ec;
} TORRENT_CATCH(std::exception&) { return false; }
} TORRENT_CATCH(std::exception const&) { return false; }
#else
io_service ios;
tcp::socket test(ios);

View File

@ -221,7 +221,7 @@ namespace libtorrent
{
TORRENT_TRY {
buffer.resize(destlen);
} TORRENT_CATCH(std::exception&) {
} TORRENT_CATCH (std::exception const&) {
ec = errors::no_memory;
return;
}

View File

@ -281,7 +281,7 @@ void lsd::on_announce(udp::endpoint const& from, char const* buf
// we got an announce, pass it on through the callback
TORRENT_TRY {
m_callback.on_lsd_peer(tcp::endpoint(from.address(), port), ih);
} TORRENT_CATCH(std::exception&) {}
} TORRENT_CATCH (std::exception const&) {}
}
}
}

View File

@ -196,6 +196,21 @@ namespace libtorrent
return ret;
}
void peer_connection::on_exception(std::exception const& e)
{
TORRENT_UNUSED(e);
#ifndef TORRENT_DISABLE_LOGGING
peer_log(peer_log_alert::info, "PEER_ERROR" ,"error: %s"
, e.what());
#endif
disconnect(error_code(), op_unknown, 2);
}
void peer_connection::on_error(error_code const& ec)
{
disconnect(ec, op_unknown, 2);
}
void peer_connection::increase_est_reciprocation_rate()
{
TORRENT_ASSERT(is_single_thread());
@ -1076,7 +1091,7 @@ namespace libtorrent
{
TORRENT_TRY {
e->on_piece_pass(index);
} TORRENT_CATCH(std::exception&) {}
} TORRENT_CATCH (std::exception const&) {}
}
#else
TORRENT_UNUSED(index);
@ -1096,7 +1111,7 @@ namespace libtorrent
{
TORRENT_TRY {
e->on_piece_failed(index);
} TORRENT_CATCH(std::exception&) {}
} TORRENT_CATCH (std::exception const&) {}
}
#else
TORRENT_UNUSED(index);

View File

@ -642,7 +642,7 @@ namespace aux {
{
TORRENT_TRY {
ext->save_state(*eptr);
} TORRENT_CATCH(std::exception&) {}
} TORRENT_CATCH (std::exception const&) {}
}
#endif
}
@ -752,7 +752,7 @@ namespace aux {
{
TORRENT_TRY {
ext->load_state(*e);
} TORRENT_CATCH(std::exception&) {}
} TORRENT_CATCH (std::exception const&) {}
}
#endif
}
@ -1795,6 +1795,25 @@ namespace aux {
return ret;
}
void session_impl::on_exception(std::exception const& e)
{
TORRENT_UNUSED(e);
#ifndef TORRENT_DISABLE_LOGGING
session_log("FATAL SESSION ERROR [%s]", e.what());
#endif
this->abort();
}
void session_impl::on_error(error_code const& ec)
{
TORRENT_UNUSED(ec);
#ifndef TORRENT_DISABLE_LOGGING
session_log("FATAL SESSION ERROR (%s : %d) [%s]"
, ec.category().name(), ec.value(), ec.message().c_str());
#endif
this->abort();
}
void session_impl::reopen_listen_sockets()
{
#ifndef TORRENT_DISABLE_LOGGING
@ -3167,7 +3186,7 @@ namespace aux {
{
TORRENT_TRY {
ext->on_tick();
} TORRENT_CATCH(std::exception&) {}
} TORRENT_CATCH (std::exception const&) {}
}
#endif

View File

@ -2059,7 +2059,7 @@ namespace libtorrent
{
TORRENT_TRY {
e->on_load();
} TORRENT_CATCH (std::exception&) {}
} TORRENT_CATCH (std::exception const&) {}
}
#endif
@ -2090,7 +2090,7 @@ namespace libtorrent
{
TORRENT_TRY {
e->on_unload();
} TORRENT_CATCH (std::exception&) {}
} TORRENT_CATCH (std::exception const&) {}
}
// also remove extensions and re-instantiate them when the torrent is loaded again
@ -4081,7 +4081,7 @@ namespace libtorrent
{
TORRENT_TRY {
ext->on_piece_pass(index);
} TORRENT_CATCH (std::exception&) {}
} TORRENT_CATCH (std::exception const&) {}
}
#endif
@ -4286,7 +4286,7 @@ namespace libtorrent
{
TORRENT_TRY {
ext->on_piece_failed(index);
} TORRENT_CATCH (std::exception&) {}
} TORRENT_CATCH (std::exception const&) {}
}
#endif
@ -6297,7 +6297,7 @@ namespace libtorrent
, num_peers());
#endif
}
TORRENT_CATCH (std::exception& e)
TORRENT_CATCH (std::exception const& e)
{
TORRENT_DECLARE_DUMMY(std::exception, e);
(void)e;
@ -6949,7 +6949,7 @@ namespace libtorrent
std::shared_ptr<peer_plugin> pp(ext->new_connection(
peer_connection_handle(c->self())));
if (pp) c->add_extension(pp);
} TORRENT_CATCH (std::exception&) {}
} TORRENT_CATCH (std::exception const&) {}
}
#endif
@ -6969,7 +6969,7 @@ namespace libtorrent
if (c->is_disconnecting()) return false;
}
TORRENT_CATCH (std::exception&)
TORRENT_CATCH (std::exception const&)
{
peer_iterator i = sorted_find(m_connections, c.get());
if (i != m_connections.end())
@ -7262,7 +7262,7 @@ namespace libtorrent
peers_erased(st.erased);
update_want_peers();
}
TORRENT_CATCH (std::exception& e)
TORRENT_CATCH (std::exception const& e)
{
TORRENT_DECLARE_DUMMY(std::exception, e);
(void)e;
@ -7892,7 +7892,7 @@ namespace libtorrent
{
TORRENT_TRY {
ext->on_files_checked();
} TORRENT_CATCH (std::exception&) {}
} TORRENT_CATCH (std::exception const&) {}
}
#endif
@ -8874,7 +8874,7 @@ namespace libtorrent
{
TORRENT_TRY {
if (ext->on_pause()) return;
} TORRENT_CATCH (std::exception&) {}
} TORRENT_CATCH (std::exception const&) {}
}
#endif
@ -9112,7 +9112,7 @@ namespace libtorrent
{
TORRENT_TRY {
if (ext->on_resume()) return;
} TORRENT_CATCH (std::exception&) {}
} TORRENT_CATCH (std::exception const&) {}
}
#endif
@ -9349,7 +9349,7 @@ namespace libtorrent
{
TORRENT_TRY {
ext->tick();
} TORRENT_CATCH (std::exception&) {}
} TORRENT_CATCH (std::exception const&) {}
}
if (m_abort) return;
@ -9465,7 +9465,7 @@ namespace libtorrent
TORRENT_TRY {
p->second_tick(tick_interval_ms);
}
TORRENT_CATCH (std::exception& e)
TORRENT_CATCH (std::exception const& e)
{
TORRENT_DECLARE_DUMMY(std::exception, e);
(void)e;
@ -10919,7 +10919,7 @@ namespace libtorrent
{
TORRENT_TRY {
ext->on_state(m_state);
} TORRENT_CATCH (std::exception&) {}
} TORRENT_CATCH (std::exception const&) {}
}
#endif
}
@ -10932,7 +10932,7 @@ namespace libtorrent
{
TORRENT_TRY {
ext->on_add_peer(ip, src, flags);
} TORRENT_CATCH (std::exception&) {}
} TORRENT_CATCH (std::exception const&) {}
}
}
#endif

View File

@ -323,7 +323,7 @@ void upnp::resend_request(error_code const& ec)
, std::ref(d), _5)));
d.upnp_connection->get(d.url, seconds(30), 1);
}
TORRENT_CATCH (std::exception& exc)
TORRENT_CATCH (std::exception const& exc)
{
TORRENT_DECLARE_DUMMY(std::exception, exc);
TORRENT_UNUSED(exc);
@ -671,7 +671,7 @@ void upnp::try_map_upnp(bool timer)
, std::ref(d), _5)));
d.upnp_connection->get(d.url, seconds(30), 1);
}
TORRENT_CATCH (std::exception& exc)
TORRENT_CATCH (std::exception const& exc)
{
TORRENT_DECLARE_DUMMY(std::exception, exc);
TORRENT_UNUSED(exc);

View File

@ -149,7 +149,7 @@ struct dht_server
#endif
++m_dht_requests;
}
catch (std::exception& e)
catch (std::exception const& e)
{
std::fprintf(stderr, "failed to decode DHT message: %s\n", e.what());
}

View File

@ -130,7 +130,7 @@ extern int EXPORT _g_test_failures;
if (!(x)) \
TEST_REPORT_AUX("TEST_ERROR: check failed: \"" #x "\"", __FILE__, __LINE__); \
} \
catch (std::exception& e) \
catch (std::exception const& e) \
{ \
TEST_ERROR("TEST_ERROR: Exception thrown: " #x " :" + std::string(e.what())); \
} \
@ -147,7 +147,7 @@ extern int EXPORT _g_test_failures;
TEST_REPORT_AUX(s__.str().c_str(), __FILE__, __LINE__); \
} \
} \
catch (std::exception& e) \
catch (std::exception const& e) \
{ \
TEST_ERROR("TEST_ERROR: Exception thrown: " #x " :" + std::string(e.what())); \
} \
@ -163,7 +163,7 @@ extern int EXPORT _g_test_failures;
TEST_REPORT_AUX(s__.str().c_str(), __FILE__, __LINE__); \
} \
} \
catch (std::exception& e) \
catch (std::exception const& e) \
{ \
TEST_ERROR("TEST_ERROR: Exception thrown: " #x " :" + std::string(e.what())); \
} \

View File

@ -866,7 +866,7 @@ TORRENT_TEST(empty_file2)
auto ti = std::make_shared<torrent_info>("", 0);
TEST_ERROR("expected exception thrown");
}
catch (system_error& e)
catch (system_error const& e)
{
std::printf("Expected error: %s\n", e.code().message().c_str());
}