merge RC_1_1 into master

This commit is contained in:
arvidn 2016-03-08 01:10:48 -05:00
commit 6d85c7c5f0
52 changed files with 1448 additions and 464 deletions

View File

@ -7,6 +7,7 @@
1.1.0 release
* support filtering which parts of session state are loaded by load_state()
* deprecate support for adding torrents by HTTP URL
* allow specifying which tracker to scrape in scrape_tracker
* tracker response alerts from user initiated announces/scrapes are now
@ -91,6 +92,8 @@
* almost completely changed the storage interface (for custom storage)
* added support for hashing pieces in multiple threads
* fix division by zero in super-seeding logic
1.0.9 release
* fix issue in checking outgoing interfaces (when that option is enabled)

View File

@ -510,18 +510,18 @@ namespace
}
#endif
void load_state(lt::session& ses, entry const& st)
{
allow_threading_guard guard;
void load_state(lt::session& ses, entry const& st, boost::uint32_t flags)
{
allow_threading_guard guard;
std::vector<char> buf;
bencode(std::back_inserter(buf), st);
bdecode_node e;
error_code ec;
bdecode(&buf[0], &buf[0] + buf.size(), e, ec);
TORRENT_ASSERT(!ec);
ses.load_state(e);
}
std::vector<char> buf;
bencode(std::back_inserter(buf), st);
bdecode_node e;
error_code ec;
bdecode(&buf[0], &buf[0] + buf.size(), e, ec);
TORRENT_ASSERT(!ec);
ses.load_state(e, flags);
}
#ifndef TORRENT_DISABLE_DHT
void dht_get_mutable_item(lt::session& ses, std::string key, std::string salt)
@ -796,7 +796,7 @@ void bind_session()
.def("get_pe_settings", allow_threads(&lt::session::get_pe_settings))
#endif
#endif
.def("load_state", &load_state)
.def("load_state", &load_state, (arg("entry"), arg("flags") = 0xffffffff))
.def("save_state", &save_state, (arg("entry"), arg("flags") = 0xffffffff))
.def("pop_alerts", &pop_alerts)
.def("wait_for_alert", &wait_for_alert
@ -885,8 +885,8 @@ void bind_session()
.value("save_dht_settings", lt::session::save_dht_settings)
.value("save_dht_state", lt::session::save_dht_state)
.value("save_encryption_settings", lt::session:: save_encryption_settings)
.value("save_as_map", lt::session::save_as_map)
#ifndef TORRENT_NO_DEPRECATE
.value("save_as_map", lt::session::save_as_map)
.value("save_i2p_proxy", lt::session::save_i2p_proxy)
.value("save_proxy", lt::session::save_proxy)
.value("save_dht_proxy", lt::session::save_dht_proxy)

View File

@ -31,7 +31,8 @@ class test_alerts(unittest.TestCase):
ses = lt.session({'alert_mask': lt.alert.category_t.all_categories})
shutil.copy(os.path.join('..', '..', 'test', 'test_torrents', 'base.torrent'), '.')
ti = lt.torrent_info('base.torrent');
h = ses.add_torrent({'ti': ti, 'save_path': '.'})
h = ses.add_torrent({'ti': ti, 'save_path': os.getcwd()})
st = h.status()
time.sleep(1)
ses.remove_torrent(h)
ses.wait_for_alert(1000) # milliseconds
@ -39,9 +40,8 @@ class test_alerts(unittest.TestCase):
for a in alerts:
print(a.message())
st = h.status()
print(st.next_announce)
print(st.name)
self.assertEqual(st.name, 'temp')
print(st.errc.message())
print(st.pieces)
print(st.last_seen_complete)
@ -51,6 +51,7 @@ class test_alerts(unittest.TestCase):
print(st.distributed_copies)
print(st.paused)
print(st.info_hash)
self.assertEqual(st.save_path, os.getcwd())
class test_bencoder(unittest.TestCase):

View File

@ -10,7 +10,7 @@
* tutorial_
* examples_
* overview_
* `reference documentation`_
* documentation_
* contributing_
* building_
* troubleshooting_
@ -41,8 +41,10 @@ Extensions
Bindings
* `ruby bindings`_
* `python bindings`_
* python_
* java_
* go_
* node_
--------
@ -64,7 +66,7 @@ libtorrent
.. _building: building.html
.. _examples: examples.html
.. _overview: manual-ref.html
.. _`reference documentation`: reference.html
.. _documentation: reference.html
.. _troubleshooting: troubleshooting.html
.. _`tuning`: tuning.html
.. _screenshot: client_test.png
@ -85,8 +87,10 @@ libtorrent
.. _`github page`: https://github.com/arvidn/libtorrent
.. _blog: http://blog.libtorrent.org
.. _`ruby bindings`: http://libtorrent-ruby.rubyforge.org/
.. _`python bindings`: python_binding.html
.. _java: https://github.com/frostwire/frostwire-jlibtorrent/
.. _python: python_binding.html
.. _go: https://github.com/steeve/libtorrent-go
.. _node: https://github.com/fanatid/node-libtorrent
.. _`Introduction, slides`: bittorrent.pdf
@ -104,22 +108,46 @@ The main goals of libtorrent are:
* to be memory efficient
* to be very easy to use
Donate
======
Getting started
===============
Support the development of libtorrent
The tutorial_ is an introduction to using libtorrent (C++). Also see the
`reference documentation`_.
.. _`reference documentation`: reference.html
Contribute
==========
If your organization use libtorrent, please consider supporting its development.
See the contribute_ page for other ways to help out.
.. raw:: html
<span style="display:inline-block">
<a class="FlattrButton" style="display:none;" href="http://libtorrent.org"></a>
<noscript><a href="https://flattr.com/thing/95662/libtorrent" target="_blank">
<img src="http://api.flattr.com/button/flattr-badge-large.png" alt="Flattr this" title="Flattr this" border="0" /></a></noscript>
</span>
<span style="display:inline-block">
<form action="https://www.paypal.com/cgi-bin/webscr" method="post" target="_top">
<input type="hidden" name="cmd" value="_donations">
<input type="hidden" name="business" value="ZNR45WU2PP5W2">
<input type="hidden" name="lc" value="US">
<input type="hidden" name="item_name" value="libtorrent">
<input type="hidden" name="currency_code" value="USD">
<input type="hidden" name="bn" value="PP-DonationsBF:btn_donate_LG.gif:NonHosted">
<input type="image" src="https://www.paypalobjects.com/webstatic/en_US/i/buttons/pp-acceptance-medium.png" border="0" name="submit" alt="PayPal - The safer, easier way to pay online!">
<img alt="" border="0" src="https://www.paypalobjects.com/en_US/i/scr/pixel.gif" width="1" height="1">
</form>
</span>
Feedback
========
Support
=======
There's a `mailing list`__, general libtorrent discussion.
Please direct questions to the `mailing list`__, general libtorrent discussion.
__ http://lists.sourceforge.net/lists/listinfo/libtorrent-discuss

View File

@ -223,13 +223,13 @@ div.contents {
#librarySidebar {
float: left;
width: 150px;
width: 170px;
}
#libraryBody {
border-left: solid 1px #eee;
padding-left: 10px;
margin-left: 158px;
margin-left: 178px;
margin-right: 10px;
}

View File

@ -52,10 +52,10 @@ First, let's extend the example to print out messages from the bittorrent engine
about progress and events happening under the hood. libtorrent has a mechanism
referred to as *alerts* to communicate back information to the client application.
Clients can poll libtorrents for new alerts via the `pop_alerts()`_ call on the
session object. This call fills in a vector of alert pointers with all new
alerts since the last call to this function. The pointers are owned by the
session object at will become invalidated by the next call to `pop_alerts()`_.
Clients can poll a session for new alerts via the `pop_alerts()`_ call. This
function fills in a vector of alert pointers with all new alerts since the last
call to this function. The pointers are owned by the session object at will
become invalidated by the next call to `pop_alerts()`_.
The alerts form a class hierarchy with alert_ as the root class. Each specific
kind of alert may include additional state, specific to the kind of message. All
@ -183,10 +183,10 @@ resuming torrents
Since bittorrent downloads pieces of files in random order, it's not trivial to
resume a partial download. When resuming a download, the bittorrent engine must
restore the state of the downloading torrent, specifically, which parts of the
restore the state of the downloading torrent, specifically which parts of the
file(s) are downloaded. There are two approaches to doing this:
1. read every piece of the downloaded files from disk and compare it against the
1. read every piece of the downloaded files from disk and compare it against its
expected hash.
2. save to disk the state of which pieces (and partial pieces) are downloaded,
and load it back in again when resuming.
@ -197,8 +197,14 @@ employ (1) by default.
To save resume data, call `save_resume_data()`_ on the torrent_handle_ object.
This will ask libtorrent to generate the resume data and post it back in
a save_resume_data_alert_. If generating the resume data fails for any reason,
a save_resume_data_failed_alert_ is posted instead. Exactly one of those alerts
will be posted for every call to `save_resume_data()`_.
a save_resume_data_failed_alert_ is posted instead.
Exactly one of those alerts will be posted for every call to
`save_resume_data()`_. This is an important property when shutting down a
session with multiple torrents, every resume alert must be handled before
resuming with shut down. Any torrent may fail to save resume data, so the client
would need to keep a count of the outstanding resume files, decremented on
either save_resume_data_alert_ or save_resume_data_failed_alert_.
The save_resume_data_alert_ looks something like this:
@ -212,10 +218,13 @@ The save_resume_data_alert_ looks something like this:
boost::shared_ptr<entry> resume_data;
};
``resume_data`` points to an entry_ object. This represents a node or a tree
of nodes in a bencoded_ structure, which is the native encoding scheme in
``resume_data`` points to an entry_ object. This represents a node or a tree of
nodes in a bencoded_ structure, which is the native encoding scheme in
bittorrent. It can be encoded into a byte buffer or file using `bencode()`_.
When adding a torrent with resume data, set the `add_torrent_params::resume_data`_
to contain the bencoded buffer of the resume data.
example
-------
@ -230,6 +239,41 @@ Here's an updated version of the above example with the following updates:
:tab-width: 2
:start-after: */
torrent files
-------------
To add torrent files to a session (as opposed to a magnet link), it must first
be loaded into a torrent_info_ object.
The torrent_info_ object can be created either by filename a buffer or a
bencoded structure. When adding by filename, there's a sanity check limit on the
size of the file, for adding arbitrarily large torrents, load the file outside
of the constructor.
The torrent_info_ object provides an opportunity to query information about the
.torrent file as well as mutating it before adding it to the session.
bencoding
---------
bencoded_ structures is the default data storage format used by bittorrent, such
as .torrent files, tracker announce and scrape responses and some wire protocol
extensions. libtorrent provides an efficient framework for decoding bencoded
data through `bdecode()`_ function.
There are two separate mechanisms for *encoding* and *decoding*. When decoding,
use the `bdecode()`_ function that returns a bdecode_node_. When encoding, use
`bencode()`_ taking an entry_ object.
The key property of `bdecode()`_ is that it does not copy any data out of the
buffer that was parsed. It builds the tree structures of references pointing
into the buffer. The buffer must stay alive and valid for as long as the
bdecode_node_ is in use.
For performance details on `bdecode()`_, see the `blog post about it`__.
__ http://blog.libtorrent.org/2015/03/bdecode-parsers/
.. _session: reference-Core.html#session
.. _session_handle: reference-Core.html#session_handle
.. _add_torrent_params: reference-Core.html#add_torrent_params
@ -258,4 +302,9 @@ Here's an updated version of the above example with the following updates:
.. _bencoded: https://en.wikipedia.org/wiki/Bencode
.. _entry: reference-Bencoding.html#entry
.. _`bencode()`: reference-Bencoding.html#bencode()
.. _torrent_info: reference-Core.html#torrent_info
.. _`add_torrent_params::resume_data`: reference-Core.html#resume_data
.. _`bdecode()`: reference-Bdecoding.html#bdecode()
.. _bdecode_node: reference-Bdecoding.html#bdecode-node

View File

@ -43,12 +43,12 @@ POSSIBILITY OF SUCH DAMAGE.
#include <libtorrent/torrent_status.hpp>
namespace lt = libtorrent;
using clock_t = std::chrono::monotonic_clock;
// return the name of a torrent status enum
char const* state(lt::torrent_status::state_t s)
{
switch(s)
{
switch(s) {
case lt::torrent_status::checking_files: return "checking";
case lt::torrent_status::downloading_metadata: return "dl metadata";
case lt::torrent_status::downloading: return "downloading";
@ -74,8 +74,8 @@ int main(int argc, char const* argv[])
| lt::alert::status_notification);
lt::session ses(pack);
lt::add_torrent_params atp;
std::chrono::time_point last_save_resume = clock_t::now();
// load resume data from disk and pass it in as we add the magnet link
std::ifstream ifs(".resume_file", std::ios_base::binary);
@ -134,9 +134,15 @@ int main(int argc, char const* argv[])
// state output for the torrent
ses.post_torrent_updates();
// TODO: 3 call save_resume_data() once every 30 seconds or so
// save resume data once every 30 seconds
if (clock_t::now() - last_save_resume > seconds(30)) {
h.save_resume_data();
}
}
done:
// TODO: ideally we should save resume data here
done:
std::cout << "\ndone, shutting down" << std::endl;
}

View File

@ -377,9 +377,13 @@ FILE* g_log_file = 0;
std::string const& piece_bar(libtorrent::bitfield const& p, int width)
{
const int table_size = 18;
#ifdef _WIN32
int const table_size = 2;
#else
int const table_size = 18;
#endif
double piece_per_char = p.size() / double(width);
double const piece_per_char = p.size() / double(width);
static std::string bar;
bar.clear();
bar.reserve(width * 6);
@ -401,9 +405,13 @@ std::string const& piece_bar(libtorrent::bitfield const& p, int width)
for (int k = int(piece); k < end; ++k, ++num_pieces)
if (p[k]) ++num_have;
int color = int(std::ceil(num_have / float((std::max)(num_pieces, 1)) * (table_size - 1)));
char buf[10];
snprintf(buf, 10, "48;5;%d", 232 + color);
bar += esc(buf);
char buf[40];
#ifdef _WIN32
snprintf(buf, sizeof(buf), "\x1b[4%dm", color ? 7 : 0);
#else
snprintf(buf, sizeof(buf), "\x1b[48;5;%dm", 232 + color);
#endif
bar += buf;
bar += " ";
}
bar += esc("0");
@ -597,6 +605,7 @@ std::string monitor_dir;
int poll_interval = 5;
int max_connections_per_torrent = 50;
bool seed_mode = false;
int cache_size = 1024;
bool share_mode = false;
bool disable_storage = false;
@ -1295,6 +1304,7 @@ int main(int argc, char* argv[])
namespace lt = libtorrent;
settings_pack settings;
settings.set_int(settings_pack::cache_size, cache_size);
settings.set_int(settings_pack::active_loaded_limit, 20);
settings.set_int(settings_pack::choking_algorithm, settings_pack::rate_based_choker);
@ -1446,9 +1456,9 @@ int main(int argc, char* argv[])
}
#endif // TORRENT_USE_I2P
case 'C':
settings.set_int(settings_pack::cache_size, atoi(arg));
settings.set_bool(settings_pack::use_read_cache, atoi(arg) > 0);
settings.set_int(settings_pack::cache_buffer_chunk_size, atoi(arg) / 100);
cache_size = atoi(arg);
settings.set_int(settings_pack::cache_size, cache_size);
settings.set_int(settings_pack::cache_buffer_chunk_size, 0);
break;
case 'A': settings.set_int(settings_pack::allowed_fast_set_size, atoi(arg)); break;
case 'R': settings.set_int(settings_pack::read_cache_line_size, atoi(arg)); break;
@ -1564,6 +1574,9 @@ int main(int argc, char* argv[])
}
ses.set_ip_filter(loaded_ip_filter);
ses.set_load_function(&load_torrent);
error_code ec;
#ifndef TORRENT_DISABLE_DHT
dht_settings dht;
@ -1581,18 +1594,15 @@ int main(int argc, char* argv[])
ses.add_dht_router(std::make_pair(
std::string("router.bitcomet.com"), 6881));
}
#endif
ses.set_load_function(&load_torrent);
std::vector<char> in;
error_code ec;
if (load_file(".ses_state", in, ec) == 0)
{
bdecode_node e;
if (bdecode(&in[0], &in[0] + in.size(), e, ec) == 0)
ses.load_state(e);
ses.load_state(e, session::save_dht_state);
}
#endif
for (std::vector<add_torrent_params>::iterator i = magnet_links.begin()
, end(magnet_links.end()); i != end; ++i)
@ -1926,6 +1936,13 @@ int main(int argc, char* argv[])
if (c == '5') print_peer_rate = !print_peer_rate;
if (c == '6') print_fails = !print_fails;
if (c == '7') print_send_bufs = !print_send_bufs;
if (c == 'C')
{
cache_size = (cache_size == 0) ? -1 : 0;
settings_pack p;
p.set_int(settings_pack::cache_size, cache_size);
ses.apply_settings(p);
}
if (c == 'h')
{
clear_screen();
@ -1936,7 +1953,7 @@ int main(int argc, char* argv[])
"[q] quit client [m] add magnet link\n"
"\n"
"TORRENT ACTIONS\n"
"[p] pause/unpause selected torrent\n"
"[p] pause/unpause selected torrent [C] toggle disk cache\n"
"[s] toggle sequential download [j] force recheck\n"
"[space] toggle session pause [c] clear error\n"
"[v] scrape [D] delete torrent and data\n"
@ -2290,11 +2307,6 @@ int main(int argc, char* argv[])
}
}
// keep track of the number of resume data
// alerts to wait for
int num_paused = 0;
int num_failed = 0;
ses.pause();
printf("saving resume data\n");
std::vector<torrent_status> temp;
@ -2337,51 +2349,29 @@ int main(int argc, char* argv[])
for (std::vector<alert*>::iterator i = alerts.begin()
, end(alerts.end()); i != end; ++i)
{
torrent_paused_alert* tp = alert_cast<torrent_paused_alert>(*i);
if (tp)
if (!::handle_alert(ses, *i, files, non_files))
{
++num_paused;
printf("\rleft: %d failed: %d pause: %d "
, num_outstanding_resume_data, num_failed, num_paused);
continue;
// if we didn't handle the alert, print it to the log
std::string event_string;
print_alert(*i, event_string);
}
if (alert_cast<save_resume_data_failed_alert>(*i))
{
++num_failed;
--num_outstanding_resume_data;
printf("\rleft: %d failed: %d pause: %d "
, num_outstanding_resume_data, num_failed, num_paused);
continue;
}
save_resume_data_alert* rd = alert_cast<save_resume_data_alert>(*i);
if (!rd) continue;
--num_outstanding_resume_data;
printf("\rleft: %d failed: %d pause: %d "
, num_outstanding_resume_data, num_failed, num_paused);
if (!rd->resume_data) continue;
torrent_handle h = rd->handle;
torrent_status st = h.status(torrent_handle::query_save_path);
std::vector<char> out;
bencode(std::back_inserter(out), *rd->resume_data);
save_file(path_append(st.save_path, path_append(".resume"
, leaf_path(hash_to_filename[st.info_hash]) + ".resume")), out);
}
}
if (g_log_file) fclose(g_log_file);
// we're just saving the DHT state
#ifndef TORRENT_DISABLE_DHT
printf("\nsaving session state\n");
{
entry session_state;
ses.save_state(session_state);
ses.save_state(session_state, session::save_dht_state);
std::vector<char> out;
bencode(std::back_inserter(out), session_state);
save_file(".ses_state", out);
}
#endif
printf("closing session");

View File

@ -88,7 +88,7 @@ std::string const& progress_bar(int progress, int width, color_code c
bar.clear();
bar.reserve(size_t(width + 10));
int progress_chars = (progress * width + 500) / 1000;
int const progress_chars = (progress * width + 500) / 1000;
if (caption.empty())
{
@ -108,14 +108,21 @@ std::string const& progress_bar(int progress, int width, color_code c
caption.resize(size_t(width), ' ');
#ifdef _WIN32
char const* background = "40";
#else
char const* background = "48;5;238";
#endif
char str[256];
if (flags & progress_invert)
snprintf(str, sizeof(str), "\x1b[48;5;238m\x1b[37m%s\x1b[4%d;3%dm%s\x1b[49;39m"
, caption.substr(0, progress_chars).c_str(), c, tc
snprintf(str, sizeof(str), "\x1b[%sm\x1b[37m%s\x1b[4%d;3%dm%s\x1b[49;39m"
, background, caption.substr(0, progress_chars).c_str(), c, tc
, caption.substr(progress_chars).c_str());
else
snprintf(str, sizeof(str), "\x1b[4%d;3%dm%s\x1b[48;5;238m\x1b[37m%s\x1b[49;39m"
, c, tc, caption.substr(0, progress_chars).c_str(), caption.substr(progress_chars).c_str());
snprintf(str, sizeof(str), "\x1b[4%d;3%dm%s\x1b[%sm\x1b[37m%s\x1b[49;39m"
, c, tc, caption.substr(0, progress_chars).c_str(), background
, caption.substr(progress_chars).c_str());
bar = str;
}
return bar;
@ -208,7 +215,7 @@ void terminal_size(int* terminal_width, int* terminal_height)
}
#ifdef _WIN32
void apply_ansi_code(int* attributes, bool* reverse, int code)
void apply_ansi_code(int* attributes, bool* reverse, bool* support_chaining, int code)
{
static const int color_table[8] =
{
@ -224,8 +231,8 @@ void apply_ansi_code(int* attributes, bool* reverse, int code)
enum
{
foreground_mask = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
background_mask = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE
foreground_mask = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY,
background_mask = BACKGROUND_RED | BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY
};
static const int fg_mask[2] = {foreground_mask, background_mask};
@ -233,14 +240,29 @@ void apply_ansi_code(int* attributes, bool* reverse, int code)
static const int fg_shift[2] = { 0, 4};
static const int bg_shift[2] = { 4, 0};
// default foreground
if (code == 39) code = 37;
// default background
if (code == 49) code = 40;
if (code == 0)
{
// reset
*attributes = color_table[7];
*reverse = false;
*support_chaining = true;
}
else if (code == 1)
{
// intensity
*attributes |= *reverse ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
*support_chaining = true;
}
else if (code == 7)
{
// reverse video
*support_chaining = true;
if (*reverse) return;
*reverse = true;
int fg_col = *attributes & foreground_mask;
@ -254,12 +276,14 @@ void apply_ansi_code(int* attributes, bool* reverse, int code)
// foreground color
*attributes &= ~fg_mask[*reverse];
*attributes |= color_table[code - 30] << fg_shift[*reverse];
*support_chaining = true;
}
else if (code >= 40 && code <= 47)
{
// foreground color
// background color
*attributes &= ~bg_mask[*reverse];
*attributes |= color_table[code - 40] << bg_shift[*reverse];
*support_chaining = true;
}
}
#endif
@ -288,14 +312,15 @@ void print(char const* buf)
CONSOLE_SCREEN_BUFFER_INFO sbi;
if (GetConsoleScreenBufferInfo(out, &sbi))
{
COORD pos = sbi.dwCursorPosition;
int width = sbi.dwSize.X;
int run = width - pos.X;
COORD const pos = sbi.dwCursorPosition;
int const width = sbi.dwSize.X;
int const run = width - pos.X;
DWORD n;
FillConsoleOutputAttribute(out, 0x7, run, pos, &n);
FillConsoleOutputCharacter(out, ' ', run, pos, &n);
}
++buf;
start = buf;
continue;
}
else if (*start == 'J')
@ -312,18 +337,30 @@ void print(char const* buf)
FillConsoleOutputCharacter(out, ' ', run, pos, &n);
}
++buf;
start = buf;
continue;
}
one_more:
one_more:
while (*buf != 'm' && *buf != ';' && *buf != 0) ++buf;
// this is where we handle reset, color and reverse codes
if (*buf == 0) break;
int code = atoi(start);
apply_ansi_code(&current_attributes, &reverse, code);
if (*buf == ';')
bool support_chaining = false;
apply_ansi_code(&current_attributes, &reverse, &support_chaining, code);
if (support_chaining)
{
++buf;
start = buf;
goto one_more;
if (*buf == ';')
{
++buf;
start = buf;
goto one_more;
}
}
else
{
// ignore codes with multiple fields for now
while (*buf != 'm' && *buf != 0) ++buf;
}
SetConsoleTextAttribute(out, current_attributes);
++buf; // skip 'm'

View File

@ -96,7 +96,11 @@ void session_view::render()
snprintf(str, sizeof(str), "%s%swaste: %s up: %s (%s) "
"disk queue: %s | %s cache w: %3d%% r: %3d%% "
"size: w: %s r: %s total: %s %s\x1b[K"
#ifdef _WIN32
, esc("40")
#else
, esc("48;5;238")
#endif
, esc("1")
, add_suffix(m_cnt[0][m_wasted_bytes_idx]).c_str()
, color(add_suffix(upload_rate, "/s"), col_red).c_str()

View File

@ -77,25 +77,12 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/time.hpp"
#include "libtorrent/config.hpp"
#ifndef TORRENT_NO_DEPRECATE
#ifndef BOOST_NO_TYPEID
#include <typeinfo>
#endif
#endif // TORRENT_NO_DEPRECATE
#ifndef TORRENT_MAX_ALERT_TYPES
#define TORRENT_MAX_ALERT_TYPES 15
#endif
#ifndef TORRENT_NO_DEPRECATE
#ifndef BOOST_NO_TYPEID
#include <typeinfo>
#endif
#endif
namespace libtorrent {
// The ``alert`` class is the base class that specific messages are derived from.
// alert types are not copyable, and cannot be constructed by the client. The
// pointers returned by libtorrent are short lived (the details are described
// under session_handle::pop_alerts())
class TORRENT_EXPORT alert
{
public:
@ -216,9 +203,6 @@ namespace libtorrent {
alert();
// hidden
virtual ~alert();
#if __cplusplus >= 201103L
alert(alert const&) = default;
#endif
// a timestamp is automatically created in the constructor
time_point timestamp() const;
@ -301,8 +285,15 @@ namespace libtorrent {
#endif // TORRENT_NO_DEPRECATE
protected:
// the alert is not copyable (but for backwards compatibility reasons it
// retains the ability to clone itself, for now).
#if __cplusplus >= 201103L
alert(alert const& rhs) = default;
#endif
private:
// explicitly disallow assignment, to silence msvc warning
// explicitly disallow assignment and copyconstruction
alert& operator=(alert const&);
time_point m_timestamp;

View File

@ -163,7 +163,25 @@ namespace libtorrent
#define TORRENT_CLONE(name)
#endif
// we can only use = default in C++11
// the purpose of this is just to make all alert types non-copyable from user
// code. The heterogeneous queue does not yet have an emplace_back(), so it
// still needs to copy alerts, but the important part is that it's not
// copyable for clients.
// TODO: Once the backwards compatibility of clone() is removed, and once
// C++11 is required, this can be simplified to just say = delete
#if __cplusplus >= 201103L
#define TORRENT_PROTECTED_CCTOR(name) \
protected: \
template <class T> friend struct heterogeneous_queue; \
name(name const&) = default; \
public:
#else
#define TORRENT_PROTECTED_CCTOR(name)
#endif
#define TORRENT_DEFINE_ALERT_IMPL(name, seq, prio) \
TORRENT_PROTECTED_CCTOR(name) \
static const int priority = prio; \
static const int alert_type = seq; \
virtual int type() const TORRENT_OVERRIDE { return alert_type; } \

View File

@ -345,6 +345,7 @@ namespace libtorrent
#ifndef TORRENT_NO_DEPRECATE
entry dht_state() const;
void start_dht_deprecated(entry const& startup_state);
#endif
void on_dht_announce(error_code const& e);
void on_dht_name_lookup(error_code const& e
@ -512,7 +513,7 @@ namespace libtorrent
void announce_lsd(sha1_hash const& ih, int port, bool broadcast = false) TORRENT_OVERRIDE;
void save_state(entry* e, boost::uint32_t flags) const;
void load_state(bdecode_node const* e);
void load_state(bdecode_node const* e, boost::uint32_t flags);
bool has_connection(peer_connection* p) const TORRENT_OVERRIDE;
void insert_peer(boost::shared_ptr<peer_connection> const& c) TORRENT_OVERRIDE;

View File

@ -136,7 +136,11 @@ namespace libtorrent
in_progress = 0x20,
// turns into file::coalesce_buffers in the file operation
coalesce_buffers = 0x40
coalesce_buffers = 0x40,
// the disk cache was enabled when this job was issued, it should use
// the disk cache once it's handled by a disk thread
use_disk_cache = 0x80
};
// for write jobs, returns true if its block

View File

@ -229,7 +229,7 @@ namespace libtorrent
// The const version of ``operator[]`` will only return a reference to an
// existing element at the given key. If the key is not found, it will
// throw ``libtorrent::type_error``.
entry& operator[](char const* key);
entry& operator[](char const* key);
entry& operator[](std::string const& key);
#ifndef BOOST_NO_EXCEPTIONS
const entry& operator[](char const* key) const;
@ -290,7 +290,7 @@ namespace libtorrent
public:
// in debug mode this is set to false by bdecode to indicate that the
// program has not yet queried the type of this entry, and sould not
// program has not yet queried the type of this entry, and should not
// assume that it has a certain type. This is asserted in the accessor
// functions. This does not apply if exceptions are used.
mutable boost::uint8_t m_type_queried:1;

View File

@ -90,7 +90,7 @@ struct key_desc_t
// generate an error response message
void TORRENT_EXPORT incoming_error(entry& e, char const* msg, int error_code = 203);
// given a redundent name to avoid clashing with libtorrent::detail
// given a redundant name to avoid clashing with libtorrent::detail
namespace dht_detail {
bool TORRENT_EXPORT verify_message(bdecode_node const& msg, key_desc_t const desc[]

View File

@ -89,7 +89,7 @@ namespace libtorrent
// a call related to bittorrent protocol encryption failed
op_encryption,
// an attempt to connect a socket failed
// an attempt to connect a socket failed
op_connect,
// establishing an SSL connection failed

View File

@ -589,7 +589,7 @@ namespace libtorrent
bool can_disconnect(error_code const& ec) const;
void incoming_dht_port(int listen_port);
void incoming_reject_request(peer_request const& r);
void incoming_have_all();
void incoming_have_none();

View File

@ -40,7 +40,7 @@ POSSIBILITY OF SUCH DAMAGE.
namespace libtorrent {
struct receive_buffer
struct TORRENT_EXTRA_EXPORT receive_buffer
{
friend struct crypto_receive_buffer;
@ -58,6 +58,7 @@ struct receive_buffer
int packet_bytes_remaining() const
{
TORRENT_ASSERT(m_recv_start == 0);
TORRENT_ASSERT(m_packet_size > 0);
return m_packet_size - m_recv_pos;
}
@ -67,13 +68,19 @@ struct receive_buffer
int pos() const { return m_recv_pos; }
int capacity() const { return m_recv_buffer.capacity() + m_disk_recv_buffer_size; }
int regular_buffer_size() const { return m_packet_size - m_disk_recv_buffer_size; }
int regular_buffer_size() const
{
TORRENT_ASSERT(m_packet_size > 0);
return m_packet_size - m_disk_recv_buffer_size;
}
// regular buffer only
boost::asio::mutable_buffer reserve(int size);
// with possible disk buffer usage
int reserve(boost::array<boost::asio::mutable_buffer, 2>& vec, int size);
// tell the buffer we just receved more bytes at the end of it. This will
// advance the end cursor
void received(int bytes_transferred)
{
TORRENT_ASSERT(m_packet_size > 0);
@ -82,9 +89,14 @@ struct receive_buffer
+ m_disk_recv_buffer_size));
}
// tell the buffer we consumed some bytes of it. This will advance the read
// cursor
int advance_pos(int bytes);
// has the read cursor reached the end cursor?
bool pos_at_end() { return m_recv_pos == m_recv_end; }
// make the buffer size dividible by 8 bytes (RC4 block size)
void clamp_size();
void set_soft_packet_size(int size) { m_soft_packet_size = size; }
@ -94,6 +106,8 @@ struct receive_buffer
// offset = the offset into the receive buffer where to remove `size` bytes
void cut(int size, int packet_size, int offset = 0);
// return the interval between the start of the buffer to the read cursor.
// This is the "current" packet.
buffer::const_interval get() const;
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)

View File

@ -92,13 +92,11 @@ namespace libtorrent
save_dht_state = 0x004,
// save pe_settings
save_encryption_settings = 0x020,
// internal
save_as_map = 0x040
save_encryption_settings = 0x020
#ifndef TORRENT_NO_DEPRECATE
,
save_as_map = 0x040,
// saves RSS feeds
save_feeds = 0x080,
save_proxy = 0x008,
@ -118,11 +116,11 @@ namespace libtorrent
// ``load_state`` expects a bdecode_node which can be built from a bencoded
// buffer with bdecode().
//
// The ``flags`` arguments passed in to ``save_state`` can be used to
// filter which parts of the session state to save. By default, all state
// is saved (except for the individual torrents). see save_state_flags_t
// The ``flags`` argument is used to filter which parts of the session
// state to save or load. By default, all state is saved/restored (except
// for the individual torrents). see save_state_flags_t
void save_state(entry& e, boost::uint32_t flags = 0xffffffff) const;
void load_state(bdecode_node const& e);
void load_state(bdecode_node const& e, boost::uint32_t flags = 0xffffffff);
// .. note::
// these calls are potentially expensive and won't scale well with
@ -547,12 +545,14 @@ namespace libtorrent
// deprecated in 0.15
// use load_state and save_state instead
TORRENT_DEPRECATED
void load_state(entry const& ses_state);
void load_state(entry const& ses_state
, boost::uint32_t flags = 0xffffffff);
TORRENT_DEPRECATED
entry state() const;
// deprecated in 1.1
TORRENT_DEPRECATED
void load_state(lazy_entry const& ses_state);
void load_state(lazy_entry const& ses_state
, boost::uint32_t flags = 0xffffffff);
#endif // TORRENT_NO_DEPRECATE
// Sets a filter that will be used to reject and accept incoming as well

View File

@ -453,7 +453,13 @@ namespace libtorrent
void flush_cache();
void pause(bool graceful = false);
void resume();
void set_allow_peers(bool b, bool graceful_pause = false);
enum pause_flags_t
{
flag_graceful_pause = 1,
flag_clear_disk_cache = 2
};
void set_allow_peers(bool b, int flags = flag_clear_disk_cache);
void set_announce_to_dht(bool b) { m_announce_to_dht = b; }
void set_announce_to_trackers(bool b) { m_announce_to_trackers = b; }
void set_announce_to_lsd(bool b) { m_announce_to_lsd = b; }
@ -462,7 +468,7 @@ namespace libtorrent
int started() const { return m_started; }
void step_session_time(int seconds);
void do_pause();
void do_pause(bool clear_disk_cache = true);
void do_resume();
int finished_time() const;

View File

@ -98,6 +98,7 @@ namespace libtorrent
// int: port-mapping index
// address: external address as queried from router
// int: external port
// int: protocol (UDP, TCP)
// std::string: error message
// an empty string as error means success
typedef boost::function<void(int, address, int, int, error_code const&)> portmap_callback_t;

View File

@ -15,6 +15,7 @@ project
<source>setup_swarm.cpp
<source>setup_dht.cpp
<source>create_torrent.cpp
<source>utils.cpp
: default-build
<threading>multi
<invariant-checks>full
@ -23,6 +24,7 @@ project
;
alias libtorrent-sims :
[ run test_checking.cpp ]
[ run test_optimistic_unchoke.cpp ]
[ run test_transfer.cpp ]
[ run test_http_connection.cpp ]

View File

@ -0,0 +1,115 @@
/*
Copyright (c) 2016, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "libtorrent/session.hpp"
#include "libtorrent/deadline_timer.hpp"
#include "libtorrent/address.hpp"
#include "libtorrent/torrent_status.hpp"
#include "simulator/simulator.hpp"
#include "test.hpp"
#include "settings.hpp"
#include "create_torrent.hpp"
#include "utils.hpp"
template <typename Setup, typename Test>
void run_test(Setup const& setup, Test const& test)
{
// this is a seeding torrent
lt::add_torrent_params atp = create_torrent(0, true);
sim::default_config network_cfg;
sim::simulation sim{network_cfg};
auto ios = std::unique_ptr<sim::asio::io_service>(new sim::asio::io_service(
sim, lt::address_v4::from_string("50.0.0.1")));
lt::session_proxy zombie;
// setup settings pack to use for the session (customization point)
lt::settings_pack pack = settings();
setup(atp, pack);
auto ses = std::make_shared<lt::session>(pack, *ios);
ses->async_add_torrent(atp);
print_alerts(*ses);
lt::deadline_timer timer(*ios);
timer.expires_from_now(lt::seconds(6));
timer.async_wait([&](lt::error_code const& ec)
{
test(*ses);
// shut down
ses->set_alert_notify([]{});
zombie = ses->abort();
ses.reset();
});
sim.run();
}
TORRENT_TEST(cache_after_checking)
{
run_test(
[](lt::add_torrent_params& atp, lt::settings_pack& p) {
atp.flags |= lt::add_torrent_params::flag_auto_managed;
p.set_int(lt::settings_pack::cache_size, 100);
},
[](lt::session& ses) {
int cache = get_cache_size(ses);
TEST_CHECK(cache > 0);
std::vector<lt::torrent_handle> tor = ses.get_torrents();
TEST_EQUAL(tor.size(), 1);
TEST_EQUAL(tor[0].status().is_seeding, true);
});
}
TORRENT_TEST(checking_no_cache)
{
run_test(
[](lt::add_torrent_params& atp, lt::settings_pack& p) {
atp.flags |= lt::add_torrent_params::flag_auto_managed;
p.set_int(lt::settings_pack::cache_size, 0);
},
[](lt::session& ses) {
int cache = get_cache_size(ses);
TEST_EQUAL(cache, 0);
std::vector<lt::torrent_handle> tor = ses.get_torrents();
TEST_EQUAL(tor.size(), 1);
TEST_EQUAL(tor[0].status().is_seeding, true);
});
}

View File

@ -97,7 +97,7 @@ TORRENT_TEST(session_stats)
// on alert
, [=](lt::alert const* a, lt::session& ses)
{
lt::session_stats_alert const* ss = lt::alert_cast<session_stats_alert>(a);
auto const* ss = lt::alert_cast<session_stats_alert>(a);
if (!ss) return;
// there's one downloading torrent

View File

@ -35,6 +35,7 @@ POSSIBILITY OF SUCH DAMAGE.
#include "create_torrent.hpp"
#include "settings.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/session_stats.hpp"
#include "libtorrent/deadline_timer.hpp"
#include "libtorrent/settings_pack.hpp"
#include "libtorrent/ip_filter.hpp"
@ -44,16 +45,12 @@ POSSIBILITY OF SUCH DAMAGE.
#include "simulator/simulator.hpp"
#include "simulator/socks_server.hpp"
#include "setup_swarm.hpp"
#include "utils.hpp"
using namespace sim;
namespace lt = libtorrent;
enum flags_t
{
ipv6 = 1,
};
template <typename Setup, typename HandleAlerts, typename Test>
void run_test(
Setup const& setup
@ -63,8 +60,6 @@ void run_test(
{
using namespace libtorrent;
lt::time_point start_time = lt::clock_type::now();
const bool use_ipv6 = flags & ipv6;
char const* peer0_ip[2] = { "50.0.0.1", "feed:face:baad:f00d::1" };
@ -112,32 +107,15 @@ void run_test(
setup(*ses[0], *ses[1]);
// only monitor alerts for session 0 (the downloader)
ses[0]->set_alert_notify([&] { ios0.post([&] {
std::vector<lt::alert*> alerts;
ses[0]->pop_alerts(&alerts);
for (lt::alert const* a : alerts)
print_alerts(*ses[0], [=](lt::session& ses, lt::alert const* a) {
if (auto ta = alert_cast<lt::torrent_added_alert>(a))
{
printf("%-3d [0] %s\n", int(lt::duration_cast<lt::seconds>(a->timestamp()
- start_time).count()), a->message().c_str());
if (auto ta = alert_cast<lt::torrent_added_alert>(a))
{
ta->handle.connect_peer(lt::tcp::endpoint(peer1, 6881));
}
// call the user handler
on_alert(*ses[0], a);
ta->handle.connect_peer(lt::tcp::endpoint(peer1, 6881));
}
} ); } );
on_alert(ses, a);
});
ses[1]->set_alert_notify([&] { ios0.post([&] {
std::vector<lt::alert*> alerts;
ses[1]->pop_alerts(&alerts);
for (lt::alert const* a : alerts)
{
printf("%-3d [1] %s\n", int(lt::duration_cast<lt::seconds>(a->timestamp()
- start_time).count()), a->message().c_str());
}
} ); } );
print_alerts(*ses[1]);
// the first peer is a downloader, the second peer is a seed
lt::add_torrent_params params = create_torrent(1);
@ -169,52 +147,6 @@ void run_test(
sim.run();
}
void utp_only(lt::session& ses)
{
using namespace libtorrent;
settings_pack p;
utp_only(p);
ses.apply_settings(p);
}
void enable_enc(lt::session& ses)
{
using namespace libtorrent;
settings_pack p;
enable_enc(p);
ses.apply_settings(p);
}
void filter_ips(lt::session& ses)
{
using namespace libtorrent;
ip_filter filter;
filter.add_rule(asio::ip::address_v4::from_string("50.0.0.1")
, asio::ip::address_v4::from_string("50.0.0.2"), ip_filter::blocked);
ses.set_ip_filter(filter);
}
void set_proxy(lt::session& ses, int proxy_type, int flags = 0, bool proxy_peer_connections = true)
{
// apply the proxy settings to session 0
using namespace libtorrent;
settings_pack p;
p.set_int(settings_pack::proxy_type, proxy_type);
if (proxy_type == settings_pack::socks4)
p.set_int(settings_pack::proxy_port, 4444);
else
p.set_int(settings_pack::proxy_port, 5555);
if (flags & ipv6)
p.set_str(settings_pack::proxy_hostname, "2001::2");
else
p.set_str(settings_pack::proxy_hostname, "50.50.50.50");
p.set_bool(settings_pack::proxy_hostnames, true);
p.set_bool(settings_pack::proxy_peer_connections, proxy_peer_connections);
p.set_bool(settings_pack::proxy_tracker_connections, true);
ses.apply_settings(p);
}
TORRENT_TEST(socks4_tcp)
{
using namespace libtorrent;
@ -391,3 +323,36 @@ TORRENT_TEST(no_proxy_utp_banned)
);
}
TORRENT_TEST(auto_disk_cache_size)
{
using namespace libtorrent;
run_test(
[](lt::session& ses0, lt::session& ses1) { set_cache_size(ses0, -1); },
[](lt::session& ses, lt::alert const* alert) {},
[](std::shared_ptr<lt::session> ses[2]) {
TEST_EQUAL(is_seed(*ses[0]), true);
int const cache_size = get_cache_size(*ses[0]);
printf("cache size: %d\n", cache_size);
// this assumes the test torrent is at least 4 blocks
TEST_CHECK(cache_size > 4);
}
);
}
TORRENT_TEST(disable_disk_cache)
{
using namespace libtorrent;
run_test(
[](lt::session& ses0, lt::session& ses1) { set_cache_size(ses0, 0); },
[](lt::session& ses, lt::alert const* alert) {},
[](std::shared_ptr<lt::session> ses[2]) {
TEST_EQUAL(is_seed(*ses[0]), true);
int const cache_size = get_cache_size(*ses[0]);
printf("cache size: %d\n", cache_size);
TEST_EQUAL(cache_size, 0);
}
);
}

139
simulation/utils.cpp Normal file
View File

@ -0,0 +1,139 @@
/*
Copyright (c) 2016, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "utils.hpp"
#include "test.hpp"
#include "libtorrent/session.hpp"
#include "libtorrent/settings_pack.hpp"
#include "libtorrent/address.hpp"
#include "libtorrent/ip_filter.hpp"
#include "libtorrent/alert_types.hpp"
#include "libtorrent/session_stats.hpp"
#include "libtorrent/alert.hpp"
#include "setup_swarm.hpp"
using namespace libtorrent;
void utp_only(lt::session& ses)
{
settings_pack p;
utp_only(p);
ses.apply_settings(p);
}
void enable_enc(lt::session& ses)
{
settings_pack p;
enable_enc(p);
ses.apply_settings(p);
}
void filter_ips(lt::session& ses)
{
ip_filter filter;
filter.add_rule(address_v4::from_string("50.0.0.1")
, address_v4::from_string("50.0.0.2"), ip_filter::blocked);
ses.set_ip_filter(filter);
}
void set_cache_size(lt::session& ses, int val)
{
settings_pack pack;
pack.set_int(settings_pack::cache_size, val);
ses.apply_settings(pack);
}
int get_cache_size(lt::session& ses)
{
std::vector<stats_metric> stats = session_stats_metrics();
int const read_cache_idx = find_metric_idx("disk.read_cache_blocks");
int const write_cache_idx = find_metric_idx("disk.write_cache_blocks");
TEST_CHECK(read_cache_idx >= 0);
TEST_CHECK(write_cache_idx >= 0);
ses.set_alert_notify([](){});
ses.post_session_stats();
std::vector<alert*> alerts;
ses.pop_alerts(&alerts);
int cache_size = -1;
for (auto const a : alerts)
{
if (auto const* st = alert_cast<session_stats_alert>(a))
{
cache_size = st->values[read_cache_idx];
cache_size += st->values[write_cache_idx];
break;
}
}
return cache_size;
}
void set_proxy(lt::session& ses, int proxy_type, int flags, bool proxy_peer_connections)
{
// apply the proxy settings to session 0
settings_pack p;
p.set_int(settings_pack::proxy_type, proxy_type);
if (proxy_type == settings_pack::socks4)
p.set_int(settings_pack::proxy_port, 4444);
else
p.set_int(settings_pack::proxy_port, 5555);
if (flags & ipv6)
p.set_str(settings_pack::proxy_hostname, "2001::2");
else
p.set_str(settings_pack::proxy_hostname, "50.50.50.50");
p.set_bool(settings_pack::proxy_hostnames, true);
p.set_bool(settings_pack::proxy_peer_connections, proxy_peer_connections);
p.set_bool(settings_pack::proxy_tracker_connections, true);
ses.apply_settings(p);
}
void print_alerts(lt::session& ses
, std::function<void(lt::session&, lt::alert const*)> on_alert)
{
lt::time_point start_time = lt::clock_type::now();
ses.set_alert_notify([&ses,start_time,on_alert] {
ses.get_io_service().post([&ses,start_time,on_alert] {
std::vector<lt::alert*> alerts;
ses.pop_alerts(&alerts);
for (lt::alert const* a : alerts)
{
printf("%-3d [0] %s\n", int(lt::duration_cast<lt::seconds>(a->timestamp()
- start_time).count()), a->message().c_str());
// call the user handler
on_alert(ses, a);
}
} ); } );
}

60
simulation/utils.hpp Normal file
View File

@ -0,0 +1,60 @@
/*
Copyright (c) 2016, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include <functional>
namespace libtorrent
{
class session;
class alert;
}
namespace lt = libtorrent;
void utp_only(lt::session& ses);
void enable_enc(lt::session& ses);
void filter_ips(lt::session& ses);
void set_cache_size(lt::session& ses, int val);
int get_cache_size(lt::session& ses);
enum flags_t
{
ipv6 = 1,
};
void set_proxy(lt::session& ses, int proxy_type, int flags = 0
, bool proxy_peer_connections = true);
void print_alerts(lt::session& ses
, std::function<void(lt::session&, lt::alert const*)> on_alert
= [](lt::session& ses, lt::alert const* a) {});

View File

@ -87,7 +87,11 @@ namespace libtorrent {
char const* torrent_alert::torrent_name() const
{
#ifndef TORRENT_NO_DEPRECATE
return name.c_str();
#else
return m_alloc.ptr(m_name_idx);
#endif
}
std::string torrent_alert::message() const
@ -124,7 +128,11 @@ namespace libtorrent {
char const* tracker_alert::tracker_url() const
{
#ifndef TORRENT_NO_DEPRECATE
return url.c_str();
#else
return m_alloc.ptr(m_url_idx);
#endif
}
std::string tracker_alert::message() const
@ -195,7 +203,11 @@ namespace libtorrent {
char const* file_renamed_alert::new_name() const
{
#ifndef TORRENT_NO_DEPRECATE
return name.c_str();
#else
return m_alloc.ptr(m_name_idx);
#endif
}
std::string file_renamed_alert::message() const
@ -292,7 +304,11 @@ namespace libtorrent {
char const* tracker_error_alert::error_message() const
{
#ifndef TORRENT_NO_DEPRECATE
return msg.c_str();
#else
return m_alloc.ptr(m_msg_idx);
#endif
}
std::string tracker_error_alert::message() const
@ -320,7 +336,11 @@ namespace libtorrent {
char const* tracker_warning_alert::warning_message() const
{
#ifndef TORRENT_NO_DEPRECATE
return msg.c_str();
#else
return m_alloc.ptr(m_msg_idx);
#endif
}
std::string tracker_warning_alert::message() const
@ -378,8 +398,12 @@ namespace libtorrent {
char const* scrape_failed_alert::error_message() const
{
#ifndef TORRENT_NO_DEPRECATE
return msg.c_str();
#else
if (m_msg_idx == -1) return "";
else return m_alloc.ptr(m_msg_idx);
#endif
}
std::string scrape_failed_alert::message() const
@ -649,7 +673,11 @@ namespace libtorrent {
char const* storage_moved_alert::storage_path() const
{
#ifndef TORRENT_NO_DEPRECATE
return path.c_str();
#else
return m_alloc.ptr(m_path_idx);
#endif
}
storage_moved_failed_alert::storage_moved_failed_alert(
@ -669,7 +697,11 @@ namespace libtorrent {
char const* storage_moved_failed_alert::file_path() const
{
#ifndef TORRENT_NO_DEPRECATE
return file.c_str();
#else
return m_alloc.ptr(m_file_idx);
#endif
}
std::string storage_moved_failed_alert::message() const
@ -935,7 +967,11 @@ namespace libtorrent {
char const* portmap_log_alert::log_message() const
{
#ifndef TORRENT_NO_DEPRECATE
return msg.c_str();
#else
return m_alloc.ptr(m_log_idx);
#endif
}
std::string portmap_log_alert::message() const
@ -976,7 +1012,11 @@ namespace libtorrent {
char const* fastresume_rejected_alert::file_path() const
{
#ifndef TORRENT_NO_DEPRECATE
return file.c_str();
#else
return m_alloc.ptr(m_path_idx);
#endif
}
peer_blocked_alert::peer_blocked_alert(aux::stack_allocator& alloc
@ -1141,7 +1181,11 @@ namespace libtorrent {
char const* trackerid_alert::tracker_id() const
{
#ifndef TORRENT_NO_DEPRECATE
return trackerid.c_str();
#else
return m_alloc.ptr(m_tracker_idx);
#endif
}
std::string trackerid_alert::message() const
@ -1706,8 +1750,12 @@ namespace libtorrent {
char const* url_seed_alert::error_message() const
{
#ifndef TORRENT_NO_DEPRECATE
return msg.c_str();
#else
if (m_msg_idx == -1) return "";
return m_alloc.ptr(m_msg_idx);
#endif
}
file_error_alert::file_error_alert(aux::stack_allocator& alloc
@ -1730,7 +1778,11 @@ namespace libtorrent {
char const* file_error_alert::filename() const
{
#ifndef TORRENT_NO_DEPRECATE
return file.c_str();
#else
return m_alloc.ptr(m_file_idx);
#endif
}
std::string file_error_alert::message() const

View File

@ -1082,7 +1082,7 @@ int block_cache::try_evict_blocks(int num, cached_piece_entry* ignore)
// the first pass, only evict blocks that have been
// hashed
if (pass == 0 && pe->hash)
end = pe->hash->offset / block_size();
end = pe->hash->offset / block_size();
// go through the blocks and evict the ones
// that are not dirty and not referenced

View File

@ -808,7 +808,7 @@ namespace libtorrent
// we support FAST extension
*(ptr + 7) |= 0x04;
#ifndef TORRENT_DISABLE_LOGGING
#ifndef TORRENT_DISABLE_LOGGING
std::string bitmask;
for (int k = 0; k < 8; ++k)
{
@ -3284,8 +3284,7 @@ namespace libtorrent
if (!m_recv_buffer.packet_finished()) return;
recv_buffer = m_recv_buffer.get();
#ifndef TORRENT_DISABLE_LOGGING
#ifndef TORRENT_DISABLE_LOGGING
std::string extensions;
extensions.resize(8 * 8);
for (int i=0; i < 8; ++i)
@ -3461,7 +3460,7 @@ namespace libtorrent
#endif
#ifndef TORRENT_DISABLE_LOGGING
peer_log(peer_log_alert::incoming_message, "HANDSHAKE");
peer_log(peer_log_alert::incoming_message, "HANDSHAKE", "connection ready");
#endif
// consider this a successful connection, reset the failcount
if (peer_info_struct())

View File

@ -133,14 +133,14 @@ namespace libtorrent
// when seeding, prefer the peer we're uploading the fastest to
c1 = lhs->uploaded_in_last_round();
c2 = rhs->uploaded_in_last_round();
// take torrent priority into account
c1 *= prio1;
c2 *= prio2;
if (c1 > c2) return true;
if (c2 > c1) return false;
// prioritize the one that has waited the longest to be unchoked
// the round-robin unchoker relies on this logic. Don't change it
// without moving this into that unchoker logic
@ -200,7 +200,7 @@ namespace libtorrent
? t2_total - rhs->num_have_pieces() : rhs->num_have_pieces()) * 1000 / t2_total;
if (score1 > score2) return true;
if (score2 > score1) return false;
// prioritize the one that has waited the longest to be unchoked
// the round-robin unchoker relies on this logic. Don't change it
// without moving this into that unchoker logic
@ -215,7 +215,7 @@ namespace libtorrent
c1 = lhs->uploaded_in_last_round();
c2 = rhs->uploaded_in_last_round();
// take torrent priority into account
c1 *= lhs->get_priority(peer_connection::upload_channel);
c2 *= rhs->get_priority(peer_connection::upload_channel);
@ -256,7 +256,18 @@ namespace libtorrent
, time_duration unchoke_interval
, aux::session_settings const& sett)
{
#if TORRENT_USE_ASSERTS
for (std::vector<peer_connection*>::iterator i = peers.begin()
, end(peers.end()); i != end; ++i)
{
TORRENT_ASSERT((*i)->self());
TORRENT_ASSERT((*i)->associated_torrent().lock());
}
#endif
int upload_slots = sett.get_int(settings_pack::unchoke_slots_limit);
if (upload_slots < 0)
upload_slots = (std::numeric_limits<int>::max)();
// ==== BitTyrant ====
//

View File

@ -371,11 +371,14 @@ namespace libtorrent
#else
if (m_using_pool_allocator)
{
ret = static_cast<char*>(m_pool.malloc());
int effective_block_size = m_cache_buffer_chunk_size
int const effective_block_size
= m_in_use >= m_max_use
? 20 // use small increments once we've exceeded the cache size
: m_cache_buffer_chunk_size
? m_cache_buffer_chunk_size
: (std::max)(m_max_use / 10, 1);
m_pool.set_next_size(effective_block_size);
ret = static_cast<char*>(m_pool.malloc());
}
else
{
@ -453,7 +456,9 @@ namespace libtorrent
m_cache_buffer_chunk_size = sett.get_int(settings_pack::cache_buffer_chunk_size);
m_lock_disk_cache = sett.get_bool(settings_pack::lock_disk_cache);
#ifndef TORRENT_DISABLE_POOL_ALLOCATOR
m_want_pool_allocator = sett.get_bool(settings_pack::use_disk_cache_pool);
// if the chunk size is set to 1, there's no point in creating a pool
m_want_pool_allocator = sett.get_bool(settings_pack::use_disk_cache_pool)
&& (m_cache_buffer_chunk_size != 1);
// if there are no allocated blocks, it's OK to switch allocator
if (m_in_use == 0)
m_using_pool_allocator = m_want_pool_allocator;
@ -473,12 +478,38 @@ namespace libtorrent
#endif
sett.get_str(settings_pack::mmap_cache).empty())
{
int cache_size = sett.get_int(settings_pack::cache_size);
int const cache_size = sett.get_int(settings_pack::cache_size);
if (cache_size < 0)
{
boost::uint64_t phys_ram = total_physical_ram();
if (phys_ram == 0) m_max_use = 1024;
else m_max_use = phys_ram / 8 / m_block_size;
else
{
// this is the logic to calculate the automatic disk cache size
// based on the amount of physical RAM.
// The more physical RAM, the smaller portion of it is allocated
// for the cache.
// we take a 30th of everything exceeding 4 GiB
// a 20th of everything exceeding 1 GiB
// and a 10th of everything below a GiB
boost::int64_t const gb = 1024 * 1024 * 1024;
boost::int64_t result = 0;
if (phys_ram > 4 * gb)
{
result += (phys_ram - 4 * gb) / 30;
phys_ram = 4 * gb;
}
if (phys_ram > 1 * gb)
{
result += (phys_ram - 1 * gb) / 20;
phys_ram = 1 * gb;
}
result += phys_ram / 10;
m_max_use = result / m_block_size;
}
if (sizeof(void*) == 4)
{
@ -500,6 +531,8 @@ namespace libtorrent
m_exceeded_max_size = true;
m_trigger_cache_trim();
}
if (m_cache_buffer_chunk_size > m_max_use)
m_cache_buffer_chunk_size = m_max_use;
}
#if TORRENT_USE_ASSERTS

View File

@ -573,7 +573,7 @@ namespace libtorrent
int piece_size = pe->storage->files()->piece_size(pe->piece);
TORRENT_PIECE_ASSERT(piece_size > 0, pe);
int iov_len = 0;
// the blocks we're flushing
int num_flushing = 0;
@ -1142,21 +1142,6 @@ namespace libtorrent
return;
}
#if TORRENT_USE_ASSERTS
// TODO: it should clear the hash state even when there's an error, right?
if (j->action == disk_io_job::hash && !j->error.ec)
{
// a hash job should never return without clearing pe->hash
l.lock();
cached_piece_entry* pe = m_disk_cache.find_piece(j);
if (pe != NULL)
{
TORRENT_PIECE_ASSERT(pe->hash == NULL, pe);
}
l.unlock();
}
#endif
if (ret == defer_handler) return;
j->ret = ret;
@ -1202,16 +1187,11 @@ namespace libtorrent
int disk_io_thread::do_read(disk_io_job* j, jobqueue_t& completed_jobs)
{
if (!m_settings.get_bool(settings_pack::use_read_cache)
|| m_settings.get_int(settings_pack::cache_size) == 0)
if ((j->flags & disk_io_job::use_disk_cache) == 0)
{
// we're not using a cache. This is the simple path
// just read straight from the file
int ret = do_uncached_read(j);
mutex::scoped_lock l(m_cache_mutex);
cached_piece_entry* pe = m_disk_cache.find_piece(j);
if (pe) maybe_issue_queued_read_jobs(pe, completed_jobs);
return ret;
}
@ -1475,8 +1455,7 @@ namespace libtorrent
// should we put this write job in the cache?
// if we don't use the cache we shouldn't.
if (m_settings.get_bool(settings_pack::use_write_cache)
&& m_settings.get_int(settings_pack::cache_size) > 0)
if (j->flags & disk_io_job::use_disk_cache)
{
mutex::scoped_lock l(m_cache_mutex);
@ -1592,7 +1571,7 @@ namespace libtorrent
TORRENT_ASSERT(j->action == disk_io_job::read);
if (m_settings.get_bool(settings_pack::use_read_cache)
&& m_settings.get_int(settings_pack::cache_size) > 0)
&& m_settings.get_int(settings_pack::cache_size) != 0)
{
int ret = m_disk_cache.try_read(j);
if (ret >= 0)
@ -1629,7 +1608,7 @@ namespace libtorrent
j->error.operation = storage_error::read;
return 0;
}
j->flags |= disk_io_job::use_disk_cache;
if (pe->outstanding_read)
{
TORRENT_PIECE_ASSERT(j->piece == pe->piece, pe);
@ -1705,10 +1684,11 @@ namespace libtorrent
TORRENT_ASSERT(m_disk_cache.is_disk_buffer(j->buffer.disk_block));
l_.unlock();
#endif
if (m_settings.get_int(settings_pack::cache_size) > 0
if (m_settings.get_int(settings_pack::cache_size) != 0
&& m_settings.get_bool(settings_pack::use_write_cache))
{
TORRENT_ASSERT((r.start % m_disk_cache.block_size()) == 0);
j->flags |= disk_io_job::use_disk_cache;
if (storage->is_blocked(j))
{
@ -1798,6 +1778,12 @@ namespace libtorrent
}
l.unlock();
if (m_settings.get_bool(settings_pack::use_read_cache)
&& m_settings.get_int(settings_pack::cache_size) != 0)
{
j->flags |= disk_io_job::use_disk_cache;
}
add_job(j);
}
@ -2233,10 +2219,10 @@ namespace libtorrent
// just read straight from the file
TORRENT_ASSERT(m_magic == 0x1337);
int piece_size = j->storage->files()->piece_size(j->piece);
int block_size = m_disk_cache.block_size();
int blocks_in_piece = (piece_size + block_size - 1) / block_size;
int file_flags = file_flags_for_job(j);
int const piece_size = j->storage->files()->piece_size(j->piece);
int const block_size = m_disk_cache.block_size();
int const blocks_in_piece = (piece_size + block_size - 1) / block_size;
int const file_flags = file_flags_for_job(j);
file::iovec_t iov;
iov.iov_base = m_disk_cache.allocate_buffer("hashing");
@ -2257,7 +2243,7 @@ namespace libtorrent
if (!j->error.ec)
{
boost::uint32_t read_time = total_microseconds(clock_type::now() - start_time);
boost::uint32_t const read_time = total_microseconds(clock_type::now() - start_time);
m_read_time.add_sample(read_time);
m_stats_counters.inc_stats_counter(counters::num_blocks_read);
@ -2281,11 +2267,11 @@ namespace libtorrent
{
INVARIANT_CHECK;
if (m_settings.get_int(settings_pack::cache_size) == 0)
if ((j->flags & disk_io_job::use_disk_cache) == 0)
return do_uncached_hash(j);
int piece_size = j->storage->files()->piece_size(j->piece);
int file_flags = file_flags_for_job(j);
int const piece_size = j->storage->files()->piece_size(j->piece);
int const file_flags = file_flags_for_job(j);
mutex::scoped_lock l(m_cache_mutex);
@ -2324,7 +2310,7 @@ namespace libtorrent
}
}
if (pe == NULL && !m_settings.get_bool(settings_pack::use_read_cache))
if (pe == NULL && m_settings.get_bool(settings_pack::use_read_cache) == false)
{
l.unlock();
// if there's no piece in the cache, and the read cache is disabled
@ -2373,7 +2359,7 @@ namespace libtorrent
int block_size = m_disk_cache.block_size();
int blocks_in_piece = (piece_size + block_size - 1) / block_size;
// keep track of which blocks we have locked by incrementing
// their refcounts. This is used to decrement only these blocks
// later.
@ -2616,7 +2602,7 @@ namespace libtorrent
{
INVARIANT_CHECK;
TORRENT_ASSERT(j->buffer.disk_block == 0);
if (m_settings.get_int(settings_pack::cache_size) == 0
|| m_settings.get_bool(settings_pack::use_read_cache) == false)
return 0;
@ -2819,17 +2805,17 @@ namespace libtorrent
if (no_pieces == false)
{
int block_size = m_disk_cache.block_size();
if (storage)
{
ret->pieces.reserve(storage->num_pieces());
for (boost::unordered_set<cached_piece_entry*>::iterator i
= storage->cached_pieces().begin(), end(storage->cached_pieces().end());
i != end; ++i)
{
TORRENT_ASSERT((*i)->storage.get() == storage);
if ((*i)->cache_state == cached_piece_entry::read_lru2_ghost
|| (*i)->cache_state == cached_piece_entry::read_lru1_ghost)
continue;
@ -2840,10 +2826,10 @@ namespace libtorrent
else
{
ret->pieces.reserve(m_disk_cache.num_pieces());
std::pair<block_cache::iterator, block_cache::iterator> range
= m_disk_cache.all_pieces();
for (block_cache::iterator i = range.first; i != range.second; ++i)
{
if (i->cache_state == cached_piece_entry::read_lru2_ghost
@ -3444,7 +3430,7 @@ namespace libtorrent
if (j->action == disk_io_job::read
&& m_settings.get_bool(settings_pack::use_read_cache)
&& m_settings.get_int(settings_pack::cache_size) > 0)
&& m_settings.get_int(settings_pack::cache_size) != 0)
{
int state = prep_read_job_impl(j, false);
switch (state)

View File

@ -599,6 +599,7 @@ namespace libtorrent
if (r == ERROR_BUFFER_OVERFLOW)
{
buffer.resize(buf_size);
adapter_addresses = reinterpret_cast<IP_ADAPTER_ADDRESSES*>(&buffer[0]);
r = GetAdaptersAddresses(AF_UNSPEC, GAA_FLAG_SKIP_MULTICAST | GAA_FLAG_SKIP_DNS_SERVER
| GAA_FLAG_SKIP_ANYCAST, NULL, adapter_addresses, &buf_size);
}

View File

@ -152,7 +152,7 @@ namespace
}
}
// return true of the first argument is a better canidate for removal, i.e.
// return true of the first argument is a better candidate for removal, i.e.
// less important to keep
struct immutable_item_comparator
{

View File

@ -803,7 +803,7 @@ namespace libtorrent
m_connected = false;
if (!m_download_queue.empty())
m_counters.inc_stats_counter(counters::num_peers_down_requests, -1);
// defensive
boost::shared_ptr<torrent> t = m_torrent.lock();
// if t is NULL, we better not be connecting, since
@ -990,13 +990,13 @@ namespace libtorrent
TORRENT_ASSERT(is_single_thread());
return m_request_queue;
}
std::vector<pending_block> const& peer_connection::download_queue() const
{
TORRENT_ASSERT(is_single_thread());
return m_download_queue;
}
std::vector<peer_request> const& peer_connection::upload_queue() const
{
TORRENT_ASSERT(is_single_thread());
@ -1878,7 +1878,7 @@ namespace libtorrent
m_have_piece.set_bit(index);
++m_num_pieces;
// if the peer is downloading stuff, it must have metadata
// if the peer is downloading stuff, it must have metadata
m_has_metadata = true;
// only update the piece_picker if
@ -2576,9 +2576,9 @@ namespace libtorrent
{
check_postcondition(boost::shared_ptr<torrent> const& t_
, bool init_check = true): t(t_) { if (init_check) check(); }
~check_postcondition() { check(); }
void check()
{
if (!t->is_seed())
@ -2596,7 +2596,7 @@ namespace libtorrent
}
}
}
shared_ptr<torrent> t;
};
#endif
@ -3229,7 +3229,7 @@ namespace libtorrent
disconnect_if_redundant();
}
// -----------------------------
// --------- HAVE NONE ---------
// -----------------------------
@ -3495,8 +3495,8 @@ namespace libtorrent
if (t->alerts().should_post<block_downloading_alert>())
{
t->alerts().emplace_alert<block_downloading_alert>(t->get_handle(),
remote(), pid(), block.block_index, block.piece_index);
t->alerts().emplace_alert<block_downloading_alert>(t->get_handle()
, remote(), pid(), block.block_index, block.piece_index);
}
pending_block pb(block);
@ -3643,6 +3643,8 @@ namespace libtorrent
TORRENT_ASSERT(is_single_thread());
INVARIANT_CHECK;
TORRENT_ASSERT(!is_connecting());
if (m_choked)
{
TORRENT_ASSERT(m_peer_info == NULL
@ -4082,6 +4084,15 @@ namespace libtorrent
, op, ec.message().c_str());
break;
}
if (ec == error_code(boost::asio::error::eof
, boost::asio::error::get_misc_category())
&& !in_handshake()
&& !is_connecting()
&& clock_type::now() - connected_time() < seconds(15))
{
peer_log(peer_log_alert::info, "SHORT_LIVED_DISCONNECT", "");
}
#endif
if ((m_channel_state[upload_channel] & peer_info::bw_network) == 0)
@ -4955,8 +4966,8 @@ namespace libtorrent
boost::int64_t piece_size = t->torrent_file().piece_length();
if (m_remote_dl_rate > 0)
m_remote_dl_rate = int((m_remote_dl_rate * 2 / 3) +
((boost::int64_t(m_remote_pieces_dled) * piece_size / 3) / 60));
m_remote_dl_rate = int((m_remote_dl_rate * 2 / 3)
+ ((boost::int64_t(m_remote_pieces_dled) * piece_size / 3) / 60));
else
m_remote_dl_rate = int(boost::int64_t(m_remote_pieces_dled)
* piece_size / 60);
@ -5355,7 +5366,7 @@ namespace libtorrent
disconnect(j->error.ec, op_file_read);
return;
}
if (j->ret != r.length)
{
// handle_disk_error may disconnect us
@ -5715,7 +5726,7 @@ namespace libtorrent
{
return;
}
if (!can_read())
{
#ifndef TORRENT_DISABLE_LOGGING
@ -5980,8 +5991,11 @@ namespace libtorrent
if (error)
{
TORRENT_ASSERT_VAL(error.value() != 0, error.value());
#ifndef TORRENT_DISABLE_LOGGING
peer_log(peer_log_alert::info, "ERROR", "in peer_connection::on_receive_data_nb error: %s"
peer_log(peer_log_alert::info, "ERROR"
, "in peer_connection::on_receive_data_nb error: (%s:%d) %s"
, error.category().name(), error.value()
, error.message().c_str());
#endif
on_receive(error, bytes_transferred);
@ -6106,8 +6120,10 @@ namespace libtorrent
{
TORRENT_ASSERT(is_single_thread());
#ifndef TORRENT_DISABLE_LOGGING
peer_log(peer_log_alert::incoming, "ON_RECEIVE_DATA", "bytes: %d error: %s"
, int(bytes_transferred), error.message().c_str());
peer_log(peer_log_alert::incoming, "ON_RECEIVE_DATA"
, "bytes: %d error: (%s:%d) %s"
, int(bytes_transferred), error.category().name(), error.value()
, error.message().c_str());
#endif
// submit all disk jobs later
@ -6836,7 +6852,7 @@ namespace libtorrent
time_duration d;
d = aux::time_now() - m_last_sent;
if (total_seconds(d) < timeout() / 2) return;
if (m_connecting) return;
if (in_handshake()) return;

View File

@ -2823,8 +2823,6 @@ get_out:
if (num_blocks <= 0) return 0;
}
TORRENT_ASSERT(num_blocks >= 0 || prefer_contiguous_blocks > 0);
if (num_blocks <= 0) return 0;
if (options & on_parole) return num_blocks;

View File

@ -54,8 +54,12 @@ boost::asio::mutable_buffer receive_buffer::reserve(int size)
{
TORRENT_ASSERT(size > 0);
TORRENT_ASSERT(!m_disk_recv_buffer);
m_recv_buffer.resize(m_recv_pos + size);
return boost::asio::buffer(&m_recv_buffer[m_recv_pos], size);
// this is unintuitive, but we used to use m_recv_pos in this function when
// we should have used m_recv_end. perhaps they always happen to be equal
TORRENT_ASSERT(m_recv_pos == m_recv_end);
m_recv_buffer.resize(m_recv_end + size);
return boost::asio::buffer(&m_recv_buffer[0] + m_recv_end, size);
}
int receive_buffer::reserve(boost::array<boost::asio::mutable_buffer, 2>& vec, int size)
@ -64,41 +68,48 @@ int receive_buffer::reserve(boost::array<boost::asio::mutable_buffer, 2>& vec, i
TORRENT_ASSERT(m_recv_pos >= 0);
TORRENT_ASSERT(m_packet_size > 0);
// normalize() must be called before receiving more data
TORRENT_ASSERT(m_recv_start == 0);
// this is unintuitive, but we used to use m_recv_pos in this function when
// we should have used m_recv_end. perhaps they always happen to be equal
TORRENT_ASSERT(m_recv_pos == m_recv_end);
int num_bufs;
int regular_buf_size = regular_buffer_size();
int const regular_buf_size = regular_buffer_size();
if (int(m_recv_buffer.size()) < regular_buf_size)
m_recv_buffer.resize(round_up8(regular_buf_size));
if (!m_disk_recv_buffer || regular_buf_size >= m_recv_pos + size)
if (!m_disk_recv_buffer || regular_buf_size >= m_recv_end + size)
{
// only receive into regular buffer
TORRENT_ASSERT(m_recv_pos + size <= int(m_recv_buffer.size()));
vec[0] = boost::asio::buffer(&m_recv_buffer[m_recv_pos], size);
TORRENT_ASSERT(m_recv_end + size <= int(m_recv_buffer.size()));
vec[0] = boost::asio::buffer(&m_recv_buffer[0] + m_recv_end, size);
TORRENT_ASSERT(boost::asio::buffer_size(vec[0]) > 0);
num_bufs = 1;
}
else if (m_recv_pos >= regular_buf_size)
else if (m_recv_end >= regular_buf_size)
{
// only receive into disk buffer
TORRENT_ASSERT(m_recv_pos - regular_buf_size >= 0);
TORRENT_ASSERT(m_recv_pos - regular_buf_size + size <= m_disk_recv_buffer_size);
vec[0] = boost::asio::buffer(m_disk_recv_buffer.get() + m_recv_pos - regular_buf_size, size);
TORRENT_ASSERT(m_recv_end - regular_buf_size >= 0);
TORRENT_ASSERT(m_recv_end - regular_buf_size + size <= m_disk_recv_buffer_size);
vec[0] = boost::asio::buffer(m_disk_recv_buffer.get() + m_recv_end - regular_buf_size, size);
TORRENT_ASSERT(boost::asio::buffer_size(vec[0]) > 0);
num_bufs = 1;
}
else
{
// receive into both regular and disk buffer
TORRENT_ASSERT(size + m_recv_pos > regular_buf_size);
TORRENT_ASSERT(m_recv_pos < regular_buf_size);
TORRENT_ASSERT(size + m_recv_end > regular_buf_size);
TORRENT_ASSERT(m_recv_end < regular_buf_size);
TORRENT_ASSERT(size - regular_buf_size
+ m_recv_pos <= m_disk_recv_buffer_size);
+ m_recv_end <= m_disk_recv_buffer_size);
vec[0] = boost::asio::buffer(&m_recv_buffer[m_recv_pos]
, regular_buf_size - m_recv_pos);
vec[0] = boost::asio::buffer(&m_recv_buffer[0] + m_recv_end
, regular_buf_size - m_recv_end);
vec[1] = boost::asio::buffer(m_disk_recv_buffer.get()
, size - regular_buf_size + m_recv_pos);
, size - regular_buf_size + m_recv_end);
TORRENT_ASSERT(boost::asio::buffer_size(vec[0])
+ boost::asio::buffer_size(vec[1])> 0);
num_bufs = 2;
@ -109,9 +120,9 @@ int receive_buffer::reserve(boost::array<boost::asio::mutable_buffer, 2>& vec, i
int receive_buffer::advance_pos(int bytes)
{
int packet_size = m_soft_packet_size ? m_soft_packet_size : m_packet_size;
int limit = packet_size > m_recv_pos ? packet_size - m_recv_pos : packet_size;
int sub_transferred = (std::min)(bytes, limit);
int const packet_size = m_soft_packet_size ? m_soft_packet_size : m_packet_size;
int const limit = packet_size > m_recv_pos ? packet_size - m_recv_pos : packet_size;
int const sub_transferred = (std::min)(bytes, limit);
m_recv_pos += sub_transferred;
if (m_recv_pos >= m_soft_packet_size) m_soft_packet_size = 0;
return sub_transferred;
@ -174,7 +185,8 @@ buffer::const_interval receive_buffer::get() const
TORRENT_ASSERT(m_recv_pos == 0);
return buffer::interval(0,0);
}
int rcv_pos = (std::min)(m_recv_pos, int(m_recv_buffer.size()));
int rcv_pos = (std::min)(m_recv_pos, int(m_recv_buffer.size()) - m_recv_start);
return buffer::const_interval(&m_recv_buffer[0] + m_recv_start
, &m_recv_buffer[0] + m_recv_start + rcv_pos);
}
@ -194,34 +206,48 @@ buffer::interval receive_buffer::mutable_buffer()
, &m_recv_buffer[0] + m_recv_start + rcv_pos);
}
void receive_buffer::mutable_buffers(std::vector<boost::asio::mutable_buffer>& vec, int bytes)
// TODO: 2 should this take a boost::array<..., 2> instead? it could return the
// number of buffers added, just like reserve.
void receive_buffer::mutable_buffers(std::vector<boost::asio::mutable_buffer>& vec, int const bytes)
{
using namespace boost;
namespace asio = boost::asio;
// bytes is the number of bytes we just received, and m_recv_pos has
// already been adjusted for these bytes. The receive pos immediately
// before we received these bytes was (m_recv_pos - bytes)
int const last_recv_pos = m_recv_pos - bytes;
TORRENT_ASSERT(bytes <= m_recv_pos);
int regular_buf_size = regular_buffer_size();
// the number of bytes in the current packet that are being received into a
// regular receive buffer (as opposed to a disk cache buffer)
int const regular_buf_size = regular_buffer_size();
TORRENT_ASSERT(regular_buf_size >= 0);
if (!m_disk_recv_buffer || regular_buf_size >= m_recv_pos)
{
// we just received into a regular disk buffer
vec.push_back(asio::mutable_buffer(&m_recv_buffer[0] + m_recv_start
+ m_recv_pos - bytes, bytes));
+ last_recv_pos, bytes));
}
else if (m_recv_pos - bytes >= regular_buf_size)
else if (last_recv_pos >= regular_buf_size)
{
vec.push_back(asio::mutable_buffer(m_disk_recv_buffer.get() + m_recv_pos
- regular_buf_size - bytes, bytes));
// we only received into a disk buffer
vec.push_back(asio::mutable_buffer(m_disk_recv_buffer.get()
+ last_recv_pos - regular_buf_size, bytes));
}
else
{
TORRENT_ASSERT(m_recv_pos - bytes < regular_buf_size);
// we received into a regular and a disk buffer
TORRENT_ASSERT(last_recv_pos < regular_buf_size);
TORRENT_ASSERT(m_recv_pos > regular_buf_size);
vec.push_back(asio::mutable_buffer(&m_recv_buffer[0] + m_recv_start + m_recv_pos - bytes
, regular_buf_size - (m_recv_start + m_recv_pos - bytes)));
vec.push_back(asio::mutable_buffer(&m_recv_buffer[0] + m_recv_start + last_recv_pos
, regular_buf_size - last_recv_pos));
vec.push_back(asio::mutable_buffer(m_disk_recv_buffer.get()
, m_recv_pos - regular_buf_size));
}
#if defined TORRENT_DEBUG || defined TORRENT_RELEASE_ASSERTS
#if TORRENT_USE_ASSERTS
int vec_bytes = 0;
for (std::vector<asio::mutable_buffer>::iterator i = vec.begin();
i != vec.end(); ++i)

View File

@ -106,11 +106,12 @@ namespace libtorrent
TORRENT_SYNC_CALL2(save_state, &e, flags);
}
void session_handle::load_state(bdecode_node const& e)
void session_handle::load_state(bdecode_node const& e
, boost::uint32_t const flags)
{
// this needs to be synchronized since the lifespan
// of e is tied to the caller
TORRENT_SYNC_CALL1(load_state, &e);
TORRENT_SYNC_CALL2(load_state, &e, flags);
}
void session_handle::get_torrent_status(std::vector<torrent_status>* ret
@ -607,7 +608,7 @@ namespace libtorrent
void session_handle::start_dht(entry const& startup_state)
{
#ifndef TORRENT_DISABLE_DHT
TORRENT_ASYNC_CALL1(start_dht, startup_state);
TORRENT_ASYNC_CALL1(start_dht_deprecated, startup_state);
#else
TORRENT_UNUSED(startup_state);
#endif
@ -644,7 +645,8 @@ namespace libtorrent
void session_handle::load_country_db(wchar_t const*) {}
#endif // TORRENT_USE_WSTRING
void session_handle::load_state(entry const& ses_state)
void session_handle::load_state(entry const& ses_state
, boost::uint32_t const flags)
{
if (ses_state.type() == entry::undefined_t) return;
std::vector<char> buf;
@ -660,7 +662,7 @@ namespace libtorrent
#ifndef BOOST_NO_EXCEPTIONS
if (ret != 0) throw libtorrent_exception(ec);
#endif
TORRENT_SYNC_CALL1(load_state, &e);
TORRENT_SYNC_CALL2(load_state, &e, flags);
}
entry session_handle::state() const
@ -670,7 +672,8 @@ namespace libtorrent
return ret;
}
void session_handle::load_state(lazy_entry const& ses_state)
void session_handle::load_state(lazy_entry const& ses_state
, boost::uint32_t const flags)
{
if (ses_state.type() == lazy_entry::none_t) return;
std::pair<char const*, int> buf = ses_state.data_section();
@ -685,7 +688,7 @@ namespace libtorrent
#ifndef BOOST_NO_EXCEPTIONS
if (ret != 0) throw libtorrent_exception(ec);
#endif
TORRENT_SYNC_CALL1(load_state, &e);
TORRENT_SYNC_CALL2(load_state, &e, flags);
}
#endif // TORRENT_NO_DEPRECATE

View File

@ -640,12 +640,16 @@ namespace aux {
void session_impl::save_state(entry* eptr, boost::uint32_t flags) const
{
TORRENT_ASSERT(is_single_thread());
TORRENT_UNUSED(flags); // potentially unused
entry& e = *eptr;
// make it a dict
e.dict();
entry::dictionary_type& sett = e["settings"].dict();
save_settings_to_dict(m_settings, sett);
if (flags & session::save_settings)
{
entry::dictionary_type& sett = e["settings"].dict();
save_settings_to_dict(m_settings, sett);
}
#ifndef TORRENT_DISABLE_DHT
if (flags & session::save_dht_settings)
@ -707,7 +711,8 @@ namespace aux {
return proxy_settings(m_settings);
}
void session_impl::load_state(bdecode_node const* e)
void session_impl::load_state(bdecode_node const* e
, boost::uint32_t const flags = 0xffffffff)
{
TORRENT_ASSERT(is_single_thread());
@ -717,77 +722,86 @@ namespace aux {
#ifndef TORRENT_DISABLE_DHT
bool need_update_dht = false;
// load from the old settings names
settings = e->dict_find_dict("dht");
if (settings)
if (flags & session::save_dht_settings)
{
bdecode_node val;
val = settings.dict_find_int("max_peers_reply");
if (val) m_dht_settings.max_peers_reply = val.int_value();
val = settings.dict_find_int("search_branching");
if (val) m_dht_settings.search_branching = val.int_value();
val = settings.dict_find_int("max_fail_count");
if (val) m_dht_settings.max_fail_count = val.int_value();
val = settings.dict_find_int("max_torrents");
if (val) m_dht_settings.max_torrents = val.int_value();
val = settings.dict_find_int("max_dht_items");
if (val) m_dht_settings.max_dht_items = val.int_value();
val = settings.dict_find_int("max_peers");
if (val) m_dht_settings.max_peers = val.int_value();
val = settings.dict_find_int("max_torrent_search_reply");
if (val) m_dht_settings.max_torrent_search_reply = val.int_value();
val = settings.dict_find_int("restrict_routing_ips");
if (val) m_dht_settings.restrict_routing_ips = val.int_value();
val = settings.dict_find_int("restrict_search_ips");
if (val) m_dht_settings.restrict_search_ips = val.int_value();
val = settings.dict_find_int("extended_routing_table");
if (val) m_dht_settings.extended_routing_table = val.int_value();
val = settings.dict_find_int("aggressive_lookups");
if (val) m_dht_settings.aggressive_lookups = val.int_value();
val = settings.dict_find_int("privacy_lookups");
if (val) m_dht_settings.privacy_lookups = val.int_value();
val = settings.dict_find_int("enforce_node_id");
if (val) m_dht_settings.enforce_node_id = val.int_value();
val = settings.dict_find_int("ignore_dark_internet");
if (val) m_dht_settings.ignore_dark_internet = val.int_value();
val = settings.dict_find_int("block_timeout");
if (val) m_dht_settings.block_timeout = val.int_value();
val = settings.dict_find_int("block_ratelimit");
if (val) m_dht_settings.block_ratelimit = val.int_value();
val = settings.dict_find_int("read_only");
if (val) m_dht_settings.read_only = val.int_value();
val = settings.dict_find_int("item_lifetime");
if (val) m_dht_settings.item_lifetime = val.int_value();
settings = e->dict_find_dict("dht");
if (settings)
{
bdecode_node val;
val = settings.dict_find_int("max_peers_reply");
if (val) m_dht_settings.max_peers_reply = val.int_value();
val = settings.dict_find_int("search_branching");
if (val) m_dht_settings.search_branching = val.int_value();
val = settings.dict_find_int("max_fail_count");
if (val) m_dht_settings.max_fail_count = val.int_value();
val = settings.dict_find_int("max_torrents");
if (val) m_dht_settings.max_torrents = val.int_value();
val = settings.dict_find_int("max_dht_items");
if (val) m_dht_settings.max_dht_items = val.int_value();
val = settings.dict_find_int("max_peers");
if (val) m_dht_settings.max_peers = val.int_value();
val = settings.dict_find_int("max_torrent_search_reply");
if (val) m_dht_settings.max_torrent_search_reply = val.int_value();
val = settings.dict_find_int("restrict_routing_ips");
if (val) m_dht_settings.restrict_routing_ips = val.int_value();
val = settings.dict_find_int("restrict_search_ips");
if (val) m_dht_settings.restrict_search_ips = val.int_value();
val = settings.dict_find_int("extended_routing_table");
if (val) m_dht_settings.extended_routing_table = val.int_value();
val = settings.dict_find_int("aggressive_lookups");
if (val) m_dht_settings.aggressive_lookups = val.int_value();
val = settings.dict_find_int("privacy_lookups");
if (val) m_dht_settings.privacy_lookups = val.int_value();
val = settings.dict_find_int("enforce_node_id");
if (val) m_dht_settings.enforce_node_id = val.int_value();
val = settings.dict_find_int("ignore_dark_internet");
if (val) m_dht_settings.ignore_dark_internet = val.int_value();
val = settings.dict_find_int("block_timeout");
if (val) m_dht_settings.block_timeout = val.int_value();
val = settings.dict_find_int("block_ratelimit");
if (val) m_dht_settings.block_ratelimit = val.int_value();
val = settings.dict_find_int("read_only");
if (val) m_dht_settings.read_only = val.int_value();
val = settings.dict_find_int("item_lifetime");
if (val) m_dht_settings.item_lifetime = val.int_value();
}
}
settings = e->dict_find_dict("dht state");
if (settings)
if (flags & session::save_dht_state)
{
m_dht_state = settings;
need_update_dht = true;
settings = e->dict_find_dict("dht state");
if (settings)
{
m_dht_state = settings;
need_update_dht = true;
}
}
#endif
#ifndef TORRENT_NO_DEPRECATE
bool need_update_proxy = false;
settings = e->dict_find_dict("proxy");
if (settings)
if (flags & session::save_proxy)
{
bdecode_node val;
val = settings.dict_find_int("port");
if (val) m_settings.set_int(settings_pack::proxy_port, val.int_value());
val = settings.dict_find_int("type");
if (val) m_settings.set_int(settings_pack::proxy_type, val.int_value());
val = settings.dict_find_int("proxy_hostnames");
if (val) m_settings.set_bool(settings_pack::proxy_hostnames, val.int_value());
val = settings.dict_find_int("proxy_peer_connections");
if (val) m_settings.set_bool(settings_pack::proxy_peer_connections, val.int_value());
val = settings.dict_find_string("hostname");
if (val) m_settings.set_str(settings_pack::proxy_hostname, val.string_value());
val = settings.dict_find_string("password");
if (val) m_settings.set_str(settings_pack::proxy_password, val.string_value());
val = settings.dict_find_string("username");
if (val) m_settings.set_str(settings_pack::proxy_username, val.string_value());
need_update_proxy = true;
settings = e->dict_find_dict("proxy");
if (settings)
{
bdecode_node val;
val = settings.dict_find_int("port");
if (val) m_settings.set_int(settings_pack::proxy_port, val.int_value());
val = settings.dict_find_int("type");
if (val) m_settings.set_int(settings_pack::proxy_type, val.int_value());
val = settings.dict_find_int("proxy_hostnames");
if (val) m_settings.set_bool(settings_pack::proxy_hostnames, val.int_value());
val = settings.dict_find_int("proxy_peer_connections");
if (val) m_settings.set_bool(settings_pack::proxy_peer_connections, val.int_value());
val = settings.dict_find_string("hostname");
if (val) m_settings.set_str(settings_pack::proxy_hostname, val.string_value());
val = settings.dict_find_string("password");
if (val) m_settings.set_str(settings_pack::proxy_password, val.string_value());
val = settings.dict_find_string("username");
if (val) m_settings.set_str(settings_pack::proxy_username, val.string_value());
need_update_proxy = true;
}
}
settings = e->dict_find_dict("encryption");
@ -804,39 +818,49 @@ namespace aux {
if (val) m_settings.set_int(settings_pack::allowed_enc_level, val.int_value());
}
settings = e->dict_find_list("feeds");
if (settings)
if (flags & session::save_feeds)
{
m_feeds.reserve(settings.list_size());
for (int i = 0; i < settings.list_size(); ++i)
settings = e->dict_find_list("feeds");
if (settings)
{
if (settings.list_at(i).type() != bdecode_node::dict_t) continue;
boost::shared_ptr<feed> f(new_feed(*this, feed_settings()));
f->load_state(settings.list_at(i));
f->update_feed();
m_feeds.push_back(f);
m_feeds.reserve(settings.list_size());
for (int i = 0; i < settings.list_size(); ++i)
{
if (settings.list_at(i).type() != bdecode_node::dict_t) continue;
boost::shared_ptr<feed> f(new_feed(*this, feed_settings()));
f->load_state(settings.list_at(i));
f->update_feed();
m_feeds.push_back(f);
}
update_rss_feeds();
}
update_rss_feeds();
}
#endif
settings = e->dict_find_dict("settings");
if (settings)
{
// apply_settings_pack will update dht and proxy
boost::shared_ptr<settings_pack> pack = load_pack_from_dict(settings);
apply_settings_pack(pack);
}
else
if (flags & session::save_settings)
{
settings = e->dict_find_dict("settings");
if (settings)
{
// apply_settings_pack will update dht and proxy
boost::shared_ptr<settings_pack> pack = load_pack_from_dict(settings);
apply_settings_pack(pack);
#ifndef TORRENT_DISABLE_DHT
if (need_update_dht) update_dht();
need_update_dht = false;
#endif
#ifndef TORRENT_NO_DEPRECATE
if (need_update_proxy) update_proxy();
need_update_proxy = false;
#endif
}
}
#ifndef TORRENT_DISABLE_DHT
if (need_update_dht) update_dht();
#endif
#ifndef TORRENT_NO_DEPRECATE
if (need_update_proxy) update_proxy();
#endif
#ifndef TORRENT_DISABLE_EXTENSIONS
for (ses_extension_list_t::iterator i = m_ses_extensions.begin()
, end(m_ses_extensions.end()); i != end; ++i)
@ -3663,7 +3687,8 @@ namespace aux {
t->log_to_all_peers("auto manager pausing torrent");
#endif
// use graceful pause for auto-managed torrents
t->set_allow_peers(false, true);
t->set_allow_peers(false, torrent::flag_graceful_pause
| torrent::flag_clear_disk_cache);
t->set_announce_to_dht(false);
t->set_announce_to_trackers(false);
t->set_announce_to_lsd(false);
@ -4141,6 +4166,7 @@ namespace aux {
int const allowed_upload_slots = unchoke_sort(peers, max_upload_rate
, unchoke_interval, m_settings);
m_stats_counters.set_value(counters::num_unchoke_slots
, allowed_upload_slots);
@ -5594,6 +5620,12 @@ namespace aux {
if (!m_dht) return entry();
return m_dht->state();
}
void session_impl::start_dht_deprecated(entry const& startup_state)
{
m_settings.set_bool(settings_pack::enable_dht, true);
start_dht(startup_state);
}
#endif
void session_impl::add_dht_node_name(std::pair<std::string, int> const& node)
@ -6024,9 +6056,7 @@ namespace aux {
void session_impl::update_unchoke_limit()
{
int unchoke_limit = m_settings.get_int(settings_pack::unchoke_slots_limit);
int allowed_upload_slots = unchoke_limit;
int allowed_upload_slots = m_settings.get_int(settings_pack::unchoke_slots_limit);
if (allowed_upload_slots < 0)
allowed_upload_slots = (std::numeric_limits<int>::max)();

View File

@ -355,10 +355,10 @@ namespace libtorrent
// the total number of blocks run through SHA-1 hashing
METRIC(disk, num_blocks_hashed)
// the number of blocks read from the disk cache
METRIC(disk, num_blocks_cache_hits)
// the number of disk I/O operation for reads and writes. One disk
// operation may transfer more then one block.
METRIC(disk, num_write_ops)

View File

@ -204,7 +204,7 @@ namespace libtorrent
SET(support_merkle_torrents, true, 0),
SET(report_redundant_bytes, true, 0),
SET_NOPREV(listen_system_port_fallback, true, 0),
SET(use_disk_cache_pool, false, 0),
SET(use_disk_cache_pool, true, 0),
SET_NOPREV(announce_crypto_support, true, 0),
SET_NOPREV(enable_upnp, true, &session_impl::update_upnp),
SET_NOPREV(enable_natpmp, true, &session_impl::update_natpmp),
@ -237,7 +237,7 @@ namespace libtorrent
SET(max_failcount, 3, &session_impl::update_max_failcount),
SET(min_reconnect_time, 60, 0),
SET(peer_connect_timeout, 15, 0),
SET(connection_speed, 6, &session_impl::update_connection_speed),
SET(connection_speed, 10, &session_impl::update_connection_speed),
SET(inactivity_timeout, 600, 0),
SET(unchoke_interval, 15, 0),
SET(optimistic_unchoke_interval, 30, 0),

View File

@ -1173,6 +1173,8 @@ namespace libtorrent
TORRENT_UNUSED(j);
TORRENT_UNUSED(b);
if (m_abort) return;
update_gauge();
// some peers that previously was no longer interesting may
// now have become interesting, since we lack this one piece now.
@ -2201,6 +2203,8 @@ namespace libtorrent
return;
}
if (m_abort) return;
state_updated();
if (m_add_torrent_params)
@ -2447,6 +2451,8 @@ namespace libtorrent
dec_refcount("force_recheck");
state_updated();
if (m_abort) return;
if (j->ret == piece_manager::fatal_disk_error)
{
handle_disk_error(j);
@ -2476,7 +2482,10 @@ namespace libtorrent
int num_outstanding = settings().get_int(settings_pack::checking_mem_usage) * block_size()
/ m_torrent_file->piece_length();
if (num_outstanding <= 0) num_outstanding = 1;
// if we only keep a single read operation in-flight at a time, we suffer
// significant performance degradation. Always keep at least two jobs
// outstanding
if (num_outstanding < 2) num_outstanding = 2;
// we might already have some outstanding jobs, if we were paused and
// resumed quickly, before the outstanding jobs completed
@ -2527,6 +2536,8 @@ namespace libtorrent
dec_refcount("start_checking");
if (m_abort) return;
if (j->ret == piece_manager::disk_check_aborted)
{
m_checking_piece = 0;
@ -2668,7 +2679,9 @@ namespace libtorrent
{
// if we're auto managed. assume we need to be paused until the auto
// managed logic runs again (which is triggered further down)
pause();
// setting flags to 0 prevents the disk cache from being evicted as a
// result of this
set_allow_peers(false, 0);
}
// we're done checking! (this should cause a call to trigger_auto_manage)
@ -2844,6 +2857,7 @@ namespace libtorrent
, int(peers.size()));
#endif
if (m_abort) return;
if (peers.empty()) return;
if (m_ses.alerts().should_post<dht_reply_alert>())
@ -3554,7 +3568,7 @@ namespace libtorrent
if (ec)
debug_log("i2p_resolve error: %s", ec.message().c_str());
#endif
if (ec || m_ses.is_aborted()) return;
if (ec || m_abort || m_ses.is_aborted()) return;
need_peer_list();
torrent_state st = get_peer_list_state();
@ -3580,7 +3594,7 @@ namespace libtorrent
debug_log("peer name lookup error: %s", e.message().c_str());
#endif
if (e || host_list.empty() || m_ses.is_aborted()) return;
if (e || m_abort || host_list.empty() || m_ses.is_aborted()) return;
// TODO: add one peer per IP the hostname resolves to
tcp::endpoint host(host_list.front(), port);
@ -3926,6 +3940,8 @@ namespace libtorrent
dec_refcount("verify_piece");
if (m_abort) return;
int ret = j->ret;
if (settings().get_bool(settings_pack::disable_hash_checks))
{
@ -4788,6 +4804,9 @@ namespace libtorrent
// seeded by any peer
TORRENT_ASSERT(m_super_seeding);
if (!need_loaded())
return -1;
// do a linear search from the first piece
int min_availability = 9999;
std::vector<int> avail_vec;
@ -4820,6 +4839,7 @@ namespace libtorrent
avail_vec.push_back(i);
}
if (avail_vec.empty()) return -1;
return avail_vec[random() % avail_vec.size()];
}
@ -9150,10 +9170,11 @@ namespace libtorrent
set_need_save_resume();
}
set_allow_peers(false, graceful);
int const flags = graceful ? flag_graceful_pause : 0;
set_allow_peers(false, flags | flag_clear_disk_cache);
}
void torrent::do_pause()
void torrent::do_pause(bool const clear_disk_cache)
{
TORRENT_ASSERT(is_single_thread());
if (!is_paused()) return;
@ -9217,7 +9238,7 @@ namespace libtorrent
{
// this will make the storage close all
// files and flush all cached data
if (m_storage.get())
if (m_storage.get() && clear_disk_cache)
{
TORRENT_ASSERT(m_storage);
m_ses.disk_thread().async_stop_torrent(m_storage.get()
@ -9317,7 +9338,7 @@ namespace libtorrent
set_need_save_resume();
}
void torrent::set_allow_peers(bool b, bool graceful)
void torrent::set_allow_peers(bool b, int flags)
{
TORRENT_ASSERT(is_single_thread());
@ -9327,7 +9348,7 @@ namespace libtorrent
// if there are no peers, we must not enter graceful pause mode, and post
// the torrent_paused_alert immediately instead.
if (m_connections.empty())
graceful = false;
flags &= ~flag_graceful_pause;
if (m_allow_peers == b)
{
@ -9336,9 +9357,9 @@ namespace libtorrent
// paused mode, we need to actually pause the torrent properly
if (m_allow_peers == false
&& m_graceful_pause_mode == true
&& graceful == false)
&& (flags & flag_graceful_pause) == 0)
{
m_graceful_pause_mode = graceful;
m_graceful_pause_mode = false;
update_gauge();
do_pause();
}
@ -9347,7 +9368,7 @@ namespace libtorrent
m_allow_peers = b;
if (!m_ses.is_paused())
m_graceful_pause_mode = graceful;
m_graceful_pause_mode = (flags & flag_graceful_pause) ? true : false;
if (!b)
{
@ -9364,7 +9385,7 @@ namespace libtorrent
if (!b)
{
do_pause();
do_pause(flags & flag_clear_disk_cache);
}
else
{
@ -10016,6 +10037,7 @@ namespace libtorrent
update_want_peers();
}
// TODO: 2 this should probably be removed
void torrent::refresh_explicit_cache(int cache_size)
{
TORRENT_ASSERT(is_single_thread());

View File

@ -923,8 +923,11 @@ int utp_stream::read_buffer_size() const
void utp_stream::on_close_reason(void* self, boost::uint16_t close_reason)
{
utp_stream* s = static_cast<utp_stream*>(self);
TORRENT_ASSERT(s->m_impl);
s->m_incoming_close_reason = close_reason;
// it's possible the socket has been unlinked already, in which case m_impl
// will be NULL
if (s->m_impl)
s->m_incoming_close_reason = close_reason;
}
void utp_stream::on_read(void* self, size_t bytes_transferred

View File

@ -154,6 +154,7 @@ test-suite libtorrent :
test_linked_list.cpp
test_file_progress.cpp ]
[ run test_receive_buffer.cpp ]
[ run test_alert_manager.cpp ]
[ run test_direct_dht.cpp ]
[ run test_magnet.cpp ]
@ -194,8 +195,8 @@ test-suite libtorrent :
[ run test_priority.cpp ]
# turn these tests into simulations
# [ run test_upnp.cpp ]
# [ run test_lsd.cpp ]
[ run test_upnp.cpp ]
[ run test_lsd.cpp ]
;
# these are the tests run on appveyor, while the flapping ones are being

View File

@ -18,6 +18,7 @@ test_programs = \
test_pe_crypto \
test_pex \
test_read_piece \
test_receive_buffer \
test_resume \
test_read_resume \
test_ssl \

View File

@ -94,7 +94,7 @@ void test_checking(int flags = read_only_files)
create_directory(combine_path("tmp1_checking", "test_torrent_dir"), ec);
if (ec) fprintf(stderr, "ERROR: creating directory test_torrent_dir: (%d) %s\n"
, ec.value(), ec.message().c_str());
file_storage fs;
std::srand(10);
int piece_size = 0x4000;

View File

@ -0,0 +1,255 @@
/*
Copyright (c) 2016, Arvid Norberg
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the distribution.
* Neither the name of the author nor the names of its
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#include "libtorrent/config.hpp"
#include "test.hpp"
#include "libtorrent/receive_buffer.hpp"
using namespace libtorrent;
struct allocator : buffer_allocator_interface
{
void free_disk_buffer(char*) {}
char* allocate_disk_buffer(char const*) { TORRENT_ASSERT(false); return NULL; }
char* allocate_disk_buffer(bool&
, boost::shared_ptr<disk_observer>
, char const*) { TORRENT_ASSERT(false); return NULL; }
char* async_allocate_disk_buffer(char const*
, boost::function<void(char*)> const&) { TORRENT_ASSERT(false); return NULL; }
void reclaim_block(block_cache_reference ref) {}
};
TORRENT_TEST(recv_buffer_init)
{
allocator a;
receive_buffer b(a);
b.cut(0, 10);
TEST_EQUAL(b.packet_size(), 10);
TEST_EQUAL(b.packet_bytes_remaining(), 10);
TEST_EQUAL(b.packet_finished(), false);
TEST_EQUAL(b.pos(), 0);
TEST_EQUAL(b.capacity(), 0);
}
TORRENT_TEST(recv_buffer_pos_at_end_false)
{
allocator a;
receive_buffer b(a);
b.cut(0, 1000);
// allocate some space to receive into
boost::array<boost::asio::mutable_buffer, 2> vec;
int num_bufs = b.reserve(vec, 1000);
// since we don't have a disk buffer, there should only be a single
// range/buffer
TEST_EQUAL(num_bufs, 1);
b.received(1000);
b.advance_pos(999);
TEST_EQUAL(b.pos_at_end(), false);
}
TORRENT_TEST(recv_buffer_pos_at_end_true)
{
allocator a;
receive_buffer b(a);
b.cut(0, 1000);
b.reserve(1000);
boost::array<boost::asio::mutable_buffer, 2> vec;
int num_bufs = b.reserve(vec, 1000);
TEST_EQUAL(num_bufs, 1);
b.received(1000);
b.advance_pos(1000);
TEST_EQUAL(b.pos_at_end(), true);
}
TORRENT_TEST(recv_buffer_packet_finished)
{
allocator a;
receive_buffer b(a);
// packet_size = 10
b.cut(0, 10);
b.reserve(1000);
boost::array<boost::asio::mutable_buffer, 2> vec;
int num_bufs = b.reserve(vec, 1000);
TEST_EQUAL(num_bufs, 1);
b.received(1000);
for (int i = 0; i < 10; ++i)
{
TEST_EQUAL(b.packet_finished(), false);
b.advance_pos(1);
}
TEST_EQUAL(b.packet_finished(), true);
}
TORRENT_TEST(recv_buffer_disk_buffer)
{
char disk_buffer; // fake disk buffer pointer
allocator a;
receive_buffer b(a);
b.reserve(1000);
b.cut(0, 1000); // packet size = 1000
boost::array<boost::asio::mutable_buffer, 2> vec;
b.assign_disk_buffer(&disk_buffer, 137);
int num_bufs = b.reserve(vec, 1000);
TEST_EQUAL(num_bufs, 2);
// regular buffer disk buffer
// -----------------======
//
// |----------------------| 1000
// |-----| 137
// |----------------| 863
TEST_EQUAL(boost::asio::buffer_size(vec[0]), 863);
TEST_EQUAL(boost::asio::buffer_size(vec[1]), 137);
}
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
TORRENT_TEST(recv_buffer_mutable_buffers_regular_and_disk)
{
char disk_buffer; // fake disk buffer pointer
allocator a;
receive_buffer b(a);
b.reserve(1100);
b.cut(0, 100); // packet size = 100
b.received(1100);
int packet_transferred = b.advance_pos(1100);
// this is just the first packet
TEST_EQUAL(packet_transferred, 100);
// the next packet is 1000, and we're done with the first 100 bytes now
b.cut(100, 1000); // packet size = 1000
// and it has a disk buffer
b.assign_disk_buffer(&disk_buffer, 137);
std::vector<boost::asio::mutable_buffer> vec;
packet_transferred = b.advance_pos(999);
TEST_EQUAL(packet_transferred, 999);
b.mutable_buffers(vec, 999);
TEST_EQUAL(vec.size(), 2);
// previous packet
// |
// v regular buffer disk buffer
// - - - -----------------======
// ^
// |
// m_recv_start
// |----------------------| 1000 packet size
// |-----| 137 disk buffer
// |----------------| 863 regular buffer
TEST_EQUAL(boost::asio::buffer_size(vec[0]), 863);
TEST_EQUAL(boost::asio::buffer_size(vec[1]), 137 - 1);
TEST_EQUAL(boost::asio::buffer_size(vec[0])
+ boost::asio::buffer_size(vec[1]), 999);
}
TORRENT_TEST(recv_buffer_mutable_buffers_regular_only)
{
allocator a;
receive_buffer b(a);
b.reserve(1100);
b.cut(0, 100); // packet size = 100
b.received(1100);
int packet_transferred = b.advance_pos(1100);
// this is just the first packet
TEST_EQUAL(packet_transferred, 100);
// the next packet is 1000, and we're done with the first 100 bytes now
b.cut(100, 1000); // packet size = 1000
std::vector<boost::asio::mutable_buffer> vec;
packet_transferred = b.advance_pos(999);
TEST_EQUAL(packet_transferred, 999);
b.mutable_buffers(vec, 999);
TEST_EQUAL(vec.size(), 1);
// previous packet
// |
// v regular buffer
// - - - -----------------------
// ^
// |
// m_recv_start
// |----------------------| 1000 packet size
// |---------------------| 999 regular buffer
TEST_EQUAL(boost::asio::buffer_size(vec[0]), 999);
}
TORRENT_TEST(recv_buffer_mutable_buffers_disk)
{
char disk_buffer; // fake disk buffer pointer
allocator a;
receive_buffer b(a);
b.reserve(1100);
b.cut(0, 100); // packet size = 100
b.received(1100);
int packet_transferred = b.advance_pos(1100);
// this is just the first packet
TEST_EQUAL(packet_transferred, 100);
// the next packet is 1000, and we're done with the first 100 bytes now
b.cut(100, 1000); // packet size = 1000
// and it has a disk buffer
b.assign_disk_buffer(&disk_buffer, 1000);
std::vector<boost::asio::mutable_buffer> vec;
packet_transferred = b.advance_pos(999);
TEST_EQUAL(packet_transferred, 999);
b.mutable_buffers(vec, 999);
TEST_EQUAL(vec.size(), 1);
// previous packet
// |
// v disk buffer
// - - - =======================
// ^
// |
// m_recv_start
// |----------------------| 1000 packet size
// |----------------------| 999 disk buffer
TEST_EQUAL(boost::asio::buffer_size(vec[0]), 999);
TEST_EQUAL(boost::asio::buffer_cast<char*>(vec[0]), &disk_buffer);
}
#endif

View File

@ -55,12 +55,20 @@ const int mask = alert::all_categories & ~(alert::performance_warning | alert::s
void wait_for_complete(lt::session& ses, torrent_handle h)
{
for (int i = 0; i < 70; ++i)
int last_progress = 0;
clock_type::time_point last_change = clock_type::now();
for (int i = 0; i < 400; ++i)
{
print_alerts(ses, "ses1");
torrent_status st = h.status();
fprintf(stderr, "%f %%\n", st.progress_ppm / 10000.f);
if (st.progress_ppm == 1000000) return;
if (st.progress_ppm != last_progress)
{
last_progress = st.progress_ppm;
last_change = clock_type::now();
}
if (clock_type::now() - last_change > seconds(10)) break;
test_sleep(500);
}
TEST_ERROR("torrent did not finish");
@ -107,3 +115,4 @@ TORRENT_TEST(recheck)
TEST_CHECK(st1.progress_ppm <= 1000000);
wait_for_complete(ses1, tor1);
}

View File

@ -38,6 +38,8 @@ POSSIBILITY OF SUCH DAMAGE.
#include "libtorrent/alert_types.hpp"
#include "libtorrent/session_stats.hpp"
#include "libtorrent/performance_counters.hpp"
#include "libtorrent/bdecode.hpp"
#include "libtorrent/bencode.hpp"
using namespace libtorrent;
namespace lt = libtorrent;
@ -105,4 +107,107 @@ TORRENT_TEST(session_stats)
TEST_EQUAL(stats[i].value_index, i);
}
}
#if __cplusplus >= 201103L
template <typename Set, typename Save, typename Default, typename Load>
void test_save_restore(Set setup, Save s, Default d, Load l)
{
entry st;
{
settings_pack p;
setup(p);
lt::session ses(p);
s(ses, st);
}
{
settings_pack p;
d(p);
lt::session ses(p);
// the loading function takes a bdecode_node, so we have to transform the
// entry
printf("%s\n", st.to_string().c_str());
std::vector<char> buf;
bencode(std::back_inserter(buf), st);
bdecode_node state;
error_code ec;
int ret = bdecode(buf.data(), buf.data() + buf.size()
, state, ec, nullptr, 100, 1000);
TEST_EQUAL(ret, 0);
if (ec)
{
printf("bdecode: %s\n", ec.message().c_str());
printf("%s\n", std::string(buf.data(), buf.size()).c_str());
}
TEST_CHECK(!ec);
l(ses, state);
}
}
TORRENT_TEST(save_restore_state)
{
test_save_restore(
[](settings_pack& p) {
// set the cache size
p.set_int(settings_pack::cache_size, 1337);
},
[](lt::session& ses, entry& st) {
ses.save_state(st);
},
[](settings_pack& p) {
p.set_int(settings_pack::cache_size, 90);
},
[](lt::session& ses, bdecode_node& st) {
ses.load_state(st);
// make sure we loaded the cache size correctly
settings_pack sett = ses.get_settings();
TEST_EQUAL(sett.get_int(settings_pack::cache_size), 1337);
});
}
TORRENT_TEST(save_restore_state_save_filter)
{
test_save_restore(
[](settings_pack& p) {
// set the cache size
p.set_int(settings_pack::cache_size, 1337);
},
[](lt::session& ses, entry& st) {
// save everything _but_ the settings
ses.save_state(st, ~session::save_settings);
},
[](settings_pack& p) {
p.set_int(settings_pack::cache_size, 90);
},
[](lt::session& ses, bdecode_node& st) {
ses.load_state(st);
// make sure whatever we loaded did not include the cache size
settings_pack sett = ses.get_settings();
TEST_EQUAL(sett.get_int(settings_pack::cache_size), 90);
});
}
TORRENT_TEST(save_restore_state_load_filter)
{
test_save_restore(
[](settings_pack& p) {
// set the cache size
p.set_int(settings_pack::cache_size, 1337);
},
[](lt::session& ses, entry& st) {
// save everything
ses.save_state(st);
},
[](settings_pack& p) {
p.set_int(settings_pack::cache_size, 90);
},
[](lt::session& ses, bdecode_node& st) {
// load everything _but_ the settings
ses.load_state(st, ~session::save_settings);
settings_pack sett = ses.get_settings();
TEST_EQUAL(sett.get_int(settings_pack::cache_size), 90);
});
}
#endif

View File

@ -119,12 +119,12 @@ struct callback_info
std::list<callback_info> callbacks;
void callback(int mapping, address const& ip, int port, error_code const& err)
void callback(int mapping, address const& ip, int port, int protocol, error_code const& err)
{
callback_info info = {mapping, port, err};
callbacks.push_back(info);
std::cerr << "mapping: " << mapping << ", port: " << port << ", IP: " << ip
<< ", error: \"" << err.message() << "\"\n";
<< ", proto: " << protocol << ", error: \"" << err.message() << "\"\n";
}
void run_upnp_test(char const* root_filename, char const* router_model, char const* control_name, int igd_version)
@ -160,7 +160,6 @@ void run_upnp_test(char const* root_filename, char const* router_model, char con
std::string user_agent = "test agent";
boost::shared_ptr<upnp> upnp_handler = boost::make_shared<upnp>(boost::ref(ios)
, address_v4::from_string("127.0.0.1")
, user_agent, &callback, &log_callback, false);
upnp_handler->start();
upnp_handler->discover_device();