diff --git a/src/command_events.cc b/src/command_events.cc index 1fb8f6a3..e3420e92 100644 --- a/src/command_events.cc +++ b/src/command_events.cc @@ -313,7 +313,7 @@ void initialize_command_events() { CMD2_ANY("test.thread_locking", std::tr1::bind(&test_thread_locking)); - CMD2_VAR_BOOL ("check_hash", true); // Rename + CMD2_VAR_BOOL ("pieces.hash.on_completion", true); CMD2_ANY_STRING ("on_ratio", std::tr1::bind(&apply_on_ratio, std::tr1::placeholders::_2)); diff --git a/src/core/download_list.cc b/src/core/download_list.cc index 951e380c..c5c5396a 100644 --- a/src/core/download_list.cc +++ b/src/core/download_list.cc @@ -558,7 +558,7 @@ void DownloadList::received_finished(Download* download) { check_contains(download); - if (rpc::call_command_value("check_hash")) + if (rpc::call_command_value("pieces.hash.on_completion")) // Set some 'checking_finished_thingie' variable to make hash_done // trigger correctly, also so it can bork on missing data. hash_queue(download, Download::variable_hashing_last); diff --git a/src/main.cc b/src/main.cc index 6ef5b88b..2b989f02 100644 --- a/src/main.cc +++ b/src/main.cc @@ -446,6 +446,8 @@ main(int argc, char** argv) { CMD2_REDIRECT ("get_session_on_completion", "system.session.on_completion"); CMD2_REDIRECT ("set_session_on_completion", "system.session.on_completion.set"); + CMD2_REDIRECT ("check_hash", "pieces.hash.on_completion.set"); + // // Download: // diff --git a/src/rpc/command.h b/src/rpc/command.h index 8798c5af..c73b3e3d 100644 --- a/src/rpc/command.h +++ b/src/rpc/command.h @@ -131,9 +131,15 @@ public: static const unsigned int max_arguments = 10; struct stack_type { - torrent::Object* begin() { return reinterpret_cast(buffer); } - torrent::Object* end() { return reinterpret_cast(buffer) + max_arguments; } + torrent::Object* begin() { return reinterpret_cast(buffer); } + torrent::Object* end() { return reinterpret_cast(buffer) + max_arguments; } + const torrent::Object* begin() const { return reinterpret_cast(buffer); } + const torrent::Object* end() const { return reinterpret_cast(buffer) + max_arguments; } + + torrent::Object& operator [] (unsigned int idx) { return *(begin() + idx); } + const torrent::Object& operator [] (unsigned int idx) const { return *(begin() + idx); } + static stack_type* from_data(char* data) { return reinterpret_cast(data); } char buffer[sizeof(torrent::Object) * max_arguments]; @@ -142,16 +148,16 @@ public: Command() {} virtual ~Command() {} - static torrent::Object* argument(unsigned int index) { return m_arguments.begin() + index; } - static torrent::Object& argument_ref(unsigned int index) { return *(m_arguments.begin() + index); } + static torrent::Object* argument(unsigned int index) { return current_stack.begin() + index; } + static torrent::Object& argument_ref(unsigned int index) { return *(current_stack.begin() + index); } - static stack_type m_arguments; + static stack_type current_stack; - static torrent::Object* stack_begin() { return m_arguments.begin(); } - static torrent::Object* stack_end() { return m_arguments.end(); } + static torrent::Object* stack_begin() { return current_stack.begin(); } + static torrent::Object* stack_end() { return current_stack.end(); } - static torrent::Object* push_stack(const torrent::Object::list_type& args, torrent::Object* tmp_stack); - static void pop_stack(torrent::Object* first_stack, torrent::Object* last_stack); + static torrent::Object* push_stack(const torrent::Object::list_type& args, stack_type* stack); + static void pop_stack(stack_type* stack, torrent::Object* last_stack); protected: Command(const Command&); diff --git a/src/rpc/command_impl.h b/src/rpc/command_impl.h index 61ea77e6..43fbf5e1 100644 --- a/src/rpc/command_impl.h +++ b/src/rpc/command_impl.h @@ -77,23 +77,26 @@ get_target_cast(target_type target, int type) { } inline torrent::Object* -Command::push_stack(const torrent::Object::list_type& args, torrent::Object* tmp_stack) { +Command::push_stack(const torrent::Object::list_type& args, stack_type* stack) { unsigned int idx = 0; for (torrent::Object::list_const_iterator itr = args.begin(), last = args.end(); itr != last && idx < Command::max_arguments; itr++, idx++) { - new (tmp_stack + idx) torrent::Object(*itr); - tmp_stack[idx].swap(*Command::argument(idx)); + new (&(*stack)[idx]) torrent::Object(*itr); + (*stack)[idx].swap(*Command::argument(idx)); } - return tmp_stack + idx; + return stack->begin() + idx; } inline void -Command::pop_stack(torrent::Object* first_stack, torrent::Object* last_stack) { - while (last_stack-- != first_stack) { - last_stack->swap(*Command::argument(std::distance(first_stack, last_stack))); +Command::pop_stack(stack_type* stack, torrent::Object* last_stack) { + while (last_stack-- != stack->begin()) { + last_stack->swap(*Command::argument(std::distance(stack->begin(), last_stack))); last_stack->~Object(); + + // To ensure we catch errors: + std::memset(last_stack, 0xAA, sizeof(torrent::Object)); } } diff --git a/src/rpc/command_map.cc b/src/rpc/command_map.cc index 00a4c4a6..22ee7bd1 100644 --- a/src/rpc/command_map.cc +++ b/src/rpc/command_map.cc @@ -55,7 +55,7 @@ namespace rpc { -Command::stack_type Command::m_arguments; +Command::stack_type Command::current_stack; CommandMap::~CommandMap() { std::vector keys; diff --git a/test/rpc/command_test.cc b/test/rpc/command_test.cc new file mode 100644 index 00000000..fd0a04b9 --- /dev/null +++ b/test/rpc/command_test.cc @@ -0,0 +1,83 @@ +#include "config.h" + +#import "command_test.h" + +CPPUNIT_TEST_SUITE_REGISTRATION(CommandTest); + +bool +command_stack_all_empty() { + return std::find_if(rpc::Command::stack_begin(), rpc::Command::stack_end(), + std::mem_fun_ref(&torrent::Object::is_not_empty)) == rpc::Command::stack_end(); +} + +void +CommandTest::test_stack() { + torrent::Object::list_type args; + rpc::Command::stack_type stack; + torrent::Object* last_stack; + + // Test empty stack. + CPPUNIT_ASSERT(command_stack_all_empty()); + + last_stack = rpc::Command::push_stack(args, &stack); + CPPUNIT_ASSERT(command_stack_all_empty()); + + rpc::Command::pop_stack(&stack, last_stack); + CPPUNIT_ASSERT(command_stack_all_empty()); + + // Test stack with one. + args.push_back(int64_t(1)); + + last_stack = rpc::Command::push_stack(args, &stack); + CPPUNIT_ASSERT(!command_stack_all_empty()); + CPPUNIT_ASSERT(rpc::Command::stack_begin()->as_value() == 1); + + rpc::Command::pop_stack(&stack, last_stack); + CPPUNIT_ASSERT(command_stack_all_empty()); + + // Test stack with two + args.clear(); + args.push_back(int64_t(2)); + args.push_back(int64_t(3)); + + last_stack = rpc::Command::push_stack(args, &stack); + CPPUNIT_ASSERT(!command_stack_all_empty()); + CPPUNIT_ASSERT(rpc::Command::current_stack[0].as_value() == 2); + CPPUNIT_ASSERT(rpc::Command::current_stack[1].as_value() == 3); + + rpc::Command::pop_stack(&stack, last_stack); + CPPUNIT_ASSERT(command_stack_all_empty()); +} + +void +CommandTest::test_stack_double() { + torrent::Object::list_type args; + rpc::Command::stack_type stack_first; + rpc::Command::stack_type stack_second; + torrent::Object* last_stack_first; + torrent::Object* last_stack_second; + + // Test double-stacked. + args.push_back(int64_t(1)); + + last_stack_first = rpc::Command::push_stack(args, &stack_first); + CPPUNIT_ASSERT(!command_stack_all_empty()); + CPPUNIT_ASSERT(rpc::Command::current_stack[0].as_value() == 1); + + args.clear(); + args.push_back(int64_t(2)); + args.push_back(int64_t(3)); + + last_stack_second = rpc::Command::push_stack(args, &stack_second); + CPPUNIT_ASSERT(!command_stack_all_empty()); + + CPPUNIT_ASSERT(rpc::Command::current_stack[0].as_value() == 2); + CPPUNIT_ASSERT(rpc::Command::current_stack[1].as_value() == 3); + + rpc::Command::pop_stack(&stack_second, last_stack_second); + CPPUNIT_ASSERT(!command_stack_all_empty()); + CPPUNIT_ASSERT(rpc::Command::current_stack[0].as_value() == 1); + + rpc::Command::pop_stack(&stack_first, last_stack_first); + CPPUNIT_ASSERT(command_stack_all_empty()); +} diff --git a/test/rpc/command_test.h b/test/rpc/command_test.h new file mode 100644 index 00000000..f9ca6725 --- /dev/null +++ b/test/rpc/command_test.h @@ -0,0 +1,19 @@ +#include + +#include "rpc/command.h" + +class CommandTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(CommandTest); + CPPUNIT_TEST(test_stack); + CPPUNIT_TEST(test_stack_double); + CPPUNIT_TEST_SUITE_END(); + +public: + void setUp() { } + void tearDown() {} + + void test_stack(); + void test_stack_double(); + +private: +};