From 750ba8912953c8f2c3dc976bbda17a2b0ce55041 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Tue, 19 Jun 2007 18:04:49 +0000 Subject: [PATCH] * Added direct support for download commands in XMLRPC. Now the first parameter of the get_d/set_d commands is the info-hash. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@917 e378c898-3ddf-0310-93e7-cc216c733640 --- src/command_download.cc | 24 +++---- src/command_network.cc | 19 ++++-- src/core/download_list.cc | 7 +++ src/core/download_list.h | 1 + src/rpc/xmlrpc.cc | 127 ++++++++++++++++++++++++++++++++++++-- src/rpc/xmlrpc.h | 19 ++++-- 6 files changed, 170 insertions(+), 27 deletions(-) diff --git a/src/command_download.cc b/src/command_download.cc index 4b5cd36c..72975ee3 100644 --- a/src/command_download.cc +++ b/src/command_download.cc @@ -177,35 +177,37 @@ apply_d_delete_link(core::Download* download, const torrent::Object& rawArgs) { commandDownloadSlotsItr->set_slot(slot); \ rpc::commands.insert(key, commandDownloadSlotsItr++, NULL, &rpc::CommandDownloadSlot::function, rpc::CommandMap::flag_dont_delete, parm, doc); -// rpc::commands.insert(key, commandDownloadSlotsItr++, NULL, &rpc::CommandDownloadSlot::function, rpc::CommandMap::flag_dont_delete | rpc::CommandMap::flag_public_xmlrpc, parm, doc); +#define ADD_COMMAND_DOWNLOAD_SLOT_PUBLIC(key, function, slot, parm, doc) \ + commandDownloadSlotsItr->set_slot(slot); \ + rpc::commands.insert(key, commandDownloadSlotsItr++, NULL, &rpc::CommandDownloadSlot::function, rpc::CommandMap::flag_dont_delete | rpc::CommandMap::flag_public_xmlrpc, parm, doc); #define ADD_COMMAND_DOWNLOAD_VOID(key, slot) \ - ADD_COMMAND_DOWNLOAD_SLOT("get_d_" key, call_unknown, rpc::object_d_fn(slot), "i:", "") + ADD_COMMAND_DOWNLOAD_SLOT_PUBLIC("get_d_" key, call_unknown, rpc::object_d_fn(slot), "i:", "") #define ADD_COMMAND_DOWNLOAD_LIST(key, slot) \ - ADD_COMMAND_DOWNLOAD_SLOT(key, call_list, slot, "i:", "") + ADD_COMMAND_DOWNLOAD_SLOT_PUBLIC(key, call_list, slot, "i:", "") #define ADD_COMMAND_DOWNLOAD_VARIABLE_VALUE(key, firstKey, secondKey) \ - ADD_COMMAND_DOWNLOAD_SLOT("get_d_" key, call_unknown, rpc::get_variable_d_fn(firstKey, secondKey), "i:", ""); \ + ADD_COMMAND_DOWNLOAD_SLOT_PUBLIC("get_d_" key, call_unknown, rpc::get_variable_d_fn(firstKey, secondKey), "i:", ""); \ ADD_COMMAND_DOWNLOAD_SLOT("set_d_" key, call_value, rpc::set_variable_d_fn(firstKey, secondKey), "i:i", ""); #define ADD_COMMAND_DOWNLOAD_VARIABLE_STRING(key, firstKey, secondKey) \ - ADD_COMMAND_DOWNLOAD_SLOT("get_d_" key, call_unknown, rpc::get_variable_d_fn(firstKey, secondKey), "i:", ""); \ + ADD_COMMAND_DOWNLOAD_SLOT_PUBLIC("get_d_" key, call_unknown, rpc::get_variable_d_fn(firstKey, secondKey), "i:", ""); \ ADD_COMMAND_DOWNLOAD_SLOT("set_d_" key, call_string, rpc::set_variable_d_fn(firstKey, secondKey), "i:s", ""); #define ADD_COMMAND_DOWNLOAD_VALUE_BI(key, set, get) \ - ADD_COMMAND_DOWNLOAD_SLOT("set_d_" key, call_value, rpc::object_value_d_fn(set), "i:i", "") \ - ADD_COMMAND_DOWNLOAD_SLOT("get_d_" key, call_unknown, rpc::object_void_d_fn(get), "i:", "") + ADD_COMMAND_DOWNLOAD_SLOT_PUBLIC("set_d_" key, call_value, rpc::object_value_d_fn(set), "i:i", "") \ + ADD_COMMAND_DOWNLOAD_SLOT_PUBLIC("get_d_" key, call_unknown, rpc::object_void_d_fn(get), "i:", "") #define ADD_COMMAND_DOWNLOAD_VALUE_MEM_BI(key, target, set, get) \ ADD_COMMAND_DOWNLOAD_VALUE_BI(key, rak::on2(std::mem_fun(target), std::mem_fun(set)), rak::on(std::mem_fun(target), std::mem_fun(get))); #define ADD_COMMAND_DOWNLOAD_VALUE_MEM_UNI(key, target, get) \ - ADD_COMMAND_DOWNLOAD_SLOT("get_d_" key, call_unknown, rpc::object_void_d_fn(rak::on(rak::on(std::mem_fun(&core::Download::download), std::mem_fun(target)), std::mem_fun(get))), "i:", ""); + ADD_COMMAND_DOWNLOAD_SLOT_PUBLIC("get_d_" key, call_unknown, rpc::object_void_d_fn(rak::on(rak::on(std::mem_fun(&core::Download::download), std::mem_fun(target)), std::mem_fun(get))), "i:", ""); #define ADD_COMMAND_DOWNLOAD_STRING_BI(key, set, get) \ - ADD_COMMAND_DOWNLOAD_SLOT("set_d_" key, call_string, rpc::object_string_d_fn(set), "i:s", "") \ - ADD_COMMAND_DOWNLOAD_SLOT("get_d_" key, call_unknown, rpc::object_void_d_fn(get), "s:", "") + ADD_COMMAND_DOWNLOAD_SLOT_PUBLIC("set_d_" key, call_string, rpc::object_string_d_fn(set), "i:s", "") \ + ADD_COMMAND_DOWNLOAD_SLOT_PUBLIC("get_d_" key, call_unknown, rpc::object_void_d_fn(get), "s:", "") void add_copy_to_download(const char* src, const char* dest) { @@ -225,8 +227,6 @@ initialize_command_download() { ADD_COMMAND_DOWNLOAD_LIST("create_link", rak::ptr_fn(&apply_d_create_link)); ADD_COMMAND_DOWNLOAD_LIST("delete_link", rak::ptr_fn(&apply_d_delete_link)); -// add_copy_to_download("print"); - // 0 - stopped // 1 - started ADD_COMMAND_DOWNLOAD_VARIABLE_VALUE("state", "rtorrent", "state"); diff --git a/src/command_network.cc b/src/command_network.cc index bf3f5175..f3756aac 100644 --- a/src/command_network.cc +++ b/src/command_network.cc @@ -146,16 +146,23 @@ apply_enable_trackers(int64_t arg) { void initialize_xmlrpc() { control->set_xmlrpc(new rpc::XmlRpc); - control->xmlrpc()->set_slot_call_command(rak::ptr_fn(&rpc::call_command)); + rpc::XmlRpc::set_slot_find_download(rak::mem_fn(control->core()->download_list(), &core::DownloadList::find_hex_ptr)); unsigned int count = 0; - for (rpc::CommandMap::const_iterator itr = rpc::commands.begin(), last = rpc::commands.end(); itr != last; itr++) - if (itr->second.m_flags & rpc::CommandMap::flag_public_xmlrpc) { - control->xmlrpc()->insert_command(itr->first, itr->second.m_parm, itr->second.m_doc); + for (rpc::CommandMap::const_iterator itr = rpc::commands.begin(), last = rpc::commands.end(); itr != last; itr++) { + if (!(itr->second.m_flags & rpc::CommandMap::flag_public_xmlrpc)) + continue; - count++; - } + if (itr->second.m_genericSlot != NULL) + control->xmlrpc()->insert_command(itr->first, itr->second.m_parm, itr->second.m_doc, false); + else if (itr->second.m_downloadSlot != NULL) + control->xmlrpc()->insert_command(itr->first, itr->second.m_parm, itr->second.m_doc, true); + else + throw torrent::internal_error("XMLRPC: Bad entry."); + + count++; + } char buffer[128]; sprintf(buffer, "XMLRPC initialized with %u functions.", count); diff --git a/src/core/download_list.cc b/src/core/download_list.cc index 29bf5c13..a8c37ac6 100644 --- a/src/core/download_list.cc +++ b/src/core/download_list.cc @@ -102,6 +102,13 @@ DownloadList::find_hex(const char* hash) { return std::find_if(begin(), end(), rak::equal(key, rak::on(std::mem_fun(&Download::download), std::mem_fun(&torrent::Download::info_hash)))); } +Download* +DownloadList::find_hex_ptr(const char* hash) { + iterator itr = find_hex(hash); + + return itr != end() ? *itr : NULL; +} + Download* DownloadList::create(std::istream* str, bool printLog) { torrent::Object* object = new torrent::Object; diff --git a/src/core/download_list.h b/src/core/download_list.h index 650c884a..52e30aaa 100644 --- a/src/core/download_list.h +++ b/src/core/download_list.h @@ -79,6 +79,7 @@ public: void session_save(); iterator find_hex(const char* hash); + Download* find_hex_ptr(const char* hash); // Might move this to DownloadFactory. Download* create(std::istream* str, bool printLog); diff --git a/src/rpc/xmlrpc.cc b/src/rpc/xmlrpc.cc index 15c926aa..56d06407 100644 --- a/src/rpc/xmlrpc.cc +++ b/src/rpc/xmlrpc.cc @@ -45,10 +45,11 @@ #include #include "xmlrpc.h" +#include "parse_commands.h" namespace rpc { -XmlRpc::slot_call_command XmlRpc::m_slotCall; +XmlRpc::slot_find_download XmlRpc::m_slotFindDownload; #ifdef HAVE_XMLRPC_C @@ -93,6 +94,7 @@ xmlrpc_to_object(xmlrpc_env* env, xmlrpc_value* value) { // Move this into a helper function. for (unsigned int i = 0; i != last; i++) { + // Need to decref. xmlrpc_value* tmp; xmlrpc_array_read_item(env, value, i, &tmp); @@ -100,6 +102,7 @@ xmlrpc_to_object(xmlrpc_env* env, xmlrpc_value* value) { return torrent::Object(); listRef.push_back(xmlrpc_to_object(env, tmp)); + xmlrpc_DECREF(tmp); } return result; @@ -115,6 +118,103 @@ xmlrpc_to_object(xmlrpc_env* env, xmlrpc_value* value) { } } +core::Download* +XmlRpc::xmlrpc_to_download(xmlrpc_env* env, xmlrpc_value* value) { + core::Download* download = NULL; + + switch (xmlrpc_value_type(value)) { + case XMLRPC_TYPE_STRING: + const char* valueString; + xmlrpc_read_string(env, value, &valueString); + + if (env->fault_occurred) + return NULL; + + if (std::strlen(valueString) != 40 || + (download = m_slotFindDownload(valueString)) == NULL) + xmlrpc_env_set_fault(env, XMLRPC_TYPE_ERROR, "Could not find info-hash."); + + // Urgh, seriously? + ::free((void*)valueString); + return download; + + default: + xmlrpc_env_set_fault(env, XMLRPC_TYPE_ERROR, "Unsupported type found."); + return NULL; + } +} + +// This should really be cleaned up and support for an array of +// downloads should be added. +torrent::Object +XmlRpc::xmlrpc_to_object_d(xmlrpc_env* env, xmlrpc_value* value, core::Download** download) { + switch (xmlrpc_value_type(value)) { + case XMLRPC_TYPE_STRING: + *download = xmlrpc_to_download(env, value); + return torrent::Object(); + + case XMLRPC_TYPE_ARRAY: + { + unsigned int last = xmlrpc_array_size(env, value); + + if (env->fault_occurred || last < 1) + return torrent::Object(); + + // Need to decref. + xmlrpc_value* tmpDownload; + xmlrpc_array_read_item(env, value, 0, &tmpDownload); + + if (env->fault_occurred) + return torrent::Object(); + + *download = xmlrpc_to_download(env, tmpDownload); + xmlrpc_DECREF(tmpDownload); + + if (env->fault_occurred) + return torrent::Object(); + + torrent::Object result; + + if (last > 2) { + result = torrent::Object(torrent::Object::TYPE_LIST); + torrent::Object::list_type& listRef = result.as_list(); + + // Move this into a helper function. + for (unsigned int i = 1; i != last; i++) { + // Need to decref. + xmlrpc_value* tmp; + xmlrpc_array_read_item(env, value, i, &tmp); + + if (env->fault_occurred) + return torrent::Object(); + + listRef.push_back(xmlrpc_to_object(env, tmp)); + xmlrpc_DECREF(tmp); + } + + return result; + + } else if (last == 2) { + // Need to decref. + xmlrpc_value* tmp; + xmlrpc_array_read_item(env, value, 1, &tmp); + + if (env->fault_occurred) + return torrent::Object(); + + result = xmlrpc_to_object(env, tmp); + xmlrpc_DECREF(tmp); + } + + return result; + } + + default: + xmlrpc_env_set_fault(env, XMLRPC_TYPE_ERROR, "Unsupported type found."); + return torrent::Object(); + } +} + xmlrpc_value* object_to_xmlrpc(xmlrpc_env* env, const torrent::Object& object) { xmlrpc_value* result; @@ -150,7 +250,24 @@ XmlRpc::call_command(xmlrpc_env* env, xmlrpc_value* args, void* voidServerInfo) return NULL; try { - return object_to_xmlrpc(env, XmlRpc::m_slotCall((const char*)voidServerInfo, object)); + return object_to_xmlrpc(env, rpc::call_command((const char*)voidServerInfo, object)); + + } catch (torrent::local_error& e) { + xmlrpc_env_set_fault(env, XMLRPC_PARSE_ERROR, e.what()); + return NULL; + } +} + +xmlrpc_value* +XmlRpc::call_command_d(xmlrpc_env* env, xmlrpc_value* args, void* voidServerInfo) { + core::Download* download; + torrent::Object object = xmlrpc_to_object_d(env, args, &download); + + if (env->fault_occurred) + return NULL; + + try { + return object_to_xmlrpc(env, rpc::call_command_d((const char*)voidServerInfo, download, object)); } catch (torrent::local_error& e) { xmlrpc_env_set_fault(env, XMLRPC_PARSE_ERROR, e.what()); @@ -185,11 +302,13 @@ XmlRpc::process(const char* inBuffer, uint32_t length, slot_write slotWrite) { } void -XmlRpc::insert_command(const char* name, const char* parm, const char* doc) { +XmlRpc::insert_command(const char* name, const char* parm, const char* doc, bool onDownload) { xmlrpc_env localEnv; xmlrpc_env_init(&localEnv); - xmlrpc_registry_add_method_w_doc(&localEnv, m_registry, NULL, name, &XmlRpc::call_command, const_cast(name), parm, doc); + xmlrpc_registry_add_method_w_doc(&localEnv, m_registry, NULL, name, + onDownload ? &XmlRpc::call_command_d : &XmlRpc::call_command, + const_cast(name), parm, doc); if (localEnv.fault_occurred) throw torrent::internal_error("Fault occured while inserting xmlrpc call."); diff --git a/src/rpc/xmlrpc.h b/src/rpc/xmlrpc.h index 2a2ba047..0f9451a3 100644 --- a/src/rpc/xmlrpc.h +++ b/src/rpc/xmlrpc.h @@ -43,6 +43,10 @@ typedef struct _xmlrpc_env xmlrpc_env; typedef struct _xmlrpc_value xmlrpc_value; typedef struct _xmlrpc_registry xmlrpc_registry; +namespace core { + class Download; +} + namespace torrent { class Object; } @@ -51,24 +55,29 @@ namespace rpc { class XmlRpc { public: - typedef rak::function2 slot_write; - typedef rak::function2 slot_call_command; + typedef rak::function1 slot_find_download; + typedef rak::function2 slot_write; XmlRpc(); ~XmlRpc(); bool process(const char* inBuffer, uint32_t length, slot_write slotWrite); - void insert_command(const char* name, const char* parm, const char* doc); + void insert_command(const char* name, const char* parm, const char* doc, bool onDownload); + + static void set_slot_find_download(slot_find_download::base_type* slot) { m_slotFindDownload.set(slot); } static xmlrpc_value* call_command(xmlrpc_env* env, xmlrpc_value* args, void* voidServerInfo); - static void set_slot_call_command(slot_call_command::base_type* s) { m_slotCall.set(s); } + static xmlrpc_value* call_command_d(xmlrpc_env* env, xmlrpc_value* args, void* voidServerInfo); private: + static core::Download* xmlrpc_to_download(xmlrpc_env* env, xmlrpc_value* value); + static torrent::Object xmlrpc_to_object_d(xmlrpc_env* env, xmlrpc_value* value, core::Download** download); + xmlrpc_env* m_env; xmlrpc_registry* m_registry; - static slot_call_command m_slotCall; + static slot_find_download m_slotFindDownload; }; }