handle errors in peer_connection

This commit is contained in:
arvidn 2017-12-25 12:36:12 +01:00 committed by Arvid Norberg
parent 56ca5fa63c
commit 347555ea8f
7 changed files with 159 additions and 61 deletions

View File

@ -214,6 +214,7 @@ nobase_include_HEADERS = \
aux_/array.hpp \
aux_/ip_notifier.hpp \
aux_/noexcept_movable.hpp \
aux_/torrent_impl.hpp \
\
extensions/smart_ban.hpp \
extensions/ut_metadata.hpp \

View File

@ -0,0 +1,80 @@
/*
Copyright (c) 2003-2017, 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_TORRENT_IMPL_HPP_INCLUDED
#define TORRENT_TORRENT_IMPL_HPP_INCLUDED
// this is not a normal header, it's just this template, to be able to call this
// function from more than one translation unit. But it's still internal
namespace libtorrent {
template <typename Fun, typename... Args>
void torrent::wrap(Fun f, Args&&... a)
#ifndef BOOST_NO_EXCEPTIONS
try
#endif
{
(this->*f)(std::forward<Args>(a)...);
}
#ifndef BOOST_NO_EXCEPTIONS
catch (system_error const& e) {
#ifndef TORRENT_DISABLE_LOGGING
debug_log("EXCEPTION: (%d %s) %s"
, e.code().value()
, e.code().message().c_str()
, e.what());
#endif
alerts().emplace_alert<torrent_error_alert>(get_handle()
, e.code(), e.what());
pause();
} catch (std::exception const& e) {
#ifndef TORRENT_DISABLE_LOGGING
debug_log("EXCEPTION: %s", e.what());
#endif
alerts().emplace_alert<torrent_error_alert>(get_handle()
, error_code(), e.what());
pause();
} catch (...) {
#ifndef TORRENT_DISABLE_LOGGING
debug_log("EXCEPTION: unknown");
#endif
alerts().emplace_alert<torrent_error_alert>(get_handle()
, error_code(), "unknown error");
pause();
}
#endif
}
#endif

View File

@ -505,7 +505,7 @@ POSSIBILITY OF SUCH DAMAGE.
constexpr std::size_t TORRENT_READ_HANDLER_MAX_SIZE = 400;
# else
// if this is not divisible by 8, we're wasting space
constexpr std::size_t TORRENT_READ_HANDLER_MAX_SIZE = 336;
constexpr std::size_t TORRENT_READ_HANDLER_MAX_SIZE = 342;
# endif
#endif
@ -514,7 +514,7 @@ constexpr std::size_t TORRENT_READ_HANDLER_MAX_SIZE = 336;
constexpr std::size_t TORRENT_WRITE_HANDLER_MAX_SIZE = 400;
# else
// if this is not divisible by 8, we're wasting space
constexpr std::size_t TORRENT_WRITE_HANDLER_MAX_SIZE = 336;
constexpr std::size_t TORRENT_WRITE_HANDLER_MAX_SIZE = 342;
# endif
#endif

View File

@ -989,6 +989,10 @@ namespace aux {
bandwidth_channel m_bandwidth_channel[num_channels];
protected:
template <typename Fun, typename... Args>
void wrap(Fun f, Args&&... a);
// statistics about upload and download speeds
// and total amount of uploads and downloads for
// this peer

View File

@ -301,13 +301,13 @@ struct TORRENT_EXTRA_EXPORT utp_stream
{
if (!endpoint.address().is_v4())
{
m_io_service.post(std::bind<void>(handler, boost::asio::error::operation_not_supported, 0));
m_io_service.post(std::bind<void>(handler, boost::asio::error::operation_not_supported));
return;
}
if (m_impl == nullptr)
{
m_io_service.post(std::bind<void>(handler, boost::asio::error::not_connected, 0));
m_io_service.post(std::bind<void>(handler, boost::asio::error::not_connected));
return;
}
@ -320,14 +320,14 @@ struct TORRENT_EXTRA_EXPORT utp_stream
{
if (m_impl == nullptr)
{
m_io_service.post(std::bind<void>(handler, boost::asio::error::not_connected, 0));
m_io_service.post(std::bind<void>(handler, boost::asio::error::not_connected, std::size_t(0)));
return;
}
TORRENT_ASSERT(!m_read_handler);
if (m_read_handler)
{
m_io_service.post(std::bind<void>(handler, boost::asio::error::operation_not_supported, 0));
m_io_service.post(std::bind<void>(handler, boost::asio::error::operation_not_supported, std::size_t(0)));
return;
}
std::size_t bytes_added = 0;
@ -349,7 +349,7 @@ struct TORRENT_EXTRA_EXPORT utp_stream
{
// if we're reading 0 bytes, post handler immediately
// asio's SSL layer depends on this behavior
m_io_service.post(std::bind<void>(handler, error_code(), 0));
m_io_service.post(std::bind<void>(handler, error_code(), std::size_t(0)));
return;
}
@ -362,7 +362,7 @@ struct TORRENT_EXTRA_EXPORT utp_stream
{
if (m_impl == nullptr)
{
m_io_service.post(std::bind<void>(handler, boost::asio::error::not_connected, 0));
m_io_service.post(std::bind<void>(handler, boost::asio::error::not_connected, std::size_t(0)));
return;
}
@ -370,7 +370,7 @@ struct TORRENT_EXTRA_EXPORT utp_stream
if (m_read_handler)
{
TORRENT_ASSERT_FAIL(); // we should never do this!
m_io_service.post(std::bind<void>(handler, boost::asio::error::operation_not_supported, 0));
m_io_service.post(std::bind<void>(handler, boost::asio::error::operation_not_supported, std::size_t(0)));
return;
}
m_read_handler = handler;
@ -464,7 +464,7 @@ struct TORRENT_EXTRA_EXPORT utp_stream
if (m_impl == nullptr)
{
m_io_service.post(std::bind<void>(handler
, boost::asio::error::not_connected, 0));
, boost::asio::error::not_connected, std::size_t(0)));
return;
}
@ -472,7 +472,7 @@ struct TORRENT_EXTRA_EXPORT utp_stream
if (m_write_handler)
{
m_io_service.post(std::bind<void>(handler
, boost::asio::error::operation_not_supported, 0));
, boost::asio::error::operation_not_supported, std::size_t(0)));
return;
}
@ -495,7 +495,7 @@ struct TORRENT_EXTRA_EXPORT utp_stream
{
// if we're writing 0 bytes, post handler immediately
// asio's SSL layer depends on this behavior
m_io_service.post(std::bind<void>(handler, error_code(), 0));
m_io_service.post(std::bind<void>(handler, error_code(), std::size_t(0)));
return;
}
m_write_handler = handler;

View File

@ -80,6 +80,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/hex.hpp" // to_hex
#endif
#include "libtorrent/aux_/torrent_impl.hpp"
//#define TORRENT_CORRUPT_DATA
using namespace std::placeholders;
@ -144,13 +146,13 @@ namespace libtorrent {
, m_slow_start(true)
{
m_counters.inc_stats_counter(counters::num_tcp_peers + m_socket->type() - 1);
std::shared_ptr<torrent> t = m_torrent.lock();
if (m_connected)
m_counters.inc_stats_counter(counters::num_peers_connected);
else if (m_connecting)
m_counters.inc_stats_counter(counters::num_peers_half_open);
std::shared_ptr<torrent> t = m_torrent.lock();
// if t is nullptr, we better not be connecting, since
// we can't decrement the connecting counter
TORRENT_ASSERT(t || !m_connecting);
@ -185,6 +187,41 @@ namespace libtorrent {
#endif
}
template <typename Fun, typename... Args>
void peer_connection::wrap(Fun f, Args&&... a)
#ifndef BOOST_NO_EXCEPTIONS
try
#endif
{
(this->*f)(std::forward<Args>(a)...);
}
#ifndef BOOST_NO_EXCEPTIONS
catch (std::bad_alloc const&) {
#ifndef TORRENT_DISABLE_LOGGING
peer_log(peer_log_alert::info, "EXCEPTION", "bad_alloc");
#endif
disconnect(make_error_code(boost::system::errc::not_enough_memory)
, operation_t::unknown);
}
catch (system_error const& e) {
#ifndef TORRENT_DISABLE_LOGGING
peer_log(peer_log_alert::info, "EXCEPTION", "(%d %s) %s"
, e.code().value()
, e.code().message().c_str()
, e.what());
#endif
disconnect(e.code(), operation_t::unknown);
}
catch (std::exception const& e) {
TORRENT_UNUSED(e);
#ifndef TORRENT_DISABLE_LOGGING
peer_log(peer_log_alert::info, "EXCEPTION", "%s", e.what());
#endif
disconnect(make_error_code(boost::system::errc::not_enough_memory)
, operation_t::sock_write);
}
#endif // BOOST_NO_EXCEPTIONS
int peer_connection::timeout() const
{
TORRENT_ASSERT(is_single_thread());
@ -384,8 +421,9 @@ namespace libtorrent {
, t->num_peers());
#endif
auto conn = self();
m_socket->async_connect(m_remote
, std::bind(&peer_connection::on_connection_complete, self(), _1));
, [conn](error_code const& e) { conn->wrap(&peer_connection::on_connection_complete, e); });
m_connect = aux::time_now();
sent_syn(m_remote.address().is_v6());
@ -415,7 +453,8 @@ namespace libtorrent {
// to not trigger another one. This effectively defer
// the update until the current message queue is
// flushed
m_ios.post(std::bind(&peer_connection::do_update_interest, self()));
auto conn = self();
m_ios.post([conn] { conn->wrap(&peer_connection::do_update_interest); });
}
m_need_interest_update = true;
}
@ -2812,9 +2851,10 @@ namespace libtorrent {
if (t->is_deleted()) return;
auto conn = self();
bool const exceeded = m_disk_thread.async_write(t->storage(), p, data, self()
, std::bind(&peer_connection::on_disk_write_complete
, self(), _1, p, t));
, [conn, p, t] (storage_error const& e)
{ conn->wrap(&peer_connection::on_disk_write_complete, e, p, t); });
// every peer is entitled to have two disk blocks allocated at any given
// time, regardless of whether the cache size is exceeded or not. If this
@ -3026,7 +3066,8 @@ namespace libtorrent {
// piece are done, and we can restore it, allowing
// new requests to it
m_disk_thread.async_clear_piece(t->storage(), p.piece
, std::bind(&torrent::on_piece_fail_sync, t, _1, block_finished));
, [t, block_finished] (piece_index_t pi)
{ t->wrap(&torrent::on_piece_fail_sync, pi, block_finished); });
}
else
{
@ -5141,9 +5182,10 @@ namespace libtorrent {
#endif
// this means we're in seed mode and we haven't yet
// verified this piece (r.piece)
auto conn = self();
m_disk_thread.async_hash(t->storage(), r.piece, {}
, std::bind(&peer_connection::on_seed_mode_hashed, self()
, _1, _2, _3));
, [conn](piece_index_t p, sha1_hash const& ph, storage_error const& e) {
conn->wrap(&peer_connection::on_seed_mode_hashed, p, ph, e); });
t->verifying(r.piece);
continue;
}
@ -5177,9 +5219,10 @@ namespace libtorrent {
TORRENT_ASSERT(r.piece >= piece_index_t(0));
TORRENT_ASSERT(r.piece < t->torrent_file().end_piece());
auto conn = self();
m_disk_thread.async_read(t->storage(), r
, std::bind(&peer_connection::on_disk_read_complete
, self(), _1, _2, _3, r, clock_type::now()));
, [conn, r](disk_buffer_holder buf, disk_job_flags_t f, storage_error const& ec)
{ conn->wrap(&peer_connection::on_disk_read_complete, std::move(buf), f, ec, r, clock_type::now()); });
}
m_last_sent_payload = clock_type::now();
m_requests.erase(m_requests.begin() + i);
@ -5606,8 +5649,10 @@ namespace libtorrent {
m_socket_is_writing = true;
#endif
m_socket->async_write_some(vec, make_handler(std::bind(
&peer_connection::on_send_data, self(), _1, _2)
auto conn = self();
m_socket->async_write_some(vec, make_handler(
[conn](error_code const& ec, std::size_t bt)
{ conn->wrap(&peer_connection::on_send_data, ec, bt); }
, m_write_handler_storage, *this));
m_channel_state[upload_channel] |= peer_info::bw_network;
@ -5691,9 +5736,11 @@ namespace libtorrent {
// utp sockets aren't thread safe...
ADD_OUTSTANDING_ASYNC("peer_connection::on_receive_data");
auto conn = self();
m_socket->async_read_some(
boost::asio::mutable_buffers_1(vec.data(), vec.size()), make_handler(
std::bind(&peer_connection::on_receive_data, self(), _1, _2)
[conn](error_code const& ec, std::size_t bt)
{ conn->wrap(&peer_connection::on_receive_data, ec, bt); }
, m_read_handler_storage, *this));
}

View File

@ -103,6 +103,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/aux_/session_impl.hpp" // for tracker_logger
#endif
#include "libtorrent/aux_/torrent_impl.hpp"
using namespace std::placeholders;
namespace libtorrent {
@ -4550,42 +4552,6 @@ namespace libtorrent {
return detail::read_uint32(ptr);
}
template <typename Fun, typename... Args>
void torrent::wrap(Fun f, Args&&... a)
#ifndef BOOST_NO_EXCEPTIONS
try
#endif
{
(this->*f)(std::forward<Args>(a)...);
}
#ifndef BOOST_NO_EXCEPTIONS
catch (system_error const& e) {
#ifndef TORRENT_DISABLE_LOGGING
debug_log("EXCEPTION: (%d %s) %s"
, e.code().value()
, e.code().message().c_str()
, e.what());
#endif
alerts().emplace_alert<torrent_error_alert>(get_handle()
, e.code(), e.what());
pause();
} catch (std::exception const& e) {
#ifndef TORRENT_DISABLE_LOGGING
debug_log("EXCEPTION: %s", e.what());
#endif
alerts().emplace_alert<torrent_error_alert>(get_handle()
, error_code(), e.what());
pause();
} catch (...) {
#ifndef TORRENT_DISABLE_LOGGING
debug_log("EXCEPTION: unknown");
#endif
alerts().emplace_alert<torrent_error_alert>(get_handle()
, error_code(), "unknown error");
pause();
}
#endif
void torrent::cancel_non_critical()
{
std::set<piece_index_t> time_critical;