mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-10-05 05:39:22 +00:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f6ea7b326f | |||
| 4492474f7e | |||
| 3af0410a6e | |||
| 3c94b03323 | |||
| c5d54fbb97 | |||
| 44d51171e1 | |||
| dc916278c2 | |||
| 366b936ded | |||
| 8bcc4c6e92 | |||
| 5421a35349 | |||
| d5ce0984fc | |||
| a89ce3cd7b | |||
| d98a441dc4 | |||
| fc6e57c3fa | |||
| 8e23ba8b17 | |||
| e656801cfa | |||
| 9f6fd7994e | |||
| bb77aa644c |
@@ -17,7 +17,6 @@ libsub_root_a_SOURCES = \
|
||||
core/http_queue.h \
|
||||
core/manager.cc \
|
||||
core/manager.h \
|
||||
core/range_map.h \
|
||||
core/view.cc \
|
||||
core/view.h \
|
||||
core/view_manager.cc \
|
||||
@@ -171,7 +170,6 @@ libsub_root_a_SOURCES = \
|
||||
utils/functional.h \
|
||||
utils/gzip.cc \
|
||||
utils/gzip.h \
|
||||
utils/list_focus.h \
|
||||
utils/lockfile.cc \
|
||||
utils/lockfile.h \
|
||||
utils/waitpid_queue.cc \
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
|
||||
#include <torrent/download/resource_manager.h>
|
||||
@@ -232,6 +233,9 @@ apply_cg_max_set(const torrent::Object::list_type& args, bool is_up) {
|
||||
int64_t second_arg = 0;
|
||||
rpc::parse_whole_value(args.back().as_string().c_str(), &second_arg);
|
||||
|
||||
if (second_arg < -1 || second_arg > std::numeric_limits<uint32_t>::max())
|
||||
throw torrent::input_error("Max unchoked must be between -1 and 4294967295.");
|
||||
|
||||
if (is_up)
|
||||
cg_get_group(args.front())->up_queue()->set_max_unchoked(second_arg);
|
||||
else
|
||||
|
||||
@@ -1,12 +1,25 @@
|
||||
#ifndef RTORRENT_UTILS_COMMAND_HELPERS_H
|
||||
#define RTORRENT_UTILS_COMMAND_HELPERS_H
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <torrent/exceptions.h>
|
||||
|
||||
#include "rpc/command.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
#include "rpc/object_storage.h"
|
||||
|
||||
void initialize_commands();
|
||||
|
||||
inline uint16_t
|
||||
checked_port_value(int64_t value, const char* label) {
|
||||
if (value < 0 || value > std::numeric_limits<uint16_t>::max())
|
||||
throw torrent::input_error(std::string("Invalid ") + label + " port number.");
|
||||
|
||||
return static_cast<uint16_t>(value);
|
||||
}
|
||||
|
||||
//
|
||||
// Aliases with CMD_* for the below
|
||||
//
|
||||
|
||||
@@ -77,54 +77,6 @@ group_insert(const torrent::Object::list_type& args) {
|
||||
return name;
|
||||
}
|
||||
|
||||
static const int file_print_use_space = 0x1;
|
||||
static const int file_print_delim_space = 0x2;
|
||||
|
||||
void
|
||||
file_print_list(torrent::Object::list_const_iterator first, torrent::Object::list_const_iterator last, FILE* output, int flags) {
|
||||
while (first != last) {
|
||||
switch (first->type()) {
|
||||
case torrent::Object::TYPE_STRING:
|
||||
fprintf(output, (const char*)" %s" + !(flags & file_print_use_space), first->as_string().c_str());
|
||||
break;
|
||||
case torrent::Object::TYPE_VALUE:
|
||||
fprintf(output, (const char*)" %" PRIi64 + !(flags & file_print_use_space), first->as_value());
|
||||
break;
|
||||
case torrent::Object::TYPE_LIST:
|
||||
file_print_list(first->as_list().begin(), first->as_list().end(), output, 0);
|
||||
break;
|
||||
case torrent::Object::TYPE_NONE:
|
||||
break;
|
||||
default:
|
||||
throw torrent::input_error("Invalid type.");
|
||||
}
|
||||
|
||||
flags |= (flags & file_print_delim_space) >> 1;
|
||||
first++;
|
||||
}
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
cmd_file_append(const torrent::Object::list_type& args) {
|
||||
if (args.empty())
|
||||
throw torrent::input_error("Invalid number of arguments.");
|
||||
|
||||
FILE* output = fopen(args.front().as_string().c_str(), "a");
|
||||
|
||||
if (output == nullptr)
|
||||
throw torrent::input_error("Could not append to file '" + args.front().as_string() + "': " + std::strerror(errno));
|
||||
|
||||
try {
|
||||
file_print_list(++args.begin(), args.end(), output, file_print_delim_space);
|
||||
fprintf(output, "\n");
|
||||
} catch (...) {
|
||||
fclose(output);
|
||||
throw;
|
||||
}
|
||||
fclose(output);
|
||||
return torrent::Object();
|
||||
}
|
||||
|
||||
void
|
||||
initialize_command_local() {
|
||||
core::DownloadList* dList = control->core()->download_list();
|
||||
|
||||
+4
-12
@@ -54,14 +54,6 @@ set_listen_port_range(const std::string& arg) {
|
||||
torrent::runtime::client_config()->set_listen_port_range(port_first, port_last);
|
||||
}
|
||||
|
||||
uint16_t
|
||||
checked_local_port_value(int64_t value, const char* label) {
|
||||
if (value < 0 || value > 65535)
|
||||
throw torrent::input_error(std::string("Invalid ") + label + " port number.");
|
||||
|
||||
return static_cast<uint16_t>(value);
|
||||
}
|
||||
|
||||
torrent::Object
|
||||
get_encryption() {
|
||||
auto encryption_modes = torrent::runtime::network_config()->encryption_modes();
|
||||
@@ -325,7 +317,7 @@ initialize_command_network() {
|
||||
auto nw_config = torrent::runtime::network_config();
|
||||
|
||||
CMD_ANY ("network.listen.port", [](auto, auto) { return torrent::runtime::network_manager()->listen_port(); });
|
||||
CMD_ANY_VALUE_V ("network.listen.port.set", [](auto, auto& value) { return torrent::runtime::network_manager()->set_listen_port(value); });
|
||||
CMD_ANY_VALUE_V ("network.listen.port.set", [](auto, auto& value) { return torrent::runtime::network_manager()->set_listen_port(checked_port_value(value, "listen")); });
|
||||
CMD_ANY ("network.listen.port.random", [](auto, auto) { return torrent::runtime::client_config()->listen_port_random(); });
|
||||
CMD_ANY_VALUE_V ("network.listen.port.random.set", [](auto, auto& value) { return torrent::runtime::client_config()->set_listen_port_random(value); });
|
||||
CMD_ANY ("network.listen.port.range", [](auto, auto) { return listen_port_range(); });
|
||||
@@ -394,11 +386,11 @@ initialize_command_network() {
|
||||
CMD_ANY_STRING_V("network.local_address.ipv6.set", [nw_config](auto, auto& str) { return nw_config->set_local_inet6_address(str); });
|
||||
|
||||
CMD_ANY ("network.local_port", [nw_config](auto, auto) { return nw_config->local_port_best_match(); });
|
||||
CMD_ANY_VALUE_V ("network.local_port.set", [nw_config](auto, auto& value) { return nw_config->set_local_port(checked_local_port_value(value, "local")); });
|
||||
CMD_ANY_VALUE_V ("network.local_port.set", [nw_config](auto, auto& value) { return nw_config->set_local_port(checked_port_value(value, "local")); });
|
||||
CMD_ANY ("network.local_port.ipv4", [nw_config](auto, auto) { return nw_config->local_inet_port(); });
|
||||
CMD_ANY_VALUE_V ("network.local_port.ipv4.set", [nw_config](auto, auto& value) { return nw_config->set_local_inet_port(checked_local_port_value(value, "local ipv4")); });
|
||||
CMD_ANY_VALUE_V ("network.local_port.ipv4.set", [nw_config](auto, auto& value) { return nw_config->set_local_inet_port(checked_port_value(value, "local ipv4")); });
|
||||
CMD_ANY ("network.local_port.ipv6", [nw_config](auto, auto) { return nw_config->local_inet6_port(); });
|
||||
CMD_ANY_VALUE_V ("network.local_port.ipv6.set", [nw_config](auto, auto& value) { return nw_config->set_local_inet6_port(checked_local_port_value(value, "local ipv6")); });
|
||||
CMD_ANY_VALUE_V ("network.local_port.ipv6.set", [nw_config](auto, auto& value) { return nw_config->set_local_inet6_port(checked_port_value(value, "local ipv6")); });
|
||||
|
||||
CMD_ANY ("network.proxy.global", [](auto, auto) { return torrent::runtime::proxy_manager()->proxy_url(); });
|
||||
CMD_ANY_STRING_V("network.proxy.global.set", [](auto, auto& str) { return torrent::runtime::proxy_manager()->set_proxy_url(str); });
|
||||
|
||||
@@ -28,9 +28,10 @@ cmd_scheduler_simple_removed(core::Download* download) {
|
||||
control->core()->download_list()->pause(download);
|
||||
|
||||
core::View* viewActive = *control->view_manager()->find("active");
|
||||
unsigned int numActive = viewActive->size_visible();
|
||||
int64_t maxActive = rpc::call_command("scheduler.max_active", torrent::Object()).as_value();
|
||||
|
||||
if ((int64_t)viewActive->size_visible() >= maxActive)
|
||||
if ((int64_t)numActive >= maxActive)
|
||||
return torrent::Object();
|
||||
|
||||
// The 'started' view contains all the views we may choose amongst.
|
||||
@@ -41,6 +42,9 @@ cmd_scheduler_simple_removed(core::Download* download) {
|
||||
continue;
|
||||
|
||||
control->core()->download_list()->resume(*itr);
|
||||
|
||||
if ((int64_t)++numActive >= maxActive)
|
||||
break;
|
||||
}
|
||||
|
||||
return torrent::Object();
|
||||
|
||||
@@ -167,6 +167,7 @@ initialize_command_system() {
|
||||
rpc::rpc.mark_safe("system.time");
|
||||
rpc::rpc.mark_safe("system.time_seconds");
|
||||
rpc::rpc.mark_safe("system.time_usec");
|
||||
rpc::rpc.mark_safe("system.file.allocate");
|
||||
rpc::rpc.mark_safe("system.file.max_size");
|
||||
rpc::rpc.mark_safe("system.file.split_size");
|
||||
rpc::rpc.mark_safe("system.file.split_suffix");
|
||||
|
||||
@@ -142,7 +142,7 @@ initialize_command_tracker() {
|
||||
lt_log_print(torrent::LOG_DHT_ERROR, "dht.port.set is no longer supported, use dht.override_port.set", 0);
|
||||
});
|
||||
CMD2_ANY ("dht.override_port", [](auto, auto) { return torrent::runtime::network_config()->override_dht_port(); });
|
||||
CMD2_ANY_VALUE_V ("dht.override_port.set", [](auto, auto& value) { return torrent::runtime::network_manager()->set_dht_port(value); });
|
||||
CMD2_ANY_VALUE_V ("dht.override_port.set", [](auto, auto& value) { return torrent::runtime::network_manager()->set_dht_port(checked_port_value(value, "DHT override")); });
|
||||
|
||||
CMD2_ANY_STRING ("dht.add_node", [](auto, auto& str) { return apply_dht_add_node(str); });
|
||||
CMD2_ANY ("dht.statistics", [](auto, auto) { return control->dht_manager()->dht_statistics(); });
|
||||
|
||||
@@ -82,7 +82,7 @@ DownloadList::find(const torrent::HashString& hash) {
|
||||
|
||||
DownloadList::iterator
|
||||
DownloadList::find_hex(const char* hash) {
|
||||
if (strlen(hash) < 40)
|
||||
if (strlen(hash) != 40)
|
||||
return end();
|
||||
|
||||
torrent::HashString key;
|
||||
@@ -709,6 +709,10 @@ DownloadList::confirm_finished(Download* download) {
|
||||
if (choke_up.is_string_empty()) choke_up = rpc::call_command("protocol.choke_heuristics.up.seed", torrent::Object(), rpc::make_target(download));
|
||||
if (choke_down.is_string_empty()) choke_down = rpc::call_command("protocol.choke_heuristics.down.seed", torrent::Object(), rpc::make_target(download));
|
||||
|
||||
// libtorrent refuses initial seeding on an active download.
|
||||
if (download->is_active() && conn_current.as_string() == "initial_seed")
|
||||
conn_current = "seed";
|
||||
|
||||
rpc::call_command("d.connection_current.set", conn_current, rpc::make_target(download));
|
||||
rpc::call_command("d.up.choke_heuristics.set", choke_up, rpc::make_target(download));
|
||||
rpc::call_command("d.down.choke_heuristics.set", choke_down, rpc::make_target(download));
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <torrent/object.h>
|
||||
|
||||
#include "download_list.h"
|
||||
#include "range_map.h"
|
||||
|
||||
namespace torrent {
|
||||
class Bencode;
|
||||
|
||||
@@ -1,199 +0,0 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2008, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <sundell.software@gmail.com>
|
||||
|
||||
|
||||
#ifndef RTORRENT_CORE_RANGE_MAP_H
|
||||
#define RTORRENT_CORE_RANGE_MAP_H
|
||||
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace core {
|
||||
|
||||
// Associate values with a range of keys, and retrieve for any key in the range.
|
||||
|
||||
// The template arguments have the same semantics as std::map.
|
||||
// Exception: if set_merge is used, the value type must have a defined operator ==.
|
||||
template<typename Key, typename T, typename Compare = std::less<Key>,
|
||||
typename Alloc = std::allocator<std::pair<const Key, T> > >
|
||||
class RangeMap : private std::map<Key, std::pair<Key, T>, Compare,
|
||||
typename std::allocator_traits<Alloc>::template rebind_alloc<std::pair<const Key, std::pair<Key, T>>>> {
|
||||
|
||||
typedef std::map<Key, std::pair<Key, T>, Compare,
|
||||
typename std::allocator_traits<Alloc>::template rebind_alloc<std::pair<const Key, std::pair<Key, T>>>> base_type;
|
||||
|
||||
//std::allocator_traits<Alloc>::template rebind_alloc<std::pair<const Key, std::pair<Key, T>>>
|
||||
|
||||
public:
|
||||
RangeMap() = default;
|
||||
RangeMap(const Compare& c) : base_type(c) {}
|
||||
|
||||
typedef typename base_type::iterator iterator;
|
||||
typedef typename base_type::reverse_iterator reverse_iterator;
|
||||
typedef typename base_type::const_iterator const_iterator;
|
||||
typedef typename base_type::const_reverse_iterator const_reverse_iterator;
|
||||
|
||||
// using typename base_type::const_iterator;
|
||||
// using typename base_type::const_reverse_iterator;
|
||||
|
||||
using base_type::clear;
|
||||
using base_type::swap;
|
||||
|
||||
using base_type::size;
|
||||
using base_type::empty;
|
||||
|
||||
using base_type::begin;
|
||||
using base_type::end;
|
||||
using base_type::rbegin;
|
||||
using base_type::rend;
|
||||
|
||||
using base_type::key_comp;
|
||||
using base_type::value_comp;
|
||||
|
||||
// Store a value for the range [begin, end). Returns iterator for the range.
|
||||
const_iterator set_range(const Key& begin, const Key& end, const T& value);
|
||||
|
||||
// Same, but merge adjacent ranges having the same value. Returns iterator for the merged range.
|
||||
const_iterator set_merge(Key begin, const Key& end, const T& value);
|
||||
|
||||
// Find range containing the given key, or end().
|
||||
const_iterator find(const Key& key) const;
|
||||
|
||||
// Retrieve value for key in a range, throw std::out_of_range if range does not exist.
|
||||
const T& get(const Key& key) const;
|
||||
|
||||
// Retrieve value for key in a range, return def if range does not exist.
|
||||
T get(const Key& key, T def) const;
|
||||
|
||||
private:
|
||||
iterator crop_overlap(const Key& begin, const Key& end);
|
||||
};
|
||||
|
||||
// Semantics of an entry:
|
||||
// .first End of range (exclusive), map key.
|
||||
// .second.first Beginning of range.
|
||||
// .second.second Value.
|
||||
|
||||
template<typename Key, typename T, typename C, typename A>
|
||||
inline typename RangeMap<Key,T,C,A>::iterator
|
||||
RangeMap<Key,T,C,A>::crop_overlap(const Key& _begin, const Key& _end) {
|
||||
typename RangeMap::iterator itr = base_type::upper_bound(_begin);
|
||||
|
||||
while (itr != end() && key_comp()(itr->second.first, _end)) {
|
||||
// There's a subrange before the new begin: need new entry (new range end means new key).
|
||||
if (key_comp()(itr->second.first, _begin))
|
||||
base_type::insert(itr, typename RangeMap::value_type(_begin, itr->second));
|
||||
|
||||
// Old end is within our range: erase entry.
|
||||
if (!key_comp()(_end, itr->first)) {
|
||||
base_type::erase(itr++);
|
||||
|
||||
// Otherwise simply set the new begin of the old range.
|
||||
} else {
|
||||
itr->second.first = _end;
|
||||
++itr;
|
||||
}
|
||||
}
|
||||
|
||||
return itr;
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename C, typename A>
|
||||
inline typename RangeMap<Key,T,C,A>::const_iterator
|
||||
RangeMap<Key,T,C,A>::set_merge(Key _begin, const Key& _end, const T& value) {
|
||||
if (!key_comp()(_begin, _end))
|
||||
return end();
|
||||
|
||||
// Crop overlapping ranges and return iterator to first range after the one we're inserting.
|
||||
typename RangeMap::iterator itr = crop_overlap(_begin, _end);
|
||||
|
||||
// Check if range before new one is adjacent and has same value: if so erase it and use its beginning.
|
||||
if (itr != begin()) {
|
||||
typename RangeMap::iterator prev = itr;
|
||||
if (!key_comp()((--prev)->first, _begin) && prev->second.second == value) {
|
||||
_begin = prev->second.first;
|
||||
base_type::erase(prev);
|
||||
}
|
||||
}
|
||||
|
||||
// Range after new one is adjacent and has same value: set new beginning.
|
||||
if (itr != end() && !key_comp()(_end, itr->second.first) && itr->second.second == value) {
|
||||
itr->second.first = _begin;
|
||||
return itr;
|
||||
}
|
||||
|
||||
// Otherwise, this range isn't mergeable, make new entry.
|
||||
return base_type::insert(itr, typename RangeMap::value_type(_end, typename RangeMap::mapped_type(_begin, value)));
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename C, typename A>
|
||||
inline typename RangeMap<Key,T,C,A>::const_iterator
|
||||
RangeMap<Key,T,C,A>::set_range(const Key& _begin, const Key& _end, const T& value) {
|
||||
if (!key_comp()(_begin, _end))
|
||||
return end();
|
||||
|
||||
return base_type::insert(crop_overlap(_begin, _end), typename RangeMap::value_type(_end, typename RangeMap::mapped_type(_begin, value)));
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename C, typename A>
|
||||
inline typename RangeMap<Key,T,C,A>::const_iterator
|
||||
RangeMap<Key,T,C,A>::find(const Key& key) const {
|
||||
typename RangeMap::const_iterator itr = base_type::upper_bound(key);
|
||||
|
||||
if (itr != end() && key_comp()(key, itr->second.first))
|
||||
itr = end();
|
||||
|
||||
return itr;
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename C, typename A>
|
||||
inline const T&
|
||||
RangeMap<Key,T,C,A>::get(const Key& key) const {
|
||||
typename RangeMap::const_iterator itr = find(key);
|
||||
|
||||
if (itr == end())
|
||||
throw std::out_of_range("RangeMap::get");
|
||||
|
||||
return itr->second.second;
|
||||
}
|
||||
|
||||
template<typename Key, typename T, typename C, typename A>
|
||||
inline T
|
||||
RangeMap<Key,T,C,A>::get(const Key& key, T def) const {
|
||||
typename RangeMap::const_iterator itr = find(key);
|
||||
return (itr == end() ? def : itr->second.second);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -16,15 +16,12 @@ namespace utils {
|
||||
|
||||
namespace torrent {
|
||||
class ClientInfo;
|
||||
class Entry;
|
||||
}
|
||||
|
||||
class Control;
|
||||
|
||||
namespace display {
|
||||
|
||||
char* print_string(char* first, char* last, char* str);
|
||||
|
||||
char* print_hhmmss(char* first, char* last, time_t t);
|
||||
char* print_hhmmss_local(char* first, char* last, time_t t);
|
||||
char* print_ddhhmm(char* first, char* last, time_t t);
|
||||
@@ -42,9 +39,6 @@ char* print_download_percentage_done(char* first, char* last, core::Downlo
|
||||
|
||||
char* print_client_version(char* first, char* last, const torrent::ClientInfo& clientInfo);
|
||||
|
||||
char* print_entry_tags(char* first, char* last);
|
||||
char* print_entry_file(char* first, char* last, const torrent::Entry& entry);
|
||||
|
||||
char* print_status_throttle_limit(char* first, char* last, bool up, const std::vector<std::string>& throttle_names);
|
||||
char* print_status_throttle_rate(char* first, char* last, bool up, const std::vector<std::string>& throttle_names, const double& global_rate);
|
||||
|
||||
|
||||
@@ -57,7 +57,8 @@ WindowDownloadChunksSeen::redraw() {
|
||||
const torrent::TransferList* transfers = m_download->download()->transfer_list();
|
||||
std::vector<torrent::BlockList*> transferChunks(transfers->begin(), transfers->end());
|
||||
|
||||
std::sort(transferChunks.begin(), transferChunks.end());
|
||||
std::sort(transferChunks.begin(), transferChunks.end(),
|
||||
[](const auto& left, const auto& right) { return left->index() < right->index(); });
|
||||
|
||||
std::vector<torrent::BlockList*>::const_iterator itrTransfer = transferChunks.begin();
|
||||
|
||||
|
||||
@@ -69,8 +69,6 @@ public:
|
||||
|
||||
bool pressed(int key);
|
||||
|
||||
void ignore(int key) { (*this)[key] = slot_void(); }
|
||||
|
||||
private:
|
||||
bool m_enabled{true};
|
||||
};
|
||||
|
||||
@@ -100,7 +100,7 @@ PathInput::receive_do_complete() {
|
||||
entry.s_name += '/';
|
||||
}
|
||||
|
||||
range_type r = find_incomplete(dir, str().substr(dirEnd, get_pos()));
|
||||
range_type r = find_incomplete(dir, str().substr(dirEnd, get_pos() - dirEnd));
|
||||
|
||||
if (r.first == r.second)
|
||||
return; // Show some nice colors here.
|
||||
|
||||
+4
-2
@@ -492,7 +492,8 @@ main(int argc, char** argv) {
|
||||
control->cleanup();
|
||||
|
||||
} catch (torrent::internal_error& e) {
|
||||
control->cleanup_exception();
|
||||
if (control != nullptr)
|
||||
control->cleanup_exception();
|
||||
|
||||
std::cout << "rtorrent: caught torrent::internal_error: "
|
||||
<< e.what() << std::endl
|
||||
@@ -505,7 +506,8 @@ main(int argc, char** argv) {
|
||||
return -1;
|
||||
|
||||
} catch (std::exception& e) {
|
||||
control->cleanup_exception();
|
||||
if (control != nullptr)
|
||||
control->cleanup_exception();
|
||||
|
||||
std::cout << "rtorrent: caught" << typeid(e).name() << " : " << e.what() << std::endl;
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "rpc/exec_file.h"
|
||||
|
||||
// #include <cassert>
|
||||
@@ -81,8 +83,9 @@ ExecFile::execute_object(const torrent::Object& rawArgs, int flags) {
|
||||
char* argsBuffer[max_args];
|
||||
char** argsCurrent = argsBuffer;
|
||||
|
||||
// Size of value strings are less than 24.
|
||||
char valueBuffer[buffer_size+1];
|
||||
// On the heap: a buffer of buffer_size does not belong on the stack of whichever thread runs the command.
|
||||
auto valueStorage = std::make_unique<char[]>(buffer_size + 1);
|
||||
char* valueBuffer = valueStorage.get();
|
||||
char* valueCurrent = valueBuffer;
|
||||
|
||||
if (rawArgs.is_list()) {
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ namespace rpc {
|
||||
class ExecFile {
|
||||
public:
|
||||
static constexpr unsigned int max_args = 128;
|
||||
static constexpr unsigned int buffer_size = 4096;
|
||||
static constexpr unsigned int buffer_size = 128 * 1024;
|
||||
|
||||
static constexpr int flag_expand_tilde = 0x1;
|
||||
static constexpr int flag_throw = 0x2;
|
||||
|
||||
@@ -394,6 +394,10 @@ execute_lua(LuaEngine* engine, rpc::target_type target_type, torrent::Object con
|
||||
switch (raw_args.type()) {
|
||||
case torrent::Object::TYPE_LIST: {
|
||||
const torrent::Object::list_type& args = raw_args.as_list();
|
||||
|
||||
if (args.empty())
|
||||
throw torrent::input_error("Too few arguments.");
|
||||
|
||||
if (flags & LuaEngine::flag_string) {
|
||||
check_lua_status(l_state, luaL_loadstring(l_state, args.begin()->as_string().c_str()));
|
||||
} else {
|
||||
|
||||
+43
-12
@@ -1,5 +1,7 @@
|
||||
#include "config.h"
|
||||
|
||||
#include <cctype>
|
||||
#include <charconv>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
#include <limits>
|
||||
@@ -113,16 +115,45 @@ parse_value_nothrow(const char* src, int64_t* value, int base, int unit) {
|
||||
if (unit <= 0)
|
||||
throw torrent::input_error("Command::string_to_value_unit(...) received unit <= 0.");
|
||||
|
||||
char* last;
|
||||
if (base != 0 && base != 8 && base != 10 && base != 16)
|
||||
throw torrent::input_error("Command::string_to_value_unit(...) received invalid base.");
|
||||
|
||||
const char* first = src;
|
||||
|
||||
while (parse_is_space(*src))
|
||||
src++;
|
||||
|
||||
if (src[0] == '+')
|
||||
return first;
|
||||
|
||||
if (src[0] == '-') {
|
||||
if (base == 8 || base == 16)
|
||||
return first;
|
||||
|
||||
if (src[1] == '0')
|
||||
return first;
|
||||
}
|
||||
|
||||
if (base == 10 && src[0] == '0' && (src[1] >= '0' && src[1] <= '9'))
|
||||
return first;
|
||||
|
||||
char* last{};
|
||||
|
||||
errno = 0;
|
||||
*value = strtoll(src, &last, base);
|
||||
|
||||
if (errno == ERANGE)
|
||||
return first;
|
||||
|
||||
if (last == src) {
|
||||
if (strcasecmp(src, "no") == 0) { *value = 0; return src + strlen("no"); }
|
||||
if (strcasecmp(src, "yes") == 0) { *value = 1; return src + strlen("yes"); }
|
||||
if (strcasecmp(src, "true") == 0) { *value = 1; return src + strlen("true"); }
|
||||
*value = 0;
|
||||
|
||||
if (strcasecmp(src, "no") == 0) { *value = 0; return src + strlen("no"); }
|
||||
if (strcasecmp(src, "yes") == 0) { *value = 1; return src + strlen("yes"); }
|
||||
if (strcasecmp(src, "true") == 0) { *value = 1; return src + strlen("true"); }
|
||||
if (strcasecmp(src, "false") == 0) { *value = 0; return src + strlen("false"); }
|
||||
|
||||
return src;
|
||||
return first;
|
||||
}
|
||||
|
||||
switch (*last) {
|
||||
@@ -130,15 +161,15 @@ parse_value_nothrow(const char* src, int64_t* value, int base, int unit) {
|
||||
case 'B': ++last; break;
|
||||
case 'k':
|
||||
case 'K':
|
||||
if (!value_fits_shifted(*value, 10)) return src; // overflow guard
|
||||
if (!value_fits_shifted(*value, 10)) return first; // overflow guard
|
||||
*value = *value << 10; ++last; break;
|
||||
case 'm':
|
||||
case 'M':
|
||||
if (!value_fits_shifted(*value, 20)) return src; // overflow guard
|
||||
if (!value_fits_shifted(*value, 20)) return first; // overflow guard
|
||||
*value = *value << 20; ++last; break;
|
||||
case 'g':
|
||||
case 'G':
|
||||
if (!value_fits_shifted(*value, 30)) return src; // overflow guard
|
||||
if (!value_fits_shifted(*value, 30)) return first; // overflow guard
|
||||
*value = *value << 30; ++last; break;
|
||||
// case ' ':
|
||||
// case '\0': *value = *value * unit; break;
|
||||
@@ -146,7 +177,7 @@ parse_value_nothrow(const char* src, int64_t* value, int base, int unit) {
|
||||
default:
|
||||
if (*value > std::numeric_limits<int64_t>::max() / unit ||
|
||||
*value < std::numeric_limits<int64_t>::min() / unit)
|
||||
return src; // overflow guard
|
||||
return first; // overflow guard
|
||||
|
||||
*value = *value * unit;
|
||||
break;
|
||||
@@ -161,7 +192,7 @@ parse_object(const char* first, const char* last, torrent::Object* dest, bool (*
|
||||
if (++depth >= max_parse_depth)
|
||||
throw torrent::input_error("Max parse depth reached.");
|
||||
|
||||
if (*first == '{') {
|
||||
if (first != last && *first == '{') {
|
||||
*dest = torrent::Object::create_list();
|
||||
first = parse_list(first + 1, last, dest, &parse_is_delim_block, depth);
|
||||
first = parse_skip_wspace(first, last);
|
||||
@@ -171,7 +202,7 @@ parse_object(const char* first, const char* last, torrent::Object* dest, bool (*
|
||||
|
||||
return ++first;
|
||||
|
||||
} else if (*first == '(') {
|
||||
} else if (first != last && *first == '(') {
|
||||
int32_t parentheses = 1;
|
||||
|
||||
while (first + 1 != last && *(first + 1) == '(') {
|
||||
@@ -393,7 +424,7 @@ convert_to_value_nothrow(const torrent::Object& src, int64_t* value, int base, i
|
||||
== unpacked.as_string().c_str() + unpacked.as_string().size();
|
||||
|
||||
case torrent::Object::TYPE_RAW_STRING: {
|
||||
const torrent::raw_string& str = src.as_raw_string();
|
||||
const torrent::raw_string& str = unpacked.as_raw_string();
|
||||
|
||||
auto buffer = std::make_unique<char[]>(str.size() + 1);
|
||||
std::memcpy(buffer.get(), str.data(), str.size());
|
||||
|
||||
@@ -1,37 +1,3 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <sundell.software@gmail.com>
|
||||
|
||||
|
||||
#ifndef RTORRENT_RPC_PARSE_H
|
||||
#define RTORRENT_RPC_PARSE_H
|
||||
|
||||
|
||||
@@ -440,6 +440,8 @@ XmlRpc::cleanup() {
|
||||
xmlrpc_registry_free((xmlrpc_registry*)m_registry);
|
||||
xmlrpc_env_clean((xmlrpc_env*)m_env);
|
||||
delete (xmlrpc_env*)m_env;
|
||||
m_env = nullptr;
|
||||
m_registry = nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -63,8 +63,10 @@ SignalHandler::set_block(unsigned int signum) {
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, signum);
|
||||
|
||||
if (pthread_sigmask(SIG_BLOCK, &mask, NULL) == -1)
|
||||
throw std::logic_error("Could not block signal: " + std::string(std::strerror(errno)));
|
||||
int result = pthread_sigmask(SIG_BLOCK, &mask, NULL);
|
||||
|
||||
if (result != 0)
|
||||
throw std::logic_error("Could not block signal: " + std::string(std::strerror(result)));
|
||||
}
|
||||
|
||||
void
|
||||
@@ -77,8 +79,10 @@ SignalHandler::set_unblock(unsigned int signum) {
|
||||
sigemptyset(&mask);
|
||||
sigaddset(&mask, signum);
|
||||
|
||||
if (pthread_sigmask(SIG_UNBLOCK, &mask, NULL) == -1)
|
||||
throw std::logic_error("Could not unblock signal: " + std::string(std::strerror(errno)));
|
||||
int result = pthread_sigmask(SIG_UNBLOCK, &mask, NULL);
|
||||
|
||||
if (result != 0)
|
||||
throw std::logic_error("Could not unblock signal: " + std::string(std::strerror(result)));
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <torrent/peer/peer.h>
|
||||
|
||||
#include "display/manager.h"
|
||||
#include "utils/list_focus.h"
|
||||
|
||||
#include "element_base.h"
|
||||
|
||||
|
||||
@@ -179,7 +179,7 @@ ElementMenu::set_entry(size_type idx, bool triggerSlot) {
|
||||
m_entry = idx;
|
||||
focus_entry(m_entry);
|
||||
|
||||
if (triggerSlot)
|
||||
if (triggerSlot && m_entry < size())
|
||||
base_type::operator[](m_entry).m_slotFocus();
|
||||
|
||||
m_window->mark_dirty();
|
||||
|
||||
@@ -1,158 +0,0 @@
|
||||
// rTorrent - BitTorrent client
|
||||
// Copyright (C) 2005-2011, Jari Sundell
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation; either version 2 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
//
|
||||
// In addition, as a special exception, the copyright holders give
|
||||
// permission to link the code of portions of this program with the
|
||||
// OpenSSL library under certain conditions as described in each
|
||||
// individual source file, and distribute linked combinations
|
||||
// including the two.
|
||||
//
|
||||
// You must obey the GNU General Public License in all respects for
|
||||
// all of the code used other than OpenSSL. If you modify file(s)
|
||||
// with this exception, you may extend this exception to your version
|
||||
// of the file(s), but you are not obligated to do so. If you do not
|
||||
// wish to do so, delete this exception statement from your version.
|
||||
// If you delete this exception statement from all source files in the
|
||||
// program, then also delete it here.
|
||||
//
|
||||
// Contact: Jari Sundell <sundell.software@gmail.com>
|
||||
|
||||
|
||||
#ifndef RTORRENT_UTILS_LIST_FOCUS_H
|
||||
#define RTORRENT_UTILS_LIST_FOCUS_H
|
||||
|
||||
#include <functional>
|
||||
#include <list>
|
||||
|
||||
namespace utils {
|
||||
|
||||
// Can't make this class inherit privately due to gcc PR 14258.
|
||||
|
||||
template <typename Base>
|
||||
class ListFocus {
|
||||
public:
|
||||
typedef Base base_type;
|
||||
typedef std::function<void ()> slot_void;
|
||||
typedef std::list<slot_void> signal_void;
|
||||
|
||||
typedef typename base_type::iterator iterator;
|
||||
typedef typename base_type::const_iterator const_iterator;
|
||||
typedef typename base_type::reverse_iterator reverse_iterator;
|
||||
typedef typename base_type::const_reverse_iterator const_reverse_iterator;
|
||||
|
||||
typedef typename base_type::value_type value_type;
|
||||
|
||||
ListFocus(base_type* b = nullptr) : m_base(b) { if (b) m_focus = b->end(); }
|
||||
|
||||
// Convinience functions, would have added more through using, but
|
||||
// can't.
|
||||
iterator begin() { return m_base->begin(); }
|
||||
iterator end() { return m_base->end(); }
|
||||
reverse_iterator rbegin() { return m_base->rbegin(); }
|
||||
reverse_iterator rend() { return m_base->rend(); }
|
||||
|
||||
// Don't do erase on this object without making sure focus is right.
|
||||
base_type& base() { return *m_base; }
|
||||
|
||||
iterator get_focus() { return m_focus; }
|
||||
void set_focus(iterator itr);
|
||||
|
||||
// These are looping increment/decrements.
|
||||
iterator inc_focus();
|
||||
iterator dec_focus();
|
||||
|
||||
iterator erase(iterator itr);
|
||||
void remove(const value_type& v);
|
||||
|
||||
// Be careful with copying signals.
|
||||
signal_void& signal_changed() { return m_signal_changed; }
|
||||
|
||||
private:
|
||||
void emit_changed();
|
||||
|
||||
base_type* m_base;
|
||||
iterator m_focus;
|
||||
|
||||
signal_void m_signal_changed;
|
||||
};
|
||||
|
||||
template <typename Base>
|
||||
void
|
||||
ListFocus<Base>::set_focus(iterator itr) {
|
||||
m_focus = itr;
|
||||
emit_changed();
|
||||
}
|
||||
|
||||
template <typename Base>
|
||||
typename ListFocus<Base>::iterator
|
||||
ListFocus<Base>::inc_focus() {
|
||||
if (m_focus != end())
|
||||
++m_focus;
|
||||
else
|
||||
m_focus = begin();
|
||||
|
||||
emit_changed();
|
||||
return m_focus;
|
||||
}
|
||||
|
||||
template <typename Base>
|
||||
typename ListFocus<Base>::iterator
|
||||
ListFocus<Base>::dec_focus() {
|
||||
if (m_focus != begin())
|
||||
--m_focus;
|
||||
else
|
||||
m_focus = end();
|
||||
|
||||
emit_changed();
|
||||
return m_focus;
|
||||
}
|
||||
|
||||
template <typename Base>
|
||||
typename ListFocus<Base>::iterator
|
||||
ListFocus<Base>::erase(iterator itr) {
|
||||
if (itr == m_focus) {
|
||||
m_focus = m_base->erase(itr);
|
||||
emit_changed();
|
||||
return m_focus;
|
||||
}
|
||||
|
||||
return m_base->erase(itr);
|
||||
}
|
||||
|
||||
template <typename Base>
|
||||
void
|
||||
ListFocus<Base>::remove(const value_type& v) {
|
||||
iterator first = begin();
|
||||
iterator last = end();
|
||||
|
||||
while (first != last)
|
||||
if (*first == v)
|
||||
first = erase(first);
|
||||
else
|
||||
++first;
|
||||
}
|
||||
|
||||
template <typename Base>
|
||||
void
|
||||
ListFocus<Base>::emit_changed() {
|
||||
for (const auto& itr : m_signal_changed)
|
||||
itr();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -51,6 +51,8 @@ rtorrent_Test_Rpc_SOURCES = $(rtorrent_Test_Common) \
|
||||
rpc/test_command_slot.h \
|
||||
rpc/test_object_storage.cc \
|
||||
rpc/test_object_storage.h \
|
||||
rpc/test_parse.cc \
|
||||
rpc/test_parse.h \
|
||||
rpc/test_parse_options.cc \
|
||||
rpc/test_parse_options.h \
|
||||
rpc/test_rpc_manager.cc \
|
||||
@@ -59,6 +61,8 @@ rtorrent_Test_Rpc_SOURCES = $(rtorrent_Test_Common) \
|
||||
rtorrent_Test_Src_SOURCES = $(rtorrent_Test_Common) \
|
||||
src/test_command_dynamic.cc \
|
||||
src/test_command_dynamic.h \
|
||||
src/test_command_groups.cc \
|
||||
src/test_command_groups.h \
|
||||
src/test_command_ip.cc \
|
||||
src/test_command_ip.h \
|
||||
src/test_command_system.cc \
|
||||
@@ -69,6 +73,12 @@ rtorrent_Test_Src_SOURCES = $(rtorrent_Test_Common) \
|
||||
src/test_command_string.h \
|
||||
src/test_command_throttle.cc \
|
||||
src/test_command_throttle.h \
|
||||
src/test_command_tracker.cc \
|
||||
src/test_command_tracker.h \
|
||||
src/test_download_list.cc \
|
||||
src/test_download_list.h \
|
||||
src/test_input_path_input.cc \
|
||||
src/test_input_path_input.h \
|
||||
src/test_session_commit.cc \
|
||||
src/test_session_commit.h \
|
||||
src/test_session_storer.cc \
|
||||
|
||||
@@ -0,0 +1,95 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "test/rpc/test_parse.h"
|
||||
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
|
||||
#include "rpc/parse.h"
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestParse);
|
||||
|
||||
void
|
||||
TestParse::test_whole_value_in_range() {
|
||||
int64_t value = 0;
|
||||
|
||||
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("9223372036854775807", &value));
|
||||
CPPUNIT_ASSERT_EQUAL(std::numeric_limits<int64_t>::max(), value);
|
||||
|
||||
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("-9223372036854775808", &value));
|
||||
CPPUNIT_ASSERT_EQUAL(std::numeric_limits<int64_t>::min(), value);
|
||||
}
|
||||
|
||||
void
|
||||
TestParse::test_whole_value_out_of_range() {
|
||||
int64_t value = 0;
|
||||
|
||||
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("9223372036854775808", &value));
|
||||
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("-9223372036854775809", &value));
|
||||
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("99999999999999999999999999", &value));
|
||||
}
|
||||
|
||||
void
|
||||
TestParse::test_whole_value_bases() {
|
||||
int64_t value = 0;
|
||||
|
||||
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("0x1f", &value));
|
||||
CPPUNIT_ASSERT_EQUAL(int64_t{31}, value);
|
||||
|
||||
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("0X1F", &value));
|
||||
CPPUNIT_ASSERT_EQUAL(int64_t{31}, value);
|
||||
|
||||
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("-0x1f", &value));
|
||||
|
||||
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("0022", &value));
|
||||
CPPUNIT_ASSERT_EQUAL(int64_t{022}, value);
|
||||
|
||||
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("0028", &value));
|
||||
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("+022", &value));
|
||||
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("-022", &value));
|
||||
|
||||
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("22", &value));
|
||||
CPPUNIT_ASSERT_EQUAL(int64_t{22}, value);
|
||||
|
||||
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("1f", &value, 16));
|
||||
CPPUNIT_ASSERT_EQUAL(int64_t{31}, value);
|
||||
|
||||
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("0x1f", &value, 16));
|
||||
CPPUNIT_ASSERT_EQUAL(int64_t{31}, value);
|
||||
|
||||
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("22", &value, 8));
|
||||
CPPUNIT_ASSERT_EQUAL(int64_t{022}, value);
|
||||
|
||||
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("022", &value, 8));
|
||||
CPPUNIT_ASSERT_EQUAL(int64_t{022}, value);
|
||||
|
||||
const char* no_digits = "0x";
|
||||
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow(no_digits, &value));
|
||||
CPPUNIT_ASSERT_EQUAL(no_digits + 1, rpc::parse_value_nothrow(no_digits, &value));
|
||||
|
||||
const char* bad_digits = "0xzz";
|
||||
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow(bad_digits, &value));
|
||||
CPPUNIT_ASSERT_EQUAL(bad_digits + 1, rpc::parse_value_nothrow(bad_digits, &value));
|
||||
}
|
||||
|
||||
void
|
||||
TestParse::test_whole_value_prefixes() {
|
||||
int64_t value = 0;
|
||||
|
||||
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("+5", &value));
|
||||
|
||||
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow(" 5 ", &value));
|
||||
CPPUNIT_ASSERT_EQUAL(int64_t{5}, value);
|
||||
|
||||
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("5k", &value));
|
||||
CPPUNIT_ASSERT_EQUAL(int64_t{5120}, value);
|
||||
|
||||
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("yes", &value));
|
||||
CPPUNIT_ASSERT_EQUAL(int64_t{1}, value);
|
||||
|
||||
CPPUNIT_ASSERT(rpc::parse_whole_value_nothrow("false", &value));
|
||||
CPPUNIT_ASSERT_EQUAL(int64_t{0}, value);
|
||||
|
||||
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("junk", &value));
|
||||
CPPUNIT_ASSERT(!rpc::parse_whole_value_nothrow("", &value));
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#include "test/helpers/test_fixture.h"
|
||||
|
||||
class TestParse : public test_fixture {
|
||||
CPPUNIT_TEST_SUITE(TestParse);
|
||||
|
||||
CPPUNIT_TEST(test_whole_value_in_range);
|
||||
CPPUNIT_TEST(test_whole_value_out_of_range);
|
||||
CPPUNIT_TEST(test_whole_value_bases);
|
||||
CPPUNIT_TEST(test_whole_value_prefixes);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
void test_whole_value_in_range();
|
||||
void test_whole_value_out_of_range();
|
||||
void test_whole_value_bases();
|
||||
void test_whole_value_prefixes();
|
||||
};
|
||||
@@ -0,0 +1,65 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "test/src/test_command_groups.h"
|
||||
|
||||
#include <torrent/torrent.h>
|
||||
|
||||
#include "control.h"
|
||||
#include "globals.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestCommandGroups);
|
||||
|
||||
void initialize_command_groups();
|
||||
|
||||
static void
|
||||
call_set(const char* value) {
|
||||
torrent::Object::list_type args;
|
||||
args.push_back(torrent::Object(int64_t{0}));
|
||||
args.push_back(torrent::Object(std::string(value)));
|
||||
|
||||
rpc::commands.call_command("choke_group.up.max.set", torrent::Object::create_list_range(args.begin(), args.end()));
|
||||
}
|
||||
|
||||
static int64_t
|
||||
call_get(const char* key) {
|
||||
return rpc::commands.call_command(key, torrent::Object(int64_t{0})).as_value();
|
||||
}
|
||||
|
||||
void
|
||||
TestCommandGroups::setUp() {
|
||||
torrent::initialize_main_thread();
|
||||
torrent::initialize();
|
||||
|
||||
if (control == nullptr)
|
||||
control = new Control;
|
||||
|
||||
if (!rpc::commands.has("choke_group.up.max.set"))
|
||||
initialize_command_groups();
|
||||
}
|
||||
|
||||
void
|
||||
TestCommandGroups::tearDown() {
|
||||
torrent::cleanup();
|
||||
}
|
||||
|
||||
void
|
||||
TestCommandGroups::test_max_unchoked_in_range() {
|
||||
call_set("50");
|
||||
CPPUNIT_ASSERT_EQUAL(int64_t{50}, call_get("choke_group.up.max"));
|
||||
CPPUNIT_ASSERT_EQUAL(int64_t{0}, call_get("choke_group.up.max.unlimited"));
|
||||
|
||||
call_set("-1");
|
||||
CPPUNIT_ASSERT_EQUAL(int64_t{1}, call_get("choke_group.up.max.unlimited"));
|
||||
}
|
||||
|
||||
void
|
||||
TestCommandGroups::test_max_unchoked_out_of_range() {
|
||||
call_set("50");
|
||||
|
||||
CPPUNIT_ASSERT_THROW(call_set("4294967296"), torrent::input_error);
|
||||
CPPUNIT_ASSERT_EQUAL(int64_t{50}, call_get("choke_group.up.max"));
|
||||
|
||||
CPPUNIT_ASSERT_THROW(call_set("-2"), torrent::input_error);
|
||||
CPPUNIT_ASSERT_EQUAL(int64_t{50}, call_get("choke_group.up.max"));
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#include "test/helpers/test_fixture.h"
|
||||
|
||||
class TestCommandGroups : public test_fixture {
|
||||
CPPUNIT_TEST_SUITE(TestCommandGroups);
|
||||
|
||||
CPPUNIT_TEST(test_max_unchoked_in_range);
|
||||
CPPUNIT_TEST(test_max_unchoked_out_of_range);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
void test_max_unchoked_in_range();
|
||||
void test_max_unchoked_out_of_range();
|
||||
};
|
||||
@@ -0,0 +1,73 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "test/src/test_command_tracker.h"
|
||||
|
||||
#include <torrent/runtime/network_config.h>
|
||||
#include <torrent/torrent.h>
|
||||
|
||||
#include "control.h"
|
||||
#include "globals.h"
|
||||
#include "command_helpers.h"
|
||||
#include "rpc/parse_commands.h"
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestCommandTracker);
|
||||
|
||||
void initialize_command_tracker();
|
||||
|
||||
static void
|
||||
call_set(const char* value) {
|
||||
rpc::commands.call_command("dht.override_port.set", torrent::Object(std::string(value)));
|
||||
}
|
||||
|
||||
static uint16_t
|
||||
override_port() {
|
||||
return torrent::runtime::network_config()->override_dht_port();
|
||||
}
|
||||
|
||||
void
|
||||
TestCommandTracker::setUp() {
|
||||
torrent::initialize_main_thread();
|
||||
torrent::initialize();
|
||||
|
||||
if (control == nullptr)
|
||||
control = new Control;
|
||||
|
||||
if (!rpc::commands.has("dht.override_port.set"))
|
||||
initialize_command_tracker();
|
||||
}
|
||||
|
||||
void
|
||||
TestCommandTracker::tearDown() {
|
||||
torrent::cleanup();
|
||||
}
|
||||
|
||||
void
|
||||
TestCommandTracker::test_dht_override_port_in_range() {
|
||||
call_set("6881");
|
||||
CPPUNIT_ASSERT_EQUAL(uint16_t{6881}, override_port());
|
||||
|
||||
call_set("65535");
|
||||
CPPUNIT_ASSERT_EQUAL(uint16_t{65535}, override_port());
|
||||
}
|
||||
|
||||
void
|
||||
TestCommandTracker::test_dht_override_port_out_of_range() {
|
||||
call_set("6881");
|
||||
|
||||
CPPUNIT_ASSERT_THROW(call_set("70000"), torrent::input_error);
|
||||
CPPUNIT_ASSERT_EQUAL(uint16_t{6881}, override_port());
|
||||
|
||||
CPPUNIT_ASSERT_THROW(call_set("-1"), torrent::input_error);
|
||||
CPPUNIT_ASSERT_EQUAL(uint16_t{6881}, override_port());
|
||||
}
|
||||
|
||||
void
|
||||
TestCommandTracker::test_checked_port_value() {
|
||||
CPPUNIT_ASSERT_EQUAL(uint16_t{0}, checked_port_value(0, "test"));
|
||||
CPPUNIT_ASSERT_EQUAL(uint16_t{6881}, checked_port_value(6881, "test"));
|
||||
CPPUNIT_ASSERT_EQUAL(uint16_t{65535}, checked_port_value(65535, "test"));
|
||||
|
||||
CPPUNIT_ASSERT_THROW(checked_port_value(-1, "test"), torrent::input_error);
|
||||
CPPUNIT_ASSERT_THROW(checked_port_value(65536, "test"), torrent::input_error);
|
||||
CPPUNIT_ASSERT_THROW(checked_port_value(4294967296, "test"), torrent::input_error);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#include "test/helpers/test_fixture.h"
|
||||
|
||||
class TestCommandTracker : public test_fixture {
|
||||
CPPUNIT_TEST_SUITE(TestCommandTracker);
|
||||
|
||||
CPPUNIT_TEST(test_dht_override_port_in_range);
|
||||
CPPUNIT_TEST(test_dht_override_port_out_of_range);
|
||||
CPPUNIT_TEST(test_checked_port_value);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
void test_dht_override_port_in_range();
|
||||
void test_dht_override_port_out_of_range();
|
||||
void test_checked_port_value();
|
||||
};
|
||||
@@ -0,0 +1,68 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "test/src/test_download_list.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <torrent/download.h>
|
||||
#include <torrent/download_info.h>
|
||||
#include <torrent/hash_string.h>
|
||||
#include <torrent/object.h>
|
||||
#include <torrent/torrent.h>
|
||||
|
||||
#include "control.h"
|
||||
#include "core/download.h"
|
||||
#include "globals.h"
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestDownloadList);
|
||||
|
||||
static std::string
|
||||
insert_download(core::DownloadList* list) {
|
||||
torrent::Object info = torrent::Object::create_map();
|
||||
info.insert_key("name", std::string("test_download_list"));
|
||||
info.insert_key("length", int64_t{16});
|
||||
info.insert_key("piece length", int64_t{262144});
|
||||
info.insert_key("pieces", std::string(20, char(0)));
|
||||
|
||||
auto* object = new torrent::Object(torrent::Object::create_map());
|
||||
object->insert_key("info", info);
|
||||
|
||||
auto download = torrent::download_add(object, 0);
|
||||
list->insert(new core::Download(download));
|
||||
|
||||
char buffer[41];
|
||||
|
||||
for (unsigned int i = 0; i < torrent::HashString::size_data; i++)
|
||||
snprintf(buffer + i * 2, 3, "%02x", static_cast<unsigned char>(download.info()->hash()[i]));
|
||||
|
||||
return std::string(buffer, 40);
|
||||
}
|
||||
|
||||
void
|
||||
TestDownloadList::setUp() {
|
||||
torrent::initialize_main_thread();
|
||||
torrent::initialize();
|
||||
|
||||
if (control == nullptr)
|
||||
control = new Control;
|
||||
|
||||
m_hex = insert_download(&m_list);
|
||||
}
|
||||
|
||||
void
|
||||
TestDownloadList::tearDown() {
|
||||
m_list.clear();
|
||||
|
||||
torrent::cleanup();
|
||||
}
|
||||
|
||||
void
|
||||
TestDownloadList::test_find_hex() {
|
||||
CPPUNIT_ASSERT(m_list.find_hex(m_hex.c_str()) != m_list.end());
|
||||
}
|
||||
|
||||
void
|
||||
TestDownloadList::test_find_hex_wrong_length() {
|
||||
CPPUNIT_ASSERT(m_list.find_hex((m_hex + "f").c_str()) == m_list.end());
|
||||
CPPUNIT_ASSERT(m_list.find_hex((m_hex + m_hex).c_str()) == m_list.end());
|
||||
CPPUNIT_ASSERT(m_list.find_hex(m_hex.substr(0, 39).c_str()) == m_list.end());
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#include <string>
|
||||
|
||||
#include "core/download_list.h"
|
||||
#include "test/helpers/test_fixture.h"
|
||||
|
||||
class TestDownloadList : public test_fixture {
|
||||
CPPUNIT_TEST_SUITE(TestDownloadList);
|
||||
|
||||
CPPUNIT_TEST(test_find_hex);
|
||||
CPPUNIT_TEST(test_find_hex_wrong_length);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
void test_find_hex();
|
||||
void test_find_hex_wrong_length();
|
||||
|
||||
private:
|
||||
core::DownloadList m_list;
|
||||
std::string m_hex;
|
||||
};
|
||||
@@ -0,0 +1,77 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "test/src/test_input_path_input.h"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "input/path_input.h"
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(TestInputPathInput);
|
||||
|
||||
void
|
||||
TestInputPathInput::setUp() {
|
||||
test_fixture::setUp();
|
||||
|
||||
char temp_dir[] = "/tmp/rtorrent_test_path_input_XXXXXX";
|
||||
|
||||
CPPUNIT_ASSERT(mkdtemp(temp_dir) != nullptr);
|
||||
|
||||
m_temp_dir = temp_dir;
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(0, mkdir((m_temp_dir + "/alpha").c_str(), 0755));
|
||||
CPPUNIT_ASSERT_EQUAL(0, mkdir((m_temp_dir + "/alpha/beta").c_str(), 0755));
|
||||
}
|
||||
|
||||
void
|
||||
TestInputPathInput::tearDown() {
|
||||
rmdir((m_temp_dir + "/alpha/beta").c_str());
|
||||
rmdir((m_temp_dir + "/alpha").c_str());
|
||||
rmdir(m_temp_dir.c_str());
|
||||
|
||||
test_fixture::tearDown();
|
||||
}
|
||||
|
||||
// Tab at the end of the line completes the trailing component.
|
||||
void
|
||||
TestInputPathInput::test_complete_at_end() {
|
||||
input::PathInput input;
|
||||
|
||||
input.str() = m_temp_dir + "/al";
|
||||
input.set_pos(input.str().size());
|
||||
|
||||
CPPUNIT_ASSERT(input.pressed('\t'));
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(m_temp_dir + "/alpha/", input.str());
|
||||
CPPUNIT_ASSERT_EQUAL(input.str().size(), input.get_pos());
|
||||
}
|
||||
|
||||
// The same completion with the cursor left inside the line. Only the text up to
|
||||
// the cursor selects the entry, and the rest of the line is discarded.
|
||||
void
|
||||
TestInputPathInput::test_complete_mid_line() {
|
||||
input::PathInput input;
|
||||
|
||||
input.str() = m_temp_dir + "/alZZZ";
|
||||
input.set_pos(m_temp_dir.size() + 3);
|
||||
|
||||
CPPUNIT_ASSERT(input.pressed('\t'));
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(m_temp_dir + "/alpha/", input.str());
|
||||
CPPUNIT_ASSERT_EQUAL(input.str().size(), input.get_pos());
|
||||
}
|
||||
|
||||
// A cursor resting on a separator keeps completing the component after it.
|
||||
void
|
||||
TestInputPathInput::test_cursor_on_separator() {
|
||||
input::PathInput input;
|
||||
|
||||
input.str() = m_temp_dir + "/alpha/be";
|
||||
input.set_pos(m_temp_dir.size() + 6);
|
||||
|
||||
CPPUNIT_ASSERT(input.pressed('\t'));
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(m_temp_dir + "/alpha/beta/", input.str());
|
||||
CPPUNIT_ASSERT_EQUAL(input.str().size(), input.get_pos());
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
#include "test/helpers/test_fixture.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class TestInputPathInput : public test_fixture {
|
||||
CPPUNIT_TEST_SUITE(TestInputPathInput);
|
||||
|
||||
CPPUNIT_TEST(test_complete_at_end);
|
||||
CPPUNIT_TEST(test_complete_mid_line);
|
||||
CPPUNIT_TEST(test_cursor_on_separator);
|
||||
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
public:
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
||||
void test_complete_at_end();
|
||||
void test_complete_mid_line();
|
||||
void test_cursor_on_separator();
|
||||
|
||||
private:
|
||||
std::string m_temp_dir;
|
||||
};
|
||||
Reference in New Issue
Block a user