mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-10-05 13:49:21 +00:00
Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f9b9629235 | |||
| 282c86597a | |||
| c41e63248a | |||
| 641626029a | |||
| 0c507c581f | |||
| af0b600b54 | |||
| c984a69fd1 | |||
| 20002ce937 | |||
| 3caa31113d | |||
| 0373d227c1 | |||
| a8be7e443a | |||
| f327523a07 | |||
| cc1fcbe3e5 | |||
| 877e5f6ed3 | |||
| ee64f8ea50 | |||
| bf1265d954 | |||
| 6c3c77a2b7 | |||
| 120fcb0273 | |||
| c36956813d | |||
| 05563b4c9b | |||
| a544f8ad68 | |||
| b35413ea71 | |||
| f9f19fb041 |
+2
-2
@@ -1,6 +1,6 @@
|
|||||||
m4_pattern_allow([PKG_CHECK_EXISTS])
|
m4_pattern_allow([PKG_CHECK_EXISTS])
|
||||||
|
|
||||||
AC_INIT([rtorrent],[0.16.21],[sundell.software@gmail.com])
|
AC_INIT([rtorrent],[0.16.22],[sundell.software@gmail.com])
|
||||||
|
|
||||||
AC_CONFIG_HEADERS([config.h])
|
AC_CONFIG_HEADERS([config.h])
|
||||||
AC_CONFIG_MACRO_DIRS([scripts])
|
AC_CONFIG_MACRO_DIRS([scripts])
|
||||||
@@ -49,7 +49,7 @@ fi
|
|||||||
|
|
||||||
PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"])
|
PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"])
|
||||||
PKG_CHECK_MODULES([ZLIB], [zlib])
|
PKG_CHECK_MODULES([ZLIB], [zlib])
|
||||||
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.16.21])
|
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.16.22])
|
||||||
|
|
||||||
AC_LANG_PUSH(C++)
|
AC_LANG_PUSH(C++)
|
||||||
TORRENT_WITH_XMLRPC_C
|
TORRENT_WITH_XMLRPC_C
|
||||||
|
|||||||
+4
-1
@@ -131,7 +131,7 @@ ipv4_range_parse(const char* address, uint32_t* address_start, uint32_t* address
|
|||||||
// copy everything up to '#' to address_copy and work from there
|
// copy everything up to '#' to address_copy and work from there
|
||||||
while(address[address_start_index] != '#' && address[address_start_index] != '\r' &&
|
while(address[address_start_index] != '#' && address[address_start_index] != '\r' &&
|
||||||
address[address_start_index] != '\n' && address[address_start_index] != '\0' &&
|
address[address_start_index] != '\n' && address[address_start_index] != '\0' &&
|
||||||
address_start_index < 4096 ) {
|
address_start_index < 4095 ) {
|
||||||
|
|
||||||
address_copy[address_start_index] = address[address_start_index];
|
address_copy[address_start_index] = address[address_start_index];
|
||||||
address_start_index++;
|
address_start_index++;
|
||||||
@@ -206,6 +206,9 @@ ipv4_range_parse(const char* address, uint32_t* address_start, uint32_t* address
|
|||||||
if (mask_bits == 0) {
|
if (mask_bits == 0) {
|
||||||
mask = 0;
|
mask = 0;
|
||||||
end_mask = ~(uint32_t)0;
|
end_mask = ~(uint32_t)0;
|
||||||
|
} else if (mask_bits == 32) {
|
||||||
|
mask = ~(uint32_t)0;
|
||||||
|
end_mask = 0;
|
||||||
} else {
|
} else {
|
||||||
mask = (~mask) << (32-mask_bits);
|
mask = (~mask) << (32-mask_bits);
|
||||||
end_mask = (~end_mask) >> mask_bits;
|
end_mask = (~end_mask) >> mask_bits;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include <functional>
|
#include <functional>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <sys/stat.h>
|
||||||
#include <torrent/utils/log.h>
|
#include <torrent/utils/log.h>
|
||||||
#include <torrent/utils/resume.h>
|
#include <torrent/utils/resume.h>
|
||||||
#include <torrent/object.h>
|
#include <torrent/object.h>
|
||||||
@@ -39,6 +40,11 @@ static constexpr const char* session_invalid_message = "Session data is invalid,
|
|||||||
|
|
||||||
static std::unique_ptr<torrent::Object>
|
static std::unique_ptr<torrent::Object>
|
||||||
download_factory_load_stream(const char* filename, bool* is_invalid) {
|
download_factory_load_stream(const char* filename, bool* is_invalid) {
|
||||||
|
struct stat sb;
|
||||||
|
|
||||||
|
if (stat(filename, &sb) != 0 || !S_ISREG(sb.st_mode))
|
||||||
|
return std::unique_ptr<torrent::Object>();
|
||||||
|
|
||||||
std::fstream stream(filename, std::ios::in | std::ios::binary);
|
std::fstream stream(filename, std::ios::in | std::ios::binary);
|
||||||
|
|
||||||
if (!stream.is_open())
|
if (!stream.is_open())
|
||||||
@@ -167,11 +173,19 @@ void
|
|||||||
DownloadFactory::receive_success() {
|
DownloadFactory::receive_success() {
|
||||||
bool session_invalid = false;
|
bool session_invalid = false;
|
||||||
|
|
||||||
auto rtorrent_object = download_factory_load_stream((expand_path(m_uri) + ".rtorrent").c_str(), &session_invalid);
|
std::unique_ptr<torrent::Object> rtorrent_object;
|
||||||
auto libtorrent_resume_object = download_factory_load_stream((expand_path(m_uri) + ".libtorrent_resume").c_str(), &session_invalid);
|
std::unique_ptr<torrent::Object> libtorrent_resume_object;
|
||||||
|
|
||||||
if (session_invalid)
|
if (m_session) {
|
||||||
lt_log_print(torrent::LOG_ERROR, "%s: %s", session_invalid_message, m_uri.c_str());
|
if (m_uri.empty())
|
||||||
|
throw torrent::input_error("Session torrent URI is empty.");
|
||||||
|
|
||||||
|
rtorrent_object = download_factory_load_stream((expand_path(m_uri) + ".rtorrent").c_str(), &session_invalid);
|
||||||
|
libtorrent_resume_object = download_factory_load_stream((expand_path(m_uri) + ".libtorrent_resume").c_str(), &session_invalid);
|
||||||
|
|
||||||
|
if (session_invalid)
|
||||||
|
lt_log_print(torrent::LOG_ERROR, "%s: %s", session_invalid_message, m_uri.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
uint32_t tracker_key;
|
uint32_t tracker_key;
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,7 @@ namespace input {
|
|||||||
|
|
||||||
void
|
void
|
||||||
InputEvent::insert() {
|
InputEvent::insert() {
|
||||||
torrent::this_thread::poll()->open(this);
|
torrent::this_thread::poll()->open_and_insert_read(this);
|
||||||
torrent::this_thread::poll()->insert_read(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
+16
-15
@@ -112,8 +112,9 @@ main(int argc, char** argv) {
|
|||||||
|
|
||||||
torrent::log_initialize();
|
torrent::log_initialize();
|
||||||
|
|
||||||
// TODO: Create a fake thread object for initializing other processes and enabling logging.
|
torrent::runtime::initialize_worker_process_and_main_thread([argc, argv]() {
|
||||||
torrent::initialize_main_thread();
|
parse_config_file(argc, argv, [](auto& path) { parse_config_file_comments("worker", path); });
|
||||||
|
});
|
||||||
|
|
||||||
// Block SIGCHLD until all threads are created, then unblock on main-thread, to avoid SIGCHLD
|
// Block SIGCHLD until all threads are created, then unblock on main-thread, to avoid SIGCHLD
|
||||||
// interrupting other threads.
|
// interrupting other threads.
|
||||||
@@ -125,9 +126,9 @@ main(int argc, char** argv) {
|
|||||||
SignalHandler::set_block(SIGCHLD);
|
SignalHandler::set_block(SIGCHLD);
|
||||||
|
|
||||||
// All signal handlers must restore errno if they return.
|
// All signal handlers must restore errno if they return.
|
||||||
SignalHandler::set_handler(SIGSEGV, std::bind(&do_panic, SIGSEGV));
|
SignalHandler::set_handler(SIGSEGV, []() { do_panic(SIGSEGV); });
|
||||||
SignalHandler::set_handler(SIGILL, std::bind(&do_panic, SIGILL));
|
SignalHandler::set_handler(SIGILL, []() { do_panic(SIGILL); });
|
||||||
SignalHandler::set_handler(SIGFPE, std::bind(&do_panic, SIGFPE));
|
SignalHandler::set_handler(SIGFPE, []() { do_panic(SIGFPE); });
|
||||||
|
|
||||||
// Limited list of commands with the following format:
|
// Limited list of commands with the following format:
|
||||||
//
|
//
|
||||||
@@ -136,19 +137,17 @@ main(int argc, char** argv) {
|
|||||||
// # do:log.open_file=system,/usr/rakshasa/system.log
|
// # do:log.open_file=system,/usr/rakshasa/system.log
|
||||||
// # do:log.add_output=system,system
|
// # do:log.add_output=system,system
|
||||||
//
|
//
|
||||||
parse_config_file(argc, argv, [](auto& path) {
|
// # do-worker:log.open_file=system,/usr/rakshasa/system-worker.log
|
||||||
if (path.empty())
|
// # do-worker:log.add_output=system,system
|
||||||
return;
|
//
|
||||||
|
parse_config_file(argc, argv, [](auto& path) { parse_config_file_comments("", path); });
|
||||||
parse_config_file_comments(path);
|
|
||||||
});
|
|
||||||
|
|
||||||
control = new Control;
|
control = new Control;
|
||||||
|
|
||||||
SignalHandler::set_handler(SIGINT, std::bind(&Control::receive_normal_shutdown, control));
|
SignalHandler::set_handler(SIGINT, []() { control->receive_normal_shutdown(); });
|
||||||
SignalHandler::set_handler(SIGHUP, std::bind(&Control::receive_normal_shutdown, control));
|
SignalHandler::set_handler(SIGHUP, []() { control->receive_normal_shutdown(); });
|
||||||
SignalHandler::set_handler(SIGTERM, std::bind(&Control::receive_quick_shutdown, control));
|
SignalHandler::set_handler(SIGTERM, []() { control->receive_quick_shutdown(); });
|
||||||
SignalHandler::set_handler(SIGWINCH, std::bind(&display::Manager::force_redraw, control->display()));
|
SignalHandler::set_handler(SIGWINCH, []() { control->display()->force_redraw(); });
|
||||||
|
|
||||||
SignalHandler::set_sigaction_handler(SIGBUS, &handle_sigbus);
|
SignalHandler::set_sigaction_handler(SIGBUS, &handle_sigbus);
|
||||||
|
|
||||||
@@ -469,6 +468,8 @@ main(int argc, char** argv) {
|
|||||||
control->ui()->load_input_history();
|
control->ui()->load_input_history();
|
||||||
|
|
||||||
torrent::net_thread::http_stack()->set_user_agent(USER_AGENT);
|
torrent::net_thread::http_stack()->set_user_agent(USER_AGENT);
|
||||||
|
|
||||||
|
torrent::runtime::initialize_worker_process();
|
||||||
torrent::runtime::initialize_network();
|
torrent::runtime::initialize_network();
|
||||||
|
|
||||||
// Load session torrents and perform scheduled tasks to ensure session torrents are loaded
|
// Load session torrents and perform scheduled tasks to ensure session torrents are loaded
|
||||||
|
|||||||
@@ -108,6 +108,6 @@ OptionParser::call_int_pair(slot_int_pair slot, const std::string& arg) {
|
|||||||
|
|
||||||
if (a < 0 || b < 0)
|
if (a < 0 || b < 0)
|
||||||
throw std::runtime_error("Invalid argument, \"" + arg + "\" should be positive numbers");
|
throw std::runtime_error("Invalid argument, \"" + arg + "\" should be positive numbers");
|
||||||
|
|
||||||
slot(a, b);
|
slot(a, b);
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -109,8 +109,7 @@ void
|
|||||||
SCgi::activate() {
|
SCgi::activate() {
|
||||||
assert(torrent::this_thread::thread() == scgi_thread::thread());
|
assert(torrent::this_thread::thread() == scgi_thread::thread());
|
||||||
|
|
||||||
torrent::this_thread::poll()->open(this);
|
torrent::this_thread::poll()->open_and_insert_read(this);
|
||||||
torrent::this_thread::poll()->insert_read(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This should close the fd to avoid reuse.
|
// TODO: This should close the fd to avoid reuse.
|
||||||
|
|||||||
@@ -50,8 +50,7 @@ SCgiTask::open(SCgi* parent, int fd) {
|
|||||||
// m_trusted=false into the next reuse, given that the
|
// m_trusted=false into the next reuse, given that the
|
||||||
// UNTRUSTED_CONNECTION=0 parse branch is a no-op.
|
// UNTRUSTED_CONNECTION=0 parse branch is a no-op.
|
||||||
|
|
||||||
torrent::this_thread::poll()->open(this);
|
torrent::this_thread::poll()->open_and_insert_read(this);
|
||||||
torrent::this_thread::poll()->insert_read(this);
|
|
||||||
|
|
||||||
torrent::this_thread::scheduler()->update_wait_for_ceil_seconds(&m_task_timeout, timeout_request);
|
torrent::this_thread::scheduler()->update_wait_for_ceil_seconds(&m_task_timeout, timeout_request);
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -16,7 +16,7 @@ class SCgiTask : public torrent::system::Event {
|
|||||||
public:
|
public:
|
||||||
static constexpr int default_buffer_size = 8191;
|
static constexpr int default_buffer_size = 8191;
|
||||||
static constexpr int max_header_size = 2000;
|
static constexpr int max_header_size = 2000;
|
||||||
static constexpr int max_content_size = (2 << 23);
|
static constexpr int max_content_size = (1 << 26);
|
||||||
|
|
||||||
static constexpr auto timeout_request = std::chrono::seconds(60);
|
static constexpr auto timeout_request = std::chrono::seconds(60);
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -77,16 +77,18 @@ xmlrpc_list_entry_to_value(xmlrpc_env* env, xmlrpc_value* src, int index) {
|
|||||||
{
|
{
|
||||||
const char* str;
|
const char* str;
|
||||||
xmlrpc_read_string(env, tmp, &str);
|
xmlrpc_read_string(env, tmp, &str);
|
||||||
|
xmlrpc_DECREF(tmp);
|
||||||
|
|
||||||
if (env->fault_occurred)
|
if (env->fault_occurred)
|
||||||
throw xmlrpc_error_c(env);
|
throw xmlrpc_error_c(env);
|
||||||
|
|
||||||
const char* end = str;
|
const char* end = str;
|
||||||
int64_t v3 = ::strtoll(str, (char**)&end, 0);
|
int64_t v3 = ::strtoll(str, (char**)&end, 0);
|
||||||
|
bool invalid = *str == '\0' || *end != '\0';
|
||||||
|
|
||||||
::free((void*)str);
|
::free((void*)str);
|
||||||
|
|
||||||
if (*str == '\0' || *end != '\0')
|
if (invalid)
|
||||||
throw xmlrpc_error_c(XMLRPC_TYPE_ERROR, "Invalid index.");
|
throw xmlrpc_error_c(XMLRPC_TYPE_ERROR, "Invalid index.");
|
||||||
|
|
||||||
return v3;
|
return v3;
|
||||||
|
|||||||
@@ -127,8 +127,12 @@ save_stream(const std::string& path, bool use_fsyncdisk, const std::stringstream
|
|||||||
if (!output.good())
|
if (!output.good())
|
||||||
throw torrent::storage_error("failed to write stream to file : " + path);
|
throw torrent::storage_error("failed to write stream to file : " + path);
|
||||||
|
|
||||||
|
// The data only reaches the kernel here, so this is where a full disk is seen.
|
||||||
output.close();
|
output.close();
|
||||||
|
|
||||||
|
if (!output.good())
|
||||||
|
throw torrent::storage_error("failed to flush stream to file : " + path);
|
||||||
|
|
||||||
// Ensure that the new file is actually written to the disk
|
// Ensure that the new file is actually written to the disk
|
||||||
int fd = ::open(path.c_str(), O_WRONLY);
|
int fd = ::open(path.c_str(), O_WRONLY);
|
||||||
|
|
||||||
@@ -137,13 +141,19 @@ save_stream(const std::string& path, bool use_fsyncdisk, const std::stringstream
|
|||||||
|
|
||||||
if (use_fsyncdisk) {
|
if (use_fsyncdisk) {
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
::fsync(fd);
|
int sync_result = ::fsync(fd);
|
||||||
#else
|
#else
|
||||||
::fdatasync(fd);
|
int sync_result = ::fdatasync(fd);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (sync_result == -1) {
|
||||||
|
::close(fd);
|
||||||
|
throw torrent::storage_error("failed to sync file to disk : " + path);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
::close(fd);
|
if (::close(fd) == -1)
|
||||||
|
throw torrent::storage_error("failed to close file descriptor : " + path);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace anonymous
|
} // namespace anonymous
|
||||||
|
|||||||
+9
-5
@@ -108,18 +108,22 @@ config_comment_log(const std::string& command, const std::string& raw_args) {
|
|||||||
throw torrent::input_error("Unknown log command: " + command);
|
throw torrent::input_error("Unknown log command: " + command);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call special commands in the format "# do:command=args" in the config file.
|
// Call special commands in the format "# do:command=args" or "# do-<category>:command=args" in the config file.
|
||||||
void
|
void
|
||||||
parse_config_file_comments(const std::string& path) {
|
parse_config_file_comments(const std::string& category, const std::string& path) {
|
||||||
|
if (path.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
std::fstream file(path, std::ios::in);
|
std::fstream file(path, std::ios::in);
|
||||||
|
|
||||||
if (!file.is_open())
|
if (!file.is_open())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string line;
|
std::string line;
|
||||||
|
std::string prefix = category.empty() ? "# do:" : "# do-" + category + ":";
|
||||||
|
|
||||||
while (std::getline(file, line)) {
|
while (std::getline(file, line)) {
|
||||||
if (line.size() <= 5 || line.compare(0, 5, "# do:") != 0)
|
if (line.size() <= prefix.size() || line.compare(0, prefix.size(), prefix) != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto equal_pos = line.find('=');
|
auto equal_pos = line.find('=');
|
||||||
@@ -127,8 +131,8 @@ parse_config_file_comments(const std::string& path) {
|
|||||||
if (equal_pos == std::string::npos)
|
if (equal_pos == std::string::npos)
|
||||||
throw torrent::input_error("Invalid command in config file comment: " + line);
|
throw torrent::input_error("Invalid command in config file comment: " + line);
|
||||||
|
|
||||||
std::string command = line.substr(5, equal_pos - 5);
|
auto command = line.substr(prefix.size(), equal_pos - prefix.size());
|
||||||
std::string args = line.substr(equal_pos + 1);
|
auto args = line.substr(equal_pos + 1);
|
||||||
|
|
||||||
if (command.empty())
|
if (command.empty())
|
||||||
throw torrent::input_error("Invalid command in config file comment: " + line);
|
throw torrent::input_error("Invalid command in config file comment: " + line);
|
||||||
|
|||||||
+2
-1
@@ -3,10 +3,11 @@
|
|||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
int parse_main_options(int argc, char** argv);
|
int parse_main_options(int argc, char** argv);
|
||||||
void parse_config_file(int argc, char** argv, std::function<void (const std::string&)> parse_fn);
|
void parse_config_file(int argc, char** argv, std::function<void (const std::string&)> parse_fn);
|
||||||
void parse_config_file_comments(const std::string& path);
|
void parse_config_file_comments(const std::string& category, const std::string& path);
|
||||||
|
|
||||||
void load_session_torrents(const std::string& path);
|
void load_session_torrents(const std::string& path);
|
||||||
void load_arg_torrents(char** first, char** last);
|
void load_arg_torrents(char** first, char** last);
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
#include <zlib.h>
|
#include <zlib.h>
|
||||||
#include <torrent/exceptions.h>
|
#include <torrent/exceptions.h>
|
||||||
|
|
||||||
|
#include "utils/functional.h"
|
||||||
|
|
||||||
namespace utils {
|
namespace utils {
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -21,6 +23,8 @@ gzip_compress_to_vector(const char* buffer, unsigned int length, std::vector<cha
|
|||||||
if (deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, window_bits | gzip_encoding, gzip_level, Z_DEFAULT_STRATEGY) != Z_OK)
|
if (deflateInit2(&zs, Z_DEFAULT_COMPRESSION, Z_DEFLATED, window_bits | gzip_encoding, gzip_level, Z_DEFAULT_STRATEGY) != Z_OK)
|
||||||
throw torrent::internal_error("gzip_compress_to_vector(...) could not initialize gzip deflate.");
|
throw torrent::internal_error("gzip_compress_to_vector(...) could not initialize gzip deflate.");
|
||||||
|
|
||||||
|
scope_guard guard([&zs]() { deflateEnd(&zs); });
|
||||||
|
|
||||||
auto max_response_size = deflateBound(&zs, length);
|
auto max_response_size = deflateBound(&zs, length);
|
||||||
|
|
||||||
output.resize(offset + max_response_size);
|
output.resize(offset + max_response_size);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define RTORRENT_UTILS_GZIP_H
|
#define RTORRENT_UTILS_GZIP_H
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace utils {
|
namespace utils {
|
||||||
|
|
||||||
|
|||||||
@@ -51,6 +51,8 @@ rtorrent_Test_Rpc_SOURCES = $(rtorrent_Test_Common) \
|
|||||||
rtorrent_Test_Src_SOURCES = $(rtorrent_Test_Common) \
|
rtorrent_Test_Src_SOURCES = $(rtorrent_Test_Common) \
|
||||||
src/test_command_dynamic.cc \
|
src/test_command_dynamic.cc \
|
||||||
src/test_command_dynamic.h \
|
src/test_command_dynamic.h \
|
||||||
|
src/test_command_ip.cc \
|
||||||
|
src/test_command_ip.h \
|
||||||
src/test_command_system.cc \
|
src/test_command_system.cc \
|
||||||
src/test_command_system.h \
|
src/test_command_system.h \
|
||||||
src/test_command_path.cc \
|
src/test_command_path.cc \
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
#include "test/src/test_command_ip.h"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
CPPUNIT_TEST_SUITE_REGISTRATION(TestCommandIp);
|
||||||
|
|
||||||
|
bool ipv4_range_parse(const char* address, uint32_t* address_start, uint32_t* address_end);
|
||||||
|
|
||||||
|
static uint32_t
|
||||||
|
ipv4(uint32_t a, uint32_t b, uint32_t c, uint32_t d) {
|
||||||
|
return (a << 24) | (b << 16) | (c << 8) | d;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define RANGE_ASSERT(address, expected_start, expected_end) \
|
||||||
|
{ \
|
||||||
|
uint32_t start = 0; \
|
||||||
|
uint32_t end = 0; \
|
||||||
|
\
|
||||||
|
CPPUNIT_ASSERT(ipv4_range_parse(address, &start, &end)); \
|
||||||
|
CPPUNIT_ASSERT_EQUAL(expected_start, start); \
|
||||||
|
CPPUNIT_ASSERT_EQUAL(expected_end, end); \
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TestCommandIp::test_single_address() {
|
||||||
|
RANGE_ASSERT("10.1.2.3", ipv4(10, 1, 2, 3), ipv4(10, 1, 2, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TestCommandIp::test_explicit_range() {
|
||||||
|
RANGE_ASSERT("10.1.2.3-10.1.2.9", ipv4(10, 1, 2, 3), ipv4(10, 1, 2, 9));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TestCommandIp::test_cidr() {
|
||||||
|
RANGE_ASSERT("10.0.0.0/8", ipv4(10, 0, 0, 0), ipv4(10, 255, 255, 255));
|
||||||
|
RANGE_ASSERT("10.1.2.0/24", ipv4(10, 1, 2, 0), ipv4(10, 1, 2, 255));
|
||||||
|
RANGE_ASSERT("10.1.2.128/25", ipv4(10, 1, 2, 128), ipv4(10, 1, 2, 255));
|
||||||
|
RANGE_ASSERT("10.1.2.3/31", ipv4(10, 1, 2, 2), ipv4(10, 1, 2, 3));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TestCommandIp::test_cidr_zero_mask() {
|
||||||
|
RANGE_ASSERT("0.0.0.0/0", ipv4(0, 0, 0, 0), ipv4(255, 255, 255, 255));
|
||||||
|
RANGE_ASSERT("10.1.2.3/0", ipv4(0, 0, 0, 0), ipv4(255, 255, 255, 255));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TestCommandIp::test_cidr_full_mask() {
|
||||||
|
RANGE_ASSERT("10.1.2.3/32", ipv4(10, 1, 2, 3), ipv4(10, 1, 2, 3));
|
||||||
|
RANGE_ASSERT("0.0.0.0/32", ipv4(0, 0, 0, 0), ipv4(0, 0, 0, 0));
|
||||||
|
RANGE_ASSERT("255.255.255.255/32", ipv4(255, 255, 255, 255), ipv4(255, 255, 255, 255));
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#include <cppunit/TestFixture.h>
|
||||||
|
#include <cppunit/extensions/HelperMacros.h>
|
||||||
|
|
||||||
|
// ipv4_range_parse is a pure function, so this does not use test_fixture and
|
||||||
|
// the mock and logging setup that comes with it.
|
||||||
|
class TestCommandIp : public CppUnit::TestFixture {
|
||||||
|
CPPUNIT_TEST_SUITE(TestCommandIp);
|
||||||
|
|
||||||
|
CPPUNIT_TEST(test_single_address);
|
||||||
|
CPPUNIT_TEST(test_explicit_range);
|
||||||
|
|
||||||
|
CPPUNIT_TEST(test_cidr);
|
||||||
|
CPPUNIT_TEST(test_cidr_zero_mask);
|
||||||
|
CPPUNIT_TEST(test_cidr_full_mask);
|
||||||
|
|
||||||
|
CPPUNIT_TEST_SUITE_END();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void test_single_address();
|
||||||
|
void test_explicit_range();
|
||||||
|
|
||||||
|
void test_cidr();
|
||||||
|
void test_cidr_zero_mask();
|
||||||
|
void test_cidr_full_mask();
|
||||||
|
};
|
||||||
Reference in New Issue
Block a user