Compatibility fixes with thread-safe list tracker changes.

This commit is contained in:
Jari Sundell
2025-03-11 12:38:04 +01:00
committed by GitHub
parent 37a5b7bccb
commit 0adfc17335
19 changed files with 207 additions and 302 deletions
+11 -8
View File
@@ -2,21 +2,20 @@
#include "rpc/jsonrpc.h"
#include "rpc/rpc_manager.h"
#include "torrent/exceptions.h"
#include "torrent/object.h"
#include <cstdint>
#include <string>
#include <torrent/common.h>
#include <torrent/torrent.h>
#include "thread_base.h"
#include "rpc/rpc_manager.h"
#include "rpc/command.h"
#include "rpc/command_map.h"
#include "rpc/nlohmann/json.h"
#include "rpc/parse_commands.h"
#include "thread_base.h"
#include "nlohmann/json.h"
#include "torrent/exceptions.h"
#include "torrent/object.h"
#include "utils/functional.h"
namespace rpc {
@@ -123,6 +122,9 @@ jsonrpc_call_command(const std::string& method, const json& params) {
auto& params_object_list = params_object.as_list();
rpc::target_type target = rpc::make_target();
std::function<void()> deleter = []() {};
utils::scope_guard guard([&deleter]() { deleter(); });
if (!(itr->second.m_flags & CommandMap::flag_no_target)) {
// Provide a blank target if none was provided
if (params_object_list.empty())
@@ -131,7 +133,8 @@ jsonrpc_call_command(const std::string& method, const json& params) {
if (!params_object_list.begin()->is_string())
throw torrent::input_error("invalid parameters: target must be a string");
RpcManager::object_to_target(params_object_list.begin()->as_string(), itr->second.m_flags, &target);
RpcManager::object_to_target(params_object_list.begin()->as_string(), itr->second.m_flags, &target, &deleter);
params_object_list.erase(params_object_list.begin());
}
+1 -5
View File
@@ -36,7 +36,6 @@
#include "config.h"
#include "rpc/rpc_manager.h"
#include <algorithm>
#include <fstream>
#include <string>
@@ -46,13 +45,10 @@
#include "parse.h"
#include "parse_commands.h"
#include "rpc/rpc_manager.h"
namespace rpc {
CommandMap commands;
RpcManager rpc;
ExecFile execFile;
inline bool command_map_is_space(char c) {
return c == ' ' || c == '\t';
}
-7
View File
@@ -40,8 +40,6 @@
#include <string>
#include <cstring>
#include "command_map.h"
#include "exec_file.h"
#include "xmlrpc.h"
#include "rpc_manager.h"
@@ -51,11 +49,6 @@ namespace core {
namespace rpc {
// Move to another file?
extern CommandMap commands;
extern RpcManager rpc;
extern ExecFile execFile;
typedef std::pair<torrent::Object, const char*> parse_command_type;
// The generic parse command function, used by the rest. At some point
+24 -10
View File
@@ -9,8 +9,12 @@
namespace rpc {
CommandMap commands;
RpcManager rpc;
ExecFile execFile;
void
RpcManager::object_to_target(const torrent::Object& obj, int call_flags, rpc::target_type* target) {
RpcManager::object_to_target(const torrent::Object& obj, int call_flags, rpc::target_type* target, std::function<void()>* deleter) {
if (call_flags & CommandMap::flag_no_target)
return;
@@ -31,6 +35,7 @@ RpcManager::object_to_target(const torrent::Object& obj, int call_flags, rpc::ta
char type = 'd';
std::string hash;
std::string index;
const auto& delim_pos = target_string.find_first_of(':', 40);
if (delim_pos == target_string.npos ||
delim_pos + 2 >= target_string.size()) {
@@ -49,34 +54,43 @@ RpcManager::object_to_target(const torrent::Object& obj, int call_flags, rpc::ta
throw torrent::input_error("invalid parameters: info-hash not found");
try {
torrent::tracker::Tracker* tracker;
switch (type) {
case 'd':
*target = rpc::make_target(download);
break;
case 'f':
*target = rpc::make_target(
command_base::target_file,
rpc.slot_find_file()(download, std::stoi(std::string(index))));
*target = rpc::make_target(command_base::target_file,
rpc.slot_find_file()(download, std::stoi(std::string(index))));
break;
case 't':
*target = rpc::make_target(
command_base::target_tracker,
rpc.slot_find_tracker()(download, std::stoi(std::string(index))));
tracker = new torrent::tracker::Tracker(rpc.slot_find_tracker()(download, std::stoi(std::string(index))));
*target = rpc::make_target(command_base::target_tracker, tracker);
*deleter = [tracker]() { delete tracker; };
break;
case 'p': {
if (index.size() < 40) {
throw torrent::input_error("invalid parameters: not a hash string.");
}
torrent::HashString hash;
torrent::hash_string_from_hex_c_str(index.c_str(), hash);
*target = rpc::make_target(
command_base::target_peer,
rpc.slot_find_peer()(download, hash));
*target = rpc::make_target(command_base::target_peer,
rpc.slot_find_peer()(download, hash));
break;
}
default:
throw torrent::input_error("invalid parameters: unexpected target type");
}
} catch (const std::logic_error&) {
throw torrent::input_error("invalid parameters: invalid index");
}
+11 -2
View File
@@ -6,6 +6,8 @@
#include <torrent/common.h>
#include "rpc/command.h"
#include "rpc/command_map.h"
#include "rpc/exec_file.h"
#include "rpc/jsonrpc.h"
#include "rpc/xmlrpc.h"
@@ -15,6 +17,9 @@ class Download;
namespace rpc {
extern ExecFile execFile;
extern CommandMap commands;
class rpc_error : public torrent::base_error {
public:
rpc_error(int type, std::string msg) :
@@ -33,7 +38,7 @@ class RpcManager {
public:
using slot_download = std::function<core::Download*(const char*)>;
using slot_file = std::function<torrent::File*(core::Download*, uint32_t)>;
using slot_tracker = std::function<torrent::tracker::Tracker*(core::Download*, uint32_t)>;
using slot_tracker = std::function<torrent::tracker::Tracker(core::Download*, uint32_t)>;
using slot_peer = std::function<torrent::Peer*(core::Download*, const torrent::HashString&)>;
using slot_response_callback = std::function<bool(const char*, uint32_t)>;
@@ -58,13 +63,14 @@ public:
bool process(RPCType type, const char* in_buffer, uint32_t length, slot_response_callback callback);
void insert_command(const char* name, const char* parm, const char* doc);
static void object_to_target(const torrent::Object& obj, int callFlags, rpc::target_type* target);
slot_download& slot_find_download() { return m_slot_find_download; }
slot_file& slot_find_file() { return m_slot_find_file; }
slot_tracker& slot_find_tracker() { return m_slot_find_tracker; }
slot_peer& slot_find_peer() { return m_slot_find_peer; }
static void object_to_target(const torrent::Object& obj, int callFlags, rpc::target_type* target, std::function<void()>* deleter);
private:
XmlRpc m_xmlrpc;
JsonRpc m_jsonrpc;
@@ -78,6 +84,9 @@ private:
slot_tracker m_slot_find_tracker;
slot_peer m_slot_find_peer;
};
extern RpcManager rpc;
} // namespace rpc
#endif
-36
View File
@@ -1,39 +1,3 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, 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 <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "config.h"
#include "xmlrpc.h"
+2 -1
View File
@@ -4,6 +4,7 @@
#include <functional>
#include <torrent/common.h>
#include <torrent/hash_string.h>
#include <torrent/tracker/tracker.h>
#include "command.h"
#include "scgi_task.h"
@@ -18,7 +19,7 @@ class XmlRpc {
public:
typedef std::function<core::Download* (const char*)> slot_download;
typedef std::function<torrent::File* (core::Download*, uint32_t)> slot_file;
typedef std::function<torrent::tracker::Tracker* (core::Download*, uint32_t)> slot_tracker;
typedef std::function<torrent::tracker::Tracker (core::Download*, uint32_t)> slot_tracker;
typedef std::function<torrent::Peer* (core::Download*, const torrent::HashString&)> slot_peer;
typedef std::function<bool (const char*, uint32_t)> slot_write;
+66 -84
View File
@@ -1,39 +1,3 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2011, 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 <jaris@ifi.uio.no>
//
// Skomakerveien 33
// 3185 Skoppum, NORWAY
#include "config.h"
#ifdef HAVE_XMLRPC_C
@@ -43,17 +7,16 @@
#include <cctype>
#include <string>
#include <stdlib.h>
#include <xmlrpc-c/server.h>
#include <rak/string_manip.h>
#include <torrent/object.h>
#include <torrent/exceptions.h>
#include <xmlrpc-c/server.h>
#include "rpc_manager.h"
#include "xmlrpc.h"
#include "parse_commands.h"
#include "utils/functional.h"
namespace rpc {
@@ -71,7 +34,7 @@ private:
const char* m_msg;
};
torrent::Object xmlrpc_to_object(xmlrpc_env* env, xmlrpc_value* value, int callType = 0, rpc::target_type* target = NULL);
torrent::Object xmlrpc_to_object(xmlrpc_env* env, xmlrpc_value* value, int call_type = 0, rpc::target_type* target = NULL, std::function<void()>* deleter = NULL);
inline torrent::Object
xmlrpc_list_entry_to_object(xmlrpc_env* env, xmlrpc_value* src, int index) {
@@ -135,59 +98,70 @@ xmlrpc_list_entry_to_value(xmlrpc_env* env, xmlrpc_value* src, int index) {
}
}
rpc::target_type
xmlrpc_to_target(xmlrpc_env* env, xmlrpc_value* value, int callType) {
std::pair<rpc::target_type, std::function<void()>>
xmlrpc_to_target(xmlrpc_env* env, xmlrpc_value* value, int call_type) {
rpc::target_type target;
std::function<void()> deleter = []() {};
Rpc::object_to_target(xmlrpc_to_object(env, value, -1, nullptr), callType, &target);
return target;
RpcManager::object_to_target(xmlrpc_to_object(env, value, -1, nullptr), call_type, &target, &deleter);
return std::make_pair(target, deleter);
}
rpc::target_type
xmlrpc_to_index_type(int index, int callType, core::Download* download) {
void* result;
std::pair<rpc::target_type, std::function<void()>>
xmlrpc_to_index_type(int index, int call_type, core::Download* download) {
void* result = nullptr;
std::function<void()> deleter = []() {};
switch (callType) {
case XmlRpc::call_file: result = xmlrpc.slot_find_file()(download, index); break;
case XmlRpc::call_tracker: result = xmlrpc.slot_find_tracker()(download, index); break;
default: result = NULL; break;
try {
switch (call_type) {
case XmlRpc::call_file:
result = rpc.slot_find_file()(download, index);
break;
case XmlRpc::call_tracker:
result = new torrent::tracker::Tracker(rpc.slot_find_tracker()(download, index));
deleter = [result]() { delete (torrent::tracker::Tracker*)result; };
break;
default:
throw torrent::input_error("invalid parameters: unexpected target type");
break;
}
} catch (const torrent::input_error& e) {
throw xmlrpc_error_c(XMLRPC_TYPE_ERROR, e.what());
}
if (result == NULL)
throw xmlrpc_error_c(XMLRPC_TYPE_ERROR, "Invalid index.");
return rpc::make_target(callType, result);
return std::make_pair(rpc::make_target(call_type, result), deleter);
}
torrent::Object
xmlrpc_to_object(xmlrpc_env* env, xmlrpc_value* value, int callType, rpc::target_type* target) {
xmlrpc_to_object(xmlrpc_env* env, xmlrpc_value* value, int call_type, rpc::target_type* target, std::function<void()>* deleter) {
switch (xmlrpc_value_type(value)) {
case XMLRPC_TYPE_INT:
int v;
xmlrpc_read_int(env, value, &v);
return torrent::Object((int64_t)v);
#ifdef XMLRPC_HAVE_I8
case XMLRPC_TYPE_I8:
xmlrpc_int64 v2;
xmlrpc_read_i8(env, value, &v2);
return torrent::Object((int64_t)v2);
#endif
// case XMLRPC_TYPE_BOOL:
// case XMLRPC_TYPE_DOUBLE:
// case XMLRPC_TYPE_DATETIME:
case XMLRPC_TYPE_STRING:
if (callType != XmlRpc::call_generic && target != nullptr) {
if (call_type != XmlRpc::call_generic && target != nullptr) {
// When the call type is not supposed to be void, we'll try to
// convert it to a command target. It's not that important that
// it is converted to the right type here, as an mismatch will
// be caught when executing the command.
*target = xmlrpc_to_target(env, value, callType);
std::tie(*target, *deleter) = xmlrpc_to_target(env, value, call_type);
return torrent::Object();
} else {
@@ -199,7 +173,6 @@ xmlrpc_to_object(xmlrpc_env* env, xmlrpc_value* value, int callType, rpc::target
torrent::Object result = torrent::Object(std::string(valueString));
// Urgh, seriously?
::free((void*)valueString);
return result;
}
@@ -216,7 +189,6 @@ xmlrpc_to_object(xmlrpc_env* env, xmlrpc_value* value, int callType, rpc::target
torrent::Object result = torrent::Object(std::string(valueString, valueSize));
// Urgh, seriously?
::free((void*)valueString);
return result;
}
@@ -229,7 +201,7 @@ xmlrpc_to_object(xmlrpc_env* env, xmlrpc_value* value, int callType, rpc::target
if (env->fault_occurred)
throw xmlrpc_error_c(env);
if (callType != XmlRpc::call_generic && last != 0) {
if (call_type != XmlRpc::call_generic && last != 0) {
if (last < 1)
throw xmlrpc_error_c(XMLRPC_TYPE_ERROR, "Too few arguments.");
@@ -240,14 +212,15 @@ xmlrpc_to_object(xmlrpc_env* env, xmlrpc_value* value, int callType, rpc::target
throw xmlrpc_error_c(env);
if (target != nullptr)
*target = xmlrpc_to_target(env, tmp, callType);
std::tie(*target, *deleter) = xmlrpc_to_target(env, tmp, call_type);
xmlrpc_DECREF(tmp);
if (env->fault_occurred)
throw xmlrpc_error_c(env);
if (target->first == XmlRpc::call_download &&
(callType == XmlRpc::call_file || callType == XmlRpc::call_tracker)) {
(call_type == XmlRpc::call_file || call_type == XmlRpc::call_tracker)) {
// If we have a download target and the call type requires
// another contained type, then we try to use the next
// parameter as the index to support old-style calls.
@@ -255,7 +228,17 @@ xmlrpc_to_object(xmlrpc_env* env, xmlrpc_value* value, int callType, rpc::target
if (current == last)
throw xmlrpc_error_c(XMLRPC_TYPE_ERROR, "Too few arguments, missing index.");
*target = xmlrpc_to_index_type(xmlrpc_list_entry_to_value(env, value, current++), callType, (core::Download*)target->second);
{
std::function<void()> old_deleter, tmp_deleter;
std::tie(*target, tmp_deleter) = xmlrpc_to_index_type(xmlrpc_list_entry_to_value(env, value, current++),
call_type,
(core::Download*)target->second);
old_deleter.swap(*deleter);
*deleter = [old_deleter, tmp_deleter]() {
tmp_deleter();
old_deleter();
};
}
}
}
@@ -276,10 +259,6 @@ xmlrpc_to_object(xmlrpc_env* env, xmlrpc_value* value, int callType, rpc::target
}
}
// case XMLRPC_TYPE_STRUCT:
// case XMLRPC_TYPE_C_PTR:
// case XMLRPC_TYPE_NIL:
// case XMLRPC_TYPE_DEAD:
default:
throw xmlrpc_error_c(XMLRPC_TYPE_ERROR, "Unsupported type found.");
}
@@ -291,7 +270,7 @@ object_to_xmlrpc(xmlrpc_env* env, const torrent::Object& object) {
case torrent::Object::TYPE_VALUE:
#ifdef XMLRPC_HAVE_I8
if (xmlrpc.dialect() != XmlRpc::dialect_generic)
if (rpc.dialect() != XmlRpc::dialect_generic)
return xmlrpc_i8_new(env, object.as_value());
#else
return xmlrpc_int_new(env, object.as_value());
@@ -329,7 +308,7 @@ object_to_xmlrpc(xmlrpc_env* env, const torrent::Object& object) {
case torrent::Object::TYPE_LIST:
{
xmlrpc_value* result = xmlrpc_array_new(env);
for (torrent::Object::list_const_iterator itr = object.as_list().begin(), last = object.as_list().end(); itr != last; itr++) {
xmlrpc_value* item = object_to_xmlrpc(env, *itr);
xmlrpc_array_append_item(env, result, item);
@@ -342,7 +321,7 @@ object_to_xmlrpc(xmlrpc_env* env, const torrent::Object& object) {
case torrent::Object::TYPE_MAP:
{
xmlrpc_value* result = xmlrpc_struct_new(env);
for (torrent::Object::map_const_iterator itr = object.as_map().begin(), last = object.as_map().end(); itr != last; itr++) {
xmlrpc_value* item = object_to_xmlrpc(env, itr->second);
xmlrpc_struct_set_value(env, result, itr->first.c_str(), item);
@@ -355,11 +334,11 @@ object_to_xmlrpc(xmlrpc_env* env, const torrent::Object& object) {
case torrent::Object::TYPE_DICT_KEY:
{
xmlrpc_value* result = xmlrpc_array_new(env);
xmlrpc_value* key_item = object_to_xmlrpc(env, object.as_dict_key());
xmlrpc_array_append_item(env, result, key_item);
xmlrpc_DECREF(key_item);
if (object.as_dict_obj().is_list()) {
for (torrent::Object::list_const_iterator
itr = object.as_dict_obj().as_list().begin(),
@@ -392,18 +371,21 @@ xmlrpc_call_command(xmlrpc_env* env, xmlrpc_value* args, void* voidServerInfo) {
return NULL;
}
std::function<void()> deleter = []() {};
utils::scope_guard guard([&deleter]() { deleter(); });
try {
torrent::Object object;
rpc::target_type target = rpc::make_target();
if (itr->second.m_flags & CommandMap::flag_no_target)
xmlrpc_to_object(env, args, XmlRpc::call_generic, &target).swap(object);
xmlrpc_to_object(env, args, XmlRpc::call_generic, &target, &deleter).swap(object);
else if (itr->second.m_flags & CommandMap::flag_file_target)
xmlrpc_to_object(env, args, XmlRpc::call_file, &target).swap(object);
xmlrpc_to_object(env, args, XmlRpc::call_file, &target, &deleter).swap(object);
else if (itr->second.m_flags & CommandMap::flag_tracker_target)
xmlrpc_to_object(env, args, XmlRpc::call_tracker, &target).swap(object);
xmlrpc_to_object(env, args, XmlRpc::call_tracker, &target, &deleter).swap(object);
else
xmlrpc_to_object(env, args, XmlRpc::call_any, &target).swap(object);
xmlrpc_to_object(env, args, XmlRpc::call_any, &target, &deleter).swap(object);
if (env->fault_occurred)
return NULL;
@@ -425,7 +407,7 @@ XmlRpc::initialize() {
#ifndef XMLRPC_HAVE_I8
m_dialect = dialect_generic;
#endif
m_env = new xmlrpc_env;
xmlrpc_env_init((xmlrpc_env*)m_env);