From 88fa0b9393144005d1fdcdafcac1198567e4aebf Mon Sep 17 00:00:00 2001 From: Arvid Norberg Date: Thu, 19 May 2011 02:41:28 +0000 Subject: [PATCH] optimize send buffer allocation and deallocation by not allowing requiring contiguous buffers --- include/libtorrent/aux_/session_impl.hpp | 5 +- include/libtorrent/bt_peer_connection.hpp | 23 +- include/libtorrent/chained_buffer.hpp | 6 +- include/libtorrent/peer_connection.hpp | 4 +- src/bt_peer_connection.cpp | 286 +++++++--------------- src/lt_trackers.cpp | 30 ++- src/metadata_transfer.cpp | 54 ++-- src/peer_connection.cpp | 63 ++--- src/session_impl.cpp | 28 +-- src/ut_pex.cpp | 34 ++- 10 files changed, 181 insertions(+), 352 deletions(-) diff --git a/include/libtorrent/aux_/session_impl.hpp b/include/libtorrent/aux_/session_impl.hpp index 22808c2ca..99fb72d3e 100644 --- a/include/libtorrent/aux_/session_impl.hpp +++ b/include/libtorrent/aux_/session_impl.hpp @@ -408,8 +408,8 @@ namespace libtorrent m_total_failed_bytes += b; } - std::pair allocate_buffer(int size); - void free_buffer(char* buf, int size); + char* allocate_buffer(); + void free_buffer(char* buf); char* allocate_disk_buffer(char const* category); void free_disk_buffer(char* buf); @@ -516,7 +516,6 @@ namespace libtorrent // buffers from. boost::pool<> m_send_buffers; #endif - mutex m_send_buffer_mutex; // the file pool that all storages in this session's // torrents uses. It sets a limit on the number of diff --git a/include/libtorrent/bt_peer_connection.hpp b/include/libtorrent/bt_peer_connection.hpp index 0713bc8d3..d2f2a4419 100644 --- a/include/libtorrent/bt_peer_connection.hpp +++ b/include/libtorrent/bt_peer_connection.hpp @@ -278,7 +278,7 @@ namespace libtorrent void write_pe3_sync(); void write_pe4_sync(int crypto_select); - void write_pe_vc_cryptofield(buffer::interval& write_buf + void write_pe_vc_cryptofield(char* write_buf, int len , int crypto_field, int pad_size); // stream key (info hash of attached torrent) @@ -293,29 +293,18 @@ public: // peer_connection functions of the same names virtual void append_const_send_buffer(char const* buffer, int size); void send_buffer(char const* buf, int size, int flags = 0); - buffer::interval allocate_send_buffer(int size); template void append_send_buffer(char* buffer, int size, Destructor const& destructor) { #ifndef TORRENT_DISABLE_ENCRYPTION if (m_rc4_encrypted) - { - TORRENT_ASSERT(send_buffer_size() == m_encrypted_bytes); m_RC4_handler->encrypt(buffer, size); -#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS - m_encrypted_bytes += size; - TORRENT_ASSERT(m_encrypted_bytes == send_buffer_size() + size); -#endif - } #endif peer_connection::append_send_buffer(buffer, size, destructor, true); } - void setup_send(); private: - void encrypt_pending_buffer(); - // Returns offset at which bytestream (src, src + src_size) // matches bytestream(target, target + target_size). // If no sync found, return -1 @@ -420,10 +409,6 @@ private: // the maximum number of bytes int m_sync_bytes_read; - // hold information about latest allocated send buffer - // need to check for non zero (begin, end) for operations with this - buffer::interval m_enc_send_buffer; - // initialized during write_pe1_2_dhkey, and destroyed on // creation of m_RC4_handler. Cannot reinitialize once // initialized. @@ -453,12 +438,6 @@ private: bool m_in_constructor; bool m_sent_handshake; - - // the number of bytes in the send buffer - // that have been encrypted (only used for - // encrypted connections) -public: - int m_encrypted_bytes; #endif }; diff --git a/include/libtorrent/chained_buffer.hpp b/include/libtorrent/chained_buffer.hpp index 2b1590517..acfb26fa2 100644 --- a/include/libtorrent/chained_buffer.hpp +++ b/include/libtorrent/chained_buffer.hpp @@ -123,12 +123,12 @@ namespace libtorrent // tries to copy the given buffer to the end of the // last chained buffer. If there's not enough room // it returns false - bool append(char const* buf, int s) + char* append(char const* buf, int s) { char* insert = allocate_appendix(s); - if (insert == 0) return false; + if (insert == 0) return 0; memcpy(insert, buf, s); - return true; + return insert; } // tries to allocate memory from the end diff --git a/include/libtorrent/peer_connection.hpp b/include/libtorrent/peer_connection.hpp index ca72170fe..d6b1b3c63 100644 --- a/include/libtorrent/peer_connection.hpp +++ b/include/libtorrent/peer_connection.hpp @@ -536,8 +536,8 @@ namespace libtorrent // these functions are virtual to let bt_peer_connection hook into them // and encrypt the content enum message_type_flags { message_type_request = 1 }; - virtual void send_buffer(char const* begin, int size, int flags = 0); - virtual buffer::interval allocate_send_buffer(int size); + virtual void send_buffer(char const* begin, int size, int flags = 0 + , void (*fun)(char*, int, void*) = 0, void* userdata = 0); virtual void setup_send(); #ifdef TORRENT_DISK_STATS diff --git a/src/bt_peer_connection.cpp b/src/bt_peer_connection.cpp index 6cedb8766..5f77fd584 100644 --- a/src/bt_peer_connection.cpp +++ b/src/bt_peer_connection.cpp @@ -53,6 +53,7 @@ POSSIBILITY OF SUCH DAMAGE. #include "libtorrent/escape_string.hpp" #include "libtorrent/peer_info.hpp" #include "libtorrent/random.hpp" +#include "libtorrent/alloca.hpp" #ifndef TORRENT_DISABLE_ENCRYPTION #include "libtorrent/pe_crypto.hpp" @@ -110,7 +111,6 @@ namespace libtorrent , m_encrypted(false) , m_rc4_encrypted(false) , m_sync_bytes_read(0) - , m_enc_send_buffer(0, 0) #endif #if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS , m_sent_bitfield(false) @@ -124,7 +124,6 @@ namespace libtorrent #if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS m_in_constructor = false; - m_encrypted_bytes = 0; #endif memset(m_reserved_bits, 0, sizeof(m_reserved_bits)); } @@ -148,7 +147,6 @@ namespace libtorrent , m_encrypted(false) , m_rc4_encrypted(false) , m_sync_bytes_read(0) - , m_enc_send_buffer(0, 0) #endif #if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS , m_sent_bitfield(false) @@ -176,7 +174,6 @@ namespace libtorrent #if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS m_in_constructor = false; - m_encrypted_bytes = 0; #endif memset(m_reserved_bits, 0, sizeof(m_reserved_bits)); } @@ -434,23 +431,15 @@ namespace libtorrent peer_log(" pad size: %d", pad_size); #endif - buffer::interval send_buf = allocate_send_buffer(dh_key_len + pad_size); - if (send_buf.begin == 0) - { - disconnect(errors::no_memory); - return; - } + char msg[dh_key_len + 512]; + char* ptr = msg; + int buf_size = dh_key_len + pad_size; - std::copy(m_dh_key_exchange->get_local_key(), - m_dh_key_exchange->get_local_key() + dh_key_len, - send_buf.begin); + memcpy(ptr, m_dh_key_exchange->get_local_key(), dh_key_len); + ptr += dh_key_len; - std::generate(send_buf.begin + dh_key_len, send_buf.end, std::rand); -#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS - m_encrypted_bytes += send_buf.left(); - TORRENT_ASSERT(m_encrypted_bytes <= send_buffer_size()); -#endif - setup_send(); + std::generate(ptr, ptr + pad_size, random); + send_buffer(msg, buf_size); #ifdef TORRENT_VERBOSE_LOGGING peer_log(" sent DH key"); @@ -475,12 +464,9 @@ namespace libtorrent int pad_size = random() % 512; - TORRENT_ASSERT(!m_rc4_encrypted || send_buffer_size() == m_encrypted_bytes); - // synchash,skeyhash,vc,crypto_provide,len(pad),pad,len(ia) - buffer::interval send_buf = - allocate_send_buffer(20 + 20 + 8 + 4 + 2 + pad_size + 2); - if (send_buf.begin == 0) return; // out of memory + char msg[20 + 20 + 8 + 4 + 2 + 512 + 2]; + char* ptr = msg; // sync hash (hash('req1',S)) h.reset(); @@ -488,8 +474,8 @@ namespace libtorrent h.update(secret, dh_key_len); sha1_hash sync_hash = h.final(); - std::copy(sync_hash.begin(), sync_hash.end(), send_buf.begin); - send_buf.begin += 20; + memcpy(ptr, &sync_hash[0], 20); + ptr += 20; // stream key obfuscated hash [ hash('req2',SKEY) xor hash('req3',S) ] h.reset(); @@ -503,16 +489,15 @@ namespace libtorrent sha1_hash obfsc_hash = h.final(); obfsc_hash ^= streamkey_hash; - std::copy(obfsc_hash.begin(), obfsc_hash.end(), send_buf.begin); - send_buf.begin += 20; + memcpy(ptr, &obfsc_hash[0], 20); + ptr += 20; // Discard DH key exchange data, setup RC4 keys init_pe_RC4_handler(secret, info_hash); m_dh_key_exchange.reset(); // secret should be invalid at this point // write the verification constant and crypto field - TORRENT_ASSERT(send_buf.left() == 8 + 4 + 2 + pad_size + 2); - int encrypt_size = send_buf.left(); + int encrypt_size = sizeof(msg) - 512 + pad_size - 40; int crypto_provide = 0; pe_settings::enc_level const& allowed_enc_level = m_ses.get_pe_settings().allowed_enc_level; @@ -530,14 +515,9 @@ namespace libtorrent , level[allowed_enc_level]); #endif - write_pe_vc_cryptofield(send_buf, crypto_provide, pad_size); - m_RC4_handler->encrypt(send_buf.end - encrypt_size, encrypt_size); -#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS - m_encrypted_bytes = send_buffer_size(); -#endif - - TORRENT_ASSERT(send_buf.begin == send_buf.end); - setup_send(); + write_pe_vc_cryptofield(ptr, encrypt_size, crypto_provide, pad_size); + m_RC4_handler->encrypt(ptr, encrypt_size); + send_buffer(msg, sizeof(msg) - 512 + pad_size); } void bt_peer_connection::write_pe4_sync(int crypto_select) @@ -552,20 +532,12 @@ namespace libtorrent int pad_size = random() % 512; - TORRENT_ASSERT(!m_rc4_encrypted || send_buffer_size() == m_encrypted_bytes); - const int buf_size = 8 + 4 + 2 + pad_size; - buffer::interval send_buf = allocate_send_buffer(buf_size); - if (send_buf.begin == 0) return; // out of memory - write_pe_vc_cryptofield(send_buf, crypto_select, pad_size); + char msg[512 + 8 + 4 + 2]; + write_pe_vc_cryptofield(msg, sizeof(msg), crypto_select, pad_size); - m_RC4_handler->encrypt(send_buf.end - buf_size, buf_size); - TORRENT_ASSERT(send_buffer_size() - buf_size == m_encrypted_bytes); -#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS - m_encrypted_bytes += buf_size; - TORRENT_ASSERT(m_encrypted_bytes <= send_buffer_size()); -#endif - setup_send(); + m_RC4_handler->encrypt(msg, buf_size); + send_buffer(msg, buf_size); // encryption method has been negotiated if (crypto_select == 0x02) @@ -579,36 +551,34 @@ namespace libtorrent #endif } - void bt_peer_connection::write_pe_vc_cryptofield(buffer::interval& write_buf + void bt_peer_connection::write_pe_vc_cryptofield(char* write_buf, int len , int crypto_field, int pad_size) { INVARIANT_CHECK; TORRENT_ASSERT(crypto_field <= 0x03 && crypto_field > 0); // vc,crypto_field,len(pad),pad, (len(ia)) - TORRENT_ASSERT( (write_buf.left() == 8+4+2+pad_size+2 && is_local()) || - (write_buf.left() == 8+4+2+pad_size && !is_local()) ); + TORRENT_ASSERT((len >= 8+4+2+pad_size+2 && is_local()) + || (len >= 8+4+2+pad_size && !is_local())); TORRENT_ASSERT(!m_sent_handshake); // encrypt(vc, crypto_provide/select, len(Pad), len(IA)) // len(pad) is zero for now, len(IA) only for outgoing connections // vc - std::fill(write_buf.begin, write_buf.begin + 8, 0); - write_buf.begin += 8; + memset(write_buf, 0, 8); + write_buf += 8; - detail::write_uint32(crypto_field, write_buf.begin); - detail::write_uint16(pad_size, write_buf.begin); // len (pad) + detail::write_uint32(crypto_field, write_buf); + detail::write_uint16(pad_size, write_buf); // len (pad) // fill pad with zeroes - std::generate(write_buf.begin, write_buf.begin + pad_size, &std::rand); - write_buf.begin += pad_size; + std::generate(write_buf, write_buf + pad_size, &random); + write_buf += pad_size; // append len(ia) if we are initiating if (is_local()) - detail::write_uint16(handshake_len, write_buf.begin); // len(IA) - - TORRENT_ASSERT(write_buf.begin == write_buf.end); + detail::write_uint16(handshake_len, write_buf); // len(IA) } void bt_peer_connection::init_pe_RC4_handler(char const* secret, sha1_hash const& stream_key) @@ -656,13 +626,14 @@ namespace libtorrent void bt_peer_connection::append_const_send_buffer(char const* buffer, int size) { - TORRENT_ASSERT(!m_rc4_encrypted || send_buffer_size() == m_encrypted_bytes); - // if we're encrypting this buffer, we need to make a copy - // since we'll mutate it #ifndef TORRENT_DISABLE_ENCRYPTION if (m_encrypted && m_rc4_encrypted) { - send_buffer(buffer, size); + // if we're encrypting this buffer, we need to make a copy + // since we'll mutate it + char* buf = (char*)malloc(size); + memcpy(buf, buffer, size); + bt_peer_connection::append_send_buffer(buf, size, boost::bind(&::free, _1)); } else #endif @@ -671,72 +642,28 @@ namespace libtorrent } } + void encrypt(char* buf, int len, void* userdata) + { + RC4_handler* rc4 = (RC4_handler*)userdata; + rc4->encrypt(buf, len); + } + void bt_peer_connection::send_buffer(char const* buf, int size, int flags) { TORRENT_ASSERT(buf); TORRENT_ASSERT(size > 0); + void* userdata = 0; + void (*fun)(char*, int, void*) = 0; #ifndef TORRENT_DISABLE_ENCRYPTION - encrypt_pending_buffer(); - if (m_encrypted && m_rc4_encrypted) { - TORRENT_ASSERT(!m_rc4_encrypted || send_buffer_size() == m_encrypted_bytes); - m_RC4_handler->encrypt(const_cast(buf), size); -#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS - m_encrypted_bytes += size; -#endif + fun = encrypt; + userdata = m_RC4_handler.get(); } #endif - peer_connection::send_buffer(buf, size, flags); - } - - buffer::interval bt_peer_connection::allocate_send_buffer(int size) - { -#ifndef TORRENT_DISABLE_ENCRYPTION - encrypt_pending_buffer(); - if (m_encrypted && m_rc4_encrypted) - { - TORRENT_ASSERT(m_enc_send_buffer.left() == 0); - m_enc_send_buffer = peer_connection::allocate_send_buffer(size); - return m_enc_send_buffer; - } - else -#endif - { - buffer::interval i = peer_connection::allocate_send_buffer(size); - return i; - } - } - -#ifndef TORRENT_DISABLE_ENCRYPTION - void bt_peer_connection::encrypt_pending_buffer() - { - if (m_encrypted && m_rc4_encrypted && m_enc_send_buffer.left()) - { - TORRENT_ASSERT(m_enc_send_buffer.begin); - TORRENT_ASSERT(m_enc_send_buffer.end); - TORRENT_ASSERT(m_RC4_handler); - TORRENT_ASSERT(send_buffer_size() - m_enc_send_buffer.left() == m_encrypted_bytes); -#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS - m_encrypted_bytes += m_enc_send_buffer.left(); - TORRENT_ASSERT(m_encrypted_bytes <= send_buffer_size()); -#endif - - m_RC4_handler->encrypt(m_enc_send_buffer.begin, m_enc_send_buffer.left()); - m_enc_send_buffer.end = m_enc_send_buffer.begin; - } - } -#endif - - void bt_peer_connection::setup_send() - { -#ifndef TORRENT_DISABLE_ENCRYPTION - encrypt_pending_buffer(); - TORRENT_ASSERT(!m_encrypted || !m_rc4_encrypted || m_encrypted_bytes == send_buffer_size()); -#endif - peer_connection::setup_send(); + peer_connection::send_buffer(buf, size, flags, fun, userdata); } int bt_peer_connection::get_syncoffset(char const* src, int src_size, @@ -801,37 +728,31 @@ namespace libtorrent const char version_string[] = "BitTorrent protocol"; const int string_len = sizeof(version_string)-1; - buffer::interval i = allocate_send_buffer(1 + string_len + 8 + 20 + 20); - if (i.begin == 0) return; // out of memory + char handshake[1 + string_len + 8 + 20 + 20]; + char* ptr = handshake; // length of version string - *i.begin = string_len; - ++i.begin; - - // version string itself - std::copy( - version_string - , version_string + string_len - , i.begin); - i.begin += string_len; - + detail::write_uint8(string_len, ptr); + // protocol identifier + memcpy(ptr, version_string, string_len); + ptr += string_len; // 8 zeroes - std::fill(i.begin, i.begin + 8, 0); + memset(ptr, 0, 8); #ifndef TORRENT_DISABLE_DHT // indicate that we support the DHT messages - *(i.begin + 7) |= 0x01; + *(ptr + 7) |= 0x01; #endif #ifndef TORRENT_DISABLE_EXTENSIONS // we support extensions - *(i.begin + 5) |= 0x10; + *(ptr + 5) |= 0x10; #endif // we support merkle torrents - *(i.begin + 5) |= 0x08; + *(ptr + 5) |= 0x08; // we support FAST extension - *(i.begin + 7) |= 0x04; + *(ptr + 7) |= 0x04; #ifdef TORRENT_VERBOSE_LOGGING std::string bitmask; @@ -839,31 +760,27 @@ namespace libtorrent { for (int j = 0; j < 8; ++j) { - if (i.begin[k] & (0x80 >> j)) bitmask += '1'; + if (ptr[k] & (0x80 >> j)) bitmask += '1'; else bitmask += '0'; } } peer_log(">>> EXTENSION_BITS [ %s ]", bitmask.c_str()); #endif - i.begin += 8; + ptr += 8; // info hash sha1_hash const& ih = t->torrent_file().info_hash(); - std::copy(ih.begin(), ih.end(), i.begin); - i.begin += 20; + memcpy(ptr, &ih[0], 20); + ptr += 20; // peer id - std::copy( - m_ses.get_peer_id().begin() - , m_ses.get_peer_id().end() - , i.begin); - i.begin += 20; - TORRENT_ASSERT(i.begin == i.end); + memcpy(ptr, &m_ses.get_peer_id()[0], 20); + ptr += 20; #ifdef TORRENT_VERBOSE_LOGGING peer_log("==> HANDSHAKE [ ih: %s ]", to_hex(ih.to_string()).c_str()); #endif - setup_send(); + send_buffer(handshake, sizeof(handshake)); } boost::optional bt_peer_connection::downloading_piece_progress() const @@ -2060,40 +1977,39 @@ namespace libtorrent const int packet_size = (num_pieces + 7) / 8 + 5; - buffer::interval i = allocate_send_buffer(packet_size); - if (i.begin == 0) return; // out of memory + char* msg = TORRENT_ALLOCA(char, packet_size); + if (msg == 0) return; // out of memory + unsigned char* ptr = (unsigned char*)msg; - detail::write_int32(packet_size - 4, i.begin); - detail::write_uint8(msg_bitfield, i.begin); + detail::write_int32(packet_size - 4, ptr); + detail::write_uint8(msg_bitfield, ptr); if (t->is_seed()) { - memset(i.begin, 0xff, packet_size - 6); + memset(ptr, 0xff, packet_size - 6); // Clear trailing bits - unsigned char *p = ((unsigned char *)i.begin) + packet_size - 6; + unsigned char *p = ((unsigned char *)msg) + packet_size - 1; *p = (0xff << ((8 - (num_pieces & 7)) & 7)) & 0xff; } else { - memset(i.begin, 0, packet_size - 5); + memset(ptr, 0, packet_size - 5); piece_picker const& p = t->picker(); int mask = 0x80; - unsigned char* byte = (unsigned char*)i.begin; for (int i = 0; i < num_pieces; ++i) { - if (p.have_piece(i)) *byte |= mask; + if (p.have_piece(i)) *ptr |= mask; mask >>= 1; if (mask == 0) { mask = 0x80; - ++byte; + ++ptr; } } } for (int c = 0; c < num_lazy_pieces; ++c) - i.begin[lazy_pieces[c] / 8] &= ~(0x80 >> (lazy_pieces[c] & 7)); - TORRENT_ASSERT(i.end - i.begin == (num_pieces + 7) / 8); + msg[5 + lazy_pieces[c] / 8] &= ~(0x80 >> (lazy_pieces[c] & 7)); #ifdef TORRENT_VERBOSE_LOGGING @@ -2101,7 +2017,7 @@ namespace libtorrent bitfield_string.resize(num_pieces); for (int k = 0; k < num_pieces; ++k) { - if (i.begin[k / 8] & (0x80 >> (k % 8))) bitfield_string[k] = '1'; + if (msg[5 + k / 8] & (0x80 >> (k % 8))) bitfield_string[k] = '1'; else bitfield_string[k] = '0'; } peer_log("==> BITFIELD [ %s ]", bitfield_string.c_str()); @@ -2110,7 +2026,7 @@ namespace libtorrent m_sent_bitfield = true; #endif - setup_send(); + send_buffer(msg, packet_size); if (num_lazy_pieces > 0) { @@ -2219,30 +2135,25 @@ namespace libtorrent } #endif - std::vector msg; - bencode(std::back_inserter(msg), handshake); + std::vector dict_msg; + bencode(std::back_inserter(dict_msg), handshake); - // make room for message - buffer::interval i = allocate_send_buffer(6 + msg.size()); - if (i.begin == 0) return; // out of memory + char msg[6]; + char* ptr = msg; // write the length of the message - detail::write_int32((int)msg.size() + 2, i.begin); - detail::write_uint8(msg_extended, i.begin); + detail::write_int32((int)dict_msg.size() + 2, ptr); + detail::write_uint8(msg_extended, ptr); // signal handshake message - detail::write_uint8(0, i.begin); - - std::copy(msg.begin(), msg.end(), i.begin); - i.begin += msg.size(); - TORRENT_ASSERT(i.begin == i.end); + detail::write_uint8(0, ptr); + send_buffer(msg, sizeof(msg)); + send_buffer(&dict_msg[0], dict_msg.size()); #if defined TORRENT_VERBOSE_LOGGING && TORRENT_USE_IOSTREAM std::stringstream handshake_str; handshake.print(handshake_str); peer_log("==> EXTENDED HANDSHAKE: %s", handshake_str.str().c_str()); #endif - - setup_send(); } #endif @@ -2449,8 +2360,6 @@ namespace libtorrent peer_log("*** received DH key"); #endif - TORRENT_ASSERT(!m_rc4_encrypted || send_buffer_size() == m_encrypted_bytes); - // 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 @@ -2791,9 +2700,6 @@ namespace libtorrent return; } m_rc4_encrypted = true; -#if defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS - m_encrypted_bytes = send_buffer_size(); -#endif } else if (crypto_field == 0x01) { @@ -3366,22 +3272,6 @@ namespace libtorrent std::remove_if(m_payloads.begin(), m_payloads.end(), range_below_zero) , m_payloads.end()); -#if (defined TORRENT_DEBUG || TORRENT_RELEASE_ASSERTS) && !defined TORRENT_DISABLE_ENCRYPTION - if (m_encrypted_bytes > 0) - { - if (m_rc4_encrypted) - { - m_encrypted_bytes -= bytes_transferred; - TORRENT_ASSERT(m_encrypted_bytes >= 0); - } - else - { - m_encrypted_bytes -= (std::min)(int(bytes_transferred), m_encrypted_bytes); - } - TORRENT_ASSERT(m_encrypted_bytes >= 0); - } -#endif - TORRENT_ASSERT(amount_payload <= (int)bytes_transferred); m_statistics.sent_bytes(amount_payload, bytes_transferred - amount_payload); diff --git a/src/lt_trackers.cpp b/src/lt_trackers.cpp index 285b88d76..a14be1699 100644 --- a/src/lt_trackers.cpp +++ b/src/lt_trackers.cpp @@ -263,15 +263,14 @@ namespace libtorrent { namespace std::vector const& tex_msg = m_tp.get_lt_tex_msg(); - buffer::interval i = m_pc.allocate_send_buffer(6 + tex_msg.size()); + char msg[6]; + char* ptr = msg; - detail::write_uint32(1 + 1 + tex_msg.size(), i.begin); - detail::write_uint8(bt_peer_connection::msg_extended, i.begin); - detail::write_uint8(m_message_index, i.begin); - std::copy(tex_msg.begin(), tex_msg.end(), i.begin); - i.begin += tex_msg.size(); - - TORRENT_ASSERT(i.begin == i.end); + detail::write_uint32(1 + 1 + tex_msg.size(), ptr); + detail::write_uint8(bt_peer_connection::msg_extended, ptr); + detail::write_uint8(m_message_index, ptr); + m_pc.send_buffer(msg, sizeof(msg)); + m_pc.send_buffer(&tex_msg[0], tex_msg.size()); m_pc.setup_send(); } @@ -303,15 +302,14 @@ namespace libtorrent { namespace (*m_pc.m_logger) << log_line.str(); #endif - buffer::interval i = m_pc.allocate_send_buffer(6 + tex_msg.size()); + char msg[6]; + char* ptr = msg; - detail::write_uint32(1 + 1 + tex_msg.size(), i.begin); - detail::write_uint8(bt_peer_connection::msg_extended, i.begin); - detail::write_uint8(m_message_index, i.begin); - std::copy(tex_msg.begin(), tex_msg.end(), i.begin); - i.begin += tex_msg.size(); - - TORRENT_ASSERT(i.begin == i.end); + detail::write_uint32(1 + 1 + tex_msg.size(), ptr); + detail::write_uint8(bt_peer_connection::msg_extended, ptr); + detail::write_uint8(m_message_index, ptr); + m_pc.send_buffer(msg, sizeof(msg)); + m_pc.send_buffer(&tex_msg[0], tex_msg.size()); m_pc.setup_send(); } diff --git a/src/metadata_transfer.cpp b/src/metadata_transfer.cpp index ca23364ca..879ffc740 100644 --- a/src/metadata_transfer.cpp +++ b/src/metadata_transfer.cpp @@ -293,16 +293,17 @@ namespace libtorrent { namespace << " ==> METADATA_REQUEST [ start: " << start << " | size: " << size << " ]\n"; #endif - buffer::interval i = m_pc.allocate_send_buffer(9); + char msg[9]; + char* ptr = msg; - detail::write_uint32(1 + 1 + 3, i.begin); - detail::write_uint8(bt_peer_connection::msg_extended, i.begin); - detail::write_uint8(m_message_index, i.begin); + detail::write_uint32(1 + 1 + 3, ptr); + detail::write_uint8(bt_peer_connection::msg_extended, ptr); + detail::write_uint8(m_message_index, ptr); // means 'request data' - detail::write_uint8(0, i.begin); - detail::write_uint8(start, i.begin); - detail::write_uint8(size - 1, i.begin); - TORRENT_ASSERT(i.begin == i.end); + detail::write_uint8(0, ptr); + detail::write_uint8(start, ptr); + detail::write_uint8(size - 1, ptr); + m_pc.send_buffer(msg, sizeof(msg)); m_pc.setup_send(); } @@ -322,9 +323,8 @@ namespace libtorrent { namespace std::pair offset = req_to_offset(req, (int)m_tp.metadata().left()); - // TODO: don't allocate send buffer for the metadata part - // just tag it on as a separate buffer like ut_metadata - buffer::interval i = m_pc.allocate_send_buffer(15 + offset.second); + char msg[15]; + char* ptr = msg; #ifdef TORRENT_VERBOSE_LOGGING (*m_pc.m_logger) << time_now_string() @@ -335,18 +335,16 @@ namespace libtorrent { namespace << " ]\n"; #endif // yes, we have metadata, send it - detail::write_uint32(11 + offset.second, i.begin); - detail::write_uint8(bt_peer_connection::msg_extended, i.begin); - detail::write_uint8(m_message_index, i.begin); + detail::write_uint32(11 + offset.second, ptr); + detail::write_uint8(bt_peer_connection::msg_extended, ptr); + detail::write_uint8(m_message_index, ptr); // means 'data packet' - detail::write_uint8(1, i.begin); - detail::write_uint32((int)m_tp.metadata().left(), i.begin); - detail::write_uint32(offset.first, i.begin); + detail::write_uint8(1, ptr); + detail::write_uint32((int)m_tp.metadata().left(), ptr); + detail::write_uint32(offset.first, ptr); + m_pc.send_buffer(msg, sizeof(msg)); char const* metadata = m_tp.metadata().begin; - std::copy(metadata + offset.first - , metadata + offset.first + offset.second, i.begin); - i.begin += offset.second; - TORRENT_ASSERT(i.begin == i.end); + m_pc.append_const_send_buffer(metadata + offset.first, offset.second); } else { @@ -354,15 +352,17 @@ namespace libtorrent { namespace (*m_pc.m_logger) << time_now_string() << " ==> DONT HAVE METADATA\n"; #endif - buffer::interval i = m_pc.allocate_send_buffer(4 + 3); + char msg[4+3]; + char* ptr = msg; + // we don't have the metadata, reply with // don't have-message - detail::write_uint32(1 + 2, i.begin); - detail::write_uint8(bt_peer_connection::msg_extended, i.begin); - detail::write_uint8(m_message_index, i.begin); + detail::write_uint32(1 + 2, ptr); + detail::write_uint8(bt_peer_connection::msg_extended, ptr); + detail::write_uint8(m_message_index, ptr); // means 'have no data' - detail::write_uint8(2, i.begin); - TORRENT_ASSERT(i.begin == i.end); + detail::write_uint8(2, ptr); + m_pc.send_buffer(msg, sizeof(msg)); } m_pc.setup_send(); } diff --git a/src/peer_connection.cpp b/src/peer_connection.cpp index 12ea38acd..51f346d8d 100644 --- a/src/peer_connection.cpp +++ b/src/peer_connection.cpp @@ -4854,7 +4854,8 @@ namespace libtorrent #endif } - void peer_connection::send_buffer(char const* buf, int size, int flags) + void peer_connection::send_buffer(char const* buf, int size, int flags + , void (*fun)(char*, int, void*), void* userdata) { if (flags == message_type_request) m_requests_in_buffer.push_back(m_send_buffer.size() + size); @@ -4863,7 +4864,9 @@ namespace libtorrent if (free_space > size) free_space = size; if (free_space > 0) { - m_send_buffer.append(buf, free_space); + char* dst = m_send_buffer.append(buf, free_space); + TORRENT_ASSERT(dst != 0); + if (fun) fun(dst, free_space, userdata); size -= free_space; buf += free_space; #if defined TORRENT_STATS && defined TORRENT_DISK_STATS @@ -4874,56 +4877,30 @@ namespace libtorrent } if (size <= 0) return; - std::pair buffer = m_ses.allocate_buffer(size); - if (buffer.first == 0) - { - disconnect(errors::no_memory); - return; - } - TORRENT_ASSERT(buffer.second >= size); - std::memcpy(buffer.first, buf, size); - m_send_buffer.append_buffer(buffer.first, buffer.second, size - , boost::bind(&session_impl::free_buffer, boost::ref(m_ses), _1, buffer.second)); #if defined TORRENT_STATS && defined TORRENT_DISK_STATS m_ses.m_buffer_usage_logger << log_time() << " send_buffer_alloc: " << size << std::endl; m_ses.log_buffer_usage(); #endif - setup_send(); - } - -// TODO: change this interface to automatically call setup_send() when the -// return value is destructed - buffer::interval peer_connection::allocate_send_buffer(int size) - { - TORRENT_ASSERT(size > 0); - char* insert = m_send_buffer.allocate_appendix(size); - if (insert == 0) + int i = 0; + while (size > 0) { - std::pair buffer = m_ses.allocate_buffer(size); - if (buffer.first == 0) + char* chain_buf = m_ses.allocate_buffer(); + if (chain_buf == 0) { disconnect(errors::no_memory); - return buffer::interval(0, 0); + return; } - TORRENT_ASSERT(buffer.second >= size); - m_send_buffer.append_buffer(buffer.first, buffer.second, size - , boost::bind(&session_impl::free_buffer, boost::ref(m_ses), _1, buffer.second)); - buffer::interval ret(buffer.first, buffer.first + size); -#if defined TORRENT_STATS && defined TORRENT_DISK_STATS - m_ses.m_buffer_usage_logger << log_time() << " allocate_buffer_alloc: " << size << std::endl; - m_ses.log_buffer_usage(); -#endif - return ret; - } - else - { -#if defined TORRENT_STATS && defined TORRENT_DISK_STATS - m_ses.m_buffer_usage_logger << log_time() << " allocate_buffer: " << size << std::endl; - m_ses.log_buffer_usage(); -#endif - buffer::interval ret(insert, insert + size); - return ret; + + int buf_size = (std::min)(int(aux::session_impl::send_buffer_size), size); + memcpy(chain_buf, buf, buf_size); + if (fun) fun(chain_buf, buf_size, userdata); + buf += buf_size; + size -= buf_size; + m_send_buffer.append_buffer(chain_buf, aux::session_impl::send_buffer_size, buf_size + , boost::bind(&session_impl::free_buffer, boost::ref(m_ses), _1)); + ++i; } + setup_send(); } template diff --git a/src/session_impl.cpp b/src/session_impl.cpp index 670326762..6ec3635ab 100644 --- a/src/session_impl.cpp +++ b/src/session_impl.cpp @@ -5159,25 +5159,21 @@ namespace aux { return m_disk_thread.allocate_buffer(category); } - std::pair session_impl::allocate_buffer(int size) + char* session_impl::allocate_buffer() { - TORRENT_ASSERT(size > 0); - int num_buffers = (size + send_buffer_size - 1) / send_buffer_size; - TORRENT_ASSERT(num_buffers > 0); + TORRENT_ASSERT(is_network_thread()); - mutex::scoped_lock l(m_send_buffer_mutex); #ifdef TORRENT_DISK_STATS TORRENT_ASSERT(m_buffer_allocations >= 0); - m_buffer_allocations += num_buffers; + m_buffer_allocations++; m_buffer_usage_logger << log_time() << " protocol_buffer: " << (m_buffer_allocations * send_buffer_size) << std::endl; #endif #ifdef TORRENT_DISABLE_POOL_ALLOCATOR - int num_bytes = num_buffers * send_buffer_size; - return std::make_pair((char*)malloc(num_bytes), num_bytes); + int num_bytes = send_buffer_size; + return (char*)malloc(num_bytes); #else - return std::make_pair((char*)m_send_buffers.ordered_malloc(num_buffers) - , num_buffers * send_buffer_size); + return (char*)m_send_buffers.malloc(); #endif } @@ -5202,16 +5198,12 @@ namespace aux { } #endif - void session_impl::free_buffer(char* buf, int size) + void session_impl::free_buffer(char* buf) { - TORRENT_ASSERT(size > 0); - TORRENT_ASSERT(size % send_buffer_size == 0); - int num_buffers = size / send_buffer_size; - TORRENT_ASSERT(num_buffers > 0); + TORRENT_ASSERT(is_network_thread()); - mutex::scoped_lock l(m_send_buffer_mutex); #ifdef TORRENT_DISK_STATS - m_buffer_allocations -= num_buffers; + m_buffer_allocations--; TORRENT_ASSERT(m_buffer_allocations >= 0); m_buffer_usage_logger << log_time() << " protocol_buffer: " << (m_buffer_allocations * send_buffer_size) << std::endl; @@ -5219,7 +5211,7 @@ namespace aux { #ifdef TORRENT_DISABLE_POOL_ALLOCATOR free(buf); #else - m_send_buffers.ordered_free(buf, num_buffers); + m_send_buffers.free(buf); #endif } diff --git a/src/ut_pex.cpp b/src/ut_pex.cpp index d76f62aae..90a98fe4b 100644 --- a/src/ut_pex.cpp +++ b/src/ut_pex.cpp @@ -435,15 +435,14 @@ namespace libtorrent { namespace std::vector const& pex_msg = m_tp.get_ut_pex_msg(); - buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size()); + char msg[6]; + char* ptr = msg; - detail::write_uint32(1 + 1 + pex_msg.size(), i.begin); - detail::write_uint8(bt_peer_connection::msg_extended, i.begin); - detail::write_uint8(m_message_index, i.begin); - std::copy(pex_msg.begin(), pex_msg.end(), i.begin); - i.begin += pex_msg.size(); - - TORRENT_ASSERT(i.begin == i.end); + detail::write_uint32(1 + 1 + pex_msg.size(), ptr); + detail::write_uint8(bt_peer_connection::msg_extended, ptr); + detail::write_uint8(m_message_index, ptr); + m_pc.send_buffer(msg, sizeof(msg)); + m_pc.send_buffer(&pex_msg[0], pex_msg.size()); #ifdef TORRENT_VERBOSE_LOGGING lazy_entry m; @@ -464,8 +463,6 @@ namespace libtorrent { namespace m_pc.peer_log("==> PEX_DIFF [ dropped: %d added: %d msg_size: %d ]" , num_dropped, num_added, int(pex_msg.size())); #endif - - m_pc.setup_send(); } void send_ut_peer_list() @@ -528,21 +525,18 @@ namespace libtorrent { namespace std::vector pex_msg; bencode(std::back_inserter(pex_msg), pex); - buffer::interval i = m_pc.allocate_send_buffer(6 + pex_msg.size()); + char msg[6]; + char* ptr = msg; - detail::write_uint32(1 + 1 + pex_msg.size(), i.begin); - detail::write_uint8(bt_peer_connection::msg_extended, i.begin); - detail::write_uint8(m_message_index, i.begin); - std::copy(pex_msg.begin(), pex_msg.end(), i.begin); - i.begin += pex_msg.size(); - - TORRENT_ASSERT(i.begin == i.end); + detail::write_uint32(1 + 1 + pex_msg.size(), ptr); + detail::write_uint8(bt_peer_connection::msg_extended, ptr); + detail::write_uint8(m_message_index, ptr); + m_pc.send_buffer(msg, sizeof(msg)); + m_pc.send_buffer(&pex_msg[0], pex_msg.size()); #ifdef TORRENT_VERBOSE_LOGGING m_pc.peer_log("==> PEX_FULL [ added: %d msg_size: %d ]", num_added, int(pex_msg.size())); #endif - - m_pc.setup_send(); } torrent& m_torrent;