diff --git a/src/command_dynamic.cc b/src/command_dynamic.cc index b7f9aa48..ba4a4a8f 100644 --- a/src/command_dynamic.cc +++ b/src/command_dynamic.cc @@ -303,6 +303,8 @@ system_method_insert(const torrent::Object::list_type& args) { new_flags = rpc::object_storage::flag_bool_type; else if (options.find("string") != std::string::npos) new_flags = rpc::object_storage::flag_string_type; + else if (options.find("list") != std::string::npos) + new_flags = rpc::object_storage::flag_list_type; else if (options.find("simple") != std::string::npos) new_flags = rpc::object_storage::flag_function_type; else @@ -428,10 +430,8 @@ initialize_command_dynamic() { CMD2_VAR_BOOL ("method.use_deprecated", true); CMD2_VAR_VALUE ("method.use_intermediate", 1); - CMD2_ANY_LIST ("method.insert", std::bind(&system_method_insert, std::placeholders::_2)); - - CMD2_ANY_LIST ("method.insert.value", std::bind(&system_method_insert_object, std::placeholders::_2, - rpc::object_storage::flag_value_type)); + CMD2_ANY_LIST ("method.insert", std::bind(&system_method_insert, std::placeholders::_2)); + CMD2_ANY_LIST ("method.insert.value", std::bind(&system_method_insert_object, std::placeholders::_2, rpc::object_storage::flag_value_type)); CMD2_METHOD_INSERT("method.insert.simple", rpc::object_storage::flag_function_type); CMD2_METHOD_INSERT("method.insert.c_simple", rpc::object_storage::flag_constant | rpc::object_storage::flag_function_type); @@ -444,6 +444,11 @@ initialize_command_dynamic() { std::placeholders::_2)); CMD2_ANY_LIST ("method.set", std::bind(&system_method_set_function, std::placeholders::_2)); + CMD2_ANY_STRING ("method.const", std::bind(&rpc::object_storage::has_flag_str, control->object_storage(), + std::placeholders::_2, rpc::object_storage::flag_constant)); + CMD2_ANY_STRING_V("method.const.enable", std::bind(&rpc::object_storage::enable_flag_str, control->object_storage(), + std::placeholders::_2, rpc::object_storage::flag_constant)); + CMD2_ANY_LIST ("method.has_key", std::bind(&system_method_has_key, std::placeholders::_2)); CMD2_ANY_LIST ("method.set_key", std::bind(&system_method_set_key, std::placeholders::_2)); CMD2_ANY_STRING ("method.list_keys", std::bind(&system_method_list_keys, std::placeholders::_2)); diff --git a/src/command_helpers.h b/src/command_helpers.h index b9b81ef5..e85c8348 100644 --- a/src/command_helpers.h +++ b/src/command_helpers.h @@ -58,6 +58,7 @@ void initialize_commands(); #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_VOID(key, slot) CMD2_A_FUNCTION(key, command_base_call, object_convert_void(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:", "") @@ -127,7 +128,9 @@ void initialize_commands(); CMD2_ANY(key, std::bind(&rpc::object_storage::get, control->object_storage(), \ torrent::raw_string::from_c_str(key))); \ CMD2_ANY_LIST(key ".set", std::bind(&rpc::object_storage::set_list, control->object_storage(), \ - torrent::raw_string::from_c_str(key), std::placeholders::_2)); + torrent::raw_string::from_c_str(key), std::placeholders::_2)); \ + CMD2_ANY_VOID(key ".push_back", std::bind(&rpc::object_storage::list_push_back, control->object_storage(), \ + torrent::raw_string::from_c_str(key), std::placeholders::_2)); #define CMD2_FUNC_SINGLE(key, cmds) \ CMD2_ANY(key, std::bind(&rpc::command_function_call, torrent::raw_string::from_c_str(cmds), \ diff --git a/src/rpc/exec_file.cc b/src/rpc/exec_file.cc index 7c017d1a..97aa7d49 100644 --- a/src/rpc/exec_file.cc +++ b/src/rpc/exec_file.cc @@ -46,6 +46,7 @@ #include "exec_file.h" #include "parse.h" +#include "thread_base.h" namespace rpc { @@ -107,57 +108,62 @@ ExecFile::execute(const char* file, char* const* argv, int flags) { int result = execvp(file, argv); _exit(result); + } - } else { - if (flags & flag_capture) { - m_capture = std::string(); - ::close(pipeFd[1]); - - char buffer[4096]; - ssize_t length; - - do { - length = read(pipeFd[0], buffer, sizeof(buffer)); - - if (length > 0) - m_capture += std::string(buffer, length); - } while (length > 0); - - ::close(pipeFd[0]); - - if (m_logFd != -1) { - write(m_logFd, "Captured output:\n", sizeof("Captured output:\n")); - write(m_logFd, m_capture.data(), m_capture.length()); - } - } - - if (flags & flag_background) { - if (m_logFd != -1) - write(m_logFd, "\n--- Background task ---\n", sizeof("\n--- Background task ---\n")); + if (flags & flag_background) { + if (m_logFd != -1) + write(m_logFd, "\n--- Background task ---\n", sizeof("\n--- Background task ---\n")); - return 0; - } + return 0; + } - int status; - int wpid; + // We yield the global lock when waiting for the executed command to + // finish so that XMLRPC and other threads can continue working. + ThreadBase::release_global_lock(); + + if (flags & flag_capture) { + m_capture = std::string(); + ::close(pipeFd[1]); + + char buffer[4096]; + ssize_t length; do { - wpid = waitpid(childPid, &status, 0); - } while (wpid == -1 && rak::error_number::current().value() == rak::error_number::e_intr); + length = read(pipeFd[0], buffer, sizeof(buffer)); - if (wpid != childPid) - throw torrent::internal_error("ExecFile::execute(...) waitpid failed."); + if (length > 0) + m_capture += std::string(buffer, length); + } while (length > 0); + + ::close(pipeFd[0]); - // Check return value? if (m_logFd != -1) { - if (status == 0) - write(m_logFd, "\n--- Success ---\n", sizeof("\n--- Success ---\n")); - else - write(m_logFd, "\n--- Error ---\n", sizeof("\n--- Error ---\n")); + write(m_logFd, "Captured output:\n", sizeof("Captured output:\n")); + write(m_logFd, m_capture.data(), m_capture.length()); } - - return status; } + + int status; + int wpid; + + do { + wpid = waitpid(childPid, &status, 0); + } while (wpid == -1 && rak::error_number::current().value() == rak::error_number::e_intr); + + ThreadBase::acquire_global_lock(); + + if (wpid != childPid) + throw torrent::internal_error("ExecFile::execute(...) waitpid failed."); + + // Check return value? + if (m_logFd != -1) { + if (status == 0) + write(m_logFd, "\n--- Success ---\n", sizeof("\n--- Success ---\n")); + else + write(m_logFd, "\n--- Error ---\n", sizeof("\n--- Error ---\n")); + } + + return status; } torrent::Object diff --git a/src/rpc/object_storage.cc b/src/rpc/object_storage.cc index 03e27e9f..1ee0b7c1 100644 --- a/src/rpc/object_storage.cc +++ b/src/rpc/object_storage.cc @@ -55,6 +55,33 @@ object_storage::find_local(const torrent::raw_string& key) { return end(bucket_count()); } +object_storage::local_iterator +object_storage::find_local_const(const torrent::raw_string& key, unsigned int type) { + local_iterator itr = find_local(key); + + if (itr == end(bucket_count())) + throw torrent::input_error("Key not found."); + + if ((type != 0 && (itr->second.flags & mask_type) != type)) + throw torrent::input_error("Object is wrong type or const."); + + return itr; +} + +object_storage::local_iterator +object_storage::find_local_mutable(const torrent::raw_string& key, unsigned int type) { + local_iterator itr = find_local(key); + + if (itr == end(bucket_count())) + throw torrent::input_error("Key not found."); + + if ((type != 0 && (itr->second.flags & mask_type) != type) || + itr->second.flags & flag_constant) + throw torrent::input_error("Object is wrong type or const."); + + return itr; +} + object_storage::iterator object_storage::insert(const char* key_data, uint32_t key_size, const torrent::Object& rawObject, unsigned int flags) { if (std::find(key_data, key_data + key_size, '\0') != key_data + key_size) @@ -92,74 +119,65 @@ object_storage::insert(const char* key_data, uint32_t key_size, const torrent::O return result.first; } +bool +object_storage::has_flag(const torrent::raw_string& key, unsigned int flag) { + local_iterator itr = find_local_const(key); + return itr->second.flags & flag; +} + +void +object_storage::enable_flag(const torrent::raw_string& key, unsigned int flag) { + local_iterator itr = find_local_mutable(key); + itr->second.flags |= (flag & (flag_constant)); +} + const torrent::Object& object_storage::get(const torrent::raw_string& key) { - local_iterator itr = find_local(key); - - if (itr == end(bucket_count())) - throw torrent::input_error("Key not found."); - + local_iterator itr = find_local_const(key); return itr->second.object; } const torrent::Object& object_storage::set_bool(const torrent::raw_string& key, int64_t object) { - local_iterator itr = find_local(key); - - if (itr == end(bucket_count()) || (itr->second.flags & mask_type) != flag_bool_type) - throw torrent::input_error("Key not found or wrong type."); - + local_iterator itr = find_local_mutable(key, flag_bool_type); return itr->second.object = !!object; } const torrent::Object& object_storage::set_value(const torrent::raw_string& key, int64_t object) { - local_iterator itr = find_local(key); - - if (itr == end(bucket_count()) || (itr->second.flags & mask_type) != flag_value_type) - throw torrent::input_error("Key not found or wrong type."); - + local_iterator itr = find_local_mutable(key, flag_value_type); return itr->second.object = object; } const torrent::Object& object_storage::set_string(const torrent::raw_string& key, const std::string& object) { - local_iterator itr = find_local(key); - - if (itr == end(bucket_count()) || (itr->second.flags & mask_type) != flag_string_type) - throw torrent::input_error("Key not found or wrong type."); - + local_iterator itr = find_local_mutable(key, flag_string_type); return itr->second.object = object; } const torrent::Object& object_storage::set_list(const torrent::raw_string& key, const torrent::Object::list_type& object) { - local_iterator itr = find_local(key); - - if (itr == end(bucket_count()) || (itr->second.flags & mask_type) != flag_list_type) - throw torrent::input_error("Key not found or wrong type."); - + local_iterator itr = find_local_mutable(key, flag_list_type); return itr->second.object = torrent::Object::create_list_range(object.begin(), object.end()); } +void +object_storage::list_push_back(const torrent::raw_string& key, const torrent::Object& object) { + local_iterator itr = find_local_mutable(key, flag_list_type); + itr->second.object.as_list().push_back(object); +} + const torrent::Object& object_storage::set_function(const torrent::raw_string& key, const std::string& object) { - local_iterator itr = find_local(key); - - if (itr == end(bucket_count()) || (itr->second.flags & mask_type) != flag_function_type) - throw torrent::input_error("Key not found or wrong type."); - + local_iterator itr = find_local_mutable(key, flag_function_type); return itr->second.object = object; } torrent::Object object_storage::call_function(const torrent::raw_string& key, target_type target, const torrent::Object& object) { - local_iterator itr = find_local(key); - - if (itr == end(bucket_count())) - throw torrent::input_error("Key not found or wrong type."); + local_iterator itr = find_local_const(key); switch (itr->second.flags & mask_type) { case flag_function_type: @@ -173,18 +191,13 @@ object_storage::call_function(const torrent::raw_string& key, target_type target bool object_storage::has_multi_key(const torrent::raw_string& key, const std::string& cmd_key) { - local_iterator itr = find_local(key); - - return itr != end(0) && (itr->second.flags & mask_type) == flag_multi_type && - itr->second.object.has_key(cmd_key); + local_iterator itr = find_local_const(key, flag_multi_type); + return itr->second.object.has_key(cmd_key); } void object_storage::erase_multi_key(const torrent::raw_string& key, const std::string& cmd_key) { - local_iterator itr = find_local(key); - - if (itr != end(0) && (itr->second.flags & mask_type) == flag_multi_type) - return; + local_iterator itr = find_local_mutable(key, flag_multi_type); itr->second.object.erase_key(cmd_key); @@ -209,10 +222,7 @@ object_storage::set_multi_key_obj(const torrent::raw_string& key, const std::str if (!object.is_string() && !object.is_dict_key()) throw torrent::input_error("Object is wrong type."); - local_iterator itr = find_local(key); - - if (itr == end(0) || (itr->second.flags & mask_type) != flag_multi_type) - throw torrent::input_error("Key not found or wrong type."); + local_iterator itr = find_local_mutable(key, flag_multi_type); if (itr->second.flags & flag_rlookup) { rlookup_iterator r_itr = m_rlookup.find(cmd_key); diff --git a/src/rpc/object_storage.h b/src/rpc/object_storage.h index 40ae9277..bcefec48 100644 --- a/src/rpc/object_storage.h +++ b/src/rpc/object_storage.h @@ -108,6 +108,8 @@ public: static const size_t key_size = key_type::max_size; local_iterator find_local(const torrent::raw_string& key); + local_iterator find_local_const(const torrent::raw_string& key, unsigned int type = 0); + local_iterator find_local_mutable(const torrent::raw_string& key, unsigned int type = 0); iterator insert(const char* key_data, uint32_t key_size, const torrent::Object& object, unsigned int flags); iterator insert_c_str(const char* key, const torrent::Object& object, unsigned int flags) { return insert(key, std::strlen(key), object, flags); } @@ -116,6 +118,12 @@ public: iterator insert(const torrent::raw_string& key, const torrent::Object& object, unsigned int flags); iterator insert_str(const std::string& key, const torrent::Object& object, unsigned int flags); + bool has_flag(const torrent::raw_string& key, unsigned int flag); + bool has_flag_str(const std::string& key, unsigned int flag) { return has_flag(torrent::raw_string::from_string(key), flag); } + + void enable_flag(const torrent::raw_string& key, unsigned int flag); + void enable_flag_str(const std::string& key, unsigned int flag) { enable_flag(torrent::raw_string::from_string(key), flag); } + // Access functions that throw on error. const torrent::Object& get(const torrent::raw_string& key); @@ -138,6 +146,9 @@ public: const torrent::Object& set_c_str_list(const char* str, const torrent::Object::list_type& object) { return set_list(torrent::raw_string::from_c_str(str), object); } const torrent::Object& set_str_list(const std::string& str, const torrent::Object::list_type& object) { return set_list(torrent::raw_string::from_string(str), object); } + void list_push_back(const torrent::raw_string& key, const torrent::Object& object); + void list_push_back_str(const std::string& str, const torrent::Object& object) { list_push_back(torrent::raw_string::from_string(str), object); } + // Functions callers: torrent::Object call_function(const torrent::raw_string& key, target_type target, const torrent::Object& object); torrent::Object call_function_str(const std::string& key, target_type target, const torrent::Object& object);