diff --git a/src/command_helpers.cc b/src/command_helpers.cc index e35a620e..0eb2efd7 100644 --- a/src/command_helpers.cc +++ b/src/command_helpers.cc @@ -58,8 +58,13 @@ initialize_commands() { initialize_command_network(); initialize_command_ui(); +#ifdef ADDING_COMMANDS + if (commandSlotsItr > commandSlots + COMMAND_SLOTS_SIZE || + commandVariablesItr > commandVariables + COMMAND_VARIABLES_SIZE) +#else if (commandSlotsItr != commandSlots + COMMAND_SLOTS_SIZE || commandVariablesItr != commandVariables + COMMAND_VARIABLES_SIZE) +#endif throw torrent::internal_error("initialize_commands() static command array size mismatch."); } diff --git a/src/command_helpers.h b/src/command_helpers.h index a3d7e3db..1c38a0c9 100644 --- a/src/command_helpers.h +++ b/src/command_helpers.h @@ -46,8 +46,10 @@ namespace utils { // By using a static array we avoid allocating the variables on the // heap. This should reduce memory use and improve cache locality. -#define COMMAND_SLOTS_SIZE 24 -#define COMMAND_VARIABLES_SIZE 24 +#define COMMAND_SLOTS_SIZE 50 +#define COMMAND_VARIABLES_SIZE 50 + +#define ADDING_COMMANDS extern utils::CommandSlot commandSlots[COMMAND_SLOTS_SIZE]; extern utils::CommandSlot* commandSlotsItr; @@ -80,4 +82,7 @@ add_variable("get_" key, "set_" key, key, &utils::CommandVariable::get_string, & commandSlotsItr->set_slot(slot); \ variables->insert(key, commandSlotsItr++, &utils::CommandSlot::function, utils::VariableMap::flag_dont_delete); +#define ADD_COMMAND_COPY(key, function) \ + variables->insert(key, (commandSlotsItr - 1), &utils::CommandSlot::function, utils::VariableMap::flag_dont_delete); + #endif diff --git a/src/command_network.cc b/src/command_network.cc index 45f10403..f20999f4 100644 --- a/src/command_network.cc +++ b/src/command_network.cc @@ -83,6 +83,36 @@ apply_encryption(const torrent::Object& rawArgs) { return torrent::Object(); } +torrent::Object +apply_tos(const torrent::Object& rawArg) { + utils::Variable::value_type value; + torrent::ConnectionManager* cm = torrent::connection_manager(); + + const std::string& arg = rawArg.as_string(); + + if (arg == "default") + value = torrent::ConnectionManager::iptos_default; + + else if (arg == "lowdelay") + value = torrent::ConnectionManager::iptos_lowdelay; + + else if (arg == "throughput") + value = torrent::ConnectionManager::iptos_throughput; + + else if (arg == "reliability") + value = torrent::ConnectionManager::iptos_reliability; + + else if (arg == "mincost") + value = torrent::ConnectionManager::iptos_mincost; + + else if (!utils::Variable::string_to_value_unit_nothrow(arg.c_str(), &value, 16, 1)) + throw torrent::input_error("Invalid TOS identifier."); + + cm->set_priority(value); + + return torrent::Object(); +} + void initialize_command_network() { utils::VariableMap* variables = control->variable(); @@ -92,7 +122,7 @@ initialize_command_network() { ADD_VARIABLE_BOOL("port_open", true); ADD_VARIABLE_BOOL("port_random", true); - ADD_VARIABLE_STRING("port_range", "6890-6999"); + ADD_VARIABLE_STRING("port_range", "6881-6999"); ADD_VARIABLE_STRING("connection_leech", "leech"); ADD_VARIABLE_STRING("connection_seed", "seed"); @@ -110,4 +140,18 @@ initialize_command_network() { ADD_VARIABLE_VALUE("tracker_numwant", -1); ADD_COMMAND_SLOT("encryption", call_list, rak::ptr_fn(&apply_encryption)); + + ADD_COMMAND_SLOT("tos", call_string, rak::ptr_fn(&apply_tos)); + + ADD_COMMAND_SLOT("bind", call_string, utils::object_string_fn(rak::make_mem_fun(control->core(), &core::Manager::set_bind_address))) + ADD_COMMAND_COPY("set_bind", call_string) + ADD_COMMAND_SLOT("get_bind", call_unknown, utils::object_void_fn(rak::make_mem_fun(control->core(), &core::Manager::bind_address))) + + ADD_COMMAND_SLOT("ip", call_string, utils::object_string_fn(rak::make_mem_fun(control->core(), &core::Manager::set_local_address))) + ADD_COMMAND_COPY("set_ip", call_string) + ADD_COMMAND_SLOT("get_ip", call_unknown, utils::object_void_fn(rak::make_mem_fun(control->core(), &core::Manager::local_address))) + + ADD_COMMAND_SLOT("proxy_address", call_string, utils::object_string_fn(rak::make_mem_fun(control->core(), &core::Manager::set_proxy_address))) + ADD_COMMAND_COPY("set_proxy_address", call_string) + ADD_COMMAND_SLOT("get_proxy_address", call_unknown, utils::object_void_fn(rak::make_mem_fun(control->core(), &core::Manager::proxy_address))) } diff --git a/src/option_handler_rules.cc b/src/option_handler_rules.cc index 08e44c58..75d05963 100644 --- a/src/option_handler_rules.cc +++ b/src/option_handler_rules.cc @@ -144,32 +144,6 @@ apply_enable_trackers(const std::string& arg) { } } -void -apply_tos(const std::string& arg) { - utils::Variable::value_type value; - torrent::ConnectionManager* cm = torrent::connection_manager(); - - if (arg == "default") - value = torrent::ConnectionManager::iptos_default; - - else if (arg == "lowdelay") - value = torrent::ConnectionManager::iptos_lowdelay; - - else if (arg == "throughput") - value = torrent::ConnectionManager::iptos_throughput; - - else if (arg == "reliability") - value = torrent::ConnectionManager::iptos_reliability; - - else if (arg == "mincost") - value = torrent::ConnectionManager::iptos_mincost; - - else if (!utils::Variable::string_to_value_unit_nothrow(arg.c_str(), &value, 16, 1)) - throw torrent::input_error("Invalid TOS identifier."); - - cm->set_priority(value); -} - void apply_fast_cgi(const std::string& arg) { if (control->fast_cgi() != NULL) @@ -233,15 +207,6 @@ initialize_variables() { ADD_VARIABLE_STRING("directory", "./"); - variables->insert("tos", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_tos))); - - variables->insert("bind", new utils::VariableStringSlot(rak::mem_fn(control->core(), &core::Manager::bind_address), - rak::mem_fn(control->core(), &core::Manager::set_bind_address))); - variables->insert("ip", new utils::VariableStringSlot(rak::mem_fn(control->core(), &core::Manager::local_address), - rak::mem_fn(control->core(), &core::Manager::set_local_address))); - variables->insert("connection_proxy", new utils::VariableStringSlot(rak::mem_fn(control->core(), &core::Manager::proxy_address), - rak::mem_fn(control->core(), &core::Manager::set_proxy_address))); - variables->insert("http_proxy", new utils::VariableStringSlot(rak::mem_fn(control->core()->get_poll_manager()->get_http_stack(), &core::CurlStack::http_proxy), rak::mem_fn(control->core()->get_poll_manager()->get_http_stack(), &core::CurlStack::set_http_proxy))); variables->insert("fast_cgi", new utils::VariableStringSlot(NULL, rak::ptr_fn(&apply_fast_cgi))); diff --git a/src/rpc/xmlrpc.cc b/src/rpc/xmlrpc.cc index 9050cb25..ed44d322 100644 --- a/src/rpc/xmlrpc.cc +++ b/src/rpc/xmlrpc.cc @@ -169,6 +169,13 @@ XmlRpc::XmlRpc() : m_env(new xmlrpc_env) { xmlrpc_registry_add_method_w_doc(m_env, m_registry, NULL, "call.get_upload_rate", &xmlrpc_call_command, new server_info_t("upload_rate", &m_slotGet), "i:", ""); xmlrpc_registry_add_method_w_doc(m_env, m_registry, NULL, "call.get_directory", &xmlrpc_call_command, new server_info_t("get_directory", &m_slotGet), "s:", ""); + xmlrpc_registry_add_method_w_doc(m_env, m_registry, NULL, "call.set_directory", &xmlrpc_call_command, new server_info_t("set_directory", &m_slotSet), "i:s", ""); + + xmlrpc_registry_add_method_w_doc(m_env, m_registry, NULL, "call.get_bind", &xmlrpc_call_command, new server_info_t("get_bind", &m_slotGet), "s:", ""); + xmlrpc_registry_add_method_w_doc(m_env, m_registry, NULL, "call.set_bind", &xmlrpc_call_command, new server_info_t("set_bind", &m_slotSet), "i:s", ""); + + xmlrpc_registry_add_method_w_doc(m_env, m_registry, NULL, "call.get_ip", &xmlrpc_call_command, new server_info_t("get_ip", &m_slotGet), "s:", ""); + xmlrpc_registry_add_method_w_doc(m_env, m_registry, NULL, "call.set_ip", &xmlrpc_call_command, new server_info_t("set_ip", &m_slotSet), "i:s", ""); xmlrpc_registry_add_method_w_doc(m_env, m_registry, NULL, "call.print", &xmlrpc_call_command, new server_info_t("print", &m_slotSet), "i:s", ""); } diff --git a/src/utils/command_slot.cc b/src/utils/command_slot.cc index 497a4d81..ed6fb4c6 100644 --- a/src/utils/command_slot.cc +++ b/src/utils/command_slot.cc @@ -40,6 +40,13 @@ namespace utils { +const torrent::Object +CommandSlot::call_unknown(Variable* rawVariable, const torrent::Object& rawArgs) { + CommandSlot* command = static_cast(rawVariable); + + return command->m_slot(rawArgs); +} + const torrent::Object CommandSlot::call_list(Variable* rawVariable, const torrent::Object& rawArgs) { CommandSlot* command = static_cast(rawVariable); diff --git a/src/utils/command_slot.h b/src/utils/command_slot.h index 4760b437..40f2b8a6 100644 --- a/src/utils/command_slot.h +++ b/src/utils/command_slot.h @@ -69,6 +69,8 @@ public: void set_slot(slot_type::base_type* s) { m_slot.set(s); } + static const torrent::Object call_unknown(Variable* rawVariable, const torrent::Object& args); + static const torrent::Object call_list(Variable* rawVariable, const torrent::Object& args); static const torrent::Object call_string(Variable* rawVariable, const torrent::Object& args); @@ -134,6 +136,7 @@ private: template object_void_fn_t* object_fn(Return (*func)(void)) { return new object_void_fn_t(func); } +template object_void_fn_t* object_void_fn(Func func) { return new object_void_fn_t(func); } template object_string_fn1_t* object_string_fn(Func func) { return new object_string_fn1_t(func); } } diff --git a/src/utils/parse.cc b/src/utils/parse.cc index d72d0a7b..03632eed 100644 --- a/src/utils/parse.cc +++ b/src/utils/parse.cc @@ -51,6 +51,15 @@ parse_skip_wspace(const char* first, const char* last) { return first; } +const char* +parse_skip_wspace(const char* first) { + // Assume iswspace('\0') == false. + while (std::iswspace(*first)) + first++; + + return first; +} + const char* parse_string(const char* first, const char* last, std::string* dest) { if (first == last) @@ -99,6 +108,26 @@ parse_whole_string(const char* first, const char* last, std::string* dest) { const char* parse_value(const char* src, int64_t* value, int base, int unit) { + const char* last = parse_value_nothrow(src, value, base, unit); + + if (last == src) + throw torrent::input_error("Could not convert string to value."); + + return last; +} + +bool +parse_whole_value_nothrow(const char* src, int64_t* value, int base, int unit) { + const char* last = parse_value_nothrow(src, value, base, unit); + + if (last == src || *parse_skip_wspace(last) != '\0') + return false; + + return true; +} + +const char* +parse_value_nothrow(const char* src, int64_t* value, int base, int unit) { if (unit <= 0) throw torrent::input_error("Variable::string_to_value_unit(...) received unit <= 0."); @@ -111,7 +140,7 @@ parse_value(const char* src, int64_t* value, int base, int unit) { if (strcasecmp(src, "true") == 0) { *value = 1; return src + strlen("true"); } if (strcasecmp(src, "false") == 0) { *value = 0; return src + strlen("false"); } - throw torrent::input_error("Could not convert string to value."); + return src; } switch (*last) { @@ -267,26 +296,39 @@ convert_list_to_command(torrent::Object::list_type::const_iterator first, int64_t convert_to_value(const torrent::Object& src, int base, int unit) { + int64_t value; + + if (!convert_to_value_nothrow(src, &value, base, unit)) + throw torrent::input_error("Not convertible to a value."); + + return value; +} + +bool +convert_to_value_nothrow(const torrent::Object& src, int64_t* value, int base, int unit) { const torrent::Object& unpacked = (src.is_list() && src.as_list().size() == 1) ? src.as_list().front() : src; switch (unpacked.type()) { case torrent::Object::TYPE_VALUE: - return unpacked.as_value(); + *value = unpacked.as_value(); + break; case torrent::Object::TYPE_STRING: - int64_t tmp; - - if (parse_skip_wspace(parse_value(unpacked.as_string().c_str(), &tmp, base, unit), + if (parse_skip_wspace(parse_value(unpacked.as_string().c_str(), value, base, unit), unpacked.as_string().c_str() + unpacked.as_string().size()) != unpacked.as_string().c_str() + unpacked.as_string().size()) - throw torrent::input_error("Junk at end of value."); + return false; - return tmp; + break; case torrent::Object::TYPE_NONE: - return 0; + *value = 0; + break; + default: - throw torrent::input_error("Not convertible to a value."); + return false; } + + return true; } } diff --git a/src/utils/parse.h b/src/utils/parse.h index 4fb09740..72b6eefb 100644 --- a/src/utils/parse.h +++ b/src/utils/parse.h @@ -50,12 +50,16 @@ inline bool parse_is_quote(const char c) { return c == '"'; } inline bool parse_is_escape(const char c) { return c == '\\'; } inline bool parse_is_seperator(const char c) { return c == ','; } +const char* parse_skip_wspace(const char* first); const char* parse_skip_wspace(const char* first, const char* last); const char* parse_string(const char* first, const char* last, std::string* dest); const char* parse_whole_string(const char* first, const char* last, std::string* dest); const char* parse_value(const char* src, int64_t* value, int base = 0, int unit = 1); +const char* parse_value_nothrow(const char* src, int64_t* value, int base = 0, int unit = 1); + +bool parse_whole_value_nothrow(const char* src, int64_t* value, int base = 0, int unit = 1); const char* parse_list(const char* first, const char* last, torrent::Object* dest); const char* parse_whole_list(const char* first, const char* last, torrent::Object* dest); @@ -65,5 +69,6 @@ std::string convert_list_to_string(torrent::Object::list_type::const_iterator fi std::string convert_list_to_command(torrent::Object::list_type::const_iterator first, torrent::Object::list_type::const_iterator last); int64_t convert_to_value(const torrent::Object& src, int base = 0, int unit = 1); +bool convert_to_value_nothrow(const torrent::Object& src, int64_t* value, int base = 0, int unit = 1); }