diff --git a/include/libtorrent/Makefile.am b/include/libtorrent/Makefile.am index 84b367857..57c7a1b38 100644 --- a/include/libtorrent/Makefile.am +++ b/include/libtorrent/Makefile.am @@ -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 \ diff --git a/include/libtorrent/aux_/torrent_impl.hpp b/include/libtorrent/aux_/torrent_impl.hpp new file mode 100644 index 000000000..d7f99a305 --- /dev/null +++ b/include/libtorrent/aux_/torrent_impl.hpp @@ -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 + void torrent::wrap(Fun f, Args&&... a) +#ifndef BOOST_NO_EXCEPTIONS + try +#endif + { + (this->*f)(std::forward(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(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(get_handle() + , error_code(), e.what()); + pause(); + } catch (...) { +#ifndef TORRENT_DISABLE_LOGGING + debug_log("EXCEPTION: unknown"); +#endif + alerts().emplace_alert(get_handle() + , error_code(), "unknown error"); + pause(); + } +#endif + +} + +#endif + diff --git a/include/libtorrent/config.hpp b/include/libtorrent/config.hpp index b1af8979c..814ea7d66 100644 --- a/include/libtorrent/config.hpp +++ b/include/libtorrent/config.hpp @@ -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 diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index e502a2d33..c4dc8f829 100644 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -989,6 +989,10 @@ namespace aux { bandwidth_channel m_bandwidth_channel[num_channels]; protected: + + template + void wrap(Fun f, Args&&... a); + // statistics about upload and download speeds // and total amount of uploads and downloads for // this peer diff --git a/include/libtorrent/utp_stream.hpp b/include/libtorrent/utp_stream.hpp index c5d58bbb5..a6ea95dec 100644 --- a/include/libtorrent/utp_stream.hpp +++ b/include/libtorrent/utp_stream.hpp @@ -301,13 +301,13 @@ struct TORRENT_EXTRA_EXPORT utp_stream { if (!endpoint.address().is_v4()) { - m_io_service.post(std::bind(handler, boost::asio::error::operation_not_supported, 0)); + m_io_service.post(std::bind(handler, boost::asio::error::operation_not_supported)); return; } if (m_impl == nullptr) { - m_io_service.post(std::bind(handler, boost::asio::error::not_connected, 0)); + m_io_service.post(std::bind(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(handler, boost::asio::error::not_connected, 0)); + m_io_service.post(std::bind(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(handler, boost::asio::error::operation_not_supported, 0)); + m_io_service.post(std::bind(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(handler, error_code(), 0)); + m_io_service.post(std::bind(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(handler, boost::asio::error::not_connected, 0)); + m_io_service.post(std::bind(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(handler, boost::asio::error::operation_not_supported, 0)); + m_io_service.post(std::bind(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(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(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(handler, error_code(), 0)); + m_io_service.post(std::bind(handler, error_code(), std::size_t(0))); return; } m_write_handler = handler; diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 0a801da7e..83259b9d7 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -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 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 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 + void peer_connection::wrap(Fun f, Args&&... a) +#ifndef BOOST_NO_EXCEPTIONS + try +#endif + { + (this->*f)(std::forward(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)); } diff --git a/src/torrent.cpp b/src/torrent.cpp index 61e1cb088..420b29af6 100644 --- a/src/torrent.cpp +++ b/src/torrent.cpp @@ -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 - void torrent::wrap(Fun f, Args&&... a) -#ifndef BOOST_NO_EXCEPTIONS - try -#endif - { - (this->*f)(std::forward(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(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(get_handle() - , error_code(), e.what()); - pause(); - } catch (...) { -#ifndef TORRENT_DISABLE_LOGGING - debug_log("EXCEPTION: unknown"); -#endif - alerts().emplace_alert(get_handle() - , error_code(), "unknown error"); - pause(); - } -#endif - void torrent::cancel_non_critical() { std::set time_critical;