2006-04-25 23:04:48 +02:00
|
|
|
/*
|
|
|
|
|
2015-06-03 07:18:48 +02:00
|
|
|
Copyright (c) 2003-2015, Arvid Norberg
|
|
|
|
Copyright (c) 2007-2015, Arvid Norberg, Un Shyam
|
2006-04-25 23:04:48 +02:00
|
|
|
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 <vector>
|
2009-11-28 23:41:21 +01:00
|
|
|
#include <boost/limits.hpp>
|
2006-04-25 23:04:48 +02:00
|
|
|
#include <boost/bind.hpp>
|
|
|
|
|
2011-09-05 07:50:41 +02:00
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
|
|
|
#include <memory> // autp_ptr
|
|
|
|
#endif
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
#include "libtorrent/bt_peer_connection.hpp"
|
|
|
|
#include "libtorrent/session.hpp"
|
|
|
|
#include "libtorrent/identify_client.hpp"
|
|
|
|
#include "libtorrent/entry.hpp"
|
|
|
|
#include "libtorrent/bencode.hpp"
|
|
|
|
#include "libtorrent/alert_types.hpp"
|
|
|
|
#include "libtorrent/invariant_check.hpp"
|
|
|
|
#include "libtorrent/io.hpp"
|
2010-11-29 02:33:05 +01:00
|
|
|
#include "libtorrent/socket_io.hpp"
|
2006-04-25 23:04:48 +02:00
|
|
|
#include "libtorrent/version.hpp"
|
2006-11-14 01:08:16 +01:00
|
|
|
#include "libtorrent/extensions.hpp"
|
2014-07-06 21:18:00 +02:00
|
|
|
#include "libtorrent/aux_/session_interface.hpp"
|
2015-05-03 04:53:54 +02:00
|
|
|
#include "libtorrent/alert_types.hpp"
|
2008-12-26 08:00:21 +01:00
|
|
|
#include "libtorrent/broadcast_socket.hpp"
|
2009-11-26 06:45:43 +01:00
|
|
|
#include "libtorrent/peer_info.hpp"
|
2011-02-26 08:55:51 +01:00
|
|
|
#include "libtorrent/random.hpp"
|
2011-05-19 04:41:28 +02:00
|
|
|
#include "libtorrent/alloca.hpp"
|
2014-07-06 21:18:00 +02:00
|
|
|
#include "libtorrent/socket_type.hpp"
|
|
|
|
#include "libtorrent/performance_counters.hpp" // for counters
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
2007-06-06 02:41:20 +02:00
|
|
|
#include "libtorrent/pe_crypto.hpp"
|
|
|
|
#include "libtorrent/hasher.hpp"
|
|
|
|
#endif
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
using boost::shared_ptr;
|
|
|
|
|
|
|
|
namespace libtorrent
|
|
|
|
{
|
|
|
|
const bt_peer_connection::message_handler
|
|
|
|
bt_peer_connection::m_message_handler[] =
|
|
|
|
{
|
|
|
|
&bt_peer_connection::on_choke,
|
|
|
|
&bt_peer_connection::on_unchoke,
|
|
|
|
&bt_peer_connection::on_interested,
|
|
|
|
&bt_peer_connection::on_not_interested,
|
|
|
|
&bt_peer_connection::on_have,
|
|
|
|
&bt_peer_connection::on_bitfield,
|
|
|
|
&bt_peer_connection::on_request,
|
|
|
|
&bt_peer_connection::on_piece,
|
|
|
|
&bt_peer_connection::on_cancel,
|
|
|
|
&bt_peer_connection::on_dht_port,
|
2007-08-14 19:47:48 +02:00
|
|
|
0, 0, 0,
|
|
|
|
// FAST extension messages
|
|
|
|
&bt_peer_connection::on_suggest_piece,
|
|
|
|
&bt_peer_connection::on_have_all,
|
|
|
|
&bt_peer_connection::on_have_none,
|
|
|
|
&bt_peer_connection::on_reject_request,
|
|
|
|
&bt_peer_connection::on_allowed_fast,
|
2013-12-20 09:35:29 +01:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
2007-08-14 19:47:48 +02:00
|
|
|
0, 0,
|
2006-04-25 23:04:48 +02:00
|
|
|
&bt_peer_connection::on_extended
|
2013-12-20 09:35:29 +01:00
|
|
|
#endif
|
2006-04-25 23:04:48 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2014-07-14 06:32:41 +02:00
|
|
|
bt_peer_connection::bt_peer_connection(peer_connection_args const& pack
|
|
|
|
, peer_id const& pid)
|
|
|
|
: peer_connection(pack)
|
2007-06-06 02:41:20 +02:00
|
|
|
, m_state(read_protocol_identifier)
|
2006-04-25 23:04:48 +02:00
|
|
|
, m_supports_extensions(false)
|
|
|
|
, m_supports_dht_port(false)
|
2007-08-14 19:47:48 +02:00
|
|
|
, m_supports_fast(false)
|
2006-11-14 01:08:16 +01:00
|
|
|
, m_sent_bitfield(false)
|
2007-07-09 06:22:38 +02:00
|
|
|
, m_sent_handshake(false)
|
2014-11-23 07:14:47 +01:00
|
|
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
2013-12-02 05:24:10 +01:00
|
|
|
, m_encrypted(false)
|
|
|
|
, m_rc4_encrypted(false)
|
2014-11-23 07:14:47 +01:00
|
|
|
, m_recv_buffer(peer_connection::m_recv_buffer)
|
2013-12-21 06:59:26 +01:00
|
|
|
#endif
|
2014-05-12 09:57:58 +02:00
|
|
|
, m_our_peer_id(pid)
|
2014-11-23 07:14:47 +01:00
|
|
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
2013-12-02 05:24:10 +01:00
|
|
|
, m_sync_bytes_read(0)
|
2013-12-21 06:59:26 +01:00
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
|
|
|
, m_upload_only_id(0)
|
|
|
|
, m_holepunch_id(0)
|
|
|
|
#endif
|
2013-12-21 06:59:26 +01:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
2013-12-02 05:24:10 +01:00
|
|
|
, m_dont_have_id(0)
|
|
|
|
, m_share_mode_id(0)
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS
|
|
|
|
, m_in_constructor(true)
|
2006-04-25 23:04:48 +02:00
|
|
|
#endif
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "CONSTRUCT", "bt_peer_connection");
|
2006-04-25 23:04:48 +02:00
|
|
|
#endif
|
|
|
|
|
2014-01-19 20:45:50 +01:00
|
|
|
#if TORRENT_USE_ASSERTS
|
2008-03-31 06:46:24 +02:00
|
|
|
m_in_constructor = false;
|
|
|
|
#endif
|
2013-12-20 09:35:29 +01:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
2011-02-25 05:28:32 +01:00
|
|
|
memset(m_reserved_bits, 0, sizeof(m_reserved_bits));
|
2013-12-20 09:35:29 +01:00
|
|
|
#endif
|
2008-03-31 06:46:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void bt_peer_connection::start()
|
|
|
|
{
|
|
|
|
peer_connection::start();
|
2015-06-16 07:24:35 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
// start in the state where we are trying to read the
|
|
|
|
// handshake from the other side
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.reset(20);
|
2006-04-25 23:04:48 +02:00
|
|
|
setup_receive();
|
|
|
|
}
|
|
|
|
|
|
|
|
bt_peer_connection::~bt_peer_connection()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
|
|
|
void bt_peer_connection::switch_send_crypto(boost::shared_ptr<crypto_plugin> crypto)
|
|
|
|
{
|
|
|
|
if (m_enc_handler.switch_send_crypto(crypto, send_buffer_size() - get_send_barrier()))
|
|
|
|
set_send_barrier(send_buffer_size());
|
|
|
|
}
|
|
|
|
|
|
|
|
void bt_peer_connection::switch_recv_crypto(boost::shared_ptr<crypto_plugin> crypto)
|
|
|
|
{
|
|
|
|
m_enc_handler.switch_recv_crypto(crypto, m_recv_buffer);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2007-07-09 06:22:38 +02:00
|
|
|
void bt_peer_connection::on_connected()
|
|
|
|
{
|
2014-01-26 09:18:13 +01:00
|
|
|
if (is_disconnecting()) return;
|
|
|
|
|
|
|
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
|
|
|
TORRENT_ASSERT(t);
|
|
|
|
|
|
|
|
if (t->graceful_pause())
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ON_CONNECTED", "graceful-paused");
|
2014-01-26 09:18:13 +01:00
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(error_code(errors::torrent_paused), op_bittorrent);
|
2014-01-26 09:18:13 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// make sure are much as possible of the response ends up in the same
|
|
|
|
// packet, or at least back-to-back packets
|
|
|
|
cork c_(*this);
|
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
2015-06-16 07:24:35 +02:00
|
|
|
|
2014-07-13 00:32:55 +02:00
|
|
|
boost::uint8_t out_enc_policy = m_settings.get_int(settings_pack::out_enc_policy);
|
2011-09-05 07:50:41 +02:00
|
|
|
|
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
2011-09-12 05:51:49 +02:00
|
|
|
// never try an encrypted connection when already using SSL
|
2012-01-16 00:34:43 +01:00
|
|
|
if (is_ssl(*get_socket()))
|
2014-07-06 21:18:00 +02:00
|
|
|
out_enc_policy = settings_pack::pe_disabled;
|
2011-09-05 07:50:41 +02:00
|
|
|
#endif
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2011-09-05 07:50:41 +02:00
|
|
|
char const* policy_name[] = {"forced", "enabled", "disabled"};
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ENCRYPTION"
|
|
|
|
, "outgoing encryption policy: %s", policy_name[out_enc_policy]);
|
2011-09-05 07:50:41 +02:00
|
|
|
#endif
|
2007-07-09 06:22:38 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (out_enc_policy == settings_pack::pe_forced)
|
2007-07-09 06:22:38 +02:00
|
|
|
{
|
|
|
|
write_pe1_2_dhkey();
|
2008-06-28 12:10:05 +02:00
|
|
|
if (is_disconnecting()) return;
|
2007-07-09 06:22:38 +02:00
|
|
|
|
|
|
|
m_state = read_pe_dhkey;
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.reset(dh_key_len);
|
2007-07-09 06:22:38 +02:00
|
|
|
setup_receive();
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
else if (out_enc_policy == settings_pack::pe_enabled)
|
2007-07-09 06:22:38 +02:00
|
|
|
{
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(peer_info_struct());
|
2007-07-09 06:22:38 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
torrent_peer* pi = peer_info_struct();
|
2007-07-09 06:22:38 +02:00
|
|
|
if (pi->pe_support == true)
|
|
|
|
{
|
|
|
|
// toggle encryption support flag, toggled back to
|
|
|
|
// true if encrypted portion of the handshake
|
|
|
|
// completes correctly
|
|
|
|
pi->pe_support = false;
|
|
|
|
|
2007-10-04 11:46:12 +02:00
|
|
|
// if this fails, we need to reconnect
|
|
|
|
// fast.
|
2007-10-04 23:26:50 +02:00
|
|
|
fast_reconnect(true);
|
2007-10-04 11:46:12 +02:00
|
|
|
|
2007-07-09 06:22:38 +02:00
|
|
|
write_pe1_2_dhkey();
|
2008-06-28 12:10:05 +02:00
|
|
|
if (is_disconnecting()) return;
|
2007-07-09 06:22:38 +02:00
|
|
|
m_state = read_pe_dhkey;
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.reset(dh_key_len);
|
2007-07-09 06:22:38 +02:00
|
|
|
setup_receive();
|
|
|
|
}
|
|
|
|
else // pi->pe_support == false
|
|
|
|
{
|
|
|
|
// toggled back to false if standard handshake
|
|
|
|
// completes correctly (without encryption)
|
|
|
|
pi->pe_support = true;
|
|
|
|
|
|
|
|
write_handshake();
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.reset(20);
|
2007-07-09 06:22:38 +02:00
|
|
|
setup_receive();
|
|
|
|
}
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
else if (out_enc_policy == settings_pack::pe_disabled)
|
2007-07-09 06:22:38 +02:00
|
|
|
#endif
|
|
|
|
{
|
|
|
|
write_handshake();
|
2015-06-16 07:24:35 +02:00
|
|
|
|
2007-07-09 06:22:38 +02:00
|
|
|
// start in the state where we are trying to read the
|
|
|
|
// handshake from the other side
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.reset(20);
|
2007-07-09 06:22:38 +02:00
|
|
|
setup_receive();
|
|
|
|
}
|
|
|
|
}
|
2015-06-16 07:24:35 +02:00
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
void bt_peer_connection::on_metadata()
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ON_METADATA");
|
2013-10-12 08:03:19 +02:00
|
|
|
#endif
|
2015-02-07 02:01:48 +01:00
|
|
|
|
|
|
|
disconnect_if_redundant();
|
|
|
|
if (m_disconnecting) return;
|
|
|
|
|
2008-08-29 19:21:56 +02:00
|
|
|
// connections that are still in the handshake
|
|
|
|
// will send their bitfield when the handshake
|
|
|
|
// is done
|
2015-02-07 02:01:48 +01:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
|
|
|
write_upload_only();
|
|
|
|
#endif
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (!m_sent_handshake) return;
|
|
|
|
if (m_sent_bitfield) return;
|
2006-11-14 01:08:16 +01:00
|
|
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(t);
|
2008-06-07 04:58:28 +02:00
|
|
|
write_bitfield();
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(m_sent_bitfield);
|
2007-08-14 19:47:48 +02:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_supports_dht_port && m_ses.has_dht())
|
|
|
|
write_dht_port(m_ses.external_udp_port());
|
2007-08-14 19:47:48 +02:00
|
|
|
#endif
|
2006-11-14 01:08:16 +01:00
|
|
|
}
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
void bt_peer_connection::write_dht_port(int listen_port)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
2007-07-09 06:22:38 +02:00
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
|
2007-07-09 06:22:38 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::outgoing_message, "DHT_PORT", "%d", listen_port);
|
2007-03-15 23:03:56 +01:00
|
|
|
#endif
|
2007-09-29 18:14:03 +02:00
|
|
|
char msg[] = {0,0,0,3, msg_dht_port, 0, 0};
|
|
|
|
char* ptr = msg + 5;
|
|
|
|
detail::write_uint16(listen_port, ptr);
|
|
|
|
send_buffer(msg, sizeof(msg));
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::num_outgoing_dht_port);
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
2007-08-14 19:47:48 +02:00
|
|
|
void bt_peer_connection::write_have_all()
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(m_sent_handshake);
|
2007-08-14 19:47:48 +02:00
|
|
|
m_sent_bitfield = true;
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::outgoing_message, "HAVE_ALL");
|
2007-08-14 19:47:48 +02:00
|
|
|
#endif
|
2007-09-29 18:14:03 +02:00
|
|
|
char msg[] = {0,0,0,1, msg_have_all};
|
|
|
|
send_buffer(msg, sizeof(msg));
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::num_outgoing_have_all);
|
2007-08-14 19:47:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void bt_peer_connection::write_have_none()
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(m_sent_handshake);
|
2007-08-14 19:47:48 +02:00
|
|
|
m_sent_bitfield = true;
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::outgoing_message, "HAVE_NONE");
|
2007-08-14 19:47:48 +02:00
|
|
|
#endif
|
2007-09-29 18:14:03 +02:00
|
|
|
char msg[] = {0,0,0,1, msg_have_none};
|
|
|
|
send_buffer(msg, sizeof(msg));
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::num_outgoing_have_none);
|
2007-08-14 19:47:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void bt_peer_connection::write_reject_request(peer_request const& r)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::piece_rejects);
|
2012-03-09 07:24:01 +01:00
|
|
|
|
2008-01-02 04:18:29 +01:00
|
|
|
if (!m_supports_fast) return;
|
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::outgoing_message, "REJECT_PIECE"
|
|
|
|
, "piece: %d | s: %d | l: %d", r.piece, r.start, r.length);
|
2012-04-23 07:48:46 +02:00
|
|
|
#endif
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
|
|
|
|
TORRENT_ASSERT(associated_torrent().lock()->valid_metadata());
|
2007-08-14 19:47:48 +02:00
|
|
|
|
2007-09-29 18:14:03 +02:00
|
|
|
char msg[] = {0,0,0,13, msg_reject_request,0,0,0,0, 0,0,0,0, 0,0,0,0};
|
|
|
|
char* ptr = msg + 5;
|
|
|
|
detail::write_int32(r.piece, ptr); // index
|
|
|
|
detail::write_int32(r.start, ptr); // begin
|
|
|
|
detail::write_int32(r.length, ptr); // length
|
|
|
|
send_buffer(msg, sizeof(msg));
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::num_outgoing_reject);
|
2007-08-14 19:47:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void bt_peer_connection::write_allow_fast(int piece)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2010-01-17 22:26:47 +01:00
|
|
|
if (!m_supports_fast) return;
|
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
|
|
|
|
TORRENT_ASSERT(associated_torrent().lock()->valid_metadata());
|
2007-08-14 19:47:48 +02:00
|
|
|
|
2007-09-29 18:14:03 +02:00
|
|
|
char msg[] = {0,0,0,5, msg_allowed_fast, 0, 0, 0, 0};
|
|
|
|
char* ptr = msg + 5;
|
2007-08-14 19:47:48 +02:00
|
|
|
detail::write_int32(piece, ptr);
|
2007-09-29 18:14:03 +02:00
|
|
|
send_buffer(msg, sizeof(msg));
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::num_outgoing_allowed_fast);
|
2007-08-14 19:47:48 +02:00
|
|
|
}
|
|
|
|
|
2010-01-15 17:45:42 +01:00
|
|
|
void bt_peer_connection::write_suggest(int piece)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2010-01-17 22:06:08 +01:00
|
|
|
if (!m_supports_fast) return;
|
|
|
|
|
2010-01-15 17:45:42 +01:00
|
|
|
TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
|
|
|
|
|
|
|
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
|
|
|
TORRENT_ASSERT(t);
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(t->valid_metadata());
|
2010-01-15 17:45:42 +01:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::outgoing_message, "SUGGEST"
|
|
|
|
, "piece: %d num_peers: %d", piece
|
2014-07-06 21:18:00 +02:00
|
|
|
, t->has_picker() ? t->picker().get_availability(piece) : -1);
|
|
|
|
#endif
|
2010-01-15 17:45:42 +01:00
|
|
|
|
|
|
|
char msg[] = {0,0,0,5, msg_suggest_piece, 0, 0, 0, 0};
|
|
|
|
char* ptr = msg + 5;
|
|
|
|
detail::write_int32(piece, ptr);
|
|
|
|
send_buffer(msg, sizeof(msg));
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::num_outgoing_suggest);
|
2010-01-15 17:45:42 +01:00
|
|
|
}
|
|
|
|
|
2015-04-20 02:01:27 +02:00
|
|
|
namespace {
|
|
|
|
char random_byte()
|
|
|
|
{ return random() & 0xff; }
|
|
|
|
}
|
2014-02-05 10:38:32 +01:00
|
|
|
|
2007-05-25 21:42:10 +02:00
|
|
|
void bt_peer_connection::get_specific_peer_info(peer_info& p) const
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(!associated_torrent().expired());
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
if (is_interesting()) p.flags |= peer_info::interesting;
|
|
|
|
if (is_choked()) p.flags |= peer_info::choked;
|
|
|
|
if (is_peer_interested()) p.flags |= peer_info::remote_interested;
|
|
|
|
if (has_peer_choked()) p.flags |= peer_info::remote_choked;
|
|
|
|
if (support_extensions()) p.flags |= peer_info::supports_extensions;
|
2012-02-07 04:46:21 +01:00
|
|
|
if (is_outgoing()) p.flags |= peer_info::local_connection;
|
2013-10-27 20:56:37 +01:00
|
|
|
#if TORRENT_USE_I2P
|
|
|
|
if (is_i2p(*get_socket())) p.flags |= peer_info::i2p_socket;
|
|
|
|
#endif
|
|
|
|
if (is_utp(*get_socket())) p.flags |= peer_info::utp_socket;
|
2014-02-02 10:33:19 +01:00
|
|
|
if (is_ssl(*get_socket())) p.flags |= peer_info::ssl_socket;
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
2007-06-06 02:41:20 +02:00
|
|
|
if (m_encrypted)
|
|
|
|
{
|
2011-06-18 18:58:36 +02:00
|
|
|
p.flags |= m_rc4_encrypted
|
|
|
|
? peer_info::rc4_encrypted
|
|
|
|
: peer_info::plaintext_encrypted;
|
2007-06-06 02:41:20 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (!is_connecting() && in_handshake())
|
2006-04-25 23:04:48 +02:00
|
|
|
p.flags |= peer_info::handshake;
|
2014-10-03 22:56:57 +02:00
|
|
|
if (is_connecting()) p.flags |= peer_info::connecting;
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
p.client = m_client_version;
|
2014-02-02 10:33:19 +01:00
|
|
|
p.connection_type = peer_info::standard_bittorrent;
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
2015-05-23 03:38:47 +02:00
|
|
|
|
2007-01-29 08:39:33 +01:00
|
|
|
bool bt_peer_connection::in_handshake() const
|
|
|
|
{
|
|
|
|
return m_state < read_packet_size;
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
void bt_peer_connection::write_pe1_2_dhkey()
|
|
|
|
{
|
2007-06-07 12:18:13 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(!m_encrypted);
|
|
|
|
TORRENT_ASSERT(!m_rc4_encrypted);
|
2008-06-28 12:10:05 +02:00
|
|
|
TORRENT_ASSERT(!m_dh_key_exchange.get());
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(!m_sent_handshake);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2012-02-07 04:46:21 +01:00
|
|
|
if (is_outgoing())
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ENCRYPTION", "initiating encrypted handshake");
|
2007-06-06 02:41:20 +02:00
|
|
|
#endif
|
|
|
|
|
2008-06-28 12:10:05 +02:00
|
|
|
m_dh_key_exchange.reset(new (std::nothrow) dh_key_exchange);
|
|
|
|
if (!m_dh_key_exchange || !m_dh_key_exchange->good())
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::no_memory, op_encryption);
|
2008-06-28 12:10:05 +02:00
|
|
|
return;
|
|
|
|
}
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2011-02-26 08:55:51 +01:00
|
|
|
int pad_size = random() % 512;
|
2007-06-18 19:12:42 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ENCRYPTION", "pad size: %d", pad_size);
|
2007-06-18 19:12:42 +02:00
|
|
|
#endif
|
|
|
|
|
2011-05-19 04:41:28 +02:00
|
|
|
char msg[dh_key_len + 512];
|
|
|
|
char* ptr = msg;
|
|
|
|
int buf_size = dh_key_len + pad_size;
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2011-05-19 04:41:28 +02:00
|
|
|
memcpy(ptr, m_dh_key_exchange->get_local_key(), dh_key_len);
|
|
|
|
ptr += dh_key_len;
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-02-05 10:38:32 +01:00
|
|
|
std::generate(ptr, ptr + pad_size, random_byte);
|
2011-05-19 04:41:28 +02:00
|
|
|
send_buffer(msg, buf_size);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ENCRYPTION", "sent DH key");
|
2007-06-06 02:41:20 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void bt_peer_connection::write_pe3_sync()
|
|
|
|
{
|
2007-06-07 12:18:13 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(!m_encrypted);
|
|
|
|
TORRENT_ASSERT(!m_rc4_encrypted);
|
2012-02-07 04:46:21 +01:00
|
|
|
TORRENT_ASSERT(is_outgoing());
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(!m_sent_handshake);
|
2015-06-16 07:24:35 +02:00
|
|
|
|
2007-06-06 02:41:20 +02:00
|
|
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(t);
|
2015-06-16 07:24:35 +02:00
|
|
|
|
2007-06-06 02:41:20 +02:00
|
|
|
hasher h;
|
|
|
|
sha1_hash const& info_hash = t->torrent_file().info_hash();
|
2008-06-28 12:10:05 +02:00
|
|
|
char const* const secret = m_dh_key_exchange->get_secret();
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2011-02-26 08:55:51 +01:00
|
|
|
int pad_size = random() % 512;
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
// synchash,skeyhash,vc,crypto_provide,len(pad),pad,len(ia)
|
2011-05-19 04:41:28 +02:00
|
|
|
char msg[20 + 20 + 8 + 4 + 2 + 512 + 2];
|
|
|
|
char* ptr = msg;
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
// sync hash (hash('req1',S))
|
|
|
|
h.reset();
|
|
|
|
h.update("req1",4);
|
|
|
|
h.update(secret, dh_key_len);
|
|
|
|
sha1_hash sync_hash = h.final();
|
|
|
|
|
2011-05-19 04:41:28 +02:00
|
|
|
memcpy(ptr, &sync_hash[0], 20);
|
|
|
|
ptr += 20;
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
// stream key obfuscated hash [ hash('req2',SKEY) xor hash('req3',S) ]
|
|
|
|
h.reset();
|
|
|
|
h.update("req2",4);
|
2015-08-02 05:57:11 +02:00
|
|
|
h.update(info_hash.data(), 20);
|
2007-06-06 02:41:20 +02:00
|
|
|
sha1_hash streamkey_hash = h.final();
|
|
|
|
|
|
|
|
h.reset();
|
|
|
|
h.update("req3",4);
|
|
|
|
h.update(secret, dh_key_len);
|
|
|
|
sha1_hash obfsc_hash = h.final();
|
|
|
|
obfsc_hash ^= streamkey_hash;
|
|
|
|
|
2011-05-19 04:41:28 +02:00
|
|
|
memcpy(ptr, &obfsc_hash[0], 20);
|
|
|
|
ptr += 20;
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
// Discard DH key exchange data, setup RC4 keys
|
2011-06-18 18:58:36 +02:00
|
|
|
init_pe_rc4_handler(secret, info_hash);
|
2008-06-28 12:10:05 +02:00
|
|
|
m_dh_key_exchange.reset(); // secret should be invalid at this point
|
2015-06-06 08:10:53 +02:00
|
|
|
|
2007-06-06 02:41:20 +02:00
|
|
|
// write the verification constant and crypto field
|
2011-05-19 04:41:28 +02:00
|
|
|
int encrypt_size = sizeof(msg) - 512 + pad_size - 40;
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-07-13 00:32:55 +02:00
|
|
|
boost::uint8_t crypto_provide = m_settings.get_int(settings_pack::allowed_enc_level);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2013-05-08 07:43:17 +02:00
|
|
|
// this is an invalid setting, but let's just make the best of the situation
|
2014-07-06 21:18:00 +02:00
|
|
|
if ((crypto_provide & settings_pack::pe_both) == 0)
|
|
|
|
crypto_provide = settings_pack::pe_both;
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2010-12-01 05:22:03 +01:00
|
|
|
char const* level[] = {"plaintext", "rc4", "plaintext rc4"};
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ENCRYPTION"
|
|
|
|
, "%s", level[crypto_provide-1]);
|
2007-06-06 02:41:20 +02:00
|
|
|
#endif
|
|
|
|
|
2011-05-19 04:41:28 +02:00
|
|
|
write_pe_vc_cryptofield(ptr, encrypt_size, crypto_provide, pad_size);
|
2015-06-06 08:10:53 +02:00
|
|
|
std::vector<boost::asio::mutable_buffer> vec;
|
|
|
|
vec.push_back(boost::asio::mutable_buffer(ptr, encrypt_size));
|
2014-11-23 07:14:47 +01:00
|
|
|
m_rc4->encrypt(vec);
|
2011-05-19 04:41:28 +02:00
|
|
|
send_buffer(msg, sizeof(msg) - 512 + pad_size);
|
2007-06-06 02:41:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void bt_peer_connection::write_pe4_sync(int crypto_select)
|
|
|
|
{
|
2007-06-07 12:18:13 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2012-02-07 04:46:21 +01:00
|
|
|
TORRENT_ASSERT(!is_outgoing());
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(!m_encrypted);
|
|
|
|
TORRENT_ASSERT(!m_rc4_encrypted);
|
|
|
|
TORRENT_ASSERT(crypto_select == 0x02 || crypto_select == 0x01);
|
|
|
|
TORRENT_ASSERT(!m_sent_handshake);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2011-02-26 08:55:51 +01:00
|
|
|
int pad_size = random() % 512;
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2008-01-31 07:34:43 +01:00
|
|
|
const int buf_size = 8 + 4 + 2 + pad_size;
|
2011-05-19 04:41:28 +02:00
|
|
|
char msg[512 + 8 + 4 + 2];
|
|
|
|
write_pe_vc_cryptofield(msg, sizeof(msg), crypto_select, pad_size);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2015-06-06 08:10:53 +02:00
|
|
|
std::vector<boost::asio::mutable_buffer> vec;
|
|
|
|
vec.push_back(boost::asio::mutable_buffer(msg, buf_size));
|
2014-11-23 07:14:47 +01:00
|
|
|
m_rc4->encrypt(vec);
|
2011-05-19 04:41:28 +02:00
|
|
|
send_buffer(msg, buf_size);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
// encryption method has been negotiated
|
2014-11-23 07:14:47 +01:00
|
|
|
if (crypto_select == 0x02)
|
2007-06-06 02:41:20 +02:00
|
|
|
m_rc4_encrypted = true;
|
|
|
|
else // 0x01
|
|
|
|
m_rc4_encrypted = false;
|
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ENCRYPTION", " crypto select: %s"
|
2010-12-01 05:22:03 +01:00
|
|
|
, (crypto_select == 0x01) ? "plaintext" : "rc4");
|
2007-06-06 02:41:20 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-05-19 05:13:49 +02:00
|
|
|
void bt_peer_connection::write_pe_vc_cryptofield(char* write_buf, int len
|
2007-07-09 06:22:38 +02:00
|
|
|
, int crypto_field, int pad_size)
|
2015-05-19 05:13:49 +02:00
|
|
|
{
|
2007-06-07 12:18:13 +02:00
|
|
|
INVARIANT_CHECK;
|
2015-05-19 05:13:49 +02:00
|
|
|
#if !TORRENT_USE_ASSERTS
|
|
|
|
TORRENT_UNUSED(len);
|
|
|
|
#endif
|
2007-06-07 12:18:13 +02:00
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(crypto_field <= 0x03 && crypto_field > 0);
|
2007-06-06 02:41:20 +02:00
|
|
|
// vc,crypto_field,len(pad),pad, (len(ia))
|
2012-02-07 04:46:21 +01:00
|
|
|
TORRENT_ASSERT((len >= 8+4+2+pad_size+2 && is_outgoing())
|
|
|
|
|| (len >= 8+4+2+pad_size && !is_outgoing()));
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(!m_sent_handshake);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
// encrypt(vc, crypto_provide/select, len(Pad), len(IA))
|
|
|
|
// len(pad) is zero for now, len(IA) only for outgoing connections
|
2015-05-19 05:13:49 +02:00
|
|
|
|
2007-06-06 02:41:20 +02:00
|
|
|
// vc
|
2011-05-19 04:41:28 +02:00
|
|
|
memset(write_buf, 0, 8);
|
|
|
|
write_buf += 8;
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2011-05-19 04:41:28 +02:00
|
|
|
detail::write_uint32(crypto_field, write_buf);
|
|
|
|
detail::write_uint16(pad_size, write_buf); // len (pad)
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
// fill pad with zeroes
|
2014-02-05 10:38:32 +01:00
|
|
|
std::generate(write_buf, write_buf + pad_size, random_byte);
|
2011-05-19 04:41:28 +02:00
|
|
|
write_buf += pad_size;
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
// append len(ia) if we are initiating
|
2012-02-07 04:46:21 +01:00
|
|
|
if (is_outgoing())
|
2011-05-19 04:41:28 +02:00
|
|
|
detail::write_uint16(handshake_len, write_buf); // len(IA)
|
2015-05-19 05:13:49 +02:00
|
|
|
}
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2015-08-02 05:57:11 +02:00
|
|
|
void bt_peer_connection::init_pe_rc4_handler(char const* secret
|
|
|
|
, sha1_hash const& stream_key)
|
2007-06-06 02:41:20 +02:00
|
|
|
{
|
2007-06-07 12:18:13 +02:00
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(secret);
|
2015-05-19 05:13:49 +02:00
|
|
|
|
2007-06-06 02:41:20 +02:00
|
|
|
hasher h;
|
2007-09-29 18:14:03 +02:00
|
|
|
static const char keyA[] = "keyA";
|
|
|
|
static const char keyB[] = "keyB";
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
// encryption rc4 longkeys
|
|
|
|
// outgoing connection : hash ('keyA',S,SKEY)
|
|
|
|
// incoming connection : hash ('keyB',S,SKEY)
|
2015-05-19 05:13:49 +02:00
|
|
|
|
2012-02-07 04:46:21 +01:00
|
|
|
if (is_outgoing()) h.update(keyA, 4); else h.update(keyB, 4);
|
2007-06-06 02:41:20 +02:00
|
|
|
h.update(secret, dh_key_len);
|
2015-08-02 05:57:11 +02:00
|
|
|
h.update(stream_key.data(), 20);
|
2007-06-06 02:41:20 +02:00
|
|
|
const sha1_hash local_key = h.final();
|
|
|
|
|
|
|
|
h.reset();
|
|
|
|
|
|
|
|
// decryption rc4 longkeys
|
|
|
|
// outgoing connection : hash ('keyB',S,SKEY)
|
|
|
|
// incoming connection : hash ('keyA',S,SKEY)
|
2015-05-19 05:13:49 +02:00
|
|
|
|
2012-02-07 04:46:21 +01:00
|
|
|
if (is_outgoing()) h.update(keyB, 4); else h.update(keyA, 4);
|
2007-06-06 02:41:20 +02:00
|
|
|
h.update(secret, dh_key_len);
|
2015-08-02 05:57:11 +02:00
|
|
|
h.update(stream_key.data(), 20);
|
2007-06-06 02:41:20 +02:00
|
|
|
const sha1_hash remote_key = h.final();
|
2015-05-19 05:13:49 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
TORRENT_ASSERT(!m_rc4.get());
|
|
|
|
m_rc4 = boost::make_shared<rc4_handler>();
|
2011-08-29 04:00:17 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_rc4)
|
2009-02-22 21:52:55 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::no_memory, op_encryption);
|
2009-02-22 21:52:55 +01:00
|
|
|
return;
|
|
|
|
}
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2015-02-28 20:51:15 +01:00
|
|
|
m_rc4->set_incoming_key(&remote_key[0], 20);
|
|
|
|
m_rc4->set_outgoing_key(&local_key[0], 20);
|
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ENCRYPTION", "computed RC4 keys");
|
2007-06-06 02:41:20 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
int bt_peer_connection::get_syncoffset(char const* src, int src_size,
|
2007-09-29 18:14:03 +02:00
|
|
|
char const* target, int target_size) const
|
2007-06-06 02:41:20 +02:00
|
|
|
{
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(target_size >= src_size);
|
|
|
|
TORRENT_ASSERT(src_size > 0);
|
|
|
|
TORRENT_ASSERT(src);
|
|
|
|
TORRENT_ASSERT(target);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
int traverse_limit = target_size - src_size;
|
|
|
|
|
|
|
|
// TODO: this could be optimized using knuth morris pratt
|
|
|
|
for (int i = 0; i < traverse_limit; ++i)
|
|
|
|
{
|
|
|
|
char const* target_ptr = target + i;
|
|
|
|
if (std::equal(src, src+src_size, target_ptr))
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2015-06-06 08:10:53 +02:00
|
|
|
// Partial sync
|
|
|
|
// for (int i = 0; i < target_size; ++i)
|
|
|
|
// {
|
|
|
|
// // first is iterator in src[] at which mismatch occurs
|
|
|
|
// // second is iterator in target[] at which mismatch occurs
|
|
|
|
// std::pair<const char*, const char*> ret;
|
|
|
|
// int src_sync_size;
|
|
|
|
// if (i > traverse_limit) // partial sync test
|
|
|
|
// {
|
|
|
|
// ret = std::mismatch(src, src + src_size - (i - traverse_limit), &target[i]);
|
|
|
|
// src_sync_size = ret.first - src;
|
|
|
|
// if (src_sync_size == (src_size - (i - traverse_limit)))
|
|
|
|
// return i;
|
|
|
|
// }
|
|
|
|
// else // complete sync test
|
|
|
|
// {
|
|
|
|
// ret = std::mismatch(src, src + src_size, &target[i]);
|
|
|
|
// src_sync_size = ret.first - src;
|
|
|
|
// if (src_sync_size == src_size)
|
|
|
|
// return i;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
|
|
|
|
// no complete sync
|
2007-06-06 02:41:20 +02:00
|
|
|
return -1;
|
|
|
|
}
|
2014-11-23 07:14:47 +01:00
|
|
|
|
|
|
|
void bt_peer_connection::rc4_decrypt(char* pos, int len)
|
|
|
|
{
|
2015-06-06 08:10:53 +02:00
|
|
|
std::vector<boost::asio::mutable_buffer> vec;
|
|
|
|
vec.push_back(boost::asio::mutable_buffer(pos, len));
|
2014-11-23 07:14:47 +01:00
|
|
|
int consume = 0;
|
|
|
|
int produce = len;
|
|
|
|
int packet_size = 0;
|
|
|
|
m_rc4->decrypt(vec, consume, produce, packet_size);
|
|
|
|
}
|
|
|
|
#endif // #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2015-04-20 02:01:27 +02:00
|
|
|
namespace {
|
|
|
|
void regular_c_free(char* buf, void* /* userdata */
|
|
|
|
, block_cache_reference /* ref */)
|
|
|
|
{
|
|
|
|
::free(buf);
|
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void bt_peer_connection::append_const_send_buffer(char const* buffer, int size
|
|
|
|
, chained_buffer::free_buffer_fun destructor, void* userdata
|
|
|
|
, block_cache_reference ref)
|
2013-11-10 12:05:11 +01:00
|
|
|
{
|
2014-11-23 07:14:47 +01:00
|
|
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
|
|
|
if (!m_enc_handler.is_send_plaintext())
|
2013-11-10 12:05:11 +01:00
|
|
|
{
|
|
|
|
// if we're encrypting this buffer, we need to make a copy
|
|
|
|
// since we'll mutate it
|
2015-08-02 05:57:11 +02:00
|
|
|
char* buf = static_cast<char*>(malloc(size));
|
2013-11-10 12:05:11 +01:00
|
|
|
memcpy(buf, buffer, size);
|
2014-11-23 07:14:47 +01:00
|
|
|
append_send_buffer(buf, size, ®ular_c_free, NULL);
|
2015-08-02 05:57:11 +02:00
|
|
|
destructor(const_cast<char*>(buffer), userdata, ref);
|
2013-11-10 12:05:11 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
peer_connection::append_const_send_buffer(buffer, size, destructor
|
|
|
|
, userdata, ref);
|
2013-11-10 12:05:11 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
void bt_peer_connection::write_handshake(bool plain_handshake)
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(!m_sent_handshake);
|
2007-07-09 06:22:38 +02:00
|
|
|
m_sent_handshake = true;
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(t);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
// add handshake to the send buffer
|
|
|
|
const char version_string[] = "BitTorrent protocol";
|
|
|
|
const int string_len = sizeof(version_string)-1;
|
|
|
|
|
2011-05-19 04:41:28 +02:00
|
|
|
char handshake[1 + string_len + 8 + 20 + 20];
|
|
|
|
char* ptr = handshake;
|
2006-04-25 23:04:48 +02:00
|
|
|
// length of version string
|
2011-05-19 04:41:28 +02:00
|
|
|
detail::write_uint8(string_len, ptr);
|
|
|
|
// protocol identifier
|
|
|
|
memcpy(ptr, version_string, string_len);
|
|
|
|
ptr += string_len;
|
2006-04-25 23:04:48 +02:00
|
|
|
// 8 zeroes
|
2011-05-19 04:41:28 +02:00
|
|
|
memset(ptr, 0, 8);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2006-08-01 17:27:08 +02:00
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2006-04-25 23:04:48 +02:00
|
|
|
// indicate that we support the DHT messages
|
2011-05-19 04:41:28 +02:00
|
|
|
*(ptr + 7) |= 0x01;
|
2006-08-01 17:27:08 +02:00
|
|
|
#endif
|
2006-11-14 01:08:16 +01:00
|
|
|
|
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
2006-04-25 23:04:48 +02:00
|
|
|
// we support extensions
|
2011-05-19 04:41:28 +02:00
|
|
|
*(ptr + 5) |= 0x10;
|
2006-11-14 01:08:16 +01:00
|
|
|
#endif
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_bool(settings_pack::support_merkle_torrents))
|
2013-02-23 23:13:25 +01:00
|
|
|
{
|
|
|
|
// we support merkle torrents
|
|
|
|
*(ptr + 5) |= 0x08;
|
|
|
|
}
|
2009-03-13 07:09:39 +01:00
|
|
|
|
2007-08-14 19:47:48 +02:00
|
|
|
// we support FAST extension
|
2011-05-19 04:41:28 +02:00
|
|
|
*(ptr + 7) |= 0x04;
|
2007-08-14 19:47:48 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2010-12-01 05:22:03 +01:00
|
|
|
std::string bitmask;
|
2009-03-13 07:09:39 +01:00
|
|
|
for (int k = 0; k < 8; ++k)
|
|
|
|
{
|
|
|
|
for (int j = 0; j < 8; ++j)
|
|
|
|
{
|
2011-05-19 04:41:28 +02:00
|
|
|
if (ptr[k] & (0x80 >> j)) bitmask += '1';
|
2010-12-01 05:22:03 +01:00
|
|
|
else bitmask += '0';
|
2009-03-13 07:09:39 +01:00
|
|
|
}
|
|
|
|
}
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::outgoing_message, "EXTENSIONS"
|
|
|
|
, "%s", bitmask.c_str());
|
2009-03-13 07:09:39 +01:00
|
|
|
#endif
|
2011-05-19 04:41:28 +02:00
|
|
|
ptr += 8;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
// info hash
|
|
|
|
sha1_hash const& ih = t->torrent_file().info_hash();
|
2011-05-19 04:41:28 +02:00
|
|
|
memcpy(ptr, &ih[0], 20);
|
|
|
|
ptr += 20;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
// peer id
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_bool(settings_pack::anonymous_mode))
|
2012-07-09 00:47:25 +02:00
|
|
|
{
|
|
|
|
// in anonymous mode, every peer connection
|
|
|
|
// has a unique peer-id
|
|
|
|
for (int i = 0; i < 20; ++i)
|
2014-04-23 01:37:21 +02:00
|
|
|
m_our_peer_id[i] = random() & 0xff;
|
2012-07-09 00:47:25 +02:00
|
|
|
}
|
2014-04-23 01:37:21 +02:00
|
|
|
|
|
|
|
memcpy(ptr, &m_our_peer_id[0], 20);
|
|
|
|
ptr += 20;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2014-10-12 20:16:46 +02:00
|
|
|
{
|
|
|
|
char hex_pid[41];
|
2015-08-02 05:57:11 +02:00
|
|
|
to_hex(m_our_peer_id.data(), 20, hex_pid);
|
2014-10-12 20:16:46 +02:00
|
|
|
hex_pid[40] = 0;
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::outgoing, "HANDSHAKE"
|
|
|
|
, "sent peer_id: %s client: %s"
|
2014-10-12 20:16:46 +02:00
|
|
|
, hex_pid, identify_client(m_our_peer_id).c_str());
|
|
|
|
}
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::outgoing_message, "HANDSHAKE"
|
|
|
|
, "ih: %s", to_hex(ih.to_string()).c_str());
|
2006-04-25 23:04:48 +02:00
|
|
|
#endif
|
2011-05-19 04:41:28 +02:00
|
|
|
send_buffer(handshake, sizeof(handshake));
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
// for encrypted peers, just send a plain handshake. We
|
|
|
|
// don't know at this point if the rest should be
|
|
|
|
// obfuscated or not, we have to wait for the other end's
|
|
|
|
// response first.
|
|
|
|
if (plain_handshake) return;
|
|
|
|
|
|
|
|
// we don't know how many pieces there are until we
|
|
|
|
// have the metadata
|
|
|
|
if (t->ready_for_connections())
|
|
|
|
{
|
|
|
|
write_bitfield();
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
if (m_supports_dht_port && m_ses.has_dht())
|
|
|
|
write_dht_port(m_ses.external_udp_port());
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// if we don't have any pieces, don't do any preemptive
|
|
|
|
// unchoking at all.
|
|
|
|
if (t->num_have() > 0)
|
|
|
|
{
|
|
|
|
// if the peer is ignoring unchoke slots, or if we have enough
|
|
|
|
// unused slots, unchoke this peer right away, to save a round-trip
|
|
|
|
// in case it's interested.
|
2014-09-22 05:47:43 +02:00
|
|
|
maybe_unchoke_this_peer();
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
boost::optional<piece_block_progress> bt_peer_connection::downloading_piece_progress() const
|
|
|
|
{
|
|
|
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(t);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
buffer::const_interval recv_buffer = m_recv_buffer.get();
|
2006-04-25 23:04:48 +02:00
|
|
|
// are we currently receiving a 'piece' message?
|
|
|
|
if (m_state != read_packet
|
2009-03-17 10:34:44 +01:00
|
|
|
|| recv_buffer.left() <= 9
|
2006-04-25 23:04:48 +02:00
|
|
|
|| recv_buffer[0] != msg_piece)
|
|
|
|
return boost::optional<piece_block_progress>();
|
|
|
|
|
|
|
|
const char* ptr = recv_buffer.begin + 1;
|
|
|
|
peer_request r;
|
|
|
|
r.piece = detail::read_int32(ptr);
|
|
|
|
r.start = detail::read_int32(ptr);
|
2014-11-23 07:14:47 +01:00
|
|
|
r.length = m_recv_buffer.packet_size() - 9;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
// is any of the piece message header data invalid?
|
|
|
|
if (!verify_piece(r))
|
|
|
|
return boost::optional<piece_block_progress>();
|
|
|
|
|
|
|
|
piece_block_progress p;
|
|
|
|
|
|
|
|
p.piece_index = r.piece;
|
|
|
|
p.block_index = r.start / t->block_size();
|
2007-02-12 06:46:29 +01:00
|
|
|
p.bytes_downloaded = recv_buffer.left() - 9;
|
2006-04-25 23:04:48 +02:00
|
|
|
p.full_block_bytes = r.length;
|
|
|
|
|
|
|
|
return boost::optional<piece_block_progress>(p);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// message handlers
|
|
|
|
|
|
|
|
// -----------------------------
|
|
|
|
// --------- KEEPALIVE ---------
|
|
|
|
// -----------------------------
|
|
|
|
|
|
|
|
void bt_peer_connection::on_keepalive()
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming_message, "KEEPALIVE");
|
2006-04-25 23:04:48 +02:00
|
|
|
#endif
|
|
|
|
incoming_keepalive();
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------
|
|
|
|
// ----------- CHOKE -----------
|
|
|
|
// -----------------------------
|
|
|
|
|
|
|
|
void bt_peer_connection::on_choke(int received)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(received >= 0);
|
|
|
|
received_bytes(0, received);
|
2014-11-23 07:14:47 +01:00
|
|
|
if (m_recv_buffer.packet_size() != 1)
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_choke, op_bittorrent, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
incoming_choke();
|
2008-05-12 05:05:27 +02:00
|
|
|
if (is_disconnecting()) return;
|
2007-08-14 19:47:48 +02:00
|
|
|
if (!m_supports_fast)
|
|
|
|
{
|
2009-08-05 20:20:33 +02:00
|
|
|
// we just got choked, and the peer that choked use
|
|
|
|
// doesn't support fast extensions, so we have to
|
|
|
|
// assume that the choke message implies that all
|
|
|
|
// of our requests are rejected. Go through them and
|
|
|
|
// pretend that we received reject request messages
|
2007-08-14 19:47:48 +02:00
|
|
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(t);
|
2007-10-10 04:27:55 +02:00
|
|
|
while (!download_queue().empty())
|
2007-08-14 19:47:48 +02:00
|
|
|
{
|
2008-07-07 14:04:06 +02:00
|
|
|
piece_block const& b = download_queue().front().block;
|
2007-08-14 19:47:48 +02:00
|
|
|
peer_request r;
|
|
|
|
r.piece = b.piece_index;
|
|
|
|
r.start = b.block_index * t->block_size();
|
|
|
|
r.length = t->block_size();
|
2009-08-05 20:20:33 +02:00
|
|
|
// if it's the last piece, make sure to
|
|
|
|
// set the length of the request to not
|
|
|
|
// exceed the end of the torrent. This is
|
|
|
|
// necessary in order to maintain a correct
|
|
|
|
// m_outsanding_bytes
|
|
|
|
if (r.piece == t->torrent_file().num_pieces() - 1)
|
|
|
|
{
|
|
|
|
r.length = (std::min)(t->torrent_file().piece_size(
|
|
|
|
r.piece) - r.start, r.length);
|
|
|
|
}
|
2007-08-14 19:47:48 +02:00
|
|
|
incoming_reject_request(r);
|
|
|
|
}
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------
|
|
|
|
// ---------- UNCHOKE ----------
|
|
|
|
// -----------------------------
|
|
|
|
|
|
|
|
void bt_peer_connection::on_unchoke(int received)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(received >= 0);
|
|
|
|
received_bytes(0, received);
|
2014-11-23 07:14:47 +01:00
|
|
|
if (m_recv_buffer.packet_size() != 1)
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_unchoke, op_bittorrent, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
incoming_unchoke();
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------
|
|
|
|
// -------- INTERESTED ---------
|
|
|
|
// -----------------------------
|
|
|
|
|
|
|
|
void bt_peer_connection::on_interested(int received)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(received >= 0);
|
|
|
|
received_bytes(0, received);
|
2014-11-23 07:14:47 +01:00
|
|
|
if (m_recv_buffer.packet_size() != 1)
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_interested, op_bittorrent, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
incoming_interested();
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------
|
|
|
|
// ------ NOT INTERESTED -------
|
|
|
|
// -----------------------------
|
|
|
|
|
|
|
|
void bt_peer_connection::on_not_interested(int received)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(received >= 0);
|
|
|
|
received_bytes(0, received);
|
2014-11-23 07:14:47 +01:00
|
|
|
if (m_recv_buffer.packet_size() != 1)
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_not_interested, op_bittorrent, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
incoming_not_interested();
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------
|
|
|
|
// ----------- HAVE ------------
|
|
|
|
// -----------------------------
|
|
|
|
|
|
|
|
void bt_peer_connection::on_have(int received)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(received >= 0);
|
|
|
|
received_bytes(0, received);
|
2014-11-23 07:14:47 +01:00
|
|
|
if (m_recv_buffer.packet_size() != 5)
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_have, op_bittorrent, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
buffer::const_interval recv_buffer = m_recv_buffer.get();
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
const char* ptr = recv_buffer.begin + 1;
|
|
|
|
int index = detail::read_int32(ptr);
|
|
|
|
|
|
|
|
incoming_have(index);
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------
|
|
|
|
// --------- BITFIELD ----------
|
|
|
|
// -----------------------------
|
|
|
|
|
|
|
|
void bt_peer_connection::on_bitfield(int received)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(received >= 0);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(t);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, received);
|
2006-04-25 23:04:48 +02:00
|
|
|
// if we don't have the metedata, we cannot
|
|
|
|
// verify the bitfield size
|
|
|
|
if (t->valid_metadata()
|
2014-11-23 07:14:47 +01:00
|
|
|
&& m_recv_buffer.packet_size() - 1 != (t->torrent_file().num_pieces() + 7) / 8)
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_bitfield_size, op_bittorrent, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
buffer::const_interval recv_buffer = m_recv_buffer.get();
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2008-05-28 04:35:02 +02:00
|
|
|
bitfield bits;
|
2015-08-09 04:53:11 +02:00
|
|
|
bits.assign(recv_buffer.begin + 1
|
2014-11-23 07:14:47 +01:00
|
|
|
, t->valid_metadata()?get_bitfield().size():(m_recv_buffer.packet_size()-1)*8);
|
2015-06-16 07:24:35 +02:00
|
|
|
|
2008-05-28 04:35:02 +02:00
|
|
|
incoming_bitfield(bits);
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------
|
|
|
|
// ---------- REQUEST ----------
|
|
|
|
// -----------------------------
|
|
|
|
|
|
|
|
void bt_peer_connection::on_request(int received)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(received >= 0);
|
|
|
|
received_bytes(0, received);
|
2014-11-23 07:14:47 +01:00
|
|
|
if (m_recv_buffer.packet_size() != 13)
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_request, op_bittorrent, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
buffer::const_interval recv_buffer = m_recv_buffer.get();
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
peer_request r;
|
|
|
|
const char* ptr = recv_buffer.begin + 1;
|
|
|
|
r.piece = detail::read_int32(ptr);
|
|
|
|
r.start = detail::read_int32(ptr);
|
|
|
|
r.length = detail::read_int32(ptr);
|
2008-12-08 07:36:22 +01:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
incoming_request(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------
|
|
|
|
// ----------- PIECE -----------
|
|
|
|
// -----------------------------
|
|
|
|
|
|
|
|
void bt_peer_connection::on_piece(int received)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(received >= 0);
|
2015-06-16 07:24:35 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
buffer::const_interval recv_buffer = m_recv_buffer.get();
|
|
|
|
int recv_pos = m_recv_buffer.pos(); // recv_buffer.end - recv_buffer.begin;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2009-03-13 07:09:39 +01:00
|
|
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
|
|
|
TORRENT_ASSERT(t);
|
2015-08-09 04:53:11 +02:00
|
|
|
bool merkle = static_cast<boost::uint8_t>(recv_buffer.begin[0]) == 250;
|
2009-03-13 07:09:39 +01:00
|
|
|
if (merkle)
|
2008-04-10 12:03:23 +02:00
|
|
|
{
|
2009-03-13 07:09:39 +01:00
|
|
|
if (recv_pos == 1)
|
|
|
|
{
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.set_soft_packet_size(13);
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, received);
|
2009-03-13 07:09:39 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (recv_pos < 13)
|
2008-10-01 17:19:31 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, received);
|
2008-04-10 12:03:23 +02:00
|
|
|
return;
|
2008-10-01 17:19:31 +02:00
|
|
|
}
|
2009-03-13 07:09:39 +01:00
|
|
|
if (recv_pos == 13)
|
|
|
|
{
|
|
|
|
const char* ptr = recv_buffer.begin + 9;
|
|
|
|
int list_size = detail::read_int32(ptr);
|
|
|
|
// now we know how long the bencoded hash list is
|
|
|
|
// and we can allocate the disk buffer and receive
|
|
|
|
// into it
|
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
if (list_size > m_recv_buffer.packet_size() - 13)
|
2009-03-13 07:09:39 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_hash_list, op_bittorrent, 2);
|
2009-03-13 07:09:39 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
if (m_recv_buffer.packet_size() - 13 - list_size > t->block_size())
|
2011-04-28 10:55:27 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::packet_too_large, op_bittorrent, 2);
|
2011-04-28 10:55:27 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.assert_no_disk_buffer();
|
|
|
|
if (!m_settings.get_bool(settings_pack::contiguous_recv_buffer) &&
|
|
|
|
m_recv_buffer.can_recv_contiguous(m_recv_buffer.packet_size() - 13 - list_size))
|
2009-03-13 07:09:39 +01:00
|
|
|
{
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!allocate_disk_receive_buffer(m_recv_buffer.packet_size() - 13 - list_size))
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
received_bytes(0, received);
|
|
|
|
return;
|
|
|
|
}
|
2009-03-13 07:09:39 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (recv_pos == 1)
|
|
|
|
{
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.assert_no_disk_buffer();
|
2011-04-28 10:55:27 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
if (m_recv_buffer.packet_size() - 9 > t->block_size())
|
2011-04-28 10:55:27 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::packet_too_large, op_bittorrent, 2);
|
2011-04-28 10:55:27 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_settings.get_bool(settings_pack::contiguous_recv_buffer) &&
|
|
|
|
m_recv_buffer.can_recv_contiguous(m_recv_buffer.packet_size() - 9))
|
2009-03-13 07:09:39 +01:00
|
|
|
{
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!allocate_disk_receive_buffer(m_recv_buffer.packet_size() - 9))
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
|
|
|
received_bytes(0, received);
|
|
|
|
return;
|
|
|
|
}
|
2009-03-13 07:09:39 +01:00
|
|
|
}
|
|
|
|
}
|
2008-04-10 12:03:23 +02:00
|
|
|
}
|
2014-11-23 07:14:47 +01:00
|
|
|
TORRENT_ASSERT(m_settings.get_bool(settings_pack::contiguous_recv_buffer) || m_recv_buffer.has_disk_buffer() || m_recv_buffer.packet_size() == 9);
|
2006-04-25 23:04:48 +02:00
|
|
|
// classify the received data as protocol chatter
|
|
|
|
// or data payload for the statistics
|
2009-03-17 10:34:44 +01:00
|
|
|
int piece_bytes = 0;
|
2011-08-05 08:10:12 +02:00
|
|
|
|
|
|
|
int header_size = merkle?13:9;
|
|
|
|
|
|
|
|
peer_request p;
|
|
|
|
int list_size = 0;
|
|
|
|
|
|
|
|
if (recv_pos >= header_size)
|
|
|
|
{
|
|
|
|
const char* ptr = recv_buffer.begin + 1;
|
|
|
|
p.piece = detail::read_int32(ptr);
|
|
|
|
p.start = detail::read_int32(ptr);
|
|
|
|
|
|
|
|
if (merkle)
|
|
|
|
{
|
|
|
|
list_size = detail::read_int32(ptr);
|
2014-11-23 07:14:47 +01:00
|
|
|
p.length = m_recv_buffer.packet_size() - list_size - header_size;
|
2011-08-05 08:10:12 +02:00
|
|
|
header_size += list_size;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-11-23 07:14:47 +01:00
|
|
|
p.length = m_recv_buffer.packet_size() - header_size;
|
2011-08-05 08:10:12 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (recv_pos <= header_size)
|
2009-03-17 10:34:44 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
// only received protocol data
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, received);
|
2009-03-17 10:34:44 +01:00
|
|
|
}
|
2011-08-05 08:10:12 +02:00
|
|
|
else if (recv_pos - received >= header_size)
|
2009-03-17 10:34:44 +01:00
|
|
|
{
|
2006-04-25 23:04:48 +02:00
|
|
|
// only received payload data
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(received, 0);
|
2009-03-17 10:34:44 +01:00
|
|
|
piece_bytes = received;
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
// received a bit of both
|
2011-08-05 08:10:12 +02:00
|
|
|
TORRENT_ASSERT(recv_pos - received < header_size);
|
|
|
|
TORRENT_ASSERT(recv_pos > header_size);
|
|
|
|
TORRENT_ASSERT(header_size - (recv_pos - received) <= header_size);
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(
|
2011-08-05 08:10:12 +02:00
|
|
|
recv_pos - header_size
|
|
|
|
, header_size - (recv_pos - received));
|
|
|
|
piece_bytes = recv_pos - header_size;
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
2009-03-19 17:50:37 +01:00
|
|
|
if (recv_pos < header_size) return;
|
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
// peer_log(peer_log_alert::incoming_message, "PIECE_FRAGMENT", "p: %d start: %d length: %d"
|
2010-12-01 05:22:03 +01:00
|
|
|
// , p.piece, p.start, p.length);
|
2009-03-13 07:09:39 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
if (recv_pos - received < header_size && recv_pos >= header_size)
|
|
|
|
{
|
2009-03-17 10:34:44 +01:00
|
|
|
// call this once, the first time the entire header
|
|
|
|
// has been received
|
|
|
|
start_receive_piece(p);
|
2009-04-17 19:56:58 +02:00
|
|
|
if (is_disconnecting()) return;
|
2009-03-13 07:09:39 +01:00
|
|
|
}
|
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
TORRENT_ASSERT(m_settings.get_bool(settings_pack::contiguous_recv_buffer) || m_recv_buffer.has_disk_buffer() || m_recv_buffer.packet_size() == header_size);
|
2009-03-13 07:09:39 +01:00
|
|
|
|
2009-03-17 10:34:44 +01:00
|
|
|
incoming_piece_fragment(piece_bytes);
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
2009-03-13 07:09:39 +01:00
|
|
|
|
|
|
|
if (merkle && list_size > 0)
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming_message, "HASHPIECE"
|
|
|
|
, "piece: %d list: %d", p.piece, list_size);
|
2009-03-13 07:09:39 +01:00
|
|
|
#endif
|
2015-03-12 06:20:12 +01:00
|
|
|
bdecode_node hash_list;
|
2010-10-28 06:01:59 +02:00
|
|
|
error_code ec;
|
2015-03-12 06:20:12 +01:00
|
|
|
if (bdecode(recv_buffer.begin + 13, recv_buffer.begin+ 13 + list_size
|
2010-10-28 06:01:59 +02:00
|
|
|
, hash_list, ec) != 0)
|
2009-03-13 07:09:39 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_hash_piece, op_bittorrent, 2);
|
2009-03-13 07:09:39 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// the list has this format:
|
|
|
|
// [ [node-index, hash], [node-index, hash], ... ]
|
2015-03-12 06:20:12 +01:00
|
|
|
if (hash_list.type() != bdecode_node::list_t)
|
2009-03-13 07:09:39 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_hash_list, op_bittorrent, 2);
|
2009-03-13 07:09:39 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::map<int, sha1_hash> nodes;
|
|
|
|
for (int i = 0; i < hash_list.list_size(); ++i)
|
|
|
|
{
|
2015-03-12 06:20:12 +01:00
|
|
|
bdecode_node e = hash_list.list_at(i);
|
|
|
|
if (e.type() != bdecode_node::list_t
|
|
|
|
|| e.list_size() != 2
|
|
|
|
|| e.list_at(0).type() != bdecode_node::int_t
|
|
|
|
|| e.list_at(1).type() != bdecode_node::string_t
|
|
|
|
|| e.list_at(1).string_length() != 20) continue;
|
|
|
|
|
|
|
|
nodes.insert(std::make_pair(int(e.list_int_value_at(0))
|
|
|
|
, sha1_hash(e.list_at(1).string_ptr())));
|
2009-03-13 07:09:39 +01:00
|
|
|
}
|
|
|
|
if (!nodes.empty() && !t->add_merkle_nodes(nodes, p.piece))
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_hash_piece, op_bittorrent, 2);
|
2009-03-13 07:09:39 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
char* disk_buffer = m_recv_buffer.release_disk_buffer();
|
2014-07-06 21:18:00 +02:00
|
|
|
if (disk_buffer)
|
|
|
|
{
|
|
|
|
disk_buffer_holder holder(m_allocator, disk_buffer);
|
|
|
|
incoming_piece(p, holder);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
incoming_piece(p, recv_buffer.begin + header_size);
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------
|
|
|
|
// ---------- CANCEL -----------
|
|
|
|
// -----------------------------
|
|
|
|
|
|
|
|
void bt_peer_connection::on_cancel(int received)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(received >= 0);
|
|
|
|
received_bytes(0, received);
|
2014-11-23 07:14:47 +01:00
|
|
|
if (m_recv_buffer.packet_size() != 13)
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_cancel, op_bittorrent, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
buffer::const_interval recv_buffer = m_recv_buffer.get();
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
peer_request r;
|
|
|
|
const char* ptr = recv_buffer.begin + 1;
|
|
|
|
r.piece = detail::read_int32(ptr);
|
|
|
|
r.start = detail::read_int32(ptr);
|
|
|
|
r.length = detail::read_int32(ptr);
|
|
|
|
|
|
|
|
incoming_cancel(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
// -----------------------------
|
|
|
|
// --------- DHT PORT ----------
|
|
|
|
// -----------------------------
|
|
|
|
|
|
|
|
void bt_peer_connection::on_dht_port(int received)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(received >= 0);
|
|
|
|
received_bytes(0, received);
|
2014-11-23 07:14:47 +01:00
|
|
|
if (m_recv_buffer.packet_size() != 3)
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_dht_port, op_bittorrent, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
buffer::const_interval recv_buffer = m_recv_buffer.get();
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
const char* ptr = recv_buffer.begin + 1;
|
|
|
|
int listen_port = detail::read_uint16(ptr);
|
2015-06-16 07:24:35 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
incoming_dht_port(listen_port);
|
2010-02-18 06:27:58 +01:00
|
|
|
|
|
|
|
if (!m_supports_dht_port)
|
|
|
|
{
|
|
|
|
m_supports_dht_port = true;
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_supports_dht_port && m_ses.has_dht())
|
|
|
|
write_dht_port(m_ses.external_udp_port());
|
2010-02-18 06:27:58 +01:00
|
|
|
#endif
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
2007-08-14 19:47:48 +02:00
|
|
|
void bt_peer_connection::on_suggest_piece(int received)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, received);
|
2007-08-14 19:47:48 +02:00
|
|
|
if (!m_supports_fast)
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_suggest, op_bittorrent, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2007-08-14 19:47:48 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
2007-09-01 09:38:10 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
buffer::const_interval recv_buffer = m_recv_buffer.get();
|
2007-09-01 09:38:10 +02:00
|
|
|
|
|
|
|
const char* ptr = recv_buffer.begin + 1;
|
|
|
|
int piece = detail::read_uint32(ptr);
|
|
|
|
incoming_suggest(piece);
|
2007-08-14 19:47:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void bt_peer_connection::on_have_all(int received)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, received);
|
2007-08-14 19:47:48 +02:00
|
|
|
if (!m_supports_fast)
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_have_all, op_bittorrent, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2007-08-14 19:47:48 +02:00
|
|
|
incoming_have_all();
|
|
|
|
}
|
|
|
|
|
|
|
|
void bt_peer_connection::on_have_none(int received)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, received);
|
2007-08-14 19:47:48 +02:00
|
|
|
if (!m_supports_fast)
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_have_none, op_bittorrent, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2007-08-14 19:47:48 +02:00
|
|
|
incoming_have_none();
|
|
|
|
}
|
|
|
|
|
|
|
|
void bt_peer_connection::on_reject_request(int received)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, received);
|
2007-08-14 19:47:48 +02:00
|
|
|
if (!m_supports_fast)
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_reject, op_bittorrent, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2007-08-14 19:47:48 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
2007-08-14 19:47:48 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
buffer::const_interval recv_buffer = m_recv_buffer.get();
|
2007-08-14 19:47:48 +02:00
|
|
|
|
|
|
|
peer_request r;
|
|
|
|
const char* ptr = recv_buffer.begin + 1;
|
|
|
|
r.piece = detail::read_int32(ptr);
|
|
|
|
r.start = detail::read_int32(ptr);
|
|
|
|
r.length = detail::read_int32(ptr);
|
|
|
|
|
|
|
|
incoming_reject_request(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
void bt_peer_connection::on_allowed_fast(int received)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, received);
|
2007-08-14 19:47:48 +02:00
|
|
|
if (!m_supports_fast)
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_allow_fast, op_bittorrent, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2007-08-14 19:47:48 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
|
|
|
buffer::const_interval recv_buffer = m_recv_buffer.get();
|
2007-08-14 19:47:48 +02:00
|
|
|
const char* ptr = recv_buffer.begin + 1;
|
|
|
|
int index = detail::read_int32(ptr);
|
|
|
|
|
|
|
|
incoming_allowed_fast(index);
|
|
|
|
}
|
|
|
|
|
2010-11-29 02:33:05 +01:00
|
|
|
// -----------------------------
|
|
|
|
// -------- RENDEZVOUS ---------
|
|
|
|
// -----------------------------
|
|
|
|
|
2011-01-29 13:13:49 +01:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
2010-11-29 02:33:05 +01:00
|
|
|
void bt_peer_connection::on_holepunch()
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
2010-11-29 02:33:05 +01:00
|
|
|
|
|
|
|
// we can't accept holepunch messages from peers
|
|
|
|
// that don't support the holepunch extension
|
|
|
|
// because we wouldn't be able to respond
|
|
|
|
if (m_holepunch_id == 0) return;
|
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
buffer::const_interval recv_buffer = m_recv_buffer.get();
|
2010-11-29 02:33:05 +01:00
|
|
|
TORRENT_ASSERT(*recv_buffer.begin == msg_extended);
|
|
|
|
++recv_buffer.begin;
|
|
|
|
TORRENT_ASSERT(*recv_buffer.begin == holepunch_msg);
|
|
|
|
++recv_buffer.begin;
|
|
|
|
|
|
|
|
const char* ptr = recv_buffer.begin;
|
|
|
|
|
|
|
|
// ignore invalid messages
|
|
|
|
if (recv_buffer.left() < 2) return;
|
|
|
|
|
|
|
|
int msg_type = detail::read_uint8(ptr);
|
|
|
|
int addr_type = detail::read_uint8(ptr);
|
|
|
|
|
|
|
|
tcp::endpoint ep;
|
|
|
|
|
|
|
|
if (addr_type == 0)
|
|
|
|
{
|
|
|
|
if (recv_buffer.left() < 2 + 4 + 2) return;
|
|
|
|
// IPv4 address
|
|
|
|
ep = detail::read_v4_endpoint<tcp::endpoint>(ptr);
|
|
|
|
}
|
|
|
|
#if TORRENT_USE_IPV6
|
|
|
|
else if (addr_type == 1)
|
|
|
|
{
|
|
|
|
// IPv6 address
|
|
|
|
if (recv_buffer.left() < 2 + 18 + 2) return;
|
|
|
|
ep = detail::read_v6_endpoint<tcp::endpoint>(ptr);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
else
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2010-11-29 02:33:05 +01:00
|
|
|
error_code ec;
|
|
|
|
static const char* hp_msg_name[] = {"rendezvous", "connect", "failed"};
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming_message, "HOLEPUNCH"
|
|
|
|
, "msg: %s from %s to: unknown address type"
|
2010-12-01 05:22:03 +01:00
|
|
|
, (msg_type >= 0 && msg_type < 3 ? hp_msg_name[msg_type] : "unknown message type")
|
|
|
|
, print_address(remote().address()).c_str());
|
2010-11-29 02:33:05 +01:00
|
|
|
#endif
|
|
|
|
|
|
|
|
return; // unknown address type
|
|
|
|
}
|
|
|
|
|
|
|
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
|
|
|
if (!t) return;
|
|
|
|
|
|
|
|
switch (msg_type)
|
|
|
|
{
|
|
|
|
case hp_rendezvous: // rendezvous
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming_message, "HOLEPUNCH"
|
|
|
|
, "msg: rendezvous to: %s", print_address(ep.address()).c_str());
|
2010-11-29 02:33:05 +01:00
|
|
|
#endif
|
|
|
|
// this peer is asking us to introduce it to
|
|
|
|
// the peer at 'ep'. We need to find which of
|
|
|
|
// our connections points to that endpoint
|
|
|
|
bt_peer_connection* p = t->find_peer(ep);
|
|
|
|
if (p == 0)
|
|
|
|
{
|
|
|
|
// we're not connected to this peer
|
|
|
|
write_holepunch_msg(hp_failed, ep, hp_not_connected);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!p->supports_holepunch())
|
|
|
|
{
|
|
|
|
write_holepunch_msg(hp_failed, ep, hp_no_support);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (p == this)
|
|
|
|
{
|
|
|
|
write_holepunch_msg(hp_failed, ep, hp_no_self);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
write_holepunch_msg(hp_connect, ep, 0);
|
|
|
|
p->write_holepunch_msg(hp_connect, remote(), 0);
|
|
|
|
} break;
|
|
|
|
case hp_connect:
|
|
|
|
{
|
|
|
|
// add or find the peer with this endpoint
|
2014-07-06 21:18:00 +02:00
|
|
|
torrent_peer* p = t->add_peer(ep, peer_info::pex);
|
2010-11-29 02:33:05 +01:00
|
|
|
if (p == 0 || p->connection)
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming_message, "HOLEPUNCH"
|
|
|
|
, "msg:connect to: %s error: failed to add peer"
|
2010-12-01 05:22:03 +01:00
|
|
|
, print_address(ep.address()).c_str());
|
2010-11-29 02:33:05 +01:00
|
|
|
#endif
|
|
|
|
// we either couldn't add this peer, or it's
|
|
|
|
// already connected. Just ignore the connect message
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (p->banned)
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming_message, "HOLEPUNCH"
|
|
|
|
, "msg:connect to: %s error: peer banned", print_address(ep.address()).c_str());
|
2010-11-29 02:33:05 +01:00
|
|
|
#endif
|
|
|
|
// this peer is banned, don't connect to it
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// to make sure we use the uTP protocol
|
|
|
|
p->supports_utp = true;
|
|
|
|
// #error make sure we make this a connection candidate
|
|
|
|
// in case it has too many failures for instance
|
|
|
|
t->connect_to_peer(p, true);
|
|
|
|
// mark this connection to be in holepunch mode
|
|
|
|
// so that it will retry faster and stick to uTP while it's
|
|
|
|
// retrying
|
2014-07-06 21:18:00 +02:00
|
|
|
t->update_want_peers();
|
2010-11-29 02:33:05 +01:00
|
|
|
if (p->connection)
|
|
|
|
p->connection->set_holepunch_mode();
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming_message, "HOLEPUNCH"
|
|
|
|
, "msg:connect to: %s"
|
2010-12-01 05:22:03 +01:00
|
|
|
, print_address(ep.address()).c_str());
|
2010-11-29 02:33:05 +01:00
|
|
|
#endif
|
|
|
|
} break;
|
|
|
|
case hp_failed:
|
|
|
|
{
|
|
|
|
boost::uint32_t error = detail::read_uint32(ptr);
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2010-11-29 02:33:05 +01:00
|
|
|
error_code ec;
|
|
|
|
char const* err_msg[] = {"no such peer", "not connected", "no support", "no self"};
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming_message, "HOLEPUNCH"
|
|
|
|
, "msg:failed error: %d msg: %s", error
|
2012-12-15 03:50:47 +01:00
|
|
|
, ((error > 0 && error < 5)?err_msg[error-1]:"unknown message id"));
|
2010-11-29 02:33:05 +01:00
|
|
|
#endif
|
|
|
|
// #error deal with holepunch errors
|
2011-02-19 22:20:03 +01:00
|
|
|
(void)error;
|
2010-11-29 02:33:05 +01:00
|
|
|
} break;
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2010-11-29 02:33:05 +01:00
|
|
|
default:
|
|
|
|
{
|
|
|
|
error_code ec;
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming_message, "HOLEPUNCH"
|
|
|
|
, "msg: unknown message type (%d) to: %s"
|
2010-12-01 05:22:03 +01:00
|
|
|
, msg_type, print_address(ep.address()).c_str());
|
2010-11-29 02:33:05 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void bt_peer_connection::write_holepunch_msg(int type, tcp::endpoint const& ep, int error)
|
|
|
|
{
|
|
|
|
char buf[35];
|
|
|
|
char* ptr = buf + 6;
|
|
|
|
detail::write_uint8(type, ptr);
|
|
|
|
if (ep.address().is_v4()) detail::write_uint8(0, ptr);
|
|
|
|
else detail::write_uint8(1, ptr);
|
|
|
|
detail::write_endpoint(ep, ptr);
|
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2010-11-29 02:33:05 +01:00
|
|
|
error_code ec;
|
|
|
|
static const char* hp_msg_name[] = {"rendezvous", "connect", "failed"};
|
|
|
|
static const char* hp_error_string[] = {"", "no such peer", "not connected", "no support", "no self"};
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::outgoing_message, "HOLEPUNCH"
|
|
|
|
, "msg: %s to: %s error: %s"
|
2010-12-01 05:22:03 +01:00
|
|
|
, (type >= 0 && type < 3 ? hp_msg_name[type] : "unknown message type")
|
|
|
|
, print_address(ep.address()).c_str()
|
|
|
|
, hp_error_string[error]);
|
2010-11-29 02:33:05 +01:00
|
|
|
#endif
|
|
|
|
if (type == hp_failed)
|
|
|
|
{
|
|
|
|
detail::write_uint32(error, ptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// write the packet length and type
|
|
|
|
char* hdr = buf;
|
|
|
|
detail::write_uint32(ptr - buf - 4, hdr);
|
|
|
|
detail::write_uint8(msg_extended, hdr);
|
|
|
|
detail::write_uint8(m_holepunch_id, hdr);
|
|
|
|
|
|
|
|
TORRENT_ASSERT(ptr <= buf + sizeof(buf));
|
|
|
|
|
|
|
|
send_buffer(buf, ptr - buf);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::num_outgoing_extended);
|
2010-11-29 02:33:05 +01:00
|
|
|
}
|
2011-01-29 13:13:49 +01:00
|
|
|
#endif // TORRENT_DISABLE_EXTENSIONS
|
2010-11-29 02:33:05 +01:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
// -----------------------------
|
|
|
|
// --------- EXTENDED ----------
|
|
|
|
// -----------------------------
|
|
|
|
|
2013-12-20 09:35:29 +01:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
2006-04-25 23:04:48 +02:00
|
|
|
void bt_peer_connection::on_extended(int received)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(received >= 0);
|
|
|
|
received_bytes(0, received);
|
2014-11-23 07:14:47 +01:00
|
|
|
if (m_recv_buffer.packet_size() < 2)
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_extended, op_bittorrent, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
if (associated_torrent().expired())
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_extended, op_bittorrent, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
buffer::const_interval recv_buffer = m_recv_buffer.get();
|
2006-11-14 01:08:16 +01:00
|
|
|
if (recv_buffer.left() < 2) return;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(*recv_buffer.begin == msg_extended);
|
2006-04-25 23:04:48 +02:00
|
|
|
++recv_buffer.begin;
|
|
|
|
|
|
|
|
int extended_id = detail::read_uint8(recv_buffer.begin);
|
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
if (extended_id == 0)
|
|
|
|
{
|
|
|
|
on_extended_handshake();
|
2012-02-10 08:31:40 +01:00
|
|
|
disconnect_if_redundant();
|
2006-11-14 01:08:16 +01:00
|
|
|
return;
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2010-11-29 02:33:05 +01:00
|
|
|
if (extended_id == upload_only_msg)
|
|
|
|
{
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
|
|
|
if (m_recv_buffer.packet_size() != 3)
|
2011-08-07 02:41:13 +02:00
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming_message, "UPLOAD_ONLY"
|
|
|
|
, "ERROR: unexpected packet size: %d", m_recv_buffer.packet_size());
|
2011-08-07 02:41:13 +02:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
2011-02-21 06:24:41 +01:00
|
|
|
bool ul = detail::read_uint8(recv_buffer.begin) != 0;
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming_message, "UPLOAD_ONLY"
|
|
|
|
, "%s", (ul?"true":"false"));
|
2010-11-29 02:33:05 +01:00
|
|
|
#endif
|
|
|
|
set_upload_only(ul);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-02-19 22:20:03 +01:00
|
|
|
if (extended_id == share_mode_msg)
|
|
|
|
{
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
|
|
|
if (m_recv_buffer.packet_size() != 3)
|
2011-08-07 02:41:13 +02:00
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming_message, "SHARE_MODE"
|
|
|
|
, "ERROR: unexpected packet size: %d", m_recv_buffer.packet_size());
|
2011-08-07 02:41:13 +02:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
2011-02-21 06:24:41 +01:00
|
|
|
bool sm = detail::read_uint8(recv_buffer.begin) != 0;
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming_message, "SHARE_MODE"
|
|
|
|
, "%s", (sm?"true":"false"));
|
2011-02-19 22:20:03 +01:00
|
|
|
#endif
|
|
|
|
set_share_mode(sm);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-11-29 02:33:05 +01:00
|
|
|
if (extended_id == holepunch_msg)
|
|
|
|
{
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming_message, "HOLEPUNCH");
|
2011-02-19 22:20:03 +01:00
|
|
|
#endif
|
2010-11-29 02:33:05 +01:00
|
|
|
on_holepunch();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-08-07 02:41:13 +02:00
|
|
|
if (extended_id == dont_have_msg)
|
|
|
|
{
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
|
|
|
if (m_recv_buffer.packet_size() != 6)
|
2011-08-07 02:41:13 +02:00
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming_message, "DONT_HAVE"
|
|
|
|
, "ERROR: unexpected packet size: %d", m_recv_buffer.packet_size());
|
2011-08-07 02:41:13 +02:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
2014-09-04 10:55:24 +02:00
|
|
|
int piece = detail::read_uint32(recv_buffer.begin);
|
2011-08-07 02:41:13 +02:00
|
|
|
incoming_dont_have(piece);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2014-11-23 07:14:47 +01:00
|
|
|
if (m_recv_buffer.packet_finished())
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming_message, "EXTENSION_MESSAGE"
|
|
|
|
, "msg: %d size: %d", extended_id, m_recv_buffer.packet_size());
|
2010-11-29 02:33:05 +01:00
|
|
|
#endif
|
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
for (extension_list_t::iterator i = m_extensions.begin()
|
|
|
|
, end(m_extensions.end()); i != end; ++i)
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2014-11-23 07:14:47 +01:00
|
|
|
if ((*i)->on_extended(m_recv_buffer.packet_size() - 2, extended_id
|
2006-11-14 01:08:16 +01:00
|
|
|
, recv_buffer))
|
|
|
|
return;
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_message, op_bittorrent, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
2006-11-14 01:08:16 +01:00
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
void bt_peer_connection::on_extended_handshake()
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(t);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
buffer::const_interval recv_buffer = m_recv_buffer.get();
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2015-03-12 06:20:12 +01:00
|
|
|
bdecode_node root;
|
2010-10-28 06:01:59 +02:00
|
|
|
error_code ec;
|
|
|
|
int pos;
|
2015-03-12 06:20:12 +01:00
|
|
|
int ret = bdecode(recv_buffer.begin + 2, recv_buffer.end, root, ec, &pos);
|
|
|
|
if (ret != 0 || ec || root.type() != bdecode_node::dict_t)
|
2006-11-14 01:08:16 +01:00
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "EXTENSION_MESSAGE"
|
|
|
|
, "invalid extended handshake: %s pos: %d"
|
2010-12-01 05:22:03 +01:00
|
|
|
, ec.message().c_str(), pos);
|
2006-11-14 01:08:16 +01:00
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming_message, "EXTENDED_HANDSHAKE"
|
|
|
|
, "%s", print_entry(root).c_str());
|
2006-04-25 23:04:48 +02:00
|
|
|
#endif
|
|
|
|
|
2008-07-01 22:22:25 +02:00
|
|
|
for (extension_list_t::iterator i = m_extensions.begin();
|
|
|
|
!m_extensions.empty() && i != m_extensions.end();)
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2006-11-14 01:08:16 +01:00
|
|
|
// a false return value means that the extension
|
|
|
|
// isn't supported by the other end. So, it is removed.
|
|
|
|
if (!(*i)->on_extension_handshake(root))
|
|
|
|
i = m_extensions.erase(i);
|
|
|
|
else
|
|
|
|
++i;
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
2008-10-23 18:31:15 +02:00
|
|
|
if (is_disconnecting()) return;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2009-11-24 19:49:59 +01:00
|
|
|
// upload_only
|
2015-03-12 06:20:12 +01:00
|
|
|
if (bdecode_node m = root.dict_find_dict("m"))
|
2010-11-29 02:33:05 +01:00
|
|
|
{
|
2015-03-12 06:20:12 +01:00
|
|
|
m_upload_only_id = boost::uint8_t(m.dict_find_int_value("upload_only", 0));
|
|
|
|
m_holepunch_id = boost::uint8_t(m.dict_find_int_value("ut_holepunch", 0));
|
|
|
|
m_dont_have_id = boost::uint8_t(m.dict_find_int_value("lt_donthave", 0));
|
2010-11-29 02:33:05 +01:00
|
|
|
}
|
2009-11-24 19:49:59 +01:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
// there is supposed to be a remote listen port
|
2011-02-21 06:24:41 +01:00
|
|
|
int listen_port = int(root.dict_find_int_value("p"));
|
2008-07-01 10:04:12 +02:00
|
|
|
if (listen_port > 0 && peer_info_struct() != 0)
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
t->update_peer_port(listen_port, peer_info_struct(), peer_info::incoming);
|
2012-01-04 21:49:54 +01:00
|
|
|
received_listen_port();
|
2008-11-01 20:34:12 +01:00
|
|
|
if (is_disconnecting()) return;
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
2012-01-04 21:49:54 +01:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
// there should be a version too
|
|
|
|
// but where do we put that info?
|
2010-03-19 19:39:51 +01:00
|
|
|
|
2011-02-21 06:24:41 +01:00
|
|
|
int last_seen_complete = boost::uint8_t(root.dict_find_int_value("complete_ago", -1));
|
2010-03-19 19:39:51 +01:00
|
|
|
if (last_seen_complete >= 0) set_last_seen_complete(last_seen_complete);
|
2015-05-23 03:38:47 +02:00
|
|
|
|
2008-07-01 10:04:12 +02:00
|
|
|
std::string client_info = root.dict_find_string_value("v");
|
|
|
|
if (!client_info.empty()) m_client_version = client_info;
|
2006-05-15 00:30:05 +02:00
|
|
|
|
2011-02-21 06:24:41 +01:00
|
|
|
int reqq = int(root.dict_find_int_value("reqq"));
|
2015-05-03 04:53:54 +02:00
|
|
|
if (reqq > 0) max_out_request_queue(reqq);
|
2008-02-28 04:09:34 +01:00
|
|
|
|
2009-11-24 19:49:59 +01:00
|
|
|
if (root.dict_find_int_value("upload_only", 0))
|
2008-07-01 10:04:12 +02:00
|
|
|
set_upload_only(true);
|
2008-05-18 07:59:47 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_bool(settings_pack::support_share_mode)
|
2013-02-23 23:13:25 +01:00
|
|
|
&& root.dict_find_int_value("share_mode", 0))
|
2010-09-05 18:01:36 +02:00
|
|
|
set_share_mode(true);
|
|
|
|
|
2008-07-01 10:04:12 +02:00
|
|
|
std::string myip = root.dict_find_string_value("yourip");
|
|
|
|
if (!myip.empty())
|
2008-02-28 04:09:34 +01:00
|
|
|
{
|
2011-08-08 01:40:39 +02:00
|
|
|
if (myip.size() == address_v4::bytes_type().size())
|
2008-07-01 10:04:12 +02:00
|
|
|
{
|
|
|
|
address_v4::bytes_type bytes;
|
|
|
|
std::copy(myip.begin(), myip.end(), bytes.begin());
|
2010-12-24 02:31:41 +01:00
|
|
|
m_ses.set_external_address(address_v4(bytes)
|
2014-07-06 21:18:00 +02:00
|
|
|
, aux::session_interface::source_peer, remote().address());
|
2008-07-01 10:04:12 +02:00
|
|
|
}
|
2009-11-27 19:46:29 +01:00
|
|
|
#if TORRENT_USE_IPV6
|
2011-08-08 01:40:39 +02:00
|
|
|
else if (myip.size() == address_v6::bytes_type().size())
|
2008-02-28 04:09:34 +01:00
|
|
|
{
|
2008-07-01 10:04:12 +02:00
|
|
|
address_v6::bytes_type bytes;
|
|
|
|
std::copy(myip.begin(), myip.end(), bytes.begin());
|
2008-09-20 18:21:16 +02:00
|
|
|
address_v6 ipv6_address(bytes);
|
|
|
|
if (ipv6_address.is_v4_mapped())
|
2010-12-24 02:31:41 +01:00
|
|
|
m_ses.set_external_address(ipv6_address.to_v4()
|
2014-07-06 21:18:00 +02:00
|
|
|
, aux::session_interface::source_peer, remote().address());
|
2008-09-20 18:21:16 +02:00
|
|
|
else
|
2010-12-24 02:31:41 +01:00
|
|
|
m_ses.set_external_address(ipv6_address
|
2014-07-06 21:18:00 +02:00
|
|
|
, aux::session_interface::source_peer, remote().address());
|
2008-02-28 04:09:34 +01:00
|
|
|
}
|
2009-11-27 19:46:29 +01:00
|
|
|
#endif
|
2008-02-28 04:09:34 +01:00
|
|
|
}
|
2008-05-18 07:59:47 +02:00
|
|
|
|
|
|
|
// if we're finished and this peer is uploading only
|
|
|
|
// disconnect it
|
2010-09-05 06:31:13 +02:00
|
|
|
if (t->is_finished() && upload_only()
|
2014-07-06 21:18:00 +02:00
|
|
|
&& m_settings.get_bool(settings_pack::close_redundant_connections)
|
2010-09-05 18:01:36 +02:00
|
|
|
&& !t->share_mode())
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::upload_upload_connection, op_bittorrent);
|
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::num_incoming_ext_handshake);
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
2013-12-20 09:35:29 +01:00
|
|
|
#endif // TORRENT_DISABLE_EXTENSIONS
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
bool bt_peer_connection::dispatch_message(int received)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(received >= 0);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
// this means the connection has been closed already
|
2008-11-06 10:01:27 +01:00
|
|
|
if (associated_torrent().expired())
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, received);
|
2008-11-06 10:01:27 +01:00
|
|
|
return false;
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
buffer::const_interval recv_buffer = m_recv_buffer.get();
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2008-04-10 12:03:23 +02:00
|
|
|
TORRENT_ASSERT(recv_buffer.left() >= 1);
|
2015-08-09 04:53:11 +02:00
|
|
|
int packet_type = static_cast<boost::uint8_t>(recv_buffer[0]);
|
2013-02-23 23:13:25 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_bool(settings_pack::support_merkle_torrents)
|
2013-02-23 23:13:25 +01:00
|
|
|
&& packet_type == 250) packet_type = msg_piece;
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
if (packet_type < 0
|
|
|
|
|| packet_type >= num_supported_messages
|
|
|
|
|| m_message_handler[packet_type] == 0)
|
|
|
|
{
|
2006-11-14 01:08:16 +01:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
|
|
|
for (extension_list_t::iterator i = m_extensions.begin()
|
|
|
|
, end(m_extensions.end()); i != end; ++i)
|
|
|
|
{
|
2014-11-23 07:14:47 +01:00
|
|
|
if ((*i)->on_unknown_message(m_recv_buffer.packet_size(), packet_type
|
2006-11-14 01:08:16 +01:00
|
|
|
, buffer::const_interval(recv_buffer.begin+1
|
|
|
|
, recv_buffer.end)))
|
2014-11-23 07:14:47 +01:00
|
|
|
return m_recv_buffer.packet_finished();
|
2006-11-14 01:08:16 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, received);
|
|
|
|
disconnect(errors::invalid_message, op_bittorrent);
|
2014-11-23 07:14:47 +01:00
|
|
|
return m_recv_buffer.packet_finished();
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_message_handler[packet_type] != 0);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2015-05-19 05:13:49 +02:00
|
|
|
#if TORRENT_USE_ASSERTS
|
2014-12-03 05:32:50 +01:00
|
|
|
boost::int64_t cur_payload_dl = statistics().last_payload_downloaded();
|
|
|
|
boost::int64_t cur_protocol_dl = statistics().last_protocol_downloaded();
|
2008-09-21 19:12:26 +02:00
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
// call the correct handler for this packet type
|
|
|
|
(this->*m_message_handler[packet_type])(received);
|
2015-05-19 05:13:49 +02:00
|
|
|
|
|
|
|
#if TORRENT_USE_ASSERTS
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(statistics().last_payload_downloaded() - cur_payload_dl >= 0);
|
|
|
|
TORRENT_ASSERT(statistics().last_protocol_downloaded() - cur_protocol_dl >= 0);
|
2014-12-03 05:32:50 +01:00
|
|
|
boost::int64_t stats_diff = statistics().last_payload_downloaded() - cur_payload_dl +
|
2014-07-06 21:18:00 +02:00
|
|
|
statistics().last_protocol_downloaded() - cur_protocol_dl;
|
2008-09-21 19:12:26 +02:00
|
|
|
TORRENT_ASSERT(stats_diff == received);
|
|
|
|
#endif
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
bool finished = m_recv_buffer.packet_finished();
|
2014-07-06 21:18:00 +02:00
|
|
|
|
|
|
|
if (finished)
|
|
|
|
{
|
|
|
|
// count this packet in the session stats counters
|
|
|
|
int counter = counters::num_incoming_extended;
|
|
|
|
if (packet_type <= msg_dht_port)
|
|
|
|
counter = counters::num_incoming_choke + packet_type;
|
|
|
|
else if (packet_type <= msg_allowed_fast)
|
|
|
|
counter = counters::num_incoming_suggest + packet_type;
|
|
|
|
else if (packet_type <= msg_extended)
|
|
|
|
counter = counters::num_incoming_extended;
|
|
|
|
else
|
|
|
|
TORRENT_ASSERT(false);
|
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counter);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return finished;
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
2009-11-24 19:49:59 +01:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
|
|
|
void bt_peer_connection::write_upload_only()
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
2015-05-19 05:13:49 +02:00
|
|
|
|
2009-11-24 19:49:59 +01:00
|
|
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
|
|
|
if (m_upload_only_id == 0) return;
|
2010-09-05 18:01:36 +02:00
|
|
|
if (t->share_mode()) return;
|
2009-11-24 19:49:59 +01:00
|
|
|
|
2013-01-27 22:25:06 +01:00
|
|
|
// if we send upload-only, the other end is very likely to disconnect
|
|
|
|
// us, at least if it's a seed. If we don't want to close redundant
|
|
|
|
// connections, don't sent upload-only
|
2014-07-06 21:18:00 +02:00
|
|
|
if (!m_settings.get_bool(settings_pack::close_redundant_connections)) return;
|
2013-01-27 22:25:06 +01:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::outgoing_message, "UPLOAD_ONLY", "%d"
|
2014-01-26 05:45:49 +01:00
|
|
|
, int(t->is_upload_only() && !t->super_seeding()));
|
|
|
|
#endif
|
|
|
|
|
2009-11-24 19:49:59 +01:00
|
|
|
char msg[7] = {0, 0, 0, 3, msg_extended};
|
|
|
|
char* ptr = msg + 5;
|
|
|
|
detail::write_uint8(m_upload_only_id, ptr);
|
2011-04-10 01:57:56 +02:00
|
|
|
// if we're super seeding, we don't want to make peers
|
|
|
|
// think that we only have a single piece and is upload
|
|
|
|
// only, since they might disconnect immediately when
|
|
|
|
// they have downloaded a single piece, although we'll
|
|
|
|
// make another piece available
|
|
|
|
detail::write_uint8(t->is_upload_only() && !t->super_seeding(), ptr);
|
2009-11-24 19:49:59 +01:00
|
|
|
send_buffer(msg, sizeof(msg));
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::num_outgoing_extended);
|
2009-11-24 19:49:59 +01:00
|
|
|
}
|
2010-09-05 18:01:36 +02:00
|
|
|
|
|
|
|
void bt_peer_connection::write_share_mode()
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
|
|
|
if (m_share_mode_id == 0) return;
|
|
|
|
|
|
|
|
char msg[7] = {0, 0, 0, 3, msg_extended};
|
|
|
|
char* ptr = msg + 5;
|
|
|
|
detail::write_uint8(m_share_mode_id, ptr);
|
|
|
|
detail::write_uint8(t->share_mode(), ptr);
|
|
|
|
send_buffer(msg, sizeof(msg));
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::num_outgoing_extended);
|
2010-09-05 18:01:36 +02:00
|
|
|
}
|
2009-11-24 19:49:59 +01:00
|
|
|
#endif
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
void bt_peer_connection::write_keepalive()
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2007-11-19 08:07:57 +01:00
|
|
|
// Don't require the bitfield to have been sent at this point
|
|
|
|
// the case where m_sent_bitfield may not be true is if the
|
|
|
|
// torrent doesn't have any metadata, and a peer is timimg out.
|
|
|
|
// then the keep-alive message will be sent before the bitfield
|
|
|
|
// this is a violation to the original protocol, but necessary
|
|
|
|
// for the metadata extension.
|
|
|
|
TORRENT_ASSERT(m_sent_handshake);
|
2007-07-09 06:22:38 +02:00
|
|
|
|
2007-09-29 18:14:03 +02:00
|
|
|
char msg[] = {0,0,0,0};
|
|
|
|
send_buffer(msg, sizeof(msg));
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void bt_peer_connection::write_cancel(peer_request const& r)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
|
|
|
|
TORRENT_ASSERT(associated_torrent().lock()->valid_metadata());
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2007-09-29 18:14:03 +02:00
|
|
|
char msg[17] = {0,0,0,13, msg_cancel};
|
|
|
|
char* ptr = msg + 5;
|
|
|
|
detail::write_int32(r.piece, ptr); // index
|
|
|
|
detail::write_int32(r.start, ptr); // begin
|
|
|
|
detail::write_int32(r.length, ptr); // length
|
|
|
|
send_buffer(msg, sizeof(msg));
|
2008-01-02 04:18:29 +01:00
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::num_outgoing_cancel);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2008-01-02 04:18:29 +01:00
|
|
|
if (!m_supports_fast)
|
|
|
|
incoming_reject_request(r);
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void bt_peer_connection::write_request(peer_request const& r)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
|
|
|
|
TORRENT_ASSERT(associated_torrent().lock()->valid_metadata());
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2007-09-29 18:14:03 +02:00
|
|
|
char msg[17] = {0,0,0,13, msg_request};
|
|
|
|
char* ptr = msg + 5;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2007-09-29 18:14:03 +02:00
|
|
|
detail::write_int32(r.piece, ptr); // index
|
|
|
|
detail::write_int32(r.start, ptr); // begin
|
|
|
|
detail::write_int32(r.length, ptr); // length
|
2008-07-08 02:03:08 +02:00
|
|
|
send_buffer(msg, sizeof(msg), message_type_request);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::num_outgoing_request);
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
2008-06-07 04:58:28 +02:00
|
|
|
void bt_peer_connection::write_bitfield()
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
|
|
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(t);
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(m_sent_handshake);
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(t->valid_metadata());
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2008-12-08 07:36:22 +01:00
|
|
|
if (t->super_seeding())
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "BITFIELD", "not sending bitfield, super seeding");
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
2008-12-08 07:36:22 +01:00
|
|
|
if (m_supports_fast) write_have_none();
|
|
|
|
|
|
|
|
// if we are super seeding, pretend to not have any piece
|
|
|
|
// and don't send a bitfield
|
|
|
|
m_sent_bitfield = true;
|
|
|
|
|
2012-04-23 07:48:46 +02:00
|
|
|
// bootstrap superseeding by sending two have message
|
2014-03-19 05:34:24 +01:00
|
|
|
int piece = t->get_piece_to_super_seed(get_bitfield());
|
|
|
|
if (piece >= 0) superseed_piece(-1, piece);
|
|
|
|
piece = t->get_piece_to_super_seed(get_bitfield());
|
|
|
|
if (piece >= 0) superseed_piece(-1, piece);
|
2008-12-08 07:36:22 +01:00
|
|
|
return;
|
|
|
|
}
|
2014-11-09 12:17:13 +01:00
|
|
|
else if (m_supports_fast && t->is_seed() && !m_settings.get_bool(settings_pack::lazy_bitfields))
|
2007-08-14 19:47:48 +02:00
|
|
|
{
|
|
|
|
write_have_all();
|
|
|
|
send_allowed_set();
|
|
|
|
return;
|
|
|
|
}
|
2008-06-07 16:03:21 +02:00
|
|
|
else if (m_supports_fast && t->num_have() == 0)
|
2007-08-14 19:47:48 +02:00
|
|
|
{
|
|
|
|
write_have_none();
|
|
|
|
send_allowed_set();
|
|
|
|
return;
|
|
|
|
}
|
2008-06-07 16:03:21 +02:00
|
|
|
else if (t->num_have() == 0)
|
2007-12-21 00:58:58 +01:00
|
|
|
{
|
|
|
|
// don't send a bitfield if we don't have any pieces
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "BITFIELD", "not sending bitfield, have none");
|
2008-08-17 00:07:15 +02:00
|
|
|
#endif
|
2007-12-22 20:10:38 +01:00
|
|
|
m_sent_bitfield = true;
|
2007-12-21 00:58:58 +01:00
|
|
|
return;
|
|
|
|
}
|
2007-08-14 19:47:48 +02:00
|
|
|
|
2015-05-04 00:21:19 +02:00
|
|
|
const int num_pieces = t->torrent_file().num_pieces();
|
|
|
|
TORRENT_ASSERT(num_pieces > 0);
|
|
|
|
if (num_pieces <= 0)
|
|
|
|
{
|
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
|
|
|
peer_log(peer_log_alert::info, "BITFIELD", "not sending bitfield, num_pieces == 0");
|
|
|
|
#endif
|
|
|
|
return;
|
|
|
|
}
|
2008-12-08 07:36:22 +01:00
|
|
|
|
2007-05-27 00:27:40 +02:00
|
|
|
int lazy_pieces[50];
|
|
|
|
int num_lazy_pieces = 0;
|
|
|
|
int lazy_piece = 0;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (t->is_seed() && m_settings.get_bool(settings_pack::lazy_bitfields)
|
2014-11-23 07:14:47 +01:00
|
|
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
2010-02-25 20:19:12 +01:00
|
|
|
&& !m_encrypted
|
|
|
|
#endif
|
|
|
|
)
|
2007-05-27 00:27:40 +02:00
|
|
|
{
|
2007-08-17 00:14:17 +02:00
|
|
|
num_lazy_pieces = (std::min)(50, num_pieces / 10);
|
2007-05-27 00:27:40 +02:00
|
|
|
if (num_lazy_pieces < 1) num_lazy_pieces = 1;
|
|
|
|
for (int i = 0; i < num_pieces; ++i)
|
|
|
|
{
|
2011-02-26 08:55:51 +01:00
|
|
|
if (int(random() % (num_pieces - i)) >= num_lazy_pieces - lazy_piece) continue;
|
2007-05-27 00:27:40 +02:00
|
|
|
lazy_pieces[lazy_piece++] = i;
|
|
|
|
}
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(lazy_piece == num_lazy_pieces);
|
2007-05-27 00:27:40 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
const int packet_size = (num_pieces + 7) / 8 + 5;
|
2015-08-09 04:53:11 +02:00
|
|
|
|
|
|
|
boost::uint8_t* msg = TORRENT_ALLOCA(boost::uint8_t, packet_size);
|
2011-05-19 04:41:28 +02:00
|
|
|
if (msg == 0) return; // out of memory
|
2015-08-09 04:53:11 +02:00
|
|
|
unsigned char* ptr = msg;
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2011-05-19 04:41:28 +02:00
|
|
|
detail::write_int32(packet_size - 4, ptr);
|
|
|
|
detail::write_uint8(msg_bitfield, ptr);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2008-06-07 04:58:28 +02:00
|
|
|
if (t->is_seed())
|
|
|
|
{
|
2013-10-12 08:03:19 +02:00
|
|
|
memset(ptr, 0xff, packet_size - 5);
|
2009-02-06 09:51:25 +01:00
|
|
|
|
|
|
|
// Clear trailing bits
|
2015-08-09 04:53:11 +02:00
|
|
|
unsigned char *p = msg + packet_size - 1;
|
2009-02-06 09:51:25 +01:00
|
|
|
*p = (0xff << ((8 - (num_pieces & 7)) & 7)) & 0xff;
|
2008-06-07 04:58:28 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-05-19 04:41:28 +02:00
|
|
|
memset(ptr, 0, packet_size - 5);
|
2008-06-07 04:58:28 +02:00
|
|
|
piece_picker const& p = t->picker();
|
|
|
|
int mask = 0x80;
|
|
|
|
for (int i = 0; i < num_pieces; ++i)
|
|
|
|
{
|
2011-05-19 04:41:28 +02:00
|
|
|
if (p.have_piece(i)) *ptr |= mask;
|
2008-06-07 04:58:28 +02:00
|
|
|
mask >>= 1;
|
|
|
|
if (mask == 0)
|
|
|
|
{
|
|
|
|
mask = 0x80;
|
2011-05-19 04:41:28 +02:00
|
|
|
++ptr;
|
2008-06-07 04:58:28 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-05-28 04:35:02 +02:00
|
|
|
for (int c = 0; c < num_lazy_pieces; ++c)
|
2011-05-19 04:41:28 +02:00
|
|
|
msg[5 + lazy_pieces[c] / 8] &= ~(0x80 >> (lazy_pieces[c] & 7));
|
2007-06-05 12:20:45 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// add predictive pieces to the bitfield as well, since we won't
|
|
|
|
// announce them again
|
|
|
|
for (std::vector<int>::const_iterator i = t->predictive_pieces().begin()
|
|
|
|
, end(t->predictive_pieces().end()); i != end; ++i)
|
|
|
|
msg[5 + *i / 8] |= (0x80 >> (*i & 7));
|
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2008-06-07 04:58:28 +02:00
|
|
|
|
2009-04-25 20:39:44 +02:00
|
|
|
std::string bitfield_string;
|
2010-12-01 05:22:03 +01:00
|
|
|
bitfield_string.resize(num_pieces);
|
2008-06-07 04:58:28 +02:00
|
|
|
for (int k = 0; k < num_pieces; ++k)
|
|
|
|
{
|
2011-05-19 04:41:28 +02:00
|
|
|
if (msg[5 + k / 8] & (0x80 >> (k % 8))) bitfield_string[k] = '1';
|
2009-04-04 11:52:25 +02:00
|
|
|
else bitfield_string[k] = '0';
|
2008-06-07 04:58:28 +02:00
|
|
|
}
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::outgoing_message, "BITFIELD"
|
|
|
|
, "%s", bitfield_string.c_str());
|
2008-06-07 04:58:28 +02:00
|
|
|
#endif
|
2007-06-05 12:20:45 +02:00
|
|
|
m_sent_bitfield = true;
|
|
|
|
|
2015-08-09 04:53:11 +02:00
|
|
|
send_buffer(reinterpret_cast<char const*>(msg), packet_size);
|
2009-01-28 05:20:05 +01:00
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::num_outgoing_bitfield);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2007-05-27 00:27:40 +02:00
|
|
|
if (num_lazy_pieces > 0)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < num_lazy_pieces; ++i)
|
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::outgoing_message, "HAVE"
|
|
|
|
, "piece: %d", lazy_pieces[i]);
|
2007-05-27 00:27:40 +02:00
|
|
|
#endif
|
2010-12-01 05:22:03 +01:00
|
|
|
write_have(lazy_pieces[i]);
|
2007-05-27 00:27:40 +02:00
|
|
|
}
|
2008-12-08 07:36:22 +01:00
|
|
|
// TODO: if we're finished, send upload_only message
|
2007-05-27 00:27:40 +02:00
|
|
|
}
|
2007-08-14 19:47:48 +02:00
|
|
|
|
|
|
|
if (m_supports_fast)
|
|
|
|
send_allowed_set();
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
2006-04-25 23:04:48 +02:00
|
|
|
void bt_peer_connection::write_extensions()
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_supports_extensions);
|
|
|
|
TORRENT_ASSERT(m_sent_handshake);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2009-11-24 19:49:59 +01:00
|
|
|
entry handshake;
|
|
|
|
entry::dictionary_type& m = handshake["m"].dict();
|
2006-11-26 18:44:15 +01:00
|
|
|
|
2014-01-26 09:36:56 +01:00
|
|
|
// if we're using a proxy, our listen port won't be useful
|
|
|
|
// anyway.
|
2014-07-06 21:18:00 +02:00
|
|
|
if (!m_settings.get_bool(settings_pack::force_proxy) && is_outgoing())
|
2014-01-26 09:36:56 +01:00
|
|
|
handshake["p"] = m_ses.listen_port();
|
|
|
|
|
2006-11-26 18:44:15 +01:00
|
|
|
// only send the port in case we bade the connection
|
|
|
|
// on incoming connections the other end already knows
|
|
|
|
// our listen port
|
2014-07-06 21:18:00 +02:00
|
|
|
if (!m_settings.get_bool(settings_pack::anonymous_mode))
|
2010-04-13 06:30:34 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
handshake["v"] = m_settings.get_str(settings_pack::handshake_client_version).empty()
|
|
|
|
? m_settings.get_str(settings_pack::user_agent)
|
|
|
|
: m_settings.get_str(settings_pack::handshake_client_version);
|
2010-04-13 06:30:34 +02:00
|
|
|
}
|
|
|
|
|
2006-09-28 02:49:40 +02:00
|
|
|
std::string remote_address;
|
|
|
|
std::back_insert_iterator<std::string> out(remote_address);
|
|
|
|
detail::write_address(remote().address(), out);
|
2007-07-07 03:36:40 +02:00
|
|
|
handshake["yourip"] = remote_address;
|
2014-07-06 21:18:00 +02:00
|
|
|
handshake["reqq"] = m_settings.get_int(settings_pack::max_allowed_in_request_queue);
|
2008-05-18 07:59:47 +02:00
|
|
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
|
|
|
TORRENT_ASSERT(t);
|
2008-12-08 07:36:22 +01:00
|
|
|
|
2009-11-24 19:49:59 +01:00
|
|
|
m["upload_only"] = upload_only_msg;
|
2010-11-29 02:33:05 +01:00
|
|
|
m["ut_holepunch"] = holepunch_msg;
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_bool(settings_pack::support_share_mode))
|
2013-02-23 23:13:25 +01:00
|
|
|
m["share_mode"] = share_mode_msg;
|
2011-08-07 02:41:13 +02:00
|
|
|
m["lt_donthave"] = dont_have_msg;
|
2010-11-29 02:33:05 +01:00
|
|
|
|
2010-03-19 19:39:51 +01:00
|
|
|
int complete_ago = -1;
|
|
|
|
if (t->last_seen_complete() > 0) complete_ago = t->time_since_complete();
|
|
|
|
handshake["complete_ago"] = complete_ago;
|
2009-11-24 19:49:59 +01:00
|
|
|
|
2008-12-08 07:36:22 +01:00
|
|
|
// if we're using lazy bitfields or if we're super seeding, don't say
|
2015-02-07 02:01:48 +01:00
|
|
|
// we're upload only, since it might make peers disconnect. don't tell
|
|
|
|
// anyone we're upload only when in share mode, we want to stay connected
|
|
|
|
// to seeds. if we're super seeding, we don't want to make peers think
|
|
|
|
// that we only have a single piece and is upload only, since they might
|
|
|
|
// disconnect immediately when they have downloaded a single piece,
|
|
|
|
// although we'll make another piece available. If we don't have
|
|
|
|
// metadata, we also need to suppress saying we're upload-only. If we do,
|
|
|
|
// we may be disconnected before we receive the metadata.
|
2011-04-10 01:57:56 +02:00
|
|
|
if (t->is_upload_only()
|
|
|
|
&& !t->share_mode()
|
2015-02-07 02:01:48 +01:00
|
|
|
&& t->valid_metadata()
|
2011-04-10 01:57:56 +02:00
|
|
|
&& !t->super_seeding()
|
2014-07-06 21:18:00 +02:00
|
|
|
&& (!m_settings.get_bool(settings_pack::lazy_bitfields)
|
2014-11-23 07:14:47 +01:00
|
|
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
2010-02-25 20:19:12 +01:00
|
|
|
|| m_encrypted
|
|
|
|
#endif
|
|
|
|
))
|
2015-02-07 02:01:48 +01:00
|
|
|
{
|
2008-12-08 07:36:22 +01:00
|
|
|
handshake["upload_only"] = 1;
|
2015-02-07 02:01:48 +01:00
|
|
|
}
|
2007-09-22 18:27:29 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_bool(settings_pack::support_share_mode)
|
2013-02-23 23:13:25 +01:00
|
|
|
&& t->share_mode())
|
2010-09-05 18:01:36 +02:00
|
|
|
handshake["share_mode"] = 1;
|
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
// loop backwards, to make the first extension be the last
|
|
|
|
// to fill in the handshake (i.e. give the first extensions priority)
|
|
|
|
for (extension_list_t::reverse_iterator i = m_extensions.rbegin()
|
|
|
|
, end(m_extensions.rend()); i != end; ++i)
|
|
|
|
{
|
|
|
|
(*i)->add_handshake(handshake);
|
|
|
|
}
|
|
|
|
|
2010-11-29 02:33:05 +01:00
|
|
|
#ifndef NDEBUG
|
|
|
|
// make sure there are not conflicting extensions
|
|
|
|
std::set<int> ext;
|
|
|
|
for (entry::dictionary_type::const_iterator i = m.begin()
|
|
|
|
, end(m.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
if (i->second.type() != entry::int_t) continue;
|
2011-02-21 06:24:41 +01:00
|
|
|
int val = int(i->second.integer());
|
2010-11-29 02:33:05 +01:00
|
|
|
TORRENT_ASSERT(ext.find(val) == ext.end());
|
|
|
|
ext.insert(val);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2011-05-19 04:41:28 +02:00
|
|
|
std::vector<char> dict_msg;
|
|
|
|
bencode(std::back_inserter(dict_msg), handshake);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2011-05-19 04:41:28 +02:00
|
|
|
char msg[6];
|
|
|
|
char* ptr = msg;
|
2015-08-09 04:53:11 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
// write the length of the message
|
2015-08-09 04:53:11 +02:00
|
|
|
detail::write_int32(int(dict_msg.size()) + 2, ptr);
|
2011-05-19 04:41:28 +02:00
|
|
|
detail::write_uint8(msg_extended, ptr);
|
2006-04-25 23:04:48 +02:00
|
|
|
// signal handshake message
|
2011-05-19 04:41:28 +02:00
|
|
|
detail::write_uint8(0, ptr);
|
|
|
|
send_buffer(msg, sizeof(msg));
|
|
|
|
send_buffer(&dict_msg[0], dict_msg.size());
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::num_outgoing_ext_handshake);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::outgoing_message, "EXTENDED_HANDSHAKE"
|
|
|
|
, "%s", handshake.to_string().c_str());
|
2006-04-25 23:04:48 +02:00
|
|
|
#endif
|
|
|
|
}
|
2006-11-14 01:08:16 +01:00
|
|
|
#endif
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
void bt_peer_connection::write_choke()
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
2007-07-09 06:22:38 +02:00
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
if (is_choked()) return;
|
|
|
|
char msg[] = {0,0,0,1,msg_choke};
|
2007-09-29 18:14:03 +02:00
|
|
|
send_buffer(msg, sizeof(msg));
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::num_outgoing_choke);
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void bt_peer_connection::write_unchoke()
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
2007-07-09 06:22:38 +02:00
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
char msg[] = {0,0,0,1,msg_unchoke};
|
2007-09-29 18:14:03 +02:00
|
|
|
send_buffer(msg, sizeof(msg));
|
2014-05-12 09:28:34 +02:00
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::num_outgoing_unchoke);
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2014-05-12 09:28:34 +02:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
|
|
|
for (extension_list_t::iterator i = m_extensions.begin()
|
|
|
|
, end(m_extensions.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
(*i)->sent_unchoke();
|
|
|
|
}
|
|
|
|
#endif
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void bt_peer_connection::write_interested()
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
2007-07-09 06:22:38 +02:00
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
char msg[] = {0,0,0,1,msg_interested};
|
2007-09-29 18:14:03 +02:00
|
|
|
send_buffer(msg, sizeof(msg));
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::num_outgoing_interested);
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void bt_peer_connection::write_not_interested()
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
2007-07-09 06:22:38 +02:00
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
char msg[] = {0,0,0,1,msg_not_interested};
|
2007-09-29 18:14:03 +02:00
|
|
|
send_buffer(msg, sizeof(msg));
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::num_outgoing_not_interested);
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void bt_peer_connection::write_have(int index)
|
|
|
|
{
|
2007-06-21 02:51:42 +02:00
|
|
|
INVARIANT_CHECK;
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(associated_torrent().lock()->valid_metadata());
|
|
|
|
TORRENT_ASSERT(index >= 0);
|
|
|
|
TORRENT_ASSERT(index < associated_torrent().lock()->torrent_file().num_pieces());
|
|
|
|
TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2007-09-29 18:14:03 +02:00
|
|
|
char msg[] = {0,0,0,5,msg_have,0,0,0,0};
|
2006-04-25 23:04:48 +02:00
|
|
|
char* ptr = msg + 5;
|
|
|
|
detail::write_int32(index, ptr);
|
2007-09-29 18:14:03 +02:00
|
|
|
send_buffer(msg, sizeof(msg));
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::num_outgoing_have);
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void bt_peer_connection::write_dont_have(int index)
|
|
|
|
{
|
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
TORRENT_ASSERT(associated_torrent().lock()->valid_metadata());
|
|
|
|
TORRENT_ASSERT(index >= 0);
|
|
|
|
TORRENT_ASSERT(index < associated_torrent().lock()->torrent_file().num_pieces());
|
|
|
|
|
|
|
|
if (in_handshake()) return;
|
|
|
|
|
|
|
|
TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
|
|
|
|
|
|
|
|
if (!m_supports_extensions || m_dont_have_id == 0) return;
|
|
|
|
|
|
|
|
char msg[] = {0,0,0,6,msg_extended,char(m_dont_have_id),0,0,0,0};
|
|
|
|
char* ptr = msg + 6;
|
|
|
|
detail::write_int32(index, ptr);
|
|
|
|
send_buffer(msg, sizeof(msg));
|
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::num_outgoing_extended);
|
2015-04-22 02:59:35 +02:00
|
|
|
#else
|
|
|
|
TORRENT_UNUSED(index);
|
2014-07-06 21:18:00 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2015-04-20 02:01:27 +02:00
|
|
|
namespace {
|
|
|
|
|
2014-07-07 08:28:48 +02:00
|
|
|
void buffer_reclaim_block(char* /* buffer */, void* userdata
|
2014-07-06 21:18:00 +02:00
|
|
|
, block_cache_reference ref)
|
|
|
|
{
|
2015-08-09 04:53:11 +02:00
|
|
|
buffer_allocator_interface* buf = static_cast<buffer_allocator_interface*>(userdata);
|
2014-07-06 21:18:00 +02:00
|
|
|
buf->reclaim_block(ref);
|
|
|
|
}
|
|
|
|
|
|
|
|
void buffer_free_disk_buf(char* buffer, void* userdata
|
2014-07-07 08:28:48 +02:00
|
|
|
, block_cache_reference /* ref */)
|
2014-07-06 21:18:00 +02:00
|
|
|
{
|
2015-08-09 04:53:11 +02:00
|
|
|
buffer_allocator_interface* buf = static_cast<buffer_allocator_interface*>(userdata);
|
2014-07-06 21:18:00 +02:00
|
|
|
buf->free_disk_buffer(buffer);
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
2015-04-20 02:01:27 +02:00
|
|
|
} // anonymous namespace
|
|
|
|
|
2008-04-10 12:03:23 +02:00
|
|
|
void bt_peer_connection::write_piece(peer_request const& r, disk_buffer_holder& buffer)
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2006-04-30 02:39:18 +02:00
|
|
|
INVARIANT_CHECK;
|
2007-07-09 06:22:38 +02:00
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_sent_handshake && m_sent_bitfield);
|
2006-04-30 02:39:18 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(t);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2009-03-13 07:09:39 +01:00
|
|
|
bool merkle = t->torrent_file().is_merkle_torrent() && r.start == 0;
|
|
|
|
// the hash piece looks like this:
|
|
|
|
// uint8_t msg
|
|
|
|
// uint32_t piece index
|
|
|
|
// uint32_t start
|
|
|
|
// uint32_t list len
|
|
|
|
// var bencoded list
|
|
|
|
// var piece data
|
|
|
|
char msg[4 + 1 + 4 + 4 + 4];
|
2007-09-29 18:14:03 +02:00
|
|
|
char* ptr = msg;
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(r.length <= 16 * 1024);
|
2007-09-29 18:14:03 +02:00
|
|
|
detail::write_int32(r.length + 1 + 4 + 4, ptr);
|
2014-07-06 21:18:00 +02:00
|
|
|
if (m_settings.get_bool(settings_pack::support_merkle_torrents) && merkle)
|
2009-03-13 07:09:39 +01:00
|
|
|
detail::write_uint8(250, ptr);
|
|
|
|
else
|
|
|
|
detail::write_uint8(msg_piece, ptr);
|
2007-09-29 18:14:03 +02:00
|
|
|
detail::write_int32(r.piece, ptr);
|
|
|
|
detail::write_int32(r.start, ptr);
|
2009-03-13 07:09:39 +01:00
|
|
|
|
|
|
|
// if this is a merkle torrent and the start offset
|
|
|
|
// is 0, we need to include the merkle node hashes
|
|
|
|
if (merkle)
|
|
|
|
{
|
2015-08-09 04:53:11 +02:00
|
|
|
std::vector<char> piece_list_buf;
|
2009-03-13 07:09:39 +01:00
|
|
|
entry piece_list;
|
|
|
|
entry::list_type& l = piece_list.list();
|
|
|
|
std::map<int, sha1_hash> merkle_node_list = t->torrent_file().build_merkle_list(r.piece);
|
|
|
|
for (std::map<int, sha1_hash>::iterator i = merkle_node_list.begin()
|
|
|
|
, end(merkle_node_list.end()); i != end; ++i)
|
|
|
|
{
|
|
|
|
l.push_back(entry(entry::list_t));
|
|
|
|
l.back().list().push_back(i->first);
|
|
|
|
l.back().list().push_back(i->second.to_string());
|
|
|
|
}
|
|
|
|
bencode(std::back_inserter(piece_list_buf), piece_list);
|
|
|
|
detail::write_int32(piece_list_buf.size(), ptr);
|
|
|
|
|
2015-08-09 04:53:11 +02:00
|
|
|
// back-patch the length field
|
|
|
|
char* ptr2 = msg;
|
|
|
|
detail::write_int32(r.length + 1 + 4 + 4 + 4 + piece_list_buf.size()
|
|
|
|
, ptr2);
|
2009-03-13 07:09:39 +01:00
|
|
|
|
2011-10-24 06:22:53 +02:00
|
|
|
send_buffer(msg, 17);
|
|
|
|
send_buffer(&piece_list_buf[0], piece_list_buf.size());
|
2009-03-13 07:09:39 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-10-24 06:22:53 +02:00
|
|
|
send_buffer(msg, 13);
|
2009-03-13 07:09:39 +01:00
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (buffer.ref().storage == 0)
|
|
|
|
{
|
|
|
|
append_send_buffer(buffer.get(), r.length
|
|
|
|
, &buffer_free_disk_buf, &m_allocator);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
append_const_send_buffer(buffer.get(), r.length
|
|
|
|
, &buffer_reclaim_block, &m_allocator, buffer.ref());
|
|
|
|
}
|
2008-04-10 12:03:23 +02:00
|
|
|
buffer.release();
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
m_payloads.push_back(range(send_buffer_size() - r.length, r.length));
|
|
|
|
setup_send();
|
2006-11-30 12:56:19 +01:00
|
|
|
|
2014-07-13 06:56:53 +02:00
|
|
|
stats_counters().inc_stats_counter(counters::num_outgoing_piece);
|
2006-11-30 12:56:19 +01:00
|
|
|
}
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
// --------------------------
|
|
|
|
// RECEIVE DATA
|
|
|
|
// --------------------------
|
|
|
|
|
2008-05-03 18:05:42 +02:00
|
|
|
void bt_peer_connection::on_receive(error_code const& error
|
2006-04-25 23:04:48 +02:00
|
|
|
, std::size_t bytes_transferred)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2008-09-21 19:12:26 +02:00
|
|
|
if (error)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, bytes_transferred);
|
2008-09-21 19:12:26 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// make sure are much as possible of the response ends up in the same
|
|
|
|
// packet, or at least back-to-back packets
|
|
|
|
cork c_(*this);
|
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
|
|
|
if (!m_enc_handler.is_recv_plaintext())
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2014-11-23 07:14:47 +01:00
|
|
|
int consumed = m_enc_handler.decrypt(m_recv_buffer, bytes_transferred);
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2014-11-23 07:14:47 +01:00
|
|
|
if (consumed + bytes_transferred > 0)
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming_message, "ENCRYPTION"
|
|
|
|
, "decrypted block s = %d", int(consumed + bytes_transferred));
|
2014-11-23 07:14:47 +01:00
|
|
|
#endif
|
|
|
|
if (bytes_transferred == SIZE_MAX)
|
|
|
|
{
|
|
|
|
disconnect(errors::parse_failed, op_encryption);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
received_bytes(0, consumed);
|
|
|
|
|
|
|
|
int sub_transferred = 0;
|
|
|
|
while (bytes_transferred > 0 &&
|
|
|
|
((sub_transferred = m_recv_buffer.advance_pos(bytes_transferred)) > 0))
|
|
|
|
{
|
|
|
|
#if TORRENT_USE_ASSERTS
|
2014-12-03 05:32:50 +01:00
|
|
|
boost::int64_t cur_payload_dl = m_statistics.last_payload_downloaded();
|
|
|
|
boost::int64_t cur_protocol_dl = m_statistics.last_protocol_downloaded();
|
2014-11-23 07:14:47 +01:00
|
|
|
#endif
|
|
|
|
on_receive_impl(sub_transferred);
|
|
|
|
bytes_transferred -= sub_transferred;
|
|
|
|
TORRENT_ASSERT(sub_transferred > 0);
|
|
|
|
|
|
|
|
#if TORRENT_USE_ASSERTS
|
|
|
|
TORRENT_ASSERT(m_statistics.last_payload_downloaded() - cur_payload_dl >= 0);
|
|
|
|
TORRENT_ASSERT(m_statistics.last_protocol_downloaded() - cur_protocol_dl >= 0);
|
2014-12-03 05:32:50 +01:00
|
|
|
boost::int64_t stats_diff = m_statistics.last_payload_downloaded() - cur_payload_dl +
|
2014-11-23 07:14:47 +01:00
|
|
|
m_statistics.last_protocol_downloaded() - cur_protocol_dl;
|
|
|
|
TORRENT_ASSERT(stats_diff == int(sub_transferred));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (m_disconnecting) return;
|
|
|
|
}
|
2007-06-06 02:41:20 +02:00
|
|
|
}
|
2014-11-23 07:14:47 +01:00
|
|
|
else
|
2007-06-06 02:41:20 +02:00
|
|
|
#endif
|
2014-11-23 07:14:47 +01:00
|
|
|
on_receive_impl(bytes_transferred);
|
|
|
|
}
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
void bt_peer_connection::on_receive_impl(std::size_t bytes_transferred)
|
|
|
|
{
|
|
|
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
|
|
|
|
|
|
|
buffer::const_interval recv_buffer = m_recv_buffer.get();
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
2007-06-06 02:41:20 +02:00
|
|
|
// m_state is set to read_pe_dhkey in initial state
|
|
|
|
// (read_protocol_identifier) for incoming, or in constructor
|
|
|
|
// for outgoing
|
|
|
|
if (m_state == read_pe_dhkey)
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, bytes_transferred);
|
2008-09-21 19:12:26 +02:00
|
|
|
|
2008-04-10 12:03:23 +02:00
|
|
|
TORRENT_ASSERT(!m_encrypted);
|
|
|
|
TORRENT_ASSERT(!m_rc4_encrypted);
|
2014-11-23 07:14:47 +01:00
|
|
|
TORRENT_ASSERT(m_recv_buffer.packet_size() == dh_key_len);
|
|
|
|
TORRENT_ASSERT(recv_buffer == m_recv_buffer.get());
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2008-06-28 12:10:05 +02:00
|
|
|
// write our dh public key. m_dh_key_exchange is
|
2007-06-06 02:41:20 +02:00
|
|
|
// initialized in write_pe1_2_dhkey()
|
2012-02-07 04:46:21 +01:00
|
|
|
if (!is_outgoing()) write_pe1_2_dhkey();
|
2008-06-28 12:10:05 +02:00
|
|
|
if (is_disconnecting()) return;
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
// read dh key, generate shared secret
|
2014-11-08 17:58:18 +01:00
|
|
|
if (m_dh_key_exchange->compute_secret(recv_buffer.begin) != 0)
|
2008-06-28 12:10:05 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::no_memory, op_encryption);
|
2008-06-28 12:10:05 +02:00
|
|
|
return;
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ENCRYPTION", "received DH key");
|
2007-06-06 02:41:20 +02:00
|
|
|
#endif
|
2014-11-23 07:14:47 +01:00
|
|
|
|
2007-06-06 02:41:20 +02:00
|
|
|
// PadA/B can be a max of 512 bytes, and 20 bytes more for
|
|
|
|
// the sync hash (if incoming), or 8 bytes more for the
|
|
|
|
// encrypted verification constant (if outgoing). Instead
|
|
|
|
// of requesting the maximum possible, request the maximum
|
|
|
|
// possible to ensure we do not overshoot the standard
|
|
|
|
// handshake.
|
|
|
|
|
2012-02-07 04:46:21 +01:00
|
|
|
if (is_outgoing())
|
2007-06-06 02:41:20 +02:00
|
|
|
{
|
|
|
|
m_state = read_pe_syncvc;
|
|
|
|
write_pe3_sync();
|
|
|
|
|
|
|
|
// initial payload is the standard handshake, this is
|
|
|
|
// always rc4 if sent here. m_rc4_encrypted is flagged
|
|
|
|
// again according to peer selection.
|
2014-11-23 07:14:47 +01:00
|
|
|
switch_send_crypto(m_rc4);
|
2014-07-06 21:18:00 +02:00
|
|
|
write_handshake(true);
|
2014-11-23 07:14:47 +01:00
|
|
|
switch_send_crypto(boost::shared_ptr<crypto_plugin>());
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
// vc,crypto_select,len(pad),pad, encrypt(handshake)
|
|
|
|
// 8+4+2+0+handshake_len
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.reset(8+4+2+0+handshake_len);
|
2007-06-06 02:41:20 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// already written dh key
|
|
|
|
m_state = read_pe_synchash;
|
|
|
|
// synchash,skeyhash,vc,crypto_provide,len(pad),pad,encrypt(handshake)
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.reset(20+20+8+4+2+0+handshake_len);
|
2007-06-06 02:41:20 +02:00
|
|
|
}
|
2014-11-23 07:14:47 +01:00
|
|
|
TORRENT_ASSERT(!m_recv_buffer.packet_finished());
|
2007-06-06 02:41:20 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// cannot fall through into
|
|
|
|
if (m_state == read_pe_synchash)
|
|
|
|
{
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(!m_encrypted);
|
|
|
|
TORRENT_ASSERT(!m_rc4_encrypted);
|
2012-02-07 04:46:21 +01:00
|
|
|
TORRENT_ASSERT(!is_outgoing());
|
2014-11-23 07:14:47 +01:00
|
|
|
TORRENT_ASSERT(recv_buffer == m_recv_buffer.get());
|
|
|
|
|
|
|
|
if (recv_buffer.left() < 20)
|
2007-06-06 02:41:20 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, bytes_transferred);
|
2008-09-21 19:12:26 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
if (m_recv_buffer.packet_finished())
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::sync_hash_not_found, op_bittorrent, 1);
|
2007-06-06 02:41:20 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!m_sync_hash.get())
|
|
|
|
{
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_sync_bytes_read == 0);
|
2007-06-06 02:41:20 +02:00
|
|
|
hasher h;
|
|
|
|
|
|
|
|
// compute synchash (hash('req1',S))
|
|
|
|
h.update("req1", 4);
|
2008-06-28 12:10:05 +02:00
|
|
|
h.update(m_dh_key_exchange->get_secret(), dh_key_len);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2009-02-22 21:52:55 +01:00
|
|
|
m_sync_hash.reset(new (std::nothrow) sha1_hash(h.final()));
|
|
|
|
if (!m_sync_hash)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, bytes_transferred);
|
|
|
|
disconnect(errors::no_memory, op_encryption);
|
2009-02-22 21:52:55 +01:00
|
|
|
return;
|
|
|
|
}
|
2007-06-06 02:41:20 +02:00
|
|
|
}
|
|
|
|
|
2015-08-09 04:53:11 +02:00
|
|
|
int syncoffset = get_syncoffset(m_sync_hash->data(), 20
|
2007-06-06 02:41:20 +02:00
|
|
|
, recv_buffer.begin, recv_buffer.left());
|
|
|
|
|
2015-08-09 04:53:11 +02:00
|
|
|
// No sync
|
2007-06-06 02:41:20 +02:00
|
|
|
if (syncoffset == -1)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, bytes_transferred);
|
2008-09-21 19:12:26 +02:00
|
|
|
|
2007-06-06 02:41:20 +02:00
|
|
|
std::size_t bytes_processed = recv_buffer.left() - 20;
|
|
|
|
m_sync_bytes_read += bytes_processed;
|
|
|
|
if (m_sync_bytes_read >= 512)
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::sync_hash_not_found, op_encryption, 1);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.cut(bytes_processed, (std::min)(m_recv_buffer.packet_size()
|
2008-08-21 01:05:12 +02:00
|
|
|
, (512+20) - m_sync_bytes_read));
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
TORRENT_ASSERT(!m_recv_buffer.packet_finished());
|
2007-06-06 02:41:20 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
// found complete sync
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::size_t bytes_processed = syncoffset + 20;
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ENCRYPTION"
|
|
|
|
, "sync point (hash) found at offset %d"
|
2015-04-25 06:22:51 +02:00
|
|
|
, int(m_sync_bytes_read + bytes_processed - 20));
|
2006-04-25 23:04:48 +02:00
|
|
|
#endif
|
2007-06-06 02:41:20 +02:00
|
|
|
m_state = read_pe_skey_vc;
|
|
|
|
// skey,vc - 28 bytes
|
|
|
|
m_sync_hash.reset();
|
2008-09-21 19:12:26 +02:00
|
|
|
int transferred_used = bytes_processed - recv_buffer.left() + bytes_transferred;
|
|
|
|
TORRENT_ASSERT(transferred_used <= int(bytes_transferred));
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, transferred_used);
|
2008-09-21 19:12:26 +02:00
|
|
|
bytes_transferred -= transferred_used;
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.cut(bytes_processed, 28);
|
2007-06-06 02:41:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_state == read_pe_skey_vc)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, bytes_transferred);
|
2008-09-24 04:38:20 +02:00
|
|
|
bytes_transferred = 0;
|
2008-09-21 19:12:26 +02:00
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(!m_encrypted);
|
|
|
|
TORRENT_ASSERT(!m_rc4_encrypted);
|
2012-02-07 04:46:21 +01:00
|
|
|
TORRENT_ASSERT(!is_outgoing());
|
2014-11-23 07:14:47 +01:00
|
|
|
TORRENT_ASSERT(m_recv_buffer.packet_size() == 28);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
2014-07-06 21:18:00 +02:00
|
|
|
if (is_disconnecting()) return;
|
|
|
|
TORRENT_ASSERT(!is_disconnecting());
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
recv_buffer = m_recv_buffer.get();
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(!is_disconnecting());
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
sha1_hash ih(recv_buffer.begin);
|
|
|
|
torrent const* ti = m_ses.find_encrypted_torrent(ih, m_dh_key_exchange->get_hash_xor_mask());
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (ti)
|
|
|
|
{
|
|
|
|
if (!t)
|
2007-06-06 02:41:20 +02:00
|
|
|
{
|
2015-04-21 02:23:00 +02:00
|
|
|
attach_to_torrent(ti->info_hash());
|
2014-07-06 21:18:00 +02:00
|
|
|
if (is_disconnecting()) return;
|
|
|
|
TORRENT_ASSERT(!is_disconnecting());
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
t = associated_torrent().lock();
|
|
|
|
TORRENT_ASSERT(t);
|
|
|
|
}
|
|
|
|
|
|
|
|
init_pe_rc4_handler(m_dh_key_exchange->get_secret(), ti->info_hash());
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ENCRYPTION", "stream key found, torrent located");
|
2007-06-06 02:41:20 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_rc4.get())
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_info_hash, op_bittorrent, 1);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
// verify constant
|
2014-11-23 07:14:47 +01:00
|
|
|
buffer::interval wr_recv_buf = m_recv_buffer.mutable_buffer();
|
|
|
|
rc4_decrypt(wr_recv_buf.begin + 20, 8);
|
2007-06-06 02:41:20 +02:00
|
|
|
wr_recv_buf.begin += 28;
|
|
|
|
|
|
|
|
const char sh_vc[] = {0,0,0,0, 0,0,0,0};
|
|
|
|
if (!std::equal(sh_vc, sh_vc+8, recv_buffer.begin + 20))
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_encryption_constant, op_encryption, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ENCRYPTION", "verification constant found");
|
2007-06-06 02:41:20 +02:00
|
|
|
#endif
|
|
|
|
m_state = read_pe_cryptofield;
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.reset(4 + 2);
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
2007-06-06 02:41:20 +02:00
|
|
|
// cannot fall through into
|
|
|
|
if (m_state == read_pe_syncvc)
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2012-02-07 04:46:21 +01:00
|
|
|
TORRENT_ASSERT(is_outgoing());
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(!m_encrypted);
|
|
|
|
TORRENT_ASSERT(!m_rc4_encrypted);
|
2014-11-23 07:14:47 +01:00
|
|
|
TORRENT_ASSERT(recv_buffer == m_recv_buffer.get());
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
if (recv_buffer.left() < 8)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, bytes_transferred);
|
2014-11-23 07:14:47 +01:00
|
|
|
if (m_recv_buffer.packet_finished())
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_encryption_constant, op_encryption, 2);
|
2007-06-06 02:41:20 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// generate the verification constant
|
|
|
|
if (!m_sync_vc.get())
|
|
|
|
{
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_sync_bytes_read == 0);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2009-02-22 21:52:55 +01:00
|
|
|
m_sync_vc.reset(new (std::nothrow) char[8]);
|
|
|
|
if (!m_sync_vc)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::no_memory, op_encryption);
|
2009-02-22 21:52:55 +01:00
|
|
|
return;
|
|
|
|
}
|
2007-06-06 02:41:20 +02:00
|
|
|
std::fill(m_sync_vc.get(), m_sync_vc.get() + 8, 0);
|
2014-11-23 07:14:47 +01:00
|
|
|
rc4_decrypt(m_sync_vc.get(), 8);
|
2007-06-06 02:41:20 +02:00
|
|
|
}
|
|
|
|
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_sync_vc.get());
|
2007-06-06 02:41:20 +02:00
|
|
|
int syncoffset = get_syncoffset(m_sync_vc.get(), 8
|
|
|
|
, recv_buffer.begin, recv_buffer.left());
|
|
|
|
|
|
|
|
// No sync
|
|
|
|
if (syncoffset == -1)
|
|
|
|
{
|
|
|
|
std::size_t bytes_processed = recv_buffer.left() - 8;
|
|
|
|
m_sync_bytes_read += bytes_processed;
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, bytes_transferred);
|
2008-09-21 19:12:26 +02:00
|
|
|
|
2007-06-06 02:41:20 +02:00
|
|
|
if (m_sync_bytes_read >= 512)
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_encryption_constant, op_encryption, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.cut(bytes_processed, (std::min)(m_recv_buffer.packet_size()
|
2008-09-21 19:12:26 +02:00
|
|
|
, (512+8) - m_sync_bytes_read));
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
TORRENT_ASSERT(!m_recv_buffer.packet_finished());
|
2007-06-06 02:41:20 +02:00
|
|
|
}
|
|
|
|
// found complete sync
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::size_t bytes_processed = syncoffset + 8;
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ENCRYPTION"
|
|
|
|
, "sync point (verification constant) found at offset %d"
|
2015-04-25 06:22:51 +02:00
|
|
|
, int(m_sync_bytes_read + bytes_processed - 8));
|
2007-06-06 02:41:20 +02:00
|
|
|
#endif
|
2008-09-21 19:12:26 +02:00
|
|
|
int transferred_used = bytes_processed - recv_buffer.left() + bytes_transferred;
|
|
|
|
TORRENT_ASSERT(transferred_used <= int(bytes_transferred));
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, transferred_used);
|
2008-09-21 19:12:26 +02:00
|
|
|
bytes_transferred -= transferred_used;
|
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.cut(bytes_processed, 4 + 2);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
// delete verification constant
|
|
|
|
m_sync_vc.reset();
|
|
|
|
m_state = read_pe_cryptofield;
|
|
|
|
// fall through
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_state == read_pe_cryptofield) // local/remote
|
|
|
|
{
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(!m_encrypted);
|
|
|
|
TORRENT_ASSERT(!m_rc4_encrypted);
|
2014-11-23 07:14:47 +01:00
|
|
|
TORRENT_ASSERT(m_recv_buffer.packet_size() == 4+2);
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, bytes_transferred);
|
2008-09-21 19:12:26 +02:00
|
|
|
bytes_transferred = 0;
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
buffer::interval wr_buf = m_recv_buffer.mutable_buffer();
|
|
|
|
rc4_decrypt(wr_buf.begin, m_recv_buffer.packet_size());
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
recv_buffer = m_recv_buffer.get();
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-12-01 11:43:34 +01:00
|
|
|
boost::uint32_t crypto_field = detail::read_uint32(recv_buffer.begin);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ENCRYPTION", "crypto %s : [%s%s ]"
|
2012-02-07 04:46:21 +01:00
|
|
|
, is_outgoing() ? "select" : "provide"
|
2010-12-01 05:22:03 +01:00
|
|
|
, (crypto_field & 1) ? " plaintext" : ""
|
|
|
|
, (crypto_field & 2) ? " rc4" : "");
|
2007-06-06 02:41:20 +02:00
|
|
|
#endif
|
|
|
|
|
2012-02-07 04:46:21 +01:00
|
|
|
if (!is_outgoing())
|
2007-06-06 02:41:20 +02:00
|
|
|
{
|
|
|
|
// select a crypto method
|
2014-07-13 00:32:55 +02:00
|
|
|
int allowed_encryption = m_settings.get_int(settings_pack::allowed_enc_level);
|
2014-12-01 11:43:34 +01:00
|
|
|
boost::uint32_t crypto_select = crypto_field & allowed_encryption;
|
2011-08-29 04:00:17 +02:00
|
|
|
|
|
|
|
// when prefer_rc4 is set, keep the most significant bit
|
|
|
|
// otherwise keep the least significant one
|
2014-07-13 00:32:55 +02:00
|
|
|
if (m_settings.get_bool(settings_pack::prefer_rc4))
|
2007-06-06 02:41:20 +02:00
|
|
|
{
|
2014-12-01 11:43:34 +01:00
|
|
|
boost::uint32_t mask = (std::numeric_limits<boost::uint32_t>::max)();
|
2011-08-29 04:00:17 +02:00
|
|
|
while (crypto_select & (mask << 1))
|
2007-06-06 02:41:20 +02:00
|
|
|
{
|
2011-08-29 04:00:17 +02:00
|
|
|
mask <<= 1;
|
|
|
|
crypto_select = crypto_select & mask;
|
2007-06-06 02:41:20 +02:00
|
|
|
}
|
2011-08-29 04:00:17 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-12-01 11:43:34 +01:00
|
|
|
boost::uint32_t mask = (std::numeric_limits<boost::uint32_t>::max)();
|
2011-08-29 04:00:17 +02:00
|
|
|
while (crypto_select & (mask >> 1))
|
2007-06-06 02:41:20 +02:00
|
|
|
{
|
2011-08-29 04:00:17 +02:00
|
|
|
mask >>= 1;
|
|
|
|
crypto_select = crypto_select & mask;
|
2007-06-06 02:41:20 +02:00
|
|
|
}
|
2011-08-29 04:00:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (crypto_select == 0)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::unsupported_encryption_mode, op_encryption, 1);
|
2013-05-08 07:43:17 +02:00
|
|
|
return;
|
2011-08-29 04:00:17 +02:00
|
|
|
}
|
|
|
|
|
2007-06-06 02:41:20 +02:00
|
|
|
// write the pe4 step
|
|
|
|
write_pe4_sync(crypto_select);
|
|
|
|
}
|
2012-02-07 04:46:21 +01:00
|
|
|
else // is_outgoing()
|
2007-06-06 02:41:20 +02:00
|
|
|
{
|
|
|
|
// check if crypto select is valid
|
2014-07-13 00:32:55 +02:00
|
|
|
int allowed_encryption = m_settings.get_int(settings_pack::allowed_enc_level);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2011-08-29 04:00:17 +02:00
|
|
|
crypto_field &= allowed_encryption;
|
|
|
|
if (crypto_field == 0)
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2011-08-29 04:00:17 +02:00
|
|
|
// we don't allow any of the offered encryption levels
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::unsupported_encryption_mode_selected, op_encryption, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2011-08-29 04:00:17 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (crypto_field == settings_pack::pe_plaintext)
|
2011-08-29 04:00:17 +02:00
|
|
|
m_rc4_encrypted = false;
|
2014-07-06 21:18:00 +02:00
|
|
|
else if (crypto_field == settings_pack::pe_rc4)
|
2011-08-29 04:00:17 +02:00
|
|
|
m_rc4_encrypted = true;
|
2007-06-06 02:41:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
int len_pad = detail::read_int16(recv_buffer.begin);
|
|
|
|
if (len_pad < 0 || len_pad > 512)
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_pad_size, op_encryption, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
m_state = read_pe_pad;
|
2012-02-07 04:46:21 +01:00
|
|
|
if (!is_outgoing())
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.reset(len_pad + 2); // len(IA) at the end of pad
|
2007-06-06 02:41:20 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (len_pad == 0)
|
|
|
|
{
|
|
|
|
m_encrypted = true;
|
2014-11-23 07:14:47 +01:00
|
|
|
if (m_rc4_encrypted)
|
|
|
|
{
|
|
|
|
switch_send_crypto(m_rc4);
|
|
|
|
switch_recv_crypto(m_rc4);
|
|
|
|
}
|
2007-06-06 02:41:20 +02:00
|
|
|
m_state = init_bt_handshake;
|
|
|
|
}
|
|
|
|
else
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.reset(len_pad);
|
2007-06-06 02:41:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_state == read_pe_pad)
|
|
|
|
{
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(!m_encrypted);
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, bytes_transferred);
|
2008-09-21 19:12:26 +02:00
|
|
|
bytes_transferred = 0;
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
int pad_size = is_outgoing() ? m_recv_buffer.packet_size() : m_recv_buffer.packet_size() - 2;
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
buffer::interval wr_buf = m_recv_buffer.mutable_buffer();
|
|
|
|
rc4_decrypt(wr_buf.begin, m_recv_buffer.packet_size());
|
|
|
|
|
|
|
|
recv_buffer = m_recv_buffer.get();
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2012-02-07 04:46:21 +01:00
|
|
|
if (!is_outgoing())
|
2007-06-06 02:41:20 +02:00
|
|
|
{
|
|
|
|
recv_buffer.begin += pad_size;
|
|
|
|
int len_ia = detail::read_int16(recv_buffer.begin);
|
2007-06-07 13:04:00 +02:00
|
|
|
|
2008-01-07 02:10:46 +01:00
|
|
|
if (len_ia < 0)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_encrypt_handshake, op_encryption, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
|
|
|
}
|
2007-06-07 13:04:00 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ENCRYPTION", "len(IA) : %d", len_ia);
|
2007-06-06 02:41:20 +02:00
|
|
|
#endif
|
|
|
|
if (len_ia == 0)
|
|
|
|
{
|
|
|
|
// everything after this is Encrypt2
|
|
|
|
m_encrypted = true;
|
2014-11-23 07:14:47 +01:00
|
|
|
if (m_rc4_encrypted)
|
|
|
|
{
|
|
|
|
switch_send_crypto(m_rc4);
|
|
|
|
switch_recv_crypto(m_rc4);
|
|
|
|
}
|
2007-06-06 02:41:20 +02:00
|
|
|
m_state = init_bt_handshake;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
m_state = read_pe_ia;
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.reset(len_ia);
|
2007-06-06 02:41:20 +02:00
|
|
|
}
|
|
|
|
}
|
2012-02-07 04:46:21 +01:00
|
|
|
else // is_outgoing()
|
2007-06-06 02:41:20 +02:00
|
|
|
{
|
|
|
|
// everything that arrives after this is Encrypt2
|
|
|
|
m_encrypted = true;
|
2014-11-23 07:14:47 +01:00
|
|
|
if (m_rc4_encrypted)
|
|
|
|
{
|
|
|
|
switch_send_crypto(m_rc4);
|
|
|
|
switch_recv_crypto(m_rc4);
|
|
|
|
}
|
2007-06-06 02:41:20 +02:00
|
|
|
m_state = init_bt_handshake;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_state == read_pe_ia)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, bytes_transferred);
|
2008-09-24 04:38:20 +02:00
|
|
|
bytes_transferred = 0;
|
2012-02-07 04:46:21 +01:00
|
|
|
TORRENT_ASSERT(!is_outgoing());
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(!m_encrypted);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
// ia is always rc4, so decrypt it
|
2014-11-23 07:14:47 +01:00
|
|
|
buffer::interval wr_buf = m_recv_buffer.mutable_buffer();
|
|
|
|
rc4_decrypt(wr_buf.begin, m_recv_buffer.packet_size());
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ENCRYPTION"
|
|
|
|
, "decrypted ia : %d bytes", m_recv_buffer.packet_size());
|
2006-04-25 23:04:48 +02:00
|
|
|
#endif
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2011-08-29 04:00:17 +02:00
|
|
|
// everything that arrives after this is encrypted
|
2007-06-06 02:41:20 +02:00
|
|
|
m_encrypted = true;
|
2014-11-23 07:14:47 +01:00
|
|
|
if (m_rc4_encrypted)
|
|
|
|
{
|
|
|
|
switch_send_crypto(m_rc4);
|
|
|
|
switch_recv_crypto(m_rc4);
|
|
|
|
}
|
|
|
|
m_rc4.reset();
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
m_state = read_protocol_identifier;
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.cut(0, 20);
|
2007-06-06 02:41:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (m_state == init_bt_handshake)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, bytes_transferred);
|
2008-09-21 19:12:26 +02:00
|
|
|
bytes_transferred = 0;
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(m_encrypted);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (is_outgoing() && t->ready_for_connections())
|
|
|
|
{
|
|
|
|
write_bitfield();
|
|
|
|
#ifndef TORRENT_DISABLE_DHT
|
|
|
|
if (m_supports_dht_port && m_ses.has_dht())
|
|
|
|
write_dht_port(m_ses.external_udp_port());
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// if we don't have any pieces, don't do any preemptive
|
|
|
|
// unchoking at all.
|
|
|
|
if (t->num_have() > 0)
|
|
|
|
{
|
|
|
|
// if the peer is ignoring unchoke slots, or if we have enough
|
|
|
|
// unused slots, unchoke this peer right away, to save a round-trip
|
|
|
|
// in case it's interested.
|
2014-09-22 05:47:43 +02:00
|
|
|
maybe_unchoke_this_peer();
|
2014-07-06 21:18:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-06-06 02:41:20 +02:00
|
|
|
// decrypt remaining received bytes
|
|
|
|
if (m_rc4_encrypted)
|
|
|
|
{
|
2014-11-23 07:14:47 +01:00
|
|
|
buffer::interval wr_buf = m_recv_buffer.mutable_buffer();
|
|
|
|
wr_buf.begin += m_recv_buffer.packet_size();
|
|
|
|
rc4_decrypt(wr_buf.begin, wr_buf.left());
|
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ENCRYPTION"
|
|
|
|
, "decrypted remaining %d bytes", wr_buf.left());
|
2007-06-06 02:41:20 +02:00
|
|
|
#endif
|
|
|
|
}
|
2014-11-23 07:14:47 +01:00
|
|
|
m_rc4.reset();
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
// payload stream, start with 20 handshake bytes
|
|
|
|
m_state = read_protocol_identifier;
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.reset(20);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
// encrypted portion of handshake completed, toggle
|
|
|
|
// peer_info pe_support flag back to true
|
2012-02-07 04:46:21 +01:00
|
|
|
if (is_outgoing() &&
|
2014-07-13 00:32:55 +02:00
|
|
|
m_settings.get_int(settings_pack::out_enc_policy)
|
2014-07-06 21:18:00 +02:00
|
|
|
== settings_pack::pe_enabled)
|
2007-06-06 02:41:20 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
torrent_peer* pi = peer_info_struct();
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(pi);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2007-06-30 09:28:44 +02:00
|
|
|
pi->pe_support = true;
|
2007-06-06 02:41:20 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
#endif // #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
if (m_state == read_protocol_identifier)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, bytes_transferred);
|
2008-09-21 19:12:26 +02:00
|
|
|
bytes_transferred = 0;
|
2014-11-23 07:14:47 +01:00
|
|
|
TORRENT_ASSERT(m_recv_buffer.packet_size() == 20);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
|
|
|
recv_buffer = m_recv_buffer.get();
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
int packet_size = recv_buffer[0];
|
2011-09-05 07:50:41 +02:00
|
|
|
const char protocol_string[] = "\x13" "BitTorrent protocol";
|
2007-06-06 02:41:20 +02:00
|
|
|
|
|
|
|
if (packet_size != 19 ||
|
2011-09-05 07:50:41 +02:00
|
|
|
memcmp(recv_buffer.begin, protocol_string, 20) != 0)
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2014-11-23 07:14:47 +01:00
|
|
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ENCRYPTION"
|
|
|
|
, "unrecognized protocol header");
|
2011-09-05 07:50:41 +02:00
|
|
|
#endif
|
|
|
|
|
2011-09-12 05:51:49 +02:00
|
|
|
#ifdef TORRENT_USE_OPENSSL
|
2012-01-16 00:34:43 +01:00
|
|
|
if (is_ssl(*get_socket()))
|
2011-09-12 05:51:49 +02:00
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ENCRYPTION"
|
|
|
|
, "SSL peers are not allowed to use any other encryption");
|
2011-09-12 05:51:49 +02:00
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_info_hash, op_bittorrent, 1);
|
2011-09-12 05:51:49 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
#endif // TORRENT_USE_OPENSSL
|
|
|
|
|
2012-02-09 07:23:58 +01:00
|
|
|
if (!is_outgoing()
|
2014-07-13 00:32:55 +02:00
|
|
|
&& m_settings.get_int(settings_pack::in_enc_policy)
|
2014-07-06 21:18:00 +02:00
|
|
|
== settings_pack::pe_disabled)
|
2008-01-07 02:10:46 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::no_incoming_encrypted, op_bittorrent);
|
2012-02-09 07:23:58 +01:00
|
|
|
return;
|
2008-01-07 02:10:46 +01:00
|
|
|
}
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2012-02-09 07:23:58 +01:00
|
|
|
// Don't attempt to perform an encrypted handshake
|
|
|
|
// within an encrypted connection. For local connections,
|
|
|
|
// we're expected to already have passed the encrypted
|
|
|
|
// handshake by this point
|
|
|
|
if (m_encrypted || is_outgoing())
|
2007-06-06 02:41:20 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_info_hash, op_bittorrent, 1);
|
2012-02-09 07:23:58 +01:00
|
|
|
return;
|
|
|
|
}
|
2011-09-05 07:50:41 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ENCRYPTION", "attempting encrypted connection");
|
2006-04-25 23:04:48 +02:00
|
|
|
#endif
|
2012-02-09 07:23:58 +01:00
|
|
|
m_state = read_pe_dhkey;
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.cut(0, dh_key_len);
|
|
|
|
TORRENT_ASSERT(!m_recv_buffer.packet_finished());
|
2012-02-09 07:23:58 +01:00
|
|
|
return;
|
2011-09-05 07:50:41 +02:00
|
|
|
#else
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_info_hash, op_bittorrent, 1);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
2011-09-05 07:50:41 +02:00
|
|
|
#endif // TORRENT_DISABLE_ENCRYPTION
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
2011-09-05 07:50:41 +02:00
|
|
|
else
|
|
|
|
{
|
2014-11-23 07:14:47 +01:00
|
|
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
2011-09-05 07:50:41 +02:00
|
|
|
TORRENT_ASSERT(m_state != read_pe_dhkey);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2012-02-07 04:46:21 +01:00
|
|
|
if (!is_outgoing()
|
2014-07-13 00:32:55 +02:00
|
|
|
&& m_settings.get_int(settings_pack::in_enc_policy)
|
2014-07-06 21:18:00 +02:00
|
|
|
== settings_pack::pe_forced
|
2012-01-16 00:34:43 +01:00
|
|
|
&& !m_encrypted
|
|
|
|
&& !is_ssl(*get_socket()))
|
2011-09-05 07:50:41 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::no_incoming_regular, op_bittorrent);
|
2011-09-05 07:50:41 +02:00
|
|
|
return;
|
|
|
|
}
|
2007-06-06 02:41:20 +02:00
|
|
|
#endif
|
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming_message, "HANDSHAKE", "BitTorrent protocol");
|
2007-06-06 02:41:20 +02:00
|
|
|
#endif
|
2011-09-05 07:50:41 +02:00
|
|
|
}
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
m_state = read_info_hash;
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.reset(28);
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
2007-06-06 02:41:20 +02:00
|
|
|
// fall through
|
|
|
|
if (m_state == read_info_hash)
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, bytes_transferred);
|
2008-09-21 19:12:26 +02:00
|
|
|
bytes_transferred = 0;
|
2014-11-23 07:14:47 +01:00
|
|
|
TORRENT_ASSERT(m_recv_buffer.packet_size() == 28);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
|
|
|
recv_buffer = m_recv_buffer.get();
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2010-12-01 05:22:03 +01:00
|
|
|
std::string extensions;
|
|
|
|
extensions.resize(8 * 8);
|
2006-04-25 23:04:48 +02:00
|
|
|
for (int i=0; i < 8; ++i)
|
|
|
|
{
|
|
|
|
for (int j=0; j < 8; ++j)
|
|
|
|
{
|
2010-12-01 05:22:03 +01:00
|
|
|
if (recv_buffer[i] & (0x80 >> j)) extensions[i*8+j] = '1';
|
|
|
|
else extensions[i*8+j] = '0';
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
}
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming_message, "EXTENSIONS", "%s ext: %s%s%s"
|
2010-12-01 05:22:03 +01:00
|
|
|
, extensions.c_str()
|
|
|
|
, (recv_buffer[7] & 0x01) ? "DHT " : ""
|
|
|
|
, (recv_buffer[7] & 0x04) ? "FAST " : ""
|
|
|
|
, (recv_buffer[5] & 0x10) ? "extension " : "");
|
2006-04-25 23:04:48 +02:00
|
|
|
#endif
|
|
|
|
|
2011-01-29 13:13:49 +01:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
2009-02-13 08:17:20 +01:00
|
|
|
std::memcpy(m_reserved_bits, recv_buffer.begin, 8);
|
2006-11-14 01:08:16 +01:00
|
|
|
if ((recv_buffer[5] & 0x10))
|
2006-04-25 23:04:48 +02:00
|
|
|
m_supports_extensions = true;
|
2006-11-14 01:08:16 +01:00
|
|
|
#endif
|
2006-04-25 23:04:48 +02:00
|
|
|
if (recv_buffer[7] & 0x01)
|
|
|
|
m_supports_dht_port = true;
|
|
|
|
|
2007-08-14 19:47:48 +02:00
|
|
|
if (recv_buffer[7] & 0x04)
|
|
|
|
m_supports_fast = true;
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
t = associated_torrent().lock();
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
// ok, now we have got enough of the handshake. Is this connection
|
|
|
|
// attached to a torrent?
|
|
|
|
if (!t)
|
|
|
|
{
|
|
|
|
// now, we have to see if there's a torrent with the
|
|
|
|
// info_hash we got from the peer
|
|
|
|
sha1_hash info_hash;
|
|
|
|
std::copy(recv_buffer.begin + 8, recv_buffer.begin + 28
|
2015-08-09 04:53:11 +02:00
|
|
|
, info_hash.data());
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2015-04-21 02:23:00 +02:00
|
|
|
attach_to_torrent(info_hash);
|
2008-01-07 02:10:46 +01:00
|
|
|
if (is_disconnecting()) return;
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// verify info hash
|
|
|
|
if (!std::equal(recv_buffer.begin + 8, recv_buffer.begin + 28
|
2015-08-09 04:53:11 +02:00
|
|
|
, t->torrent_file().info_hash().data()))
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::info, "ERROR", "received invalid info_hash");
|
2006-04-25 23:04:48 +02:00
|
|
|
#endif
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::invalid_info_hash, op_bittorrent, 1);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming, "HANDSHAKE", "info_hash received");
|
2007-06-06 02:41:20 +02:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2007-06-07 12:18:13 +02:00
|
|
|
t = associated_torrent().lock();
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(t);
|
2015-08-09 04:53:11 +02:00
|
|
|
|
2007-06-21 02:51:42 +02:00
|
|
|
// if this is a local connection, we have already
|
2007-08-14 19:47:48 +02:00
|
|
|
// sent the handshake
|
2012-02-07 04:46:21 +01:00
|
|
|
if (!is_outgoing()) write_handshake();
|
2011-05-09 01:52:06 +02:00
|
|
|
TORRENT_ASSERT(m_sent_handshake);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2008-01-07 02:10:46 +01:00
|
|
|
if (is_disconnecting()) return;
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
m_state = read_peer_id;
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.reset(20);
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
2007-06-06 02:41:20 +02:00
|
|
|
// fall through
|
|
|
|
if (m_state == read_peer_id)
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2011-05-09 01:52:06 +02:00
|
|
|
TORRENT_ASSERT(m_sent_handshake);
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, bytes_transferred);
|
2015-05-23 03:38:47 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
t = associated_torrent().lock();
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!t)
|
2007-06-06 02:41:20 +02:00
|
|
|
{
|
2014-11-23 07:14:47 +01:00
|
|
|
TORRENT_ASSERT(!m_recv_buffer.packet_finished()); // TODO
|
2007-06-06 02:41:20 +02:00
|
|
|
return;
|
|
|
|
}
|
2014-11-23 07:14:47 +01:00
|
|
|
TORRENT_ASSERT(m_recv_buffer.packet_size() == 20);
|
2015-05-23 03:38:47 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
if (!m_recv_buffer.packet_finished()) return;
|
|
|
|
recv_buffer = m_recv_buffer.get();
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2009-04-04 11:52:25 +02:00
|
|
|
char hex_pid[41];
|
|
|
|
to_hex(recv_buffer.begin, 20, hex_pid);
|
2011-11-28 12:11:29 +01:00
|
|
|
hex_pid[40] = 0;
|
2009-04-04 11:52:25 +02:00
|
|
|
char ascii_pid[21];
|
2011-11-28 12:11:29 +01:00
|
|
|
ascii_pid[20] = 0;
|
2009-04-04 11:52:25 +02:00
|
|
|
for (int i = 0; i != 20; ++i)
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2009-06-23 03:53:47 +02:00
|
|
|
if (is_print(recv_buffer.begin[i])) ascii_pid[i] = recv_buffer.begin[i];
|
2009-04-04 11:52:25 +02:00
|
|
|
else ascii_pid[i] = '.';
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming, "HANDSHAKE", "received peer_id: %s client: %s ascii: \"%s\""
|
2009-04-04 11:52:25 +02:00
|
|
|
, hex_pid, identify_client(peer_id(recv_buffer.begin)).c_str(), ascii_pid);
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
peer_id pid;
|
2015-08-02 05:57:11 +02:00
|
|
|
std::copy(recv_buffer.begin, recv_buffer.begin + 20, pid.data());
|
2014-11-23 07:14:47 +01:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
if (t->settings().get_bool(settings_pack::allow_multiple_connections_per_ip))
|
2006-11-30 12:56:19 +01:00
|
|
|
{
|
|
|
|
// now, let's see if this connection should be closed
|
2014-07-06 21:18:00 +02:00
|
|
|
peer_connection* p = t->find_peer(pid);
|
|
|
|
if (p)
|
2006-11-30 12:56:19 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(p->pid() == pid);
|
2006-11-30 12:56:19 +01:00
|
|
|
// we found another connection with the same peer-id
|
|
|
|
// which connection should be closed in order to be
|
|
|
|
// sure that the other end closes the same connection?
|
|
|
|
// the peer with greatest peer-id is the one allowed to
|
|
|
|
// initiate connections. So, if our peer-id is greater than
|
|
|
|
// the others, we should close the incoming connection,
|
|
|
|
// if not, we should close the outgoing one.
|
2014-09-13 21:47:51 +02:00
|
|
|
if (pid < m_our_peer_id && is_outgoing())
|
2006-11-30 12:56:19 +01:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
p->disconnect(errors::duplicate_peer_id, op_bittorrent);
|
2006-11-30 12:56:19 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
disconnect(errors::duplicate_peer_id, op_bittorrent);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
2006-11-30 12:56:19 +01:00
|
|
|
}
|
|
|
|
}
|
2007-05-25 19:06:30 +02:00
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
set_pid(pid);
|
|
|
|
|
2009-05-23 23:42:29 +02:00
|
|
|
// disconnect if the peer has the same peer-id as ourself
|
|
|
|
// since it most likely is ourself then
|
2014-09-03 05:17:47 +02:00
|
|
|
if (pid == m_our_peer_id)
|
2007-05-25 19:06:30 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
if (peer_info_struct()) t->ban_peer(peer_info_struct());
|
|
|
|
disconnect(errors::self_connection, op_bittorrent, 1);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
2006-11-30 12:56:19 +01:00
|
|
|
}
|
2015-05-23 03:38:47 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
m_client_version = identify_client(pid);
|
2006-05-15 00:30:05 +02:00
|
|
|
boost::optional<fingerprint> f = client_fingerprint(pid);
|
|
|
|
if (f && std::equal(f->name, f->name + 2, "BC"))
|
|
|
|
{
|
|
|
|
// if this is a bitcomet client, lower the request queue size limit
|
2013-11-26 08:47:48 +01:00
|
|
|
if (max_out_request_queue() > 50) max_out_request_queue(50);
|
2006-05-15 00:30:05 +02:00
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2006-11-14 01:08:16 +01:00
|
|
|
#ifndef TORRENT_DISABLE_EXTENSIONS
|
|
|
|
for (extension_list_t::iterator i = m_extensions.begin()
|
|
|
|
, end(m_extensions.end()); i != end;)
|
|
|
|
{
|
2008-05-12 05:05:27 +02:00
|
|
|
if (!(*i)->on_handshake(m_reserved_bits))
|
2006-11-14 01:08:16 +01:00
|
|
|
{
|
|
|
|
i = m_extensions.erase(i);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
}
|
2008-05-12 05:05:27 +02:00
|
|
|
if (is_disconnecting()) return;
|
2006-11-14 01:08:16 +01:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
if (m_supports_extensions) write_extensions();
|
2006-11-14 01:08:16 +01:00
|
|
|
#endif
|
|
|
|
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::incoming_message, "HANDSHAKE");
|
2007-06-06 02:41:20 +02:00
|
|
|
#endif
|
2007-04-15 04:14:02 +02:00
|
|
|
// consider this a successful connection, reset the failcount
|
2014-07-06 21:18:00 +02:00
|
|
|
if (peer_info_struct())
|
|
|
|
t->clear_failcount(peer_info_struct());
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
2007-06-06 02:41:20 +02:00
|
|
|
// Toggle pe_support back to false if this is a
|
|
|
|
// standard successful connection
|
2012-02-07 04:46:21 +01:00
|
|
|
if (is_outgoing() && !m_encrypted &&
|
2014-07-13 00:32:55 +02:00
|
|
|
m_settings.get_int(settings_pack::out_enc_policy)
|
2014-07-06 21:18:00 +02:00
|
|
|
== settings_pack::pe_enabled)
|
2007-06-06 02:41:20 +02:00
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
torrent_peer* pi = peer_info_struct();
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(pi);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2007-06-30 09:28:44 +02:00
|
|
|
pi->pe_support = false;
|
2007-06-06 02:41:20 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
m_state = read_packet_size;
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.reset(5);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
TORRENT_ASSERT(!m_recv_buffer.packet_finished());
|
2007-06-06 02:41:20 +02:00
|
|
|
return;
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
2007-06-06 02:41:20 +02:00
|
|
|
// cannot fall through into
|
|
|
|
if (m_state == read_packet_size)
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2007-06-06 02:41:20 +02:00
|
|
|
// Make sure this is not fallen though into
|
2014-11-23 07:14:47 +01:00
|
|
|
TORRENT_ASSERT(recv_buffer == m_recv_buffer.get());
|
|
|
|
TORRENT_ASSERT(m_recv_buffer.packet_size() == 5);
|
2007-06-06 02:41:20 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
if (!t) return;
|
2008-04-10 12:03:23 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// the 5th byte (if one) should not count as protocol
|
|
|
|
// byte here, instead it's counted in the message
|
|
|
|
// handler itself, for the specific message
|
|
|
|
TORRENT_ASSERT(bytes_transferred <= 5);
|
|
|
|
int used_bytes = recv_buffer.left() > 4 ? bytes_transferred - 1: bytes_transferred;
|
|
|
|
received_bytes(0, used_bytes);
|
|
|
|
bytes_transferred -= used_bytes;
|
|
|
|
if (recv_buffer.left() < 4) return;
|
|
|
|
|
|
|
|
TORRENT_ASSERT(bytes_transferred <= 1);
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
const char* ptr = recv_buffer.begin;
|
|
|
|
int packet_size = detail::read_int32(ptr);
|
|
|
|
|
|
|
|
// don't accept packets larger than 1 MB
|
|
|
|
if (packet_size > 1024*1024 || packet_size < 0)
|
|
|
|
{
|
|
|
|
// packet too large
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, bytes_transferred);
|
|
|
|
disconnect(errors::packet_too_large, op_bittorrent, 2);
|
2008-01-07 02:10:46 +01:00
|
|
|
return;
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
|
2006-04-25 23:04:48 +02:00
|
|
|
if (packet_size == 0)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(bytes_transferred <= 1);
|
|
|
|
received_bytes(0, bytes_transferred);
|
2006-04-25 23:04:48 +02:00
|
|
|
incoming_keepalive();
|
2008-05-12 05:05:27 +02:00
|
|
|
if (is_disconnecting()) return;
|
2006-04-25 23:04:48 +02:00
|
|
|
// keepalive message
|
|
|
|
m_state = read_packet_size;
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.cut(4, 5);
|
2008-04-10 12:03:23 +02:00
|
|
|
return;
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
2014-07-06 21:18:00 +02:00
|
|
|
if (recv_buffer.left() < 5) return;
|
2008-04-10 12:03:23 +02:00
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
m_state = read_packet;
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.cut(4, packet_size);
|
|
|
|
recv_buffer = m_recv_buffer.get();
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(recv_buffer.left() == 1);
|
|
|
|
TORRENT_ASSERT(bytes_transferred == 1);
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
2007-06-06 02:41:20 +02:00
|
|
|
if (m_state == read_packet)
|
2006-04-25 23:04:48 +02:00
|
|
|
{
|
2014-11-23 07:14:47 +01:00
|
|
|
TORRENT_ASSERT(recv_buffer == m_recv_buffer.get());
|
2008-10-09 05:33:53 +02:00
|
|
|
if (!t)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
received_bytes(0, bytes_transferred);
|
|
|
|
disconnect(errors::torrent_removed, op_bittorrent, 1);
|
2008-10-09 05:33:53 +02:00
|
|
|
return;
|
|
|
|
}
|
2015-05-19 05:13:49 +02:00
|
|
|
#if TORRENT_USE_ASSERTS
|
2014-12-03 05:32:50 +01:00
|
|
|
boost::int64_t cur_payload_dl = statistics().last_payload_downloaded();
|
|
|
|
boost::int64_t cur_protocol_dl = statistics().last_protocol_downloaded();
|
2008-10-09 05:33:53 +02:00
|
|
|
#endif
|
2006-04-25 23:04:48 +02:00
|
|
|
if (dispatch_message(bytes_transferred))
|
|
|
|
{
|
|
|
|
m_state = read_packet_size;
|
2014-11-23 07:14:47 +01:00
|
|
|
m_recv_buffer.reset(5);
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
2015-05-19 05:13:49 +02:00
|
|
|
|
|
|
|
#if TORRENT_USE_ASSERTS
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(statistics().last_payload_downloaded() - cur_payload_dl >= 0);
|
|
|
|
TORRENT_ASSERT(statistics().last_protocol_downloaded() - cur_protocol_dl >= 0);
|
2014-12-03 05:32:50 +01:00
|
|
|
boost::int64_t stats_diff = statistics().last_payload_downloaded() - cur_payload_dl +
|
2014-07-06 21:18:00 +02:00
|
|
|
statistics().last_protocol_downloaded() - cur_protocol_dl;
|
2014-12-03 05:32:50 +01:00
|
|
|
TORRENT_ASSERT(stats_diff == boost::int64_t(bytes_transferred));
|
2014-11-23 07:14:47 +01:00
|
|
|
TORRENT_ASSERT(!m_recv_buffer.packet_finished());
|
2015-05-19 05:13:49 +02:00
|
|
|
#endif
|
2007-06-06 02:41:20 +02:00
|
|
|
return;
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
2014-11-23 07:14:47 +01:00
|
|
|
|
|
|
|
TORRENT_ASSERT(!m_recv_buffer.packet_finished());
|
|
|
|
}
|
|
|
|
|
|
|
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
2015-06-06 08:10:53 +02:00
|
|
|
int bt_peer_connection::hit_send_barrier(std::vector<boost::asio::mutable_buffer>& iovec)
|
2014-11-23 07:14:47 +01:00
|
|
|
{
|
|
|
|
int next_barrier = m_enc_handler.encrypt(iovec);
|
2015-04-17 03:15:33 +02:00
|
|
|
#ifndef TORRENT_DISABLE_LOGGING
|
2014-11-23 07:14:47 +01:00
|
|
|
if (next_barrier != 0)
|
2015-05-03 04:53:54 +02:00
|
|
|
peer_log(peer_log_alert::outgoing_message, "SEND_BARRIER"
|
|
|
|
, "encrypted block s = %d", next_barrier);
|
2014-11-23 07:14:47 +01:00
|
|
|
#endif
|
|
|
|
return next_barrier;
|
|
|
|
}
|
|
|
|
#endif
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
// --------------------------
|
|
|
|
// SEND DATA
|
|
|
|
// --------------------------
|
|
|
|
|
2008-05-03 18:05:42 +02:00
|
|
|
void bt_peer_connection::on_sent(error_code const& error
|
2006-04-25 23:04:48 +02:00
|
|
|
, std::size_t bytes_transferred)
|
|
|
|
{
|
|
|
|
INVARIANT_CHECK;
|
|
|
|
|
2008-09-21 19:12:26 +02:00
|
|
|
if (error)
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
sent_bytes(0, bytes_transferred);
|
2008-09-21 19:12:26 +02:00
|
|
|
return;
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
|
|
|
|
// manage the payload markers
|
|
|
|
int amount_payload = 0;
|
|
|
|
if (!m_payloads.empty())
|
|
|
|
{
|
2014-07-06 21:18:00 +02:00
|
|
|
// this points to the first entry to not erase. i.e.
|
|
|
|
// [begin, first_to_keep) will be erased because
|
|
|
|
// the payload ranges they represent have been sent
|
|
|
|
std::vector<range>::iterator first_to_keep = m_payloads.begin();
|
|
|
|
|
2009-05-03 22:21:24 +02:00
|
|
|
for (std::vector<range>::iterator i = m_payloads.begin();
|
2006-04-25 23:04:48 +02:00
|
|
|
i != m_payloads.end(); ++i)
|
|
|
|
{
|
|
|
|
i->start -= bytes_transferred;
|
|
|
|
if (i->start < 0)
|
|
|
|
{
|
|
|
|
if (i->start + i->length <= 0)
|
|
|
|
{
|
|
|
|
amount_payload += i->length;
|
2014-07-06 21:18:00 +02:00
|
|
|
TORRENT_ASSERT(first_to_keep == i);
|
|
|
|
++first_to_keep;
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
amount_payload += -i->start;
|
|
|
|
i->length -= -i->start;
|
|
|
|
i->start = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-06 21:18:00 +02:00
|
|
|
// remove all payload ranges that have been sent
|
|
|
|
m_payloads.erase(m_payloads.begin(), first_to_keep);
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
|
2015-08-09 04:53:11 +02:00
|
|
|
TORRENT_ASSERT(amount_payload <= int(bytes_transferred));
|
2014-07-06 21:18:00 +02:00
|
|
|
sent_bytes(amount_payload, bytes_transferred - amount_payload);
|
2015-08-09 04:53:11 +02:00
|
|
|
|
2010-07-08 21:29:38 +02:00
|
|
|
if (amount_payload > 0)
|
|
|
|
{
|
|
|
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
|
|
|
TORRENT_ASSERT(t);
|
|
|
|
if (t) t->update_last_upload();
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
|
2014-01-21 20:26:09 +01:00
|
|
|
#if TORRENT_USE_INVARIANT_CHECKS
|
2006-04-25 23:04:48 +02:00
|
|
|
void bt_peer_connection::check_invariant() const
|
|
|
|
{
|
2009-11-29 20:38:32 +01:00
|
|
|
boost::shared_ptr<torrent> t = associated_torrent().lock();
|
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
|
2008-06-28 12:10:05 +02:00
|
|
|
TORRENT_ASSERT( (bool(m_state != read_pe_dhkey) || m_dh_key_exchange.get())
|
2012-02-07 04:46:21 +01:00
|
|
|
|| !is_outgoing());
|
2007-06-07 12:18:13 +02:00
|
|
|
|
2014-11-23 07:14:47 +01:00
|
|
|
TORRENT_ASSERT(!m_rc4_encrypted || (!m_encrypted && m_rc4) || (m_encrypted && !m_enc_handler.is_send_plaintext()));
|
2007-06-06 02:41:20 +02:00
|
|
|
#endif
|
2007-11-19 08:07:57 +01:00
|
|
|
if (!in_handshake())
|
|
|
|
{
|
|
|
|
TORRENT_ASSERT(m_sent_handshake);
|
|
|
|
}
|
|
|
|
|
2006-04-30 02:39:18 +02:00
|
|
|
if (!m_payloads.empty())
|
|
|
|
{
|
2009-05-03 22:21:24 +02:00
|
|
|
for (std::vector<range>::const_iterator i = m_payloads.begin();
|
2006-04-30 02:39:18 +02:00
|
|
|
i != m_payloads.end() - 1; ++i)
|
|
|
|
{
|
2007-10-05 02:30:00 +02:00
|
|
|
TORRENT_ASSERT(i->start + i->length <= (i+1)->start);
|
2006-04-30 02:39:18 +02:00
|
|
|
}
|
|
|
|
}
|
2006-04-25 23:04:48 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
}
|
|
|
|
|