diff --git a/src/command_dynamic.cc b/src/command_dynamic.cc index 20c960f1..8a2b9d9a 100644 --- a/src/command_dynamic.cc +++ b/src/command_dynamic.cc @@ -109,10 +109,22 @@ system_method_insert(const torrent::Object::list_type& args) { rpc::commands.insert_type(create_new_key<0>(rawKey, ""), command, slot, flags, NULL, NULL); } else if (options.find("simple") != std::string::npos) { - rpc::Command::any_slot slot = &rpc::CommandFunction::call; - rpc::Command* command = new rpc::CommandFunction(system_method_generate_command(++itrArgs, args.end())); + rpc::command_base* command = new rpc::command_base(); - rpc::commands.insert_type(create_new_key<0>(rawKey, ""), command, slot, flags, NULL, NULL); + command->set_function >::type>(std::tr1::bind(&rpc::command_function_call_str, + system_method_generate_command(++itrArgs, args.end()), + std::tr1::placeholders::_1, + std::tr1::placeholders::_2)); + + rpc::commands.insert_type(create_new_key<0>(rawKey, ""), command, &rpc::command_base_call, + flags, NULL, NULL); + +// rpc::Command::any_slot slot = &rpc::CommandFunction::call; +// rpc::Command* command = new rpc::CommandFunction(system_method_generate_command(++itrArgs, args.end())); + +// rpc::commands.insert_type(create_new_key<0>(rawKey, ""), command, slot, flags, NULL, NULL); } else if (options.find("value") != std::string::npos || options.find("bool") != std::string::npos || @@ -197,29 +209,30 @@ system_method_redirect(const torrent::Object::list_type& args) { torrent::Object system_method_get(const torrent::Object::string_type& args) { - rpc::CommandFunction* function; - rpc::CommandMap::iterator itr = rpc::commands.find(args.c_str()); +// rpc::CommandFunction* function; +// rpc::CommandMap::iterator itr = rpc::commands.find(args.c_str()); - if (itr == rpc::commands.end() || - (function = dynamic_cast(itr->second.m_variable)) == NULL) - throw torrent::input_error("Command not modifiable or wrong type."); +// if (itr == rpc::commands.end() || +// (function = dynamic_cast(itr->second.m_variable)) == NULL) +// throw torrent::input_error("Command not modifiable or wrong type."); - return torrent::Object(function->command()); +// return torrent::Object(function->command()); + return torrent::Object(); } torrent::Object system_method_set(const torrent::Object::list_type& args) { - if (args.empty()) - throw torrent::input_error("Invalid argument count."); +// if (args.empty()) +// throw torrent::input_error("Invalid argument count."); - rpc::CommandFunction* function; - rpc::CommandMap::iterator itr = rpc::commands.find(args.front().as_string().c_str()); +// rpc::CommandFunction* function; +// rpc::CommandMap::iterator itr = rpc::commands.find(args.front().as_string().c_str()); - if (itr == rpc::commands.end() || !rpc::commands.is_modifiable(itr) || - (function = dynamic_cast(itr->second.m_variable)) == NULL) - throw torrent::input_error("Command not modifiable or wrong type."); +// if (itr == rpc::commands.end() || !rpc::commands.is_modifiable(itr) || +// (function = dynamic_cast(itr->second.m_variable)) == NULL) +// throw torrent::input_error("Command not modifiable or wrong type."); - function->set_command(system_method_generate_command(++args.begin(), args.end())); +// function->set_command(system_method_generate_command(++args.begin(), args.end())); return torrent::Object(); } diff --git a/src/command_events.cc b/src/command_events.cc index e3420e92..9cb2a560 100644 --- a/src/command_events.cc +++ b/src/command_events.cc @@ -341,5 +341,5 @@ initialize_command_events() { CMD2_ANY_VALUE ("close_low_diskspace", std::tr1::bind(&apply_close_low_diskspace, std::tr1::placeholders::_2)); CMD2_ANY_LIST ("download_list", std::tr1::bind(&apply_download_list, std::tr1::placeholders::_2)); - CMD2_ANY_LIST ("d.multicall", std::tr1::bind(&d_multicall, std::tr1::placeholders::_2)); + CMD2_ANY_LIST ("d.multicall2", std::tr1::bind(&d_multicall, std::tr1::placeholders::_2)); } diff --git a/src/command_helpers.h b/src/command_helpers.h index c0fd3a87..e4fa731c 100644 --- a/src/command_helpers.h +++ b/src/command_helpers.h @@ -71,12 +71,11 @@ void initialize_commands(); rpc::commands.insert_type(key, commandNewSlotItr++, &rpc::function, \ rpc::CommandMap::flag_dont_delete, NULL, NULL); -// #define CMD2_ANY(key, slot) CMD2_A_FUNCTION(key, command_base_call_any, slot, "i:", "") -#define CMD2_ANY(key, slot) CMD2_A_FUNCTION(key, command_base_call, slot, "i:", "") +#define CMD2_ANY(key, slot) CMD2_A_FUNCTION(key, command_base_call, slot, "i:", "") -#define CMD2_ANY_P(key, slot) CMD2_A_FUNCTION_PRIVATE(key, command_base_call, slot, "i:", "") -#define CMD2_ANY_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_list, object_convert_void(slot), "i:", "") -#define CMD2_ANY_L(key, slot) CMD2_A_FUNCTION(key, command_base_call_list, slot, "A:", "") +#define CMD2_ANY_P(key, slot) CMD2_A_FUNCTION_PRIVATE(key, command_base_call, slot, "i:", "") +#define CMD2_ANY_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_list, object_convert_void(slot), "i:", "") +#define CMD2_ANY_L(key, slot) CMD2_A_FUNCTION(key, command_base_call_list, slot, "A:", "") #define CMD2_ANY_VALUE(key, slot) CMD2_A_FUNCTION(key, command_base_call_value, slot, "i:i", "") #define CMD2_ANY_VALUE_V(key, slot) CMD2_A_FUNCTION(key, command_base_call_value, object_convert_void(slot), "i:i", "") diff --git a/src/command_local.cc b/src/command_local.cc index 7d5c2ff4..0f0bf4fd 100644 --- a/src/command_local.cc +++ b/src/command_local.cc @@ -240,8 +240,8 @@ initialize_command_local() { CMD2_ANY("execute_capture", std::tr1::bind(&rpc::ExecFile::execute_object, &rpc::execFile, std::tr1::placeholders::_2, rpc::ExecFile::flag_throw | rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture)); CMD2_ANY("execute_capture_nothrow", std::tr1::bind(&rpc::ExecFile::execute_object, &rpc::execFile, std::tr1::placeholders::_2, rpc::ExecFile::flag_expand_tilde | rpc::ExecFile::flag_capture)); - CMD2_ANY_STRING("log.execute", std::tr1::bind(&apply_log, std::tr1::placeholders::_2, 0)); - CMD2_ANY_STRING("log.xmlrpc", std::tr1::bind(&apply_log, std::tr1::placeholders::_2, 1)); + CMD2_ANY_STRING ("log.execute", std::tr1::bind(&apply_log, std::tr1::placeholders::_2, 0)); + CMD2_ANY_STRING_V("log.xmlrpc", std::tr1::bind(&ThreadWorker::set_xmlrpc_log, worker_thread, std::tr1::placeholders::_2)); // TODO: Convert to new command types: *rpc::Command::argument(0) = "placeholder.0"; diff --git a/src/main.cc b/src/main.cc index 2b989f02..c9fd650b 100644 --- a/src/main.cc +++ b/src/main.cc @@ -611,6 +611,9 @@ main(int argc, char** argv) { CMD2_REDIRECT ("view_sort_current", "view.sort_current"); CMD2_REDIRECT ("view_sort_new", "view.sort_new"); + // Rename these to avoid conflicts with old style. + CMD2_REDIRECT_GENERIC("d.multicall", "d.multicall2"); + // Functions that might not get depracted as they are nice for // configuration files, and thus might do with just some // cleanup. diff --git a/src/rpc/Makefile.am b/src/rpc/Makefile.am index d3818796..bbbeb116 100644 --- a/src/rpc/Makefile.am +++ b/src/rpc/Makefile.am @@ -19,6 +19,8 @@ libsub_rpc_a_SOURCES = \ command_new_slot.h \ exec_file.cc \ exec_file.h \ + object_storage.cc \ + object_storage.h \ parse.cc \ parse.h \ parse_commands.cc \ diff --git a/src/rpc/command.h b/src/rpc/command.h index c73b3e3d..9746b0ce 100644 --- a/src/rpc/command.h +++ b/src/rpc/command.h @@ -157,6 +157,7 @@ public: static torrent::Object* stack_end() { return current_stack.end(); } static torrent::Object* push_stack(const torrent::Object::list_type& args, stack_type* stack); + static torrent::Object* push_stack(const torrent::Object* first_arg, const torrent::Object* last_arg, stack_type* stack); static void pop_stack(stack_type* stack, torrent::Object* last_stack); protected: diff --git a/src/rpc/command_function.cc b/src/rpc/command_function.cc index 743ee9d2..f1dd2ea8 100644 --- a/src/rpc/command_function.cc +++ b/src/rpc/command_function.cc @@ -49,105 +49,39 @@ namespace rpc { // Temp until it can be moved somewhere better... const torrent::Object command_function_call(const torrent::raw_string& cmd, target_type target, const torrent::Object& args) { - char* buffer[sizeof(torrent::Object) * Command::max_arguments]; - torrent::Object* stack = (torrent::Object*)buffer; - torrent::Object* first = (torrent::Object*)buffer; + rpc::Command::stack_type stack; + torrent::Object* last_stack; - if (args.is_list()) { - // Do nothing for now. - for (torrent::Object::list_const_iterator itr = args.as_list().begin(), last = args.as_list().end(); - itr != last && first != stack + Command::max_arguments; - itr++, first++) { - new (first) torrent::Object(*itr); - first->swap(*Command::argument(std::distance(stack, first))); - } - - } else if (args.type() != torrent::Object::TYPE_NONE) { - new (first) torrent::Object(args); - (first++)->swap(*Command::argument(0)); - } + if (args.is_list()) + last_stack = rpc::Command::push_stack(args.as_list(), &stack); + else if (args.type() != torrent::Object::TYPE_NONE) + last_stack = rpc::Command::push_stack(&args, &args + 1, &stack); + else + last_stack = rpc::Command::push_stack(NULL, NULL, &stack); try { torrent::Object result = parse_command_multiple(target, cmd.begin(), cmd.end()); - while (first-- != stack) { - first->swap(*Command::argument(std::distance(stack, first))); - first->~Object(); - } - + rpc::Command::pop_stack(&stack, last_stack); return result; } catch (torrent::bencode_error& e) { - while (first-- != stack) { - first->swap(*Command::argument(std::distance(stack, first))); - first->~Object(); - } - - throw e; - } -} - -const torrent::Object -CommandFunction::call(Command* rawCommand, target_type target, const torrent::Object& args) { - char* buffer[sizeof(torrent::Object) * Command::max_arguments]; - torrent::Object* stack = (torrent::Object*)buffer; - torrent::Object* first = (torrent::Object*)buffer; - - if (args.is_list()) { - // Do nothing for now. - for (torrent::Object::list_const_iterator itr = args.as_list().begin(), last = args.as_list().end(); - itr != last && first != stack + Command::max_arguments; - itr++, first++) { - new (first) torrent::Object(*itr); - first->swap(*argument(std::distance(stack, first))); - } - - } else if (args.type() != torrent::Object::TYPE_NONE) { - new (first) torrent::Object(args); - (first++)->swap(*argument(0)); - } - - CommandFunction* command = reinterpret_cast(rawCommand); - - try { - torrent::Object result = parse_command_multiple(target, command->m_command.c_str(), command->m_command.c_str() + command->m_command.size()); - - while (first-- != stack) { - first->swap(*argument(std::distance(stack, first))); - first->~Object(); - } - - return result; - - } catch (torrent::bencode_error& e) { - while (first-- != stack) { - first->swap(*Command::argument(std::distance(stack, first))); - first->~Object(); - } - + rpc::Command::pop_stack(&stack, last_stack); throw e; } } const torrent::Object CommandFunctionList::call(Command* rawCommand, target_type target, const torrent::Object& args) { - char* buffer[sizeof(torrent::Object) * Command::max_arguments]; - torrent::Object* stack = (torrent::Object*)buffer; - torrent::Object* first = (torrent::Object*)buffer; + rpc::Command::stack_type stack; + torrent::Object* last_stack; - if (args.is_list()) { - // Do nothing for now. - for (torrent::Object::list_const_iterator itr = args.as_list().begin(), last = args.as_list().end(); - itr != last && first != stack + Command::max_arguments; - itr++, first++) { - new (first) torrent::Object(*itr); - first->swap(*argument(std::distance(stack, first))); - } - - } else if (args.type() != torrent::Object::TYPE_NONE) { - new (first) torrent::Object(args); - (first++)->swap(*argument(0)); - } + if (args.is_list()) + last_stack = rpc::Command::push_stack(args.as_list(), &stack); + else if (args.type() != torrent::Object::TYPE_NONE) + last_stack = rpc::Command::push_stack(&args, &args + 1, &stack); + else + last_stack = rpc::Command::push_stack(NULL, NULL, &stack); CommandFunctionList* command = reinterpret_cast(rawCommand); @@ -156,19 +90,11 @@ CommandFunctionList::call(Command* rawCommand, target_type target, const torrent parse_command_multiple(target, itr->second.c_str(), itr->second.c_str() + itr->second.size()); } catch (torrent::bencode_error& e) { - while (first-- != stack) { - first->swap(*Command::argument(std::distance(stack, first))); - first->~Object(); - } - + rpc::Command::pop_stack(&stack, last_stack); throw e; } - while (first-- != stack) { - first->swap(*argument(std::distance(stack, first))); - first->~Object(); - } - + rpc::Command::pop_stack(&stack, last_stack); return torrent::Object(); } diff --git a/src/rpc/command_function.h b/src/rpc/command_function.h index 117a0378..73624c89 100644 --- a/src/rpc/command_function.h +++ b/src/rpc/command_function.h @@ -47,20 +47,6 @@ namespace rpc { -class CommandFunction : public Command { -public: - CommandFunction(const std::string& cmd = std::string()) : m_command(cmd) {} - - const std::string& command() const { return m_command; } - void set_command(const std::string& cmd) { m_command = cmd; } - - static const torrent::Object call(Command* rawCommand, target_type target, const torrent::Object& args); - -private: - // TODO: Replace with a delete-me flag and const char*. - std::string m_command; -}; - class CommandFunctionList : public Command, private std::vector > { public: @@ -86,6 +72,11 @@ public: const torrent::Object command_function_call(const torrent::raw_string& cmd, target_type target, const torrent::Object& args); +inline const torrent::Object +command_function_call_str(const std::string& cmd, target_type target, const torrent::Object& args) { + return command_function_call(torrent::raw_string::from_string(cmd), target, args); +} + } #endif diff --git a/src/rpc/command_impl.h b/src/rpc/command_impl.h index 43fbf5e1..b0c183d8 100644 --- a/src/rpc/command_impl.h +++ b/src/rpc/command_impl.h @@ -77,18 +77,24 @@ get_target_cast(target_type target, int type) { } inline torrent::Object* -Command::push_stack(const torrent::Object::list_type& args, stack_type* stack) { +Command::push_stack(const torrent::Object* first_arg, const torrent::Object* last_arg, 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 (&(*stack)[idx]) torrent::Object(*itr); + while (first_arg != last_arg && idx < Command::max_arguments) { + new (&(*stack)[idx]) torrent::Object(*first_arg++); (*stack)[idx].swap(*Command::argument(idx)); + + idx++; } return stack->begin() + idx; } +inline torrent::Object* +Command::push_stack(const torrent::Object::list_type& args, stack_type* stack) { + return push_stack(args.data(), args.data() + args.size(), stack); +} + inline void Command::pop_stack(stack_type* stack, torrent::Object* last_stack) { while (last_stack-- != stack->begin()) { diff --git a/src/rpc/object_storage.cc b/src/rpc/object_storage.cc new file mode 100644 index 00000000..911b641b --- /dev/null +++ b/src/rpc/object_storage.cc @@ -0,0 +1,43 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005-2007, 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 +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#include "config.h" + +#include "object_storage.h" + +namespace rpc { + +} diff --git a/src/rpc/object_storage.h b/src/rpc/object_storage.h new file mode 100644 index 00000000..d4b7025b --- /dev/null +++ b/src/rpc/object_storage.h @@ -0,0 +1,93 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005-2007, 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 +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +// The object_storage type is responsible for storing variables, +// commands, command lists and other types encoded in torrent::Object +// format. + +#ifndef RTORRENT_RPC_OBJECT_STORAGE_H +#define RTORRENT_RPC_OBJECT_STORAGE_H + +#include +#include +#include + +namespace rpc { + +// The key size should be such that the value type size which includes +// the next-pointer. + +struct object_storage_node_internal { + torrent::Object object; + char key[0]; +}; + +struct object_storage_node : public object_storage_node_internal { + // TODO: Use the size of the unordered_map::value_type with a struct {}. + static const size_t key_size = 128 - sizeof(object_storage_node_internal) - sizeof(void*); +}; + +struct hash_object_storage_node { + inline std::size_t operator () (const object_storage_node& p); +}; + +bool operator == (const object_storage_node& left, const object_storage_node& right) { return std::strcmp(left.key, right.key) == 0; } +bool operator != (const object_storage_node& left, const object_storage_node& right) { return std::strcmp(left.key, right.key) != 0; } +bool operator < (const object_storage_node& left, const object_storage_node& right) { return std::strcmp(left.key, right.key) < 0; } +bool operator <= (const object_storage_node& left, const object_storage_node& right) { return std::strcmp(left.key, right.key) <= 0; } +bool operator > (const object_storage_node& left, const object_storage_node& right) { return std::strcmp(left.key, right.key) > 0; } +bool operator >= (const object_storage_node& left, const object_storage_node& right) { return std::strcmp(left.key, right.key) >= 0; } + +class object_storage : private std::tr1::unordered_set { + typedef std::tr1::unordered_set base_type; + + using base_type::iterator; +}; + +inline std::size_t +hash_object_storage_node::operator () (const object_storage_node& p) { + std::size_t result = 0; + const char* first = p.key; + + while (*first != '\0') + result = (result * 131) + *first++; + + return result; +} + +} + +#endif diff --git a/src/rpc/scgi_task.cc b/src/rpc/scgi_task.cc index f7d664a6..91848b2b 100644 --- a/src/rpc/scgi_task.cc +++ b/src/rpc/scgi_task.cc @@ -229,8 +229,15 @@ SCgiTask::receive_write(const char* buffer, uint32_t length) { m_bufferSize = length + headerSize; std::memcpy(m_buffer + headerSize, buffer, length); - event_write(); + if (m_parent->log_fd() >= 0) { + // Clean up logging, this is just plain ugly... + // write(m_logFd, "\n---\n", sizeof("\n---\n")); + write(m_parent->log_fd(), m_buffer, m_bufferSize); + write(m_parent->log_fd(), "\n---\n", sizeof("\n---\n")); + } + + event_write(); return true; } diff --git a/src/thread_worker.cc b/src/thread_worker.cc index 62b8d8d0..204b6ddc 100644 --- a/src/thread_worker.cc +++ b/src/thread_worker.cc @@ -40,7 +40,10 @@ #include "globals.h" #include "control.h" +#include +#include #include +#include #include #include "core/manager.h" @@ -67,6 +70,8 @@ ThreadWorker::set_scgi(rpc::SCgi* scgi) { if (!__sync_bool_compare_and_swap(&m_safe.scgi, NULL, scgi)) return false; + change_xmlrpc_log(); + // The xmlrpc process call requires a global lock. // m_safe.scgi->set_slot_process(rak::mem_fn(&rpc::xmlrpc, &rpc::XmlRpc::process)); @@ -77,6 +82,13 @@ ThreadWorker::set_scgi(rpc::SCgi* scgi) { return true; } +void +ThreadWorker::set_xmlrpc_log(const std::string& filename) { + m_xmlrpcLog = filename; + + queue_item((thread_base_func)&msg_change_xmlrpc_log); +} + void ThreadWorker::start_scgi(ThreadBase* baseThread) { ThreadWorker* thread = (ThreadWorker*)baseThread; @@ -95,6 +107,38 @@ ThreadWorker::start_log_counter(ThreadBase* baseThread) { priority_queue_insert(&thread->m_taskScheduler, &thread->m_taskTouchLog, cachedTime); } +void +ThreadWorker::msg_change_xmlrpc_log(ThreadBase* baseThread) { + ThreadWorker* thread = (ThreadWorker*)baseThread; + + acquire_global_lock(); + thread->change_xmlrpc_log(); + release_global_lock(); +} + +void +ThreadWorker::change_xmlrpc_log() { + if (scgi() == NULL) + return; + + if (scgi()->log_fd() != -1) + ::close(scgi()->log_fd()); + + if (m_xmlrpcLog.empty()) { + control->core()->push_log("Closed XMLRPC log."); + return; + } + + scgi()->set_log_fd(open(rak::path_expand(m_xmlrpcLog).c_str(), O_WRONLY | O_APPEND | O_CREAT, 0644)); + + if (scgi()->log_fd() == -1) { + control->core()->push_log_std("Could not open XMLRPC log file '" + m_xmlrpcLog + "'."); + return; + } + + control->core()->push_log_std("Logging XMLRPC events to '" + m_xmlrpcLog + "'."); +} + void ThreadWorker::task_touch_log() { priority_queue_insert(&m_taskScheduler, &m_taskTouchLog, cachedTime + rak::timer::from_seconds(1)); diff --git a/src/thread_worker.h b/src/thread_worker.h index 6d7e0412..e04352a9 100644 --- a/src/thread_worker.h +++ b/src/thread_worker.h @@ -58,13 +58,16 @@ public: rpc::SCgi* scgi() { return m_safe.scgi; } bool set_scgi(rpc::SCgi* scgi); + void set_xmlrpc_log(const std::string& filename); + static void start_scgi(ThreadBase* thread); static void start_log_counter(ThreadBase* thread); + static void msg_change_xmlrpc_log(ThreadBase* thread); private: void task_touch_log(); - rak::priority_item m_taskTouchLog; + void change_xmlrpc_log(); struct lt_cacheline_aligned safe_type { safe_type() : scgi(NULL) {} @@ -72,7 +75,12 @@ private: rpc::SCgi* scgi; }; - safe_type m_safe; + rak::priority_item m_taskTouchLog; + safe_type m_safe; + + // The following types shall only be modified while holding the + // global lock. + std::string m_xmlrpcLog; }; #endif