implemented utp extension header to indicate the reason to close the connection
This commit is contained in:
parent
c4b112f23a
commit
0c8aee014c
|
@ -17,6 +17,7 @@ set(sources
|
|||
bloom_filter
|
||||
chained_buffer
|
||||
choker
|
||||
close_reason
|
||||
crc32c
|
||||
create_torrent
|
||||
disk_buffer_holder
|
||||
|
|
1
Jamfile
1
Jamfile
|
@ -533,6 +533,7 @@ SOURCES =
|
|||
bloom_filter
|
||||
chained_buffer
|
||||
choker
|
||||
close_reason
|
||||
crc32c
|
||||
create_torrent
|
||||
disk_buffer_holder
|
||||
|
|
|
@ -26,6 +26,7 @@ nobase_include_HEADERS = \
|
|||
byteswap.hpp \
|
||||
chained_buffer.hpp \
|
||||
choker.hpp \
|
||||
close_reason.hpp \
|
||||
config.hpp \
|
||||
ConvertUTF.h \
|
||||
copy_ptr.hpp \
|
||||
|
|
|
@ -43,6 +43,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/stat.hpp"
|
||||
#include "libtorrent/rss.hpp" // for feed_handle
|
||||
#include "libtorrent/operations.hpp" // for operation_t enum
|
||||
#include "libtorrent/close_reason.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
@ -703,11 +704,13 @@ namespace libtorrent
|
|||
{
|
||||
// internal
|
||||
peer_disconnected_alert(torrent_handle const& h, tcp::endpoint const& ep
|
||||
, peer_id const& peer_id, operation_t op, int type, error_code const& e)
|
||||
, peer_id const& peer_id, operation_t op, int type, error_code const& e
|
||||
, close_reason_t r)
|
||||
: peer_alert(h, ep, peer_id)
|
||||
, socket_type(type)
|
||||
, operation(op)
|
||||
, error(e)
|
||||
, reason(r)
|
||||
{
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
msg = convert_from_native(error.message());
|
||||
|
@ -729,6 +732,9 @@ namespace libtorrent
|
|||
// tells you what error caused peer to disconnect.
|
||||
error_code error;
|
||||
|
||||
// the reason the peer disconnected (if specified)
|
||||
close_reason_t reason;
|
||||
|
||||
#ifndef TORRENT_NO_DEPRECATE
|
||||
std::string msg;
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,158 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2015, 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_CLOSE_REASON_HPP
|
||||
#define TORRENT_CLOSE_REASON_HPP
|
||||
|
||||
#include "libtorrent/error_code.hpp"
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
// these are all the reasons to disconnect a peer
|
||||
// all reasons caused by the peer sending unexpected data
|
||||
// are 256 and up.
|
||||
enum close_reason_t
|
||||
{
|
||||
// no reason specified. Generic close.
|
||||
close_no_reason = 0,
|
||||
|
||||
// we're already connected to
|
||||
close_duplicate_peer_id,
|
||||
|
||||
// this torrent has been removed, paused or stopped from this client.
|
||||
close_torrent_removed,
|
||||
|
||||
// client failed to allocate necessary memory for this peer connection
|
||||
close_no_memory,
|
||||
|
||||
// the source port of this peer is blocked
|
||||
close_port_blocked,
|
||||
|
||||
// the source IP has been blocked
|
||||
close_blocked,
|
||||
|
||||
// both ends of the connection are upload-only. staying connected would
|
||||
// be redundant
|
||||
close_upload_to_upload,
|
||||
|
||||
// connection was closed because the other end is upload only and does
|
||||
// not have any pieces we're interested in
|
||||
close_not_interested_upload_only,
|
||||
|
||||
// peer connection timed out (generic timeout)
|
||||
close_timeout,
|
||||
|
||||
// the peers have not been interested in each other for a very long time.
|
||||
// disconnect
|
||||
close_timed_out_interest,
|
||||
|
||||
// the peer has not sent any message in a long time.
|
||||
close_timed_out_activity,
|
||||
|
||||
// the peer did not complete the handshake in too long
|
||||
close_timed_out_handshake,
|
||||
|
||||
// the peer sent an interested message, but did not send a request
|
||||
// after a very long time after being unchoked.
|
||||
close_timed_out_request,
|
||||
|
||||
// the encryption mode is blocked
|
||||
close_protocol_blocked,
|
||||
|
||||
// the peer was disconnected in the hopes of finding a better peer
|
||||
// in the swarm
|
||||
close_peer_churn,
|
||||
|
||||
// we have too many peers connected
|
||||
close_too_many_connections,
|
||||
|
||||
// we have too many file-descriptors open
|
||||
close_too_many_files,
|
||||
|
||||
// the encryption handshake failed
|
||||
close_encryption_error = 256,
|
||||
|
||||
// the info hash sent as part of the handshake was not what we expected
|
||||
close_invalid_info_hash,
|
||||
|
||||
close_self_connection,
|
||||
|
||||
// the metadata received matched the info-hash, but failed to parse.
|
||||
// this is either someone finding a SHA1 collision, or the author of
|
||||
// the magnet link creating it from an invalid torrent
|
||||
close_invalid_metadata,
|
||||
|
||||
// the advertised metadata size
|
||||
close_metadata_too_big,
|
||||
|
||||
// invalid bittorrent messages
|
||||
close_message_too_big,
|
||||
close_invalid_message_id,
|
||||
close_invalid_message,
|
||||
close_invalid_piece_message,
|
||||
close_invalid_have_message,
|
||||
close_invalid_bitfield_message,
|
||||
close_invalid_choke_message,
|
||||
close_invalid_unchoke_message,
|
||||
close_invalid_interested_message,
|
||||
close_invalid_not_interested_message,
|
||||
close_invalid_request_message,
|
||||
close_invalid_reject_message,
|
||||
close_invalid_allow_fast_message,
|
||||
close_invalid_extended_message,
|
||||
close_invalid_cancel_message,
|
||||
close_invalid_dht_port_message,
|
||||
close_invalid_suggest_message,
|
||||
close_invalid_have_all_message,
|
||||
close_invalid_dont_have_message,
|
||||
close_invalid_have_none_message,
|
||||
close_invalid_pex_message,
|
||||
close_invalid_metadata_request_message,
|
||||
close_invalid_metadata_message,
|
||||
close_invalid_metadata_offset,
|
||||
|
||||
// the peer sent a request while being choked
|
||||
close_request_when_choked,
|
||||
|
||||
// the peer sent corrupt data
|
||||
close_corrupt_pieces,
|
||||
|
||||
close_pex_message_too_big,
|
||||
close_pex_too_frequent,
|
||||
|
||||
};
|
||||
|
||||
close_reason_t error_to_close_reason(error_code const& ec);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
@ -202,6 +202,11 @@ namespace libtorrent
|
|||
|
||||
void open(protocol_type const& p, error_code& ec);
|
||||
void close(error_code& ec);
|
||||
|
||||
// this is only relevant for uTP connections
|
||||
void set_close_reason(boost::uint16_t code);
|
||||
boost::uint16_t get_close_reason();
|
||||
|
||||
endpoint_type local_endpoint(error_code& ec) const;
|
||||
endpoint_type remote_endpoint(error_code& ec) const;
|
||||
void bind(endpoint_type const& endpoint, error_code& ec);
|
||||
|
|
|
@ -121,6 +121,11 @@ namespace libtorrent
|
|||
enum utp_socket_state_t
|
||||
{ ST_DATA, ST_FIN, ST_STATE, ST_RESET, ST_SYN, NUM_TYPES };
|
||||
|
||||
// extension headers. 2 is skipped because there is a deprecated
|
||||
// extension with that number in the wild
|
||||
enum utp_extensions_t
|
||||
{ utp_no_extension = 0, utp_sack = 1, utp_close_reason = 3 };
|
||||
|
||||
struct utp_header
|
||||
{
|
||||
unsigned char type_ver;
|
||||
|
@ -215,7 +220,8 @@ public:
|
|||
#endif
|
||||
|
||||
template <class GettableSocketOption>
|
||||
error_code get_option(GettableSocketOption&, error_code& ec) { return ec; }
|
||||
error_code get_option(GettableSocketOption&, error_code& ec)
|
||||
{ return ec; }
|
||||
|
||||
error_code cancel(error_code& ec)
|
||||
{
|
||||
|
@ -225,12 +231,19 @@ public:
|
|||
|
||||
void close();
|
||||
void close(error_code const& /*ec*/) { close(); }
|
||||
|
||||
void set_close_reason(boost::uint16_t code);
|
||||
boost::uint16_t get_close_reason();
|
||||
|
||||
bool is_open() const { return m_open; }
|
||||
|
||||
int read_buffer_size() const;
|
||||
static void on_read(void* self, size_t bytes_transferred, error_code const& ec, bool kill);
|
||||
static void on_write(void* self, size_t bytes_transferred, error_code const& ec, bool kill);
|
||||
static void on_read(void* self, size_t bytes_transferred
|
||||
, error_code const& ec, bool kill);
|
||||
static void on_write(void* self, size_t bytes_transferred
|
||||
, error_code const& ec, bool kill);
|
||||
static void on_connect(void* self, error_code const& ec, bool kill);
|
||||
static void on_close_reason(void* self, boost::uint16_t reason);
|
||||
|
||||
void add_read_buffer(void* buf, size_t len);
|
||||
void issue_read();
|
||||
|
@ -421,14 +434,16 @@ public:
|
|||
{
|
||||
if (m_impl == 0)
|
||||
{
|
||||
m_io_service.post(boost::bind<void>(handler, asio::error::not_connected, 0));
|
||||
m_io_service.post(boost::bind<void>(handler
|
||||
, asio::error::not_connected, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
TORRENT_ASSERT(!m_write_handler);
|
||||
if (m_write_handler)
|
||||
{
|
||||
m_io_service.post(boost::bind<void>(handler, asio::error::operation_not_supported, 0));
|
||||
m_io_service.post(boost::bind<void>(handler
|
||||
, asio::error::operation_not_supported, 0));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -453,7 +468,7 @@ public:
|
|||
issue_write();
|
||||
}
|
||||
|
||||
//private:
|
||||
private:
|
||||
|
||||
void cancel_handlers(error_code const&);
|
||||
|
||||
|
@ -464,6 +479,8 @@ public:
|
|||
asio::io_service& m_io_service;
|
||||
utp_socket_impl* m_impl;
|
||||
|
||||
boost::uint16_t m_incoming_close_reason;
|
||||
|
||||
// this field requires another 8 bytes (including padding)
|
||||
bool m_open;
|
||||
};
|
||||
|
|
|
@ -49,6 +49,7 @@ libtorrent_rasterbar_la_SOURCES = \
|
|||
bt_peer_connection.cpp \
|
||||
chained_buffer.cpp \
|
||||
choker.cpp \
|
||||
close_reason.cpp \
|
||||
ConvertUTF.cpp \
|
||||
crc32c.cpp \
|
||||
create_torrent.cpp \
|
||||
|
|
|
@ -575,8 +575,10 @@ namespace libtorrent {
|
|||
std::string peer_error_alert::message() const
|
||||
{
|
||||
char msg[200];
|
||||
snprintf(msg, sizeof(msg), "%s peer error [%s] [%s]: %s", peer_alert::message().c_str()
|
||||
, operation_name(operation), error.category().name(), convert_from_native(error.message()).c_str());
|
||||
snprintf(msg, sizeof(msg), "%s peer error [%s] [%s]: %s"
|
||||
, peer_alert::message().c_str()
|
||||
, operation_name(operation), error.category().name()
|
||||
, convert_from_native(error.message()).c_str());
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
@ -630,11 +632,12 @@ namespace libtorrent {
|
|||
std::string peer_disconnected_alert::message() const
|
||||
{
|
||||
char msg[600];
|
||||
snprintf(msg, sizeof(msg), "%s disconnecting (%s) [%s] [%s]: %s"
|
||||
snprintf(msg, sizeof(msg), "%s disconnecting (%s) [%s] [%s]: %s (reason: %d)"
|
||||
, peer_alert::message().c_str()
|
||||
, socket_type_str[socket_type]
|
||||
, operation_name(operation), error.category().name()
|
||||
, convert_from_native(error.message()).c_str());
|
||||
, convert_from_native(error.message()).c_str()
|
||||
, int(reason));
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
|
|
@ -644,8 +644,6 @@ namespace libtorrent
|
|||
|
||||
TORRENT_ASSERT(!m_rc4.get());
|
||||
m_rc4 = boost::make_shared<rc4_handler>();
|
||||
m_rc4->set_incoming_key(&remote_key[0], 20);
|
||||
m_rc4->set_outgoing_key(&local_key[0], 20);
|
||||
|
||||
if (!m_rc4)
|
||||
{
|
||||
|
@ -653,6 +651,9 @@ namespace libtorrent
|
|||
return;
|
||||
}
|
||||
|
||||
m_rc4->set_incoming_key(&remote_key[0], 20);
|
||||
m_rc4->set_outgoing_key(&local_key[0], 20);
|
||||
|
||||
#ifdef TORRENT_LOGGING
|
||||
peer_log(" computed RC4 keys");
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,182 @@
|
|||
/*
|
||||
|
||||
Copyright (c) 2015, 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.
|
||||
|
||||
*/
|
||||
|
||||
#include "libtorrent/close_reason.hpp"
|
||||
#include "libtorrent/error_code.hpp"
|
||||
#include "libtorrent/assert.hpp"
|
||||
|
||||
#include <boost/asio/error.hpp>
|
||||
|
||||
namespace libtorrent
|
||||
{
|
||||
|
||||
close_reason_t error_to_close_reason(error_code const& ec)
|
||||
{
|
||||
if (ec.category() == get_libtorrent_category())
|
||||
{
|
||||
#define TORRENT_MAP(error, close_reason) \
|
||||
case errors:: error : \
|
||||
return close_reason;
|
||||
|
||||
switch (ec.value())
|
||||
{
|
||||
TORRENT_MAP(invalid_swarm_metadata, close_invalid_metadata)
|
||||
TORRENT_MAP(session_is_closing, close_torrent_removed)
|
||||
TORRENT_MAP(peer_sent_empty_piece, close_invalid_piece_message)
|
||||
TORRENT_MAP(mismatching_info_hash, close_invalid_info_hash)
|
||||
TORRENT_MAP(port_blocked, close_port_blocked)
|
||||
TORRENT_MAP(destructing_torrent, close_torrent_removed)
|
||||
TORRENT_MAP(timed_out, close_timeout)
|
||||
TORRENT_MAP(upload_upload_connection, close_upload_to_upload)
|
||||
TORRENT_MAP(uninteresting_upload_peer, close_not_interested_upload_only)
|
||||
TORRENT_MAP(invalid_info_hash, close_invalid_info_hash)
|
||||
TORRENT_MAP(torrent_paused, close_torrent_removed)
|
||||
TORRENT_MAP(invalid_have, close_invalid_have_message)
|
||||
TORRENT_MAP(invalid_bitfield_size, close_invalid_bitfield_message)
|
||||
TORRENT_MAP(too_many_requests_when_choked, close_request_when_choked)
|
||||
TORRENT_MAP(invalid_piece, close_invalid_piece_message)
|
||||
TORRENT_MAP(invalid_piece_size, close_invalid_piece_message)
|
||||
TORRENT_MAP(no_memory, close_no_memory)
|
||||
TORRENT_MAP(torrent_aborted, close_torrent_removed)
|
||||
TORRENT_MAP(self_connection, close_self_connection)
|
||||
TORRENT_MAP(timed_out_no_interest, close_timed_out_interest)
|
||||
TORRENT_MAP(timed_out_inactivity, close_timed_out_activity)
|
||||
TORRENT_MAP(timed_out_no_handshake, close_timed_out_handshake)
|
||||
TORRENT_MAP(timed_out_no_request, close_timed_out_request)
|
||||
TORRENT_MAP(invalid_choke, close_invalid_choke_message)
|
||||
TORRENT_MAP(invalid_unchoke, close_invalid_unchoke_message)
|
||||
TORRENT_MAP(invalid_interested, close_invalid_interested_message)
|
||||
TORRENT_MAP(invalid_not_interested, close_invalid_not_interested_message)
|
||||
TORRENT_MAP(invalid_request, close_invalid_request_message)
|
||||
TORRENT_MAP(invalid_hash_list, close_invalid_message)
|
||||
TORRENT_MAP(invalid_hash_piece, close_invalid_message)
|
||||
TORRENT_MAP(invalid_cancel, close_invalid_cancel_message)
|
||||
TORRENT_MAP(invalid_dht_port, close_invalid_dht_port_message)
|
||||
TORRENT_MAP(invalid_suggest, close_invalid_suggest_message)
|
||||
TORRENT_MAP(invalid_have_all, close_invalid_have_all_message)
|
||||
TORRENT_MAP(invalid_have_none, close_invalid_have_none_message)
|
||||
TORRENT_MAP(invalid_reject, close_invalid_reject_message)
|
||||
TORRENT_MAP(invalid_allow_fast, close_invalid_allow_fast_message)
|
||||
TORRENT_MAP(invalid_extended, close_invalid_extended_message)
|
||||
TORRENT_MAP(invalid_message, close_invalid_message_id)
|
||||
TORRENT_MAP(sync_hash_not_found, close_encryption_error)
|
||||
TORRENT_MAP(invalid_encryption_constant, close_encryption_error)
|
||||
TORRENT_MAP(no_plaintext_mode, close_protocol_blocked)
|
||||
TORRENT_MAP(no_rc4_mode, close_protocol_blocked)
|
||||
TORRENT_MAP(unsupported_encryption_mode_selected, close_protocol_blocked)
|
||||
TORRENT_MAP(invalid_pad_size, close_encryption_error)
|
||||
TORRENT_MAP(invalid_encrypt_handshake, close_encryption_error)
|
||||
TORRENT_MAP(no_incoming_encrypted, close_protocol_blocked)
|
||||
TORRENT_MAP(no_incoming_regular, close_protocol_blocked)
|
||||
TORRENT_MAP(duplicate_peer_id, close_duplicate_peer_id)
|
||||
TORRENT_MAP(torrent_removed, close_torrent_removed)
|
||||
TORRENT_MAP(packet_too_large, close_message_too_big)
|
||||
TORRENT_MAP(torrent_not_ready, close_torrent_removed)
|
||||
TORRENT_MAP(session_closing, close_torrent_removed)
|
||||
TORRENT_MAP(optimistic_disconnect, close_peer_churn)
|
||||
TORRENT_MAP(torrent_finished, close_upload_to_upload)
|
||||
TORRENT_MAP(too_many_corrupt_pieces, close_corrupt_pieces)
|
||||
TORRENT_MAP(too_many_connections, close_too_many_connections)
|
||||
TORRENT_MAP(peer_banned, close_blocked)
|
||||
TORRENT_MAP(stopping_torrent, close_torrent_removed)
|
||||
TORRENT_MAP(metadata_too_large, close_metadata_too_big)
|
||||
TORRENT_MAP(invalid_metadata_size, close_metadata_too_big)
|
||||
TORRENT_MAP(invalid_metadata_request, close_invalid_metadata_request_message)
|
||||
TORRENT_MAP(invalid_metadata_offset, close_invalid_metadata_offset)
|
||||
TORRENT_MAP(invalid_metadata_message, close_invalid_metadata_message)
|
||||
TORRENT_MAP(pex_message_too_large, close_pex_message_too_big)
|
||||
TORRENT_MAP(invalid_pex_message, close_invalid_pex_message)
|
||||
TORRENT_MAP(invalid_lt_tracker_message, close_invalid_message)
|
||||
TORRENT_MAP(too_frequent_pex, close_pex_too_frequent)
|
||||
TORRENT_MAP(invalid_dont_have, close_invalid_dont_have_message)
|
||||
TORRENT_MAP(requires_ssl_connection, close_protocol_blocked)
|
||||
TORRENT_MAP(invalid_ssl_cert, close_blocked)
|
||||
TORRENT_MAP(not_an_ssl_torrent, close_blocked)
|
||||
TORRENT_MAP(banned_by_port_filter, close_port_blocked)
|
||||
|
||||
#ifdef TORRENT_USE_ASSERTS
|
||||
case errors::redirecting:
|
||||
return close_no_reason;
|
||||
#endif
|
||||
|
||||
default:
|
||||
// we should include this error code in the map
|
||||
fprintf(stderr, "(%s : %d) %s\n", ec.category().name(), ec.value()
|
||||
, ec.message().c_str());
|
||||
TORRENT_ASSERT(false);
|
||||
return close_no_reason;
|
||||
}
|
||||
}
|
||||
else if (ec.category() == boost::asio::error::get_misc_category())
|
||||
{
|
||||
switch (ec.value())
|
||||
{
|
||||
case boost::asio::error::eof:
|
||||
return close_no_reason;
|
||||
}
|
||||
}
|
||||
else if (ec.category() == boost::system::system_category())
|
||||
{
|
||||
switch (ec.value())
|
||||
{
|
||||
#ifdef TORRENT_USE_ASSERTS
|
||||
case boost::system::errc::connection_reset:
|
||||
case boost::system::errc::broken_pipe:
|
||||
return close_no_reason;
|
||||
#endif
|
||||
case boost::system::errc::timed_out:
|
||||
return close_timeout;
|
||||
case boost::system::errc::too_many_files_open:
|
||||
case boost::system::errc::too_many_files_open_in_system:
|
||||
return close_too_many_files;
|
||||
case boost::system::errc::not_enough_memory:
|
||||
case boost::system::errc::no_buffer_space:
|
||||
return close_no_memory;
|
||||
}
|
||||
}
|
||||
else if (ec.category() == get_http_category())
|
||||
{
|
||||
return close_no_memory;
|
||||
}
|
||||
|
||||
fprintf(stderr, "(%s : %d) %s\n", ec.category().name(), ec.value()
|
||||
, ec.message().c_str());
|
||||
|
||||
// we should proboably include this in the map
|
||||
TORRENT_ASSERT(false);
|
||||
|
||||
// TODO: map some system errors too?
|
||||
|
||||
return close_no_reason;
|
||||
}
|
||||
}
|
||||
|
|
@ -70,6 +70,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
|||
#include "libtorrent/alert_manager.hpp" // for alert_manageralert_manager
|
||||
#include "libtorrent/ip_filter.hpp"
|
||||
#include "libtorrent/kademlia/node_id.hpp"
|
||||
#include "libtorrent/close_reason.hpp"
|
||||
|
||||
#ifdef TORRENT_DEBUG
|
||||
#include <set>
|
||||
|
@ -2290,8 +2291,13 @@ namespace libtorrent
|
|||
// every ten invalid request, remind the peer that it's choked
|
||||
if (!m_peer_interested && m_num_invalid_requests % 10 == 0 && m_choked)
|
||||
{
|
||||
// TODO: 2 this should probably be based on time instead of number
|
||||
// of request messages. For a very high throughput connection, 300
|
||||
// may be a legitimate number of requests to have in flight when
|
||||
// getting choked
|
||||
if (m_num_invalid_requests > 300 && !m_peer_choked
|
||||
&& can_disconnect(error_code(errors::too_many_requests_when_choked, get_libtorrent_category())))
|
||||
&& can_disconnect(error_code(errors::too_many_requests_when_choked
|
||||
, get_libtorrent_category())))
|
||||
{
|
||||
disconnect(errors::too_many_requests_when_choked, op_bittorrent, 2);
|
||||
return;
|
||||
|
@ -3908,6 +3914,15 @@ namespace libtorrent
|
|||
|
||||
if (m_disconnecting) return;
|
||||
|
||||
m_socket->set_close_reason(error_to_close_reason(ec));
|
||||
close_reason_t close_reason = (close_reason_t)m_socket->get_close_reason();
|
||||
#if defined TORRENT_LOGGING
|
||||
if (close_reason != 0)
|
||||
{
|
||||
peer_log("*** CLOSE REASON [ %d ]", int(close_reason));
|
||||
}
|
||||
#endif
|
||||
|
||||
// while being disconnected, it's possible that our torrent_peer
|
||||
// pointer gets cleared. Make sure we save it to be able to keep
|
||||
// proper books in the piece_picker (when debugging is enabled)
|
||||
|
@ -4078,11 +4093,12 @@ namespace libtorrent
|
|||
t->alerts().post_alert(
|
||||
peer_error_alert(handle, remote(), pid(), op, ec));
|
||||
}
|
||||
else if (error <= 1 && t->alerts().should_post<peer_disconnected_alert>())
|
||||
|
||||
if (error <= 1 && t->alerts().should_post<peer_disconnected_alert>())
|
||||
{
|
||||
t->alerts().post_alert(
|
||||
peer_disconnected_alert(handle, remote(), pid(), op
|
||||
, m_socket->type(), ec));
|
||||
, m_socket->type(), ec, close_reason));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4657,7 +4673,7 @@ namespace libtorrent
|
|||
&& d2 > time_limit
|
||||
&& (m_ses.num_connections() >= m_settings.get_int(settings_pack::connections_limit)
|
||||
|| (t && t->num_peers() >= t->max_connections()))
|
||||
&& can_disconnect(error_code(errors::timed_out_no_interest, get_libtorrent_category())))
|
||||
&& can_disconnect(error_code(errors::timed_out_no_interest)))
|
||||
{
|
||||
#if defined TORRENT_LOGGING
|
||||
peer_log("*** MUTUAL NO INTEREST [ t1: %d t2: %d ]"
|
||||
|
@ -6404,12 +6420,12 @@ namespace libtorrent
|
|||
if (m_settings.get_bool(settings_pack::close_redundant_connections) && !t->share_mode())
|
||||
{
|
||||
bool ok_to_disconnect =
|
||||
can_disconnect(error_code(errors::upload_upload_connection, get_libtorrent_category()))
|
||||
|| can_disconnect(error_code(errors::uninteresting_upload_peer, get_libtorrent_category()))
|
||||
|| can_disconnect(error_code(errors::too_many_requests_when_choked, get_libtorrent_category()))
|
||||
|| can_disconnect(error_code(errors::timed_out_no_interest, get_libtorrent_category()))
|
||||
|| can_disconnect(error_code(errors::timed_out_no_request, get_libtorrent_category()))
|
||||
|| can_disconnect(error_code(errors::timed_out_inactivity, get_libtorrent_category()));
|
||||
can_disconnect(error_code(errors::upload_upload_connection))
|
||||
|| can_disconnect(error_code(errors::uninteresting_upload_peer))
|
||||
|| can_disconnect(error_code(errors::too_many_requests_when_choked))
|
||||
|| can_disconnect(error_code(errors::timed_out_no_interest))
|
||||
|| can_disconnect(error_code(errors::timed_out_no_request))
|
||||
|| can_disconnect(error_code(errors::timed_out_inactivity));
|
||||
|
||||
// make sure upload only peers are disconnected
|
||||
if (t->is_upload_only()
|
||||
|
|
|
@ -2513,7 +2513,8 @@ retry:
|
|||
m_alerts.post_alert(
|
||||
peer_disconnected_alert(torrent_handle(), endp, peer_id()
|
||||
, op_bittorrent, s->type()
|
||||
, error_code(errors::too_many_connections, get_libtorrent_category())));
|
||||
, error_code(errors::too_many_connections, get_libtorrent_category())
|
||||
, close_no_reason));
|
||||
}
|
||||
#if defined TORRENT_LOGGING
|
||||
session_log("number of connections limit exceeded (conns: %d, limit: %d, slack: %d), connection rejected"
|
||||
|
|
|
@ -301,6 +301,36 @@ namespace libtorrent
|
|||
TORRENT_SOCKTYPE_FORWARD(close(ec))
|
||||
}
|
||||
|
||||
void socket_type::set_close_reason(boost::uint16_t code)
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case socket_type_int_impl<utp_stream>::value:
|
||||
get<utp_stream>()->set_close_reason(code);
|
||||
break;
|
||||
#ifdef TORRENT_USE_OPENSSL
|
||||
case socket_type_int_impl<ssl_stream<utp_stream> >::value:
|
||||
get<ssl_stream<utp_stream> >()->set_close_reason(boost::uint16_t code);
|
||||
break;
|
||||
#endif
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
boost::uint16_t socket_type::get_close_reason()
|
||||
{
|
||||
switch (m_type)
|
||||
{
|
||||
case socket_type_int_impl<utp_stream>::value:
|
||||
return get<utp_stream>()->get_close_reason();
|
||||
#ifdef TORRENT_USE_OPENSSL
|
||||
case socket_type_int_impl<ssl_stream<utp_stream> >::value:
|
||||
return get<ssl_stream<utp_stream> >()->get_close_reason();
|
||||
#endif
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
socket_type::endpoint_type socket_type::local_endpoint(error_code& ec) const
|
||||
{ TORRENT_SOCKTYPE_FORWARD_RET(local_endpoint(ec), socket_type::endpoint_type()) }
|
||||
|
||||
|
|
|
@ -252,6 +252,7 @@ struct utp_socket_impl
|
|||
, m_out_packets(0)
|
||||
, m_send_delay(0)
|
||||
, m_recv_delay(0)
|
||||
, m_close_reason(0)
|
||||
, m_port(0)
|
||||
, m_send_id(send_id)
|
||||
, m_recv_id(recv_id)
|
||||
|
@ -306,6 +307,7 @@ struct utp_socket_impl
|
|||
// returns true if there were handlers cancelled
|
||||
// if it returns false, we can detach immediately
|
||||
bool destroy();
|
||||
void set_close_reason(boost::uint16_t code);
|
||||
void detach();
|
||||
void send_syn();
|
||||
void send_fin();
|
||||
|
@ -318,8 +320,9 @@ struct utp_socket_impl
|
|||
bool send_pkt(int flags = 0);
|
||||
bool resend_packet(packet* p, bool fast_resend = false);
|
||||
void send_reset(utp_header* ph);
|
||||
void parse_sack(boost::uint16_t packet_ack, boost::uint8_t const* ptr, int size, int* acked_bytes
|
||||
, ptime const now, boost::uint32_t& min_rtt);
|
||||
void parse_sack(boost::uint16_t packet_ack, boost::uint8_t const* ptr
|
||||
, int size, int* acked_bytes, ptime const now, boost::uint32_t& min_rtt);
|
||||
void parse_close_reason(boost::uint8_t const* ptr, int size);
|
||||
void write_payload(boost::uint8_t* ptr, int size);
|
||||
void maybe_inc_acked_seq_nr();
|
||||
void ack_packet(packet* p, ptime const& receive_time
|
||||
|
@ -514,6 +517,11 @@ public:
|
|||
// average RTT
|
||||
sliding_average<16> m_rtt;
|
||||
|
||||
// if this is != 0, it means the upper layer provided a reason for why
|
||||
// the connection is being closed. The reason is indicated by this
|
||||
// non-zero value which is included in a packet header extension
|
||||
boost::uint16_t m_close_reason;
|
||||
|
||||
// port of destination endpoint
|
||||
boost::uint16_t m_port;
|
||||
|
||||
|
@ -789,6 +797,7 @@ int utp_stream::recv_delay() const
|
|||
utp_stream::utp_stream(asio::io_service& io_service)
|
||||
: m_io_service(io_service)
|
||||
, m_impl(0)
|
||||
, m_incoming_close_reason(0)
|
||||
, m_open(false)
|
||||
{
|
||||
}
|
||||
|
@ -798,6 +807,17 @@ utp_socket_impl* utp_stream::get_impl()
|
|||
return m_impl;
|
||||
}
|
||||
|
||||
void utp_stream::set_close_reason(boost::uint16_t code)
|
||||
{
|
||||
if (!m_impl) return;
|
||||
m_impl->set_close_reason(code);
|
||||
}
|
||||
|
||||
boost::uint16_t utp_stream::get_close_reason()
|
||||
{
|
||||
return m_incoming_close_reason;
|
||||
}
|
||||
|
||||
void utp_stream::close()
|
||||
{
|
||||
if (!m_impl) return;
|
||||
|
@ -860,7 +880,15 @@ int utp_stream::read_buffer_size() const
|
|||
return m_impl->m_receive_buffer_size;
|
||||
}
|
||||
|
||||
void utp_stream::on_read(void* self, size_t bytes_transferred, error_code const& ec, bool kill)
|
||||
void utp_stream::on_close_reason(void* self, boost::uint16_t close_reason)
|
||||
{
|
||||
utp_stream* s = (utp_stream*)self;
|
||||
TORRENT_ASSERT(s->m_impl);
|
||||
s->m_incoming_close_reason = close_reason;
|
||||
}
|
||||
|
||||
void utp_stream::on_read(void* self, size_t bytes_transferred
|
||||
, error_code const& ec, bool kill)
|
||||
{
|
||||
utp_stream* s = (utp_stream*)self;
|
||||
|
||||
|
@ -882,7 +910,8 @@ void utp_stream::on_read(void* self, size_t bytes_transferred, error_code const&
|
|||
// tmp(ec, bytes_transferred);
|
||||
}
|
||||
|
||||
void utp_stream::on_write(void* self, size_t bytes_transferred, error_code const& ec, bool kill)
|
||||
void utp_stream::on_write(void* self, size_t bytes_transferred
|
||||
, error_code const& ec, bool kill)
|
||||
{
|
||||
utp_stream* s = (utp_stream*)self;
|
||||
|
||||
|
@ -1227,12 +1256,22 @@ void utp_socket_impl::maybe_trigger_send_callback()
|
|||
m_write_buffer.clear();
|
||||
}
|
||||
|
||||
void utp_socket_impl::set_close_reason(boost::uint16_t code)
|
||||
{
|
||||
#if TORRENT_UTP_LOG
|
||||
UTP_LOGV("%8p: set_close_reason: %d\n"
|
||||
, this, int(m_close_reason));
|
||||
#endif
|
||||
m_close_reason = code;
|
||||
}
|
||||
|
||||
bool utp_socket_impl::destroy()
|
||||
{
|
||||
INVARIANT_CHECK;
|
||||
|
||||
#if TORRENT_UTP_LOG
|
||||
UTP_LOGV("%8p: destroy state:%s\n", this, socket_state_names[m_state]);
|
||||
UTP_LOGV("%8p: destroy state:%s (close-reason: %d)\n"
|
||||
, this, socket_state_names[m_state], int(m_close_reason));
|
||||
#endif
|
||||
|
||||
if (m_userdata == 0) return false;
|
||||
|
@ -1293,7 +1332,7 @@ void utp_socket_impl::send_syn()
|
|||
p->need_resend = false;
|
||||
utp_header* h = (utp_header*)p->buf;
|
||||
h->type_ver = (ST_SYN << 4) | 1;
|
||||
h->extension = 0;
|
||||
h->extension = utp_no_extension;
|
||||
// using recv_id here is intentional! This is an odd
|
||||
// thing in uTP. The syn packet is sent with the connection
|
||||
// ID that it expects to receive the syn ack on. All
|
||||
|
@ -1392,7 +1431,7 @@ void utp_socket_impl::send_reset(utp_header* ph)
|
|||
|
||||
utp_header h;
|
||||
h.type_ver = (ST_RESET << 4) | 1;
|
||||
h.extension = 0;
|
||||
h.extension = utp_no_extension;
|
||||
h.connection_id = m_send_id;
|
||||
h.timestamp_difference_microseconds = m_reply_micro;
|
||||
h.wnd_size = 0;
|
||||
|
@ -1415,6 +1454,21 @@ std::size_t utp_socket_impl::available() const
|
|||
return m_receive_buffer_size;
|
||||
}
|
||||
|
||||
void utp_socket_impl::parse_close_reason(boost::uint8_t const* ptr, int size)
|
||||
{
|
||||
if (size != 4) return;
|
||||
// skip reserved bytes
|
||||
ptr += 2;
|
||||
boost::uint16_t incoming_close_reason = detail::read_uint16(ptr);
|
||||
|
||||
UTP_LOGV("%8p: incoming close_reason: %d\n"
|
||||
, this, int(incoming_close_reason));
|
||||
|
||||
if (m_userdata == 0) return;
|
||||
|
||||
utp_stream::on_close_reason(m_userdata, incoming_close_reason);
|
||||
}
|
||||
|
||||
void utp_socket_impl::parse_sack(boost::uint16_t packet_ack, boost::uint8_t const* ptr
|
||||
, int size, int* acked_bytes, ptime const now, boost::uint32_t& min_rtt)
|
||||
{
|
||||
|
@ -1600,11 +1654,12 @@ void utp_socket_impl::remove_sack_header(packet* p)
|
|||
boost::uint8_t* ptr = p->buf + sizeof(utp_header);
|
||||
utp_header* h = (utp_header*)p->buf;
|
||||
|
||||
TORRENT_ASSERT(h->extension == 1);
|
||||
TORRENT_ASSERT(h->extension == utp_sack);
|
||||
|
||||
h->extension = ptr[0];
|
||||
int sack_size = ptr[1];
|
||||
TORRENT_ASSERT(h->extension == 0);
|
||||
TORRENT_ASSERT(h->extension == utp_no_extension
|
||||
|| h->extension == utp_close_reason);
|
||||
|
||||
UTP_LOGV("%8p: removing SACK header, %d bytes\n"
|
||||
, this, sack_size + 2);
|
||||
|
@ -1655,7 +1710,8 @@ bool utp_socket_impl::send_pkt(int flags)
|
|||
|
||||
// first see if we need to resend any packets
|
||||
|
||||
// TODO: this loop may not be very efficient
|
||||
// TODO: this loop is not very efficient. It could be fixed by having
|
||||
// a separate list of sequence numbers that need resending
|
||||
for (int i = (m_acked_seq_nr + 1) & ACK_MASK; i != m_seq_nr; i = (i + 1) & ACK_MASK)
|
||||
{
|
||||
packet* p = (packet*)m_outbuf.at(i);
|
||||
|
@ -1687,7 +1743,11 @@ bool utp_socket_impl::send_pkt(int flags)
|
|||
if (sack > 32) sack = 32;
|
||||
}
|
||||
|
||||
int header_size = sizeof(utp_header) + (sack ? sack + 2 : 0);
|
||||
boost::uint32_t close_reason = m_close_reason;
|
||||
|
||||
int header_size = sizeof(utp_header)
|
||||
+ (sack ? sack + 2 : 0)
|
||||
+ (close_reason ? 6 : 0);
|
||||
int payload_size = m_write_buffer_size;
|
||||
if (m_mtu - header_size < payload_size)
|
||||
payload_size = m_mtu - header_size;
|
||||
|
@ -1798,7 +1858,8 @@ bool utp_socket_impl::send_pkt(int flags)
|
|||
h = (utp_header*)ptr;
|
||||
ptr += sizeof(utp_header);
|
||||
|
||||
h->extension = sack ? 1 : 0;
|
||||
h->extension = sack ? utp_sack
|
||||
: close_reason ? utp_close_reason : utp_no_extension;
|
||||
h->connection_id = m_send_id;
|
||||
// seq_nr is ignored for ST_STATE packets, so it doesn't
|
||||
// matter that we say this is a sequence number we haven't
|
||||
|
@ -1819,7 +1880,7 @@ bool utp_socket_impl::send_pkt(int flags)
|
|||
|
||||
// if the packet has a selective force header, we'll need
|
||||
// to update it
|
||||
if (h->extension == 1)
|
||||
if (h->extension == utp_sack)
|
||||
{
|
||||
sack = ptr[1];
|
||||
// if we no longer have any out-of-order packets waiting
|
||||
|
@ -1864,13 +1925,20 @@ bool utp_socket_impl::send_pkt(int flags)
|
|||
|
||||
if (sack)
|
||||
{
|
||||
*ptr++ = 0; // end of extension chain
|
||||
*ptr++ = close_reason ? utp_close_reason : utp_no_extension;
|
||||
*ptr++ = sack; // bytes for SACK bitfield
|
||||
write_sack(ptr, sack);
|
||||
ptr += sack;
|
||||
TORRENT_ASSERT(ptr <= p->buf + p->header_size);
|
||||
}
|
||||
|
||||
if (close_reason)
|
||||
{
|
||||
*ptr++ = utp_no_extension;
|
||||
*ptr++ = 4;
|
||||
detail::write_uint32(close_reason, ptr);
|
||||
}
|
||||
|
||||
if (m_bytes_in_flight > 0
|
||||
&& p->size < p->allocated
|
||||
&& !force
|
||||
|
@ -2114,7 +2182,7 @@ bool utp_socket_impl::resend_packet(packet* p, bool fast_resend)
|
|||
|
||||
// if the packet has a selective ack header, we'll need
|
||||
// to update it
|
||||
if (h->extension == 1 && h->ack_nr != m_ack_nr)
|
||||
if (h->extension == utp_sack && h->ack_nr != m_ack_nr)
|
||||
{
|
||||
boost::uint8_t* ptr = p->buf + sizeof(utp_header);
|
||||
int sack_size = ptr[1];
|
||||
|
@ -2842,9 +2910,12 @@ bool utp_socket_impl::incoming_packet(boost::uint8_t const* buf, int size
|
|||
}
|
||||
switch(extension)
|
||||
{
|
||||
case 1: // selective ACKs
|
||||
case utp_sack: // selective ACKs
|
||||
parse_sack(ph->ack_nr, ptr, len, &acked_bytes, receive_time, min_rtt);
|
||||
break;
|
||||
case utp_close_reason:
|
||||
parse_close_reason(ptr, len);
|
||||
break;
|
||||
}
|
||||
ptr += len;
|
||||
extension = next_extension;
|
||||
|
|
Loading…
Reference in New Issue