Added new send buffer class to avoid unecessary copying of outgoing data.
This commit is contained in:
parent
8c8a375168
commit
7f890239c4
2
COPYING
2
COPYING
|
@ -10,7 +10,7 @@ are met:
|
||||||
* Redistributions in binary form must reproduce the above copyright
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
notice, this list of conditions and the following disclaimer in
|
notice, this list of conditions and the following disclaimer in
|
||||||
the documentation and/or other materials provided with the distribution.
|
the documentation and/or other materials provided with the distribution.
|
||||||
* Neither the name of the author nor the names of its
|
* Neither the name of Rasterbar Software nor the names of its
|
||||||
contributors may be used to endorse or promote products derived
|
contributors may be used to endorse or promote products derived
|
||||||
from this software without specific prior written permission.
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
|
1
Jamfile
1
Jamfile
|
@ -28,6 +28,7 @@ project torrent
|
||||||
<variant>release:<define>NDEBUG
|
<variant>release:<define>NDEBUG
|
||||||
<define>BOOST_ALL_NO_LIB
|
<define>BOOST_ALL_NO_LIB
|
||||||
<define>_FILE_OFFSET_BITS=64
|
<define>_FILE_OFFSET_BITS=64
|
||||||
|
<define>BOOST_THREAD_USE_LIB
|
||||||
<library>/boost/thread//boost_thread/<link>static
|
<library>/boost/thread//boost_thread/<link>static
|
||||||
<library>/boost/filesystem//boost_filesystem/<link>static
|
<library>/boost/filesystem//boost_filesystem/<link>static
|
||||||
<library>/boost/date_time//boost_date_time/<link>static
|
<library>/boost/date_time//boost_date_time/<link>static
|
||||||
|
|
|
@ -87,8 +87,8 @@ int main(int argc, char* argv[])
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
torrent_info t;
|
torrent_info t;
|
||||||
path full_path = initial_path() / path(argv[3]);
|
path full_path = complete(path(argv[3]));
|
||||||
ofstream out(initial_path() / path(argv[1]), std::ios_base::binary);
|
ofstream out(complete(path(argv[1])), std::ios_base::binary);
|
||||||
|
|
||||||
int piece_size = 256 * 1024;
|
int piece_size = 256 * 1024;
|
||||||
char const* creator_str = "libtorrent";
|
char const* creator_str = "libtorrent";
|
||||||
|
|
|
@ -0,0 +1,336 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2003 - 2005, Arvid Norberg, Daniel Wallin
|
||||||
|
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 Rasterbar Software nor the names of its
|
||||||
|
contributors may be used to endorse or promote products derived
|
||||||
|
from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||||
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBTORRENT_BUFFER_HPP
|
||||||
|
#define LIBTORRENT_BUFFER_HPP
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
namespace libtorrent {
|
||||||
|
|
||||||
|
class buffer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct interval
|
||||||
|
{
|
||||||
|
interval(char* begin, char* end)
|
||||||
|
: begin(begin)
|
||||||
|
, end(end)
|
||||||
|
{}
|
||||||
|
|
||||||
|
char* begin;
|
||||||
|
char* end;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct const_interval
|
||||||
|
{
|
||||||
|
const_interval(char const* begin, char const* end)
|
||||||
|
: begin(begin)
|
||||||
|
, end(end)
|
||||||
|
{}
|
||||||
|
|
||||||
|
char const* begin;
|
||||||
|
char const* end;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::pair<const_interval, const_interval> interval_type;
|
||||||
|
|
||||||
|
buffer(std::size_t n = 0);
|
||||||
|
~buffer();
|
||||||
|
|
||||||
|
interval allocate(std::size_t n);
|
||||||
|
void insert(char const* first, char const* last);
|
||||||
|
void erase(std::size_t n);
|
||||||
|
std::size_t size() const;
|
||||||
|
std::size_t capacity() const;
|
||||||
|
void reserve(std::size_t n);
|
||||||
|
interval_type data() const;
|
||||||
|
bool empty() const;
|
||||||
|
|
||||||
|
std::size_t space_left() const;
|
||||||
|
|
||||||
|
char const* raw_data() const
|
||||||
|
{
|
||||||
|
return m_first;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
char* m_first;
|
||||||
|
char* m_last;
|
||||||
|
char* m_write_cursor;
|
||||||
|
char* m_read_cursor;
|
||||||
|
char* m_read_end;
|
||||||
|
bool m_empty;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline buffer::buffer(std::size_t n)
|
||||||
|
: m_first((char*)::operator new(n))
|
||||||
|
, m_last(m_first + n)
|
||||||
|
, m_write_cursor(m_first)
|
||||||
|
, m_read_cursor(m_first)
|
||||||
|
, m_read_end(m_last)
|
||||||
|
, m_empty(true)
|
||||||
|
{}
|
||||||
|
|
||||||
|
inline buffer::~buffer()
|
||||||
|
{
|
||||||
|
::operator delete (m_first);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline buffer::interval buffer::allocate(std::size_t n)
|
||||||
|
{
|
||||||
|
assert(m_read_cursor <= m_read_end || m_empty);
|
||||||
|
|
||||||
|
if (m_read_cursor < m_write_cursor || m_empty)
|
||||||
|
{
|
||||||
|
// ..R***W..
|
||||||
|
if (m_last - m_write_cursor >= (std::ptrdiff_t)n)
|
||||||
|
{
|
||||||
|
interval ret(m_write_cursor, m_write_cursor + n);
|
||||||
|
m_write_cursor += n;
|
||||||
|
m_read_end = m_write_cursor;
|
||||||
|
assert(m_read_cursor <= m_read_end);
|
||||||
|
if (n) m_empty = false;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_read_cursor - m_first >= (std::ptrdiff_t)n)
|
||||||
|
{
|
||||||
|
m_read_end = m_write_cursor;
|
||||||
|
interval ret(m_first, m_first + n);
|
||||||
|
m_write_cursor = m_first + n;
|
||||||
|
assert(m_read_cursor <= m_read_end);
|
||||||
|
if (n) m_empty = false;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
reserve(capacity() + n - (m_last - m_write_cursor));
|
||||||
|
assert(m_last - m_write_cursor >= (std::ptrdiff_t)n);
|
||||||
|
interval ret(m_write_cursor, m_write_cursor + n);
|
||||||
|
m_write_cursor += n;
|
||||||
|
m_read_end = m_write_cursor;
|
||||||
|
if (n) m_empty = false;
|
||||||
|
assert(m_read_cursor <= m_read_end);
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
}
|
||||||
|
//**W...R**
|
||||||
|
if (m_read_cursor - m_write_cursor >= (std::ptrdiff_t)n)
|
||||||
|
{
|
||||||
|
interval ret(m_write_cursor, m_write_cursor + n);
|
||||||
|
m_write_cursor += n;
|
||||||
|
if (n) m_empty = false;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
reserve(capacity() + n - (m_read_cursor - m_write_cursor));
|
||||||
|
assert(m_read_cursor - m_write_cursor >= (std::ptrdiff_t)n);
|
||||||
|
interval ret(m_write_cursor, m_write_cursor + n);
|
||||||
|
m_write_cursor += n;
|
||||||
|
if (n) m_empty = false;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void buffer::insert(char const* first, char const* last)
|
||||||
|
{
|
||||||
|
std::size_t n = last - first;
|
||||||
|
|
||||||
|
if (space_left() < n)
|
||||||
|
{
|
||||||
|
reserve(capacity() + n);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_empty = false;
|
||||||
|
|
||||||
|
char const* end = (m_last - m_write_cursor) < (std::ptrdiff_t)n ?
|
||||||
|
m_last : m_write_cursor + n;
|
||||||
|
|
||||||
|
std::size_t copied = end - m_write_cursor;
|
||||||
|
std::memcpy(m_write_cursor, first, copied);
|
||||||
|
|
||||||
|
m_write_cursor += copied;
|
||||||
|
if (m_write_cursor > m_read_end) m_read_end = m_write_cursor;
|
||||||
|
first += copied;
|
||||||
|
n -= copied;
|
||||||
|
|
||||||
|
if (n == 0) return;
|
||||||
|
|
||||||
|
if (m_write_cursor == m_last) m_write_cursor = m_first;
|
||||||
|
|
||||||
|
memcpy(m_write_cursor, first, n);
|
||||||
|
m_write_cursor += n;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void buffer::erase(std::size_t n)
|
||||||
|
{
|
||||||
|
assert(!m_empty);
|
||||||
|
#ifndef NDEBUG
|
||||||
|
int prev_size = size();
|
||||||
|
#endif
|
||||||
|
assert(m_read_cursor <= m_read_end);
|
||||||
|
m_read_cursor += n;
|
||||||
|
if (m_read_cursor > m_read_end)
|
||||||
|
{
|
||||||
|
m_read_cursor = m_first + (m_read_cursor - m_read_end);
|
||||||
|
assert(m_read_cursor <= m_write_cursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_empty = m_read_cursor == m_write_cursor;
|
||||||
|
|
||||||
|
assert(prev_size - n == size());
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::size_t buffer::size() const
|
||||||
|
{
|
||||||
|
// ...R***W.
|
||||||
|
if (m_read_cursor < m_write_cursor)
|
||||||
|
{
|
||||||
|
return m_write_cursor - m_read_cursor;
|
||||||
|
}
|
||||||
|
// ***W..R*
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (m_empty) return 0;
|
||||||
|
return (m_write_cursor - m_first) + (m_read_end - m_read_cursor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::size_t buffer::capacity() const
|
||||||
|
{
|
||||||
|
return m_last - m_first;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void buffer::reserve(std::size_t size)
|
||||||
|
{
|
||||||
|
std::size_t n = (std::size_t)(capacity() * 1.f);
|
||||||
|
if (n < size) n = size;
|
||||||
|
|
||||||
|
char* buf = (char*)::operator new(n);
|
||||||
|
char* old = m_first;
|
||||||
|
|
||||||
|
if (m_read_cursor < m_write_cursor)
|
||||||
|
{
|
||||||
|
// ...R***W.<>.
|
||||||
|
std::memcpy(
|
||||||
|
buf + (m_read_cursor - m_first)
|
||||||
|
, m_read_cursor
|
||||||
|
, m_write_cursor - m_read_cursor
|
||||||
|
);
|
||||||
|
|
||||||
|
m_write_cursor = buf + (m_write_cursor - m_first);
|
||||||
|
m_read_cursor = buf + (m_read_cursor - m_first);
|
||||||
|
m_read_end = 0;
|
||||||
|
m_first = buf;
|
||||||
|
m_last = buf + n;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// **W..<>.R**
|
||||||
|
std::size_t skip = n - (m_last - m_first);
|
||||||
|
|
||||||
|
std::memcpy(buf, m_first, m_write_cursor - m_first);
|
||||||
|
std::memcpy(
|
||||||
|
buf + (m_read_cursor - m_first) + skip
|
||||||
|
, m_read_cursor
|
||||||
|
, m_last - m_read_cursor
|
||||||
|
);
|
||||||
|
|
||||||
|
m_write_cursor = buf + (m_write_cursor - m_first);
|
||||||
|
|
||||||
|
if (!m_empty)
|
||||||
|
{
|
||||||
|
m_read_cursor = buf + (m_read_cursor - m_first) + skip;
|
||||||
|
m_read_end = buf + (m_read_end - m_first) + skip;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_read_cursor = m_write_cursor;
|
||||||
|
m_read_end = m_write_cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_first = buf;
|
||||||
|
m_last = buf + n;
|
||||||
|
}
|
||||||
|
|
||||||
|
::operator delete (old);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline buffer::interval_type buffer::data() const
|
||||||
|
{
|
||||||
|
// ...R***W.
|
||||||
|
if (m_read_cursor < m_write_cursor)
|
||||||
|
{
|
||||||
|
return interval_type(
|
||||||
|
const_interval(m_read_cursor, m_write_cursor)
|
||||||
|
, const_interval(m_last, m_last)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// **W...R**
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (m_read_cursor == m_read_end)
|
||||||
|
{
|
||||||
|
return interval_type(
|
||||||
|
const_interval(m_first, m_write_cursor)
|
||||||
|
, const_interval(m_last, m_last));
|
||||||
|
}
|
||||||
|
assert(m_read_cursor <= m_read_end || m_empty);
|
||||||
|
return interval_type(
|
||||||
|
const_interval(m_read_cursor, m_read_end)
|
||||||
|
, const_interval(m_first, m_write_cursor)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline bool buffer::empty() const
|
||||||
|
{
|
||||||
|
return m_empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline std::size_t buffer::space_left() const
|
||||||
|
{
|
||||||
|
if (m_empty) return m_last - m_first;
|
||||||
|
|
||||||
|
// ...R***W.
|
||||||
|
if (m_read_cursor < m_write_cursor)
|
||||||
|
{
|
||||||
|
return (m_last - m_write_cursor) + (m_read_cursor - m_first);
|
||||||
|
}
|
||||||
|
// ***W..R*
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return m_read_cursor - m_write_cursor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // LIBTORRENT_BUFFER_HPP
|
||||||
|
|
|
@ -54,6 +54,7 @@ POSSIBILITY OF SUCH DAMAGE.
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "libtorrent/buffer.hpp"
|
||||||
#include "libtorrent/socket.hpp"
|
#include "libtorrent/socket.hpp"
|
||||||
#include "libtorrent/peer_id.hpp"
|
#include "libtorrent/peer_id.hpp"
|
||||||
#include "libtorrent/storage.hpp"
|
#include "libtorrent/storage.hpp"
|
||||||
|
@ -337,7 +338,8 @@ namespace libtorrent
|
||||||
// this is the buffer where data that is
|
// this is the buffer where data that is
|
||||||
// to be sent is stored until it gets
|
// to be sent is stored until it gets
|
||||||
// consumed by send()
|
// consumed by send()
|
||||||
std::vector<char> m_send_buffer;
|
// std::vector<char> m_send_buffer;
|
||||||
|
buffer m_send_buffer;
|
||||||
|
|
||||||
// this is a queue of ranges that describes
|
// this is a queue of ranges that describes
|
||||||
// where in the send buffer actual payload
|
// where in the send buffer actual payload
|
||||||
|
|
|
@ -454,43 +454,46 @@ namespace libtorrent
|
||||||
// add handshake to the send buffer
|
// add handshake to the send buffer
|
||||||
const char version_string[] = "BitTorrent protocol";
|
const char version_string[] = "BitTorrent protocol";
|
||||||
const int string_len = sizeof(version_string)-1;
|
const int string_len = sizeof(version_string)-1;
|
||||||
int pos = 1;
|
|
||||||
|
|
||||||
m_send_buffer.resize(1 + string_len + 8 + 20 + 20);
|
m_send_buffer.reserve(1 + string_len + 8 + 20 + 20);
|
||||||
|
|
||||||
|
buffer::interval i = m_send_buffer.allocate(1 + string_len + 8 + 20 + 20);
|
||||||
// length of version string
|
// length of version string
|
||||||
m_send_buffer[0] = string_len;
|
*i.begin = string_len;
|
||||||
|
++i.begin;
|
||||||
|
|
||||||
// version string itself
|
// version string itself
|
||||||
std::copy(
|
std::copy(
|
||||||
version_string
|
version_string
|
||||||
, version_string + string_len
|
, version_string + string_len
|
||||||
, m_send_buffer.begin()+pos);
|
, i.begin);
|
||||||
pos += string_len;
|
i.begin += string_len;
|
||||||
|
|
||||||
// 8 zeroes
|
// 8 zeroes
|
||||||
std::fill(
|
std::fill(
|
||||||
m_send_buffer.begin() + pos
|
i.begin
|
||||||
, m_send_buffer.begin() + pos + 8
|
, i.begin + 8
|
||||||
, 0);
|
, 0);
|
||||||
// indicate that we support the extension protocol
|
// indicate that we support the extension protocol
|
||||||
|
|
||||||
if (m_ses.extensions_enabled())
|
if (m_ses.extensions_enabled())
|
||||||
m_send_buffer[pos+7] = 0x01;
|
*(i.begin + 7) = 0x01;
|
||||||
pos += 8;
|
i.begin += 8;
|
||||||
|
|
||||||
// info hash
|
// info hash
|
||||||
std::copy(
|
std::copy(
|
||||||
m_torrent->torrent_file().info_hash().begin()
|
m_torrent->torrent_file().info_hash().begin()
|
||||||
, m_torrent->torrent_file().info_hash().end()
|
, m_torrent->torrent_file().info_hash().end()
|
||||||
, m_send_buffer.begin() + pos);
|
, i.begin);
|
||||||
pos += 20;
|
i.begin += 20;
|
||||||
|
|
||||||
// peer id
|
// peer id
|
||||||
std::copy(
|
std::copy(
|
||||||
m_ses.get_peer_id().begin()
|
m_ses.get_peer_id().begin()
|
||||||
, m_ses.get_peer_id().end()
|
, m_ses.get_peer_id().end()
|
||||||
, m_send_buffer.begin() + pos);
|
, i.begin);
|
||||||
|
i.begin += 20;
|
||||||
|
assert(i.begin == i.end);
|
||||||
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
using namespace boost::posix_time;
|
using namespace boost::posix_time;
|
||||||
|
@ -1447,11 +1450,11 @@ namespace libtorrent
|
||||||
|
|
||||||
m_torrent->picker().abort_download(block);
|
m_torrent->picker().abort_download(block);
|
||||||
|
|
||||||
std::deque<piece_block>::iterator i
|
std::deque<piece_block>::iterator it
|
||||||
= std::find(m_download_queue.begin(), m_download_queue.end(), block);
|
= std::find(m_download_queue.begin(), m_download_queue.end(), block);
|
||||||
assert(i != m_download_queue.end());
|
assert(it != m_download_queue.end());
|
||||||
|
|
||||||
m_download_queue.erase(i);
|
m_download_queue.erase(it);
|
||||||
|
|
||||||
|
|
||||||
int block_offset = block.block_index * m_torrent->block_size();
|
int block_offset = block.block_index * m_torrent->block_size();
|
||||||
|
@ -1463,20 +1466,19 @@ namespace libtorrent
|
||||||
|
|
||||||
char buf[] = {0,0,0,13, msg_cancel};
|
char buf[] = {0,0,0,13, msg_cancel};
|
||||||
|
|
||||||
std::size_t start_offset = m_send_buffer.size();
|
buffer::interval i = m_send_buffer.allocate(17);
|
||||||
m_send_buffer.resize(start_offset + 17);
|
|
||||||
|
|
||||||
std::copy(buf, buf + 5, m_send_buffer.begin()+start_offset);
|
std::copy(buf, buf + 5, i.begin);
|
||||||
start_offset += 5;
|
i.begin += 5;
|
||||||
|
|
||||||
char* ptr = &m_send_buffer[start_offset];
|
|
||||||
|
|
||||||
// index
|
// index
|
||||||
detail::write_int32(block.piece_index, ptr);
|
detail::write_int32(block.piece_index, i.begin);
|
||||||
// begin
|
// begin
|
||||||
detail::write_int32(block_offset, ptr);
|
detail::write_int32(block_offset, i.begin);
|
||||||
// length
|
// length
|
||||||
detail::write_int32(block_size, ptr);
|
detail::write_int32(block_size, i.begin);
|
||||||
|
|
||||||
|
assert(i.begin == i.end);
|
||||||
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
using namespace boost::posix_time;
|
using namespace boost::posix_time;
|
||||||
|
@ -1512,20 +1514,19 @@ namespace libtorrent
|
||||||
|
|
||||||
char buf[] = {0,0,0,13, msg_request};
|
char buf[] = {0,0,0,13, msg_request};
|
||||||
|
|
||||||
std::size_t start_offset = m_send_buffer.size();
|
buffer::interval i = m_send_buffer.allocate(17);
|
||||||
m_send_buffer.resize(start_offset + 17);
|
|
||||||
|
|
||||||
std::copy(buf, buf + 5, m_send_buffer.begin()+start_offset);
|
std::copy(buf, buf + 5, i.begin);
|
||||||
|
i.begin += 5;
|
||||||
|
|
||||||
char* ptr = &m_send_buffer[start_offset+5];
|
|
||||||
// index
|
// index
|
||||||
detail::write_int32(block.piece_index, ptr);
|
detail::write_int32(block.piece_index, i.begin);
|
||||||
|
|
||||||
// begin
|
// begin
|
||||||
detail::write_int32(block_offset, ptr);
|
detail::write_int32(block_offset, i.begin);
|
||||||
|
|
||||||
// length
|
// length
|
||||||
detail::write_int32(block_size, ptr);
|
detail::write_int32(block_size, i.begin);
|
||||||
|
|
||||||
|
assert(i.begin == i.end);
|
||||||
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
using namespace boost::posix_time;
|
using namespace boost::posix_time;
|
||||||
|
@ -1558,34 +1559,38 @@ namespace libtorrent
|
||||||
// abort if the peer doesn't support the metadata extension
|
// abort if the peer doesn't support the metadata extension
|
||||||
if (!supports_extension(extended_metadata_message)) return;
|
if (!supports_extension(extended_metadata_message)) return;
|
||||||
|
|
||||||
std::back_insert_iterator<std::vector<char> > ptr(m_send_buffer);
|
|
||||||
|
|
||||||
if (m_torrent->valid_metadata())
|
if (m_torrent->valid_metadata())
|
||||||
{
|
{
|
||||||
std::pair<int, int> offset
|
std::pair<int, int> offset
|
||||||
= req_to_offset(req, (int)m_torrent->metadata().size());
|
= req_to_offset(req, (int)m_torrent->metadata().size());
|
||||||
|
|
||||||
|
buffer::interval i = m_send_buffer.allocate(18 + offset.second);
|
||||||
|
|
||||||
// yes, we have metadata, send it
|
// yes, we have metadata, send it
|
||||||
detail::write_uint32(5 + 9 + offset.second, ptr);
|
detail::write_uint32(5 + 9 + offset.second, i.begin);
|
||||||
detail::write_uint8(msg_extended, ptr);
|
detail::write_uint8(msg_extended, i.begin);
|
||||||
detail::write_int32(m_extension_messages[extended_metadata_message], ptr);
|
detail::write_int32(m_extension_messages[extended_metadata_message], i.begin);
|
||||||
// means 'data packet'
|
// means 'data packet'
|
||||||
detail::write_uint8(1, ptr);
|
detail::write_uint8(1, i.begin);
|
||||||
detail::write_uint32((int)m_torrent->metadata().size(), ptr);
|
detail::write_uint32((int)m_torrent->metadata().size(), i.begin);
|
||||||
detail::write_uint32(offset.first, ptr);
|
detail::write_uint32(offset.first, i.begin);
|
||||||
std::vector<char> const& metadata = m_torrent->metadata();
|
std::vector<char> const& metadata = m_torrent->metadata();
|
||||||
std::copy(metadata.begin() + offset.first
|
std::copy(metadata.begin() + offset.first
|
||||||
, metadata.begin() + offset.first + offset.second, ptr);
|
, metadata.begin() + offset.first + offset.second, i.begin);
|
||||||
|
i.begin += offset.second;
|
||||||
|
assert(i.begin == i.end);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
buffer::interval i = m_send_buffer.allocate(10);
|
||||||
// we don't have the metadata, reply with
|
// we don't have the metadata, reply with
|
||||||
// don't have-message
|
// don't have-message
|
||||||
detail::write_uint32(1 + 4 + 1, ptr);
|
detail::write_uint32(1 + 4 + 1, i.begin);
|
||||||
detail::write_uint8(msg_extended, ptr);
|
detail::write_uint8(msg_extended, i.begin);
|
||||||
detail::write_int32(m_extension_messages[extended_metadata_message], ptr);
|
detail::write_int32(m_extension_messages[extended_metadata_message], i.begin);
|
||||||
// means 'have no data'
|
// means 'have no data'
|
||||||
detail::write_uint8(2, ptr);
|
detail::write_uint8(2, i.begin);
|
||||||
|
assert(i.begin == i.end);
|
||||||
}
|
}
|
||||||
send_buffer_updated();
|
send_buffer_updated();
|
||||||
}
|
}
|
||||||
|
@ -1612,15 +1617,16 @@ namespace libtorrent
|
||||||
<< " size: " << req.second << " ]\n";
|
<< " size: " << req.second << " ]\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::back_insert_iterator<std::vector<char> > ptr(m_send_buffer);
|
buffer::interval i = m_send_buffer.allocate(12);
|
||||||
|
|
||||||
detail::write_uint32(1 + 4 + 3, ptr);
|
detail::write_uint32(1 + 4 + 3, i.begin);
|
||||||
detail::write_uint8(msg_extended, ptr);
|
detail::write_uint8(msg_extended, i.begin);
|
||||||
detail::write_int32(m_extension_messages[extended_metadata_message], ptr);
|
detail::write_int32(m_extension_messages[extended_metadata_message], i.begin);
|
||||||
// means 'request data'
|
// means 'request data'
|
||||||
detail::write_uint8(0, ptr);
|
detail::write_uint8(0, i.begin);
|
||||||
detail::write_uint8(start, ptr);
|
detail::write_uint8(start, i.begin);
|
||||||
detail::write_uint8(size - 1, ptr);
|
detail::write_uint8(size - 1, i.begin);
|
||||||
|
assert(i.begin == i.end);
|
||||||
send_buffer_updated();
|
send_buffer_updated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1636,12 +1642,15 @@ namespace libtorrent
|
||||||
|
|
||||||
std::vector<char> message;
|
std::vector<char> message;
|
||||||
bencode(std::back_inserter(message), e);
|
bencode(std::back_inserter(message), e);
|
||||||
std::back_insert_iterator<std::vector<char> > ptr(m_send_buffer);
|
|
||||||
|
|
||||||
detail::write_uint32(1 + 4 + (int)message.size(), ptr);
|
buffer::interval i = m_send_buffer.allocate(message.size() + 9);
|
||||||
detail::write_uint8(msg_extended, ptr);
|
|
||||||
detail::write_int32(m_extension_messages[extended_chat_message], ptr);
|
detail::write_uint32(1 + 4 + (int)message.size(), i.begin);
|
||||||
std::copy(message.begin(), message.end(), ptr);
|
detail::write_uint8(msg_extended, i.begin);
|
||||||
|
detail::write_int32(m_extension_messages[extended_chat_message], i.begin);
|
||||||
|
std::copy(message.begin(), message.end(), i.begin);
|
||||||
|
i.begin += message.size();
|
||||||
|
assert(i.begin == i.end);
|
||||||
send_buffer_updated();
|
send_buffer_updated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1664,19 +1673,19 @@ namespace libtorrent
|
||||||
(*m_logger) << "\n";
|
(*m_logger) << "\n";
|
||||||
#endif
|
#endif
|
||||||
const int packet_size = ((int)m_have_piece.size() + 7) / 8 + 5;
|
const int packet_size = ((int)m_have_piece.size() + 7) / 8 + 5;
|
||||||
const int old_size = (int)m_send_buffer.size();
|
|
||||||
m_send_buffer.resize(old_size + packet_size);
|
|
||||||
|
|
||||||
char* ptr = &m_send_buffer[old_size];
|
buffer::interval i = m_send_buffer.allocate(packet_size);
|
||||||
detail::write_int32(packet_size - 4, ptr);
|
|
||||||
detail::write_uint8(msg_bitfield, ptr);
|
|
||||||
|
|
||||||
std::fill(m_send_buffer.begin() + old_size + 5, m_send_buffer.end(), 0);
|
detail::write_int32(packet_size - 4, i.begin);
|
||||||
for (int i = 0; i < (int)m_have_piece.size(); ++i)
|
detail::write_uint8(msg_bitfield, i.begin);
|
||||||
|
|
||||||
|
std::fill(i.begin, i.end, 0);
|
||||||
|
for (int c = 0; c < (int)m_have_piece.size(); ++c)
|
||||||
{
|
{
|
||||||
if (m_torrent->have_piece(i))
|
if (m_torrent->have_piece(c))
|
||||||
m_send_buffer[old_size + 5 + (i>>3)] |= 1 << (7 - (i&7));
|
i.begin[c >> 3] |= 1 << (7 - (c & 7));
|
||||||
}
|
}
|
||||||
|
assert(i.end - i.begin == ((int)m_have_piece.size() + 7) / 8);
|
||||||
send_buffer_updated();
|
send_buffer_updated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1701,17 +1710,20 @@ namespace libtorrent
|
||||||
extension_list[extension_names[i]] = i;
|
extension_list[extension_names[i]] = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make room for message size
|
std::vector<char> msg;
|
||||||
const int msg_size_pos = (int)m_send_buffer.size();
|
bencode(std::back_inserter(msg), extension_list);
|
||||||
m_send_buffer.resize(msg_size_pos + 4);
|
|
||||||
|
|
||||||
m_send_buffer.push_back(msg_extension_list);
|
// make room for message
|
||||||
|
buffer::interval i = m_send_buffer.allocate(5 + msg.size());
|
||||||
bencode(std::back_inserter(m_send_buffer), extension_list);
|
|
||||||
|
|
||||||
// write the length of the message
|
// write the length of the message
|
||||||
char* ptr = &m_send_buffer[msg_size_pos];
|
detail::write_int32((int)msg.size() + 1, i.begin);
|
||||||
detail::write_int32((int)m_send_buffer.size() - msg_size_pos - 4, ptr);
|
|
||||||
|
detail::write_uint8(msg_extension_list, i.begin);
|
||||||
|
|
||||||
|
std::copy(msg.begin(), msg.end(), i.begin);
|
||||||
|
i.begin += msg.size();
|
||||||
|
assert(i.begin == i.end);
|
||||||
|
|
||||||
send_buffer_updated();
|
send_buffer_updated();
|
||||||
}
|
}
|
||||||
|
@ -1722,7 +1734,7 @@ namespace libtorrent
|
||||||
|
|
||||||
if (m_choked) return;
|
if (m_choked) return;
|
||||||
char msg[] = {0,0,0,1,msg_choke};
|
char msg[] = {0,0,0,1,msg_choke};
|
||||||
m_send_buffer.insert(m_send_buffer.end(), msg, msg+sizeof(msg));
|
m_send_buffer.insert(msg, msg + sizeof(msg));
|
||||||
m_choked = true;
|
m_choked = true;
|
||||||
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
|
@ -1754,7 +1766,7 @@ namespace libtorrent
|
||||||
|
|
||||||
if (!m_choked) return;
|
if (!m_choked) return;
|
||||||
char msg[] = {0,0,0,1,msg_unchoke};
|
char msg[] = {0,0,0,1,msg_unchoke};
|
||||||
m_send_buffer.insert(m_send_buffer.end(), msg, msg+sizeof(msg));
|
m_send_buffer.insert(msg, msg + sizeof(msg));
|
||||||
m_choked = false;
|
m_choked = false;
|
||||||
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
|
@ -1771,7 +1783,7 @@ namespace libtorrent
|
||||||
|
|
||||||
if (m_interesting) return;
|
if (m_interesting) return;
|
||||||
char msg[] = {0,0,0,1,msg_interested};
|
char msg[] = {0,0,0,1,msg_interested};
|
||||||
m_send_buffer.insert(m_send_buffer.end(), msg, msg+sizeof(msg));
|
m_send_buffer.insert(msg, msg + sizeof(msg));
|
||||||
m_interesting = true;
|
m_interesting = true;
|
||||||
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
|
@ -1788,7 +1800,7 @@ namespace libtorrent
|
||||||
|
|
||||||
if (!m_interesting) return;
|
if (!m_interesting) return;
|
||||||
char msg[] = {0,0,0,1,msg_not_interested};
|
char msg[] = {0,0,0,1,msg_not_interested};
|
||||||
m_send_buffer.insert(m_send_buffer.end(), msg, msg+sizeof(msg));
|
m_send_buffer.insert(msg, msg + sizeof(msg));
|
||||||
m_interesting = false;
|
m_interesting = false;
|
||||||
|
|
||||||
m_became_uninteresting = second_clock::universal_time();
|
m_became_uninteresting = second_clock::universal_time();
|
||||||
|
@ -1816,7 +1828,7 @@ namespace libtorrent
|
||||||
char msg[packet_size] = {0,0,0,5,msg_have};
|
char msg[packet_size] = {0,0,0,5,msg_have};
|
||||||
char* ptr = msg + 5;
|
char* ptr = msg + 5;
|
||||||
detail::write_int32(index, ptr);
|
detail::write_int32(index, ptr);
|
||||||
m_send_buffer.insert(m_send_buffer.end(), msg, msg + packet_size);
|
m_send_buffer.insert(msg, msg + packet_size);
|
||||||
|
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
using namespace boost::posix_time;
|
using namespace boost::posix_time;
|
||||||
|
@ -2306,30 +2318,28 @@ namespace libtorrent
|
||||||
assert(r.start + r.length <= m_torrent->torrent_file().piece_size(r.piece));
|
assert(r.start + r.length <= m_torrent->torrent_file().piece_size(r.piece));
|
||||||
assert(r.length > 0 && r.start >= 0);
|
assert(r.length > 0 && r.start >= 0);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
// assert(m_torrent->verify_piece(r.piece) && "internal error");
|
|
||||||
#endif
|
|
||||||
const int send_buffer_offset = (int)m_send_buffer.size();
|
|
||||||
const int packet_size = 4 + 5 + 4 + r.length;
|
const int packet_size = 4 + 5 + 4 + r.length;
|
||||||
m_send_buffer.resize(send_buffer_offset + packet_size);
|
|
||||||
char* ptr = &m_send_buffer[send_buffer_offset];
|
buffer::interval i = m_send_buffer.allocate(packet_size);
|
||||||
detail::write_int32(packet_size-4, ptr);
|
|
||||||
*ptr = msg_piece; ++ptr;
|
detail::write_int32(packet_size-4, i.begin);
|
||||||
detail::write_int32(r.piece, ptr);
|
detail::write_uint8(msg_piece, i.begin);
|
||||||
detail::write_int32(r.start, ptr);
|
detail::write_int32(r.piece, i.begin);
|
||||||
|
detail::write_int32(r.start, i.begin);
|
||||||
|
|
||||||
m_torrent->filesystem().read(
|
m_torrent->filesystem().read(
|
||||||
&m_send_buffer[send_buffer_offset+13]
|
i.begin
|
||||||
, r.piece
|
, r.piece
|
||||||
, r.start
|
, r.start
|
||||||
, r.length);
|
, r.length);
|
||||||
|
assert(i.begin + r.length == i.end);
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
using namespace boost::posix_time;
|
using namespace boost::posix_time;
|
||||||
(*m_logger) << to_simple_string(second_clock::universal_time())
|
(*m_logger) << to_simple_string(second_clock::universal_time())
|
||||||
<< " ==> PIECE [ piece: " << r.piece << " | s: " << r.start << " | l: " << r.length << " ]\n";
|
<< " ==> PIECE [ piece: " << r.piece << " | s: " << r.start << " | l: " << r.length << " ]\n";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_payloads.push_back(range(send_buffer_offset+13, r.length));
|
m_payloads.push_back(range(m_send_buffer.size() - r.length, r.length));
|
||||||
m_requests.erase(m_requests.begin());
|
m_requests.erase(m_requests.begin());
|
||||||
|
|
||||||
if (m_requests.empty()
|
if (m_requests.empty()
|
||||||
|
@ -2350,8 +2360,7 @@ namespace libtorrent
|
||||||
{
|
{
|
||||||
assert(m_torrent->valid_metadata());
|
assert(m_torrent->valid_metadata());
|
||||||
for (std::vector<int>::iterator i = m_announce_queue.begin();
|
for (std::vector<int>::iterator i = m_announce_queue.begin();
|
||||||
i != m_announce_queue.end();
|
i != m_announce_queue.end(); ++i)
|
||||||
++i)
|
|
||||||
{
|
{
|
||||||
send_have(*i);
|
send_have(*i);
|
||||||
}
|
}
|
||||||
|
@ -2368,22 +2377,34 @@ namespace libtorrent
|
||||||
|
|
||||||
assert(amount_to_send > 0);
|
assert(amount_to_send > 0);
|
||||||
|
|
||||||
|
buffer::interval_type send_buffer = m_send_buffer.data();
|
||||||
// we have data that's scheduled for sending
|
// we have data that's scheduled for sending
|
||||||
int sent = m_socket->send(
|
int to_send = std::min(send_buffer.first.end - send_buffer.first.begin
|
||||||
&m_send_buffer[0]
|
, m_ul_bandwidth_quota.left());
|
||||||
, amount_to_send);
|
int sent = m_socket->send(send_buffer.first.begin, to_send);
|
||||||
|
|
||||||
|
if (sent == send_buffer.first.end - send_buffer.first.end
|
||||||
|
&& send_buffer.second.begin != send_buffer.second.end
|
||||||
|
&& to_send > sent)
|
||||||
|
{
|
||||||
|
to_send -= sent;
|
||||||
|
to_send = std::min(to_send, send_buffer.second.end
|
||||||
|
- send_buffer.second.begin);
|
||||||
|
int ret = m_socket->send(send_buffer.second.begin, to_send);
|
||||||
|
if (ret > 0) sent += ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (sent > 0)
|
if (sent > 0)
|
||||||
{
|
{
|
||||||
m_ul_bandwidth_quota.used += sent;
|
m_ul_bandwidth_quota.used += sent;
|
||||||
|
m_send_buffer.erase(sent);
|
||||||
|
|
||||||
// manage the payload markers
|
// manage the payload markers
|
||||||
int amount_payload = 0;
|
int amount_payload = 0;
|
||||||
if (!m_payloads.empty())
|
if (!m_payloads.empty())
|
||||||
{
|
{
|
||||||
for (std::deque<range>::iterator i = m_payloads.begin();
|
for (std::deque<range>::iterator i = m_payloads.begin();
|
||||||
i != m_payloads.end();
|
i != m_payloads.end(); ++i)
|
||||||
++i)
|
|
||||||
{
|
{
|
||||||
i->start -= sent;
|
i->start -= sent;
|
||||||
if (i->start < 0)
|
if (i->start < 0)
|
||||||
|
@ -2401,6 +2422,7 @@ namespace libtorrent
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO: move the erasing into the loop above
|
||||||
// remove all payload ranges that has been sent
|
// remove all payload ranges that has been sent
|
||||||
m_payloads.erase(
|
m_payloads.erase(
|
||||||
std::remove_if(m_payloads.begin(), m_payloads.end(), range_below_zero)
|
std::remove_if(m_payloads.begin(), m_payloads.end(), range_below_zero)
|
||||||
|
@ -2408,20 +2430,6 @@ namespace libtorrent
|
||||||
|
|
||||||
assert(amount_payload <= sent);
|
assert(amount_payload <= sent);
|
||||||
m_statistics.sent_bytes(amount_payload, sent - amount_payload);
|
m_statistics.sent_bytes(amount_payload, sent - amount_payload);
|
||||||
|
|
||||||
// empty the entire buffer at once or if
|
|
||||||
// only a part of the buffer could be sent
|
|
||||||
// remove the part that was sent from the buffer
|
|
||||||
if (sent == (int)m_send_buffer.size())
|
|
||||||
{
|
|
||||||
m_send_buffer.clear();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
m_send_buffer.erase(
|
|
||||||
m_send_buffer.begin()
|
|
||||||
, m_send_buffer.begin() + sent);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -2496,7 +2504,7 @@ namespace libtorrent
|
||||||
if (m_announce_queue.empty())
|
if (m_announce_queue.empty())
|
||||||
{
|
{
|
||||||
char noop[] = {0,0,0,0};
|
char noop[] = {0,0,0,0};
|
||||||
m_send_buffer.insert(m_send_buffer.end(), noop, noop+4);
|
m_send_buffer.insert(noop, noop + 4);
|
||||||
m_last_sent = second_clock::universal_time();
|
m_last_sent = second_clock::universal_time();
|
||||||
#ifdef TORRENT_VERBOSE_LOGGING
|
#ifdef TORRENT_VERBOSE_LOGGING
|
||||||
using namespace boost::posix_time;
|
using namespace boost::posix_time;
|
||||||
|
@ -2507,8 +2515,7 @@ namespace libtorrent
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for (std::vector<int>::iterator i = m_announce_queue.begin();
|
for (std::vector<int>::iterator i = m_announce_queue.begin();
|
||||||
i != m_announce_queue.end();
|
i != m_announce_queue.end(); ++i)
|
||||||
++i)
|
|
||||||
{
|
{
|
||||||
send_have(*i);
|
send_have(*i);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ project
|
||||||
;
|
;
|
||||||
|
|
||||||
test-suite libtorrent :
|
test-suite libtorrent :
|
||||||
|
[ run test_buffer.cpp ]
|
||||||
[ run test_storage.cpp ]
|
[ run test_storage.cpp ]
|
||||||
[ run test_piece_picker.cpp ]
|
[ run test_piece_picker.cpp ]
|
||||||
# [ run test_entry.cpp ]
|
# [ run test_entry.cpp ]
|
||||||
|
|
|
@ -0,0 +1,165 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2003 - 2005, Arvid Norberg, Daniel Wallin
|
||||||
|
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 Rasterbar Software 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 <cassert>
|
||||||
|
#include <boost/timer.hpp>
|
||||||
|
#include <iostream>
|
||||||
|
#include <vector>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "libtorrent/buffer.hpp"
|
||||||
|
|
||||||
|
#include "test.hpp"
|
||||||
|
|
||||||
|
using libtorrent::buffer;
|
||||||
|
/*
|
||||||
|
template<class T>
|
||||||
|
T const& min_(T const& x, T const& y)
|
||||||
|
{
|
||||||
|
return x < y ? x : y;
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_speed()
|
||||||
|
{
|
||||||
|
buffer b;
|
||||||
|
|
||||||
|
char data[32];
|
||||||
|
|
||||||
|
srand(0);
|
||||||
|
|
||||||
|
boost::timer t;
|
||||||
|
|
||||||
|
int const iterations = 5000000;
|
||||||
|
int const step = iterations / 20;
|
||||||
|
|
||||||
|
for (int i = 0; i < iterations; ++i)
|
||||||
|
{
|
||||||
|
int x = rand();
|
||||||
|
|
||||||
|
if (i % step == 0) std::cerr << ".";
|
||||||
|
|
||||||
|
std::size_t n = rand() % 32;
|
||||||
|
n = 32;
|
||||||
|
|
||||||
|
if (x % 2)
|
||||||
|
{
|
||||||
|
b.insert(data, data + n);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
b.erase(min_(b.size(), n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float t1 = t.elapsed();
|
||||||
|
std::cerr << "buffer elapsed: " << t.elapsed() << "\n";
|
||||||
|
|
||||||
|
std::vector<char> v;
|
||||||
|
|
||||||
|
srand(0);
|
||||||
|
t.restart();
|
||||||
|
|
||||||
|
for (int i = 0; i < iterations; ++i)
|
||||||
|
{
|
||||||
|
int x = rand();
|
||||||
|
|
||||||
|
if (i % step == 0) std::cerr << ".";
|
||||||
|
|
||||||
|
std::size_t n = rand() % 32;
|
||||||
|
n = 32;
|
||||||
|
|
||||||
|
if (x % 2)
|
||||||
|
{
|
||||||
|
v.insert(v.end(), data, data + n);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
v.erase(v.begin(), v.begin() + min_(v.size(), n));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float t2 = t.elapsed();
|
||||||
|
std::cerr << "std::vector elapsed: " << t.elapsed() << "\n";
|
||||||
|
|
||||||
|
assert(t1 < t2);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
int test_main()
|
||||||
|
{
|
||||||
|
char data[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||||
|
|
||||||
|
buffer b;
|
||||||
|
|
||||||
|
TEST_CHECK(b.size() == 0);
|
||||||
|
TEST_CHECK(b.capacity() == 0);
|
||||||
|
TEST_CHECK(b.empty());
|
||||||
|
|
||||||
|
buffer::interval i = b.allocate(1);
|
||||||
|
memcpy(i.begin, data, 1);
|
||||||
|
|
||||||
|
TEST_CHECK(b.size() == 1);
|
||||||
|
TEST_CHECK(b.capacity() >= 1);
|
||||||
|
|
||||||
|
i = b.allocate(4);
|
||||||
|
memcpy(i.begin, data + 1, 4);
|
||||||
|
TEST_CHECK(b.size() == 5);
|
||||||
|
TEST_CHECK(b.capacity() >= 5);
|
||||||
|
|
||||||
|
i = b.allocate(4);
|
||||||
|
memcpy(i.begin, data + 5, 4);
|
||||||
|
TEST_CHECK(b.size() == 9);
|
||||||
|
TEST_CHECK(b.capacity() >= 9);
|
||||||
|
|
||||||
|
TEST_CHECK(!b.empty());
|
||||||
|
|
||||||
|
buffer::interval_type read_data = b.data();
|
||||||
|
TEST_CHECK(std::equal(read_data.first.begin, read_data.first.end, data));
|
||||||
|
|
||||||
|
b.erase(5);
|
||||||
|
|
||||||
|
TEST_CHECK(b.space_left() == 5);
|
||||||
|
|
||||||
|
i = b.allocate(3);
|
||||||
|
memcpy(i.begin, data, 3);
|
||||||
|
TEST_CHECK(b.space_left() == 2);
|
||||||
|
TEST_CHECK(b.size() == 7);
|
||||||
|
|
||||||
|
read_data = b.data();
|
||||||
|
TEST_CHECK(std::equal(read_data.first.begin, read_data.first.end, data + 5));
|
||||||
|
TEST_CHECK(std::equal(read_data.second.begin, read_data.second.end, data));
|
||||||
|
|
||||||
|
b.erase(7);
|
||||||
|
|
||||||
|
TEST_CHECK(b.empty());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
@ -9,15 +9,6 @@
|
||||||
|
|
||||||
#include "test.hpp"
|
#include "test.hpp"
|
||||||
|
|
||||||
#define _FILE_OFFSET_BITS 64
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/stat.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
using namespace libtorrent;
|
using namespace libtorrent;
|
||||||
using namespace boost::filesystem;
|
using namespace boost::filesystem;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue