From 0e69677dbcb7c235e7026a49d8cf65700156edfd Mon Sep 17 00:00:00 2001 From: rakshasa Date: Fri, 8 Oct 2010 08:10:08 +0000 Subject: [PATCH] * Added xmlrpc calls for peer snubbed, banned and disconnect. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@1180 e378c898-3ddf-0310-93e7-cc216c733640 --- src/command_download.cc | 41 +++++++++++++++++++++++++++++++++++- src/command_network.cc | 11 ++++++++++ src/command_peer.cc | 9 ++++++++ src/rpc/command_map.h | 2 +- src/rpc/command_scheduler.cc | 8 ------- src/rpc/scgi_task.cc | 3 +++ src/rpc/xmlrpc.cc | 28 ++++++++++++++++++------ src/rpc/xmlrpc.h | 6 ++++++ src/ui/element_peer_list.cc | 2 +- 9 files changed, 92 insertions(+), 18 deletions(-) diff --git a/src/command_download.cc b/src/command_download.cc index 12e3fc57..70085ecb 100644 --- a/src/command_download.cc +++ b/src/command_download.cc @@ -418,7 +418,8 @@ p_multicall(core::Download* download, const torrent::Object::list_type& args) { torrent::Object resultRaw = torrent::Object::create_list(); torrent::Object::list_type& result = resultRaw.as_list(); - for (torrent::ConnectionList::const_iterator itr = download->connection_list()->begin(), last = download->connection_list()->end(); itr != last; itr++) { + for (torrent::ConnectionList::const_iterator itr = download->connection_list()->begin(), last = download->connection_list()->end(); + itr != last; itr++) { torrent::Object::list_type& row = result.insert(result.end(), torrent::Object::create_list())->as_list(); for (torrent::Object::list_const_iterator cItr = ++args.begin(), cLast = args.end(); cItr != args.end(); cItr++) { @@ -431,6 +432,42 @@ p_multicall(core::Download* download, const torrent::Object::list_type& args) { return resultRaw; } +torrent::Object +p_call_target(const torrent::Object::list_type& args) { + if (args.empty() || args.begin() + 1 == args.end() || args.begin() + 2 == args.end()) + throw torrent::input_error("Too few arguments."); + + // We ignore the first arg for now, but it will be used for + // selecting what files to include. + + // Add some pre-parsing of the commands, so we don't spend time + // parsing and searching command map for every single call. + torrent::Object::list_const_iterator itr = args.begin(); + + core::Download* download = control->core()->download_list()->find_hex_ptr(itr++->as_string().c_str()); + const std::string& peer_id = itr++->as_string(); + const std::string& command_key = itr++->as_string(); + + torrent::HashString hash; + + if (peer_id.size() != 40 || + torrent::hash_string_from_hex_c_str(peer_id.c_str(), hash) == peer_id.c_str()) + throw torrent::input_error("Not a hash string."); + + torrent::ConnectionList::iterator peerItr = download->connection_list()->find(hash.c_str()); + + if (peerItr == download->connection_list()->end()) + throw torrent::input_error("Could not find peer."); + + if (itr == args.end()) + return rpc::commands.call(command_key.c_str()); + + if (itr + 1 == args.end()) + return rpc::commands.call(command_key.c_str(), *itr); + + return rpc::commands.call(command_key.c_str(), torrent::Object::create_list_range(itr, args.end())); +} + // // New download commands and macros: // @@ -730,4 +767,6 @@ initialize_command_download() { CMD2_DL_LIST ("f.multicall", std::tr1::bind(&f_multicall, std::tr1::placeholders::_1, std::tr1::placeholders::_2)); CMD2_DL_LIST ("p.multicall", std::tr1::bind(&p_multicall, std::tr1::placeholders::_1, std::tr1::placeholders::_2)); CMD2_DL_LIST ("t.multicall", std::tr1::bind(&t_multicall, std::tr1::placeholders::_1, std::tr1::placeholders::_2)); + + CMD2_ANY_LIST ("p.call_target", std::tr1::bind(&p_call_target, std::tr1::placeholders::_2)); } diff --git a/src/command_network.cc b/src/command_network.cc index 74c29178..ee6b5541 100644 --- a/src/command_network.cc +++ b/src/command_network.cc @@ -295,12 +295,23 @@ xmlrpc_find_tracker(core::Download* download, uint32_t index) { return download->tracker_list()->at(index); } +torrent::Peer* +xmlrpc_find_peer(core::Download* download, const torrent::HashString& hash) { + torrent::ConnectionList::iterator itr = download->connection_list()->find(hash.c_str()); + + if (itr == download->connection_list()->end()) + return NULL; + + return *itr; +} + void initialize_xmlrpc() { rpc::xmlrpc.initialize(); rpc::xmlrpc.set_slot_find_download(rak::mem_fn(control->core()->download_list(), &core::DownloadList::find_hex_ptr)); rpc::xmlrpc.set_slot_find_file(rak::ptr_fn(&xmlrpc_find_file)); rpc::xmlrpc.set_slot_find_tracker(rak::ptr_fn(&xmlrpc_find_tracker)); + rpc::xmlrpc.set_slot_find_peer(rak::ptr_fn(&xmlrpc_find_peer)); unsigned int count = 0; diff --git a/src/command_peer.cc b/src/command_peer.cc index 1e0cc9be..9cdb51c3 100644 --- a/src/command_peer.cc +++ b/src/command_peer.cc @@ -42,6 +42,7 @@ #include #include #include +#include #include #include @@ -118,4 +119,12 @@ initialize_command_peer() { CMD2_PEER("p.down_total", std::tr1::bind(&torrent::Rate::total, std::tr1::bind(&torrent::Peer::down_rate, std::tr1::placeholders::_1))); CMD2_PEER("p.peer_rate", std::tr1::bind(&torrent::Rate::rate, std::tr1::bind(&torrent::Peer::peer_rate, std::tr1::placeholders::_1))); CMD2_PEER("p.peer_total", std::tr1::bind(&torrent::Rate::total, std::tr1::bind(&torrent::Peer::peer_rate, std::tr1::placeholders::_1))); + + CMD2_PEER ("p.snubbed", std::tr1::bind(&torrent::Peer::is_snubbed, std::tr1::placeholders::_1)); + CMD2_PEER_VALUE_V("p.snubbed.set", std::tr1::bind(&torrent::Peer::set_snubbed, std::tr1::placeholders::_1, std::tr1::placeholders::_2)); + CMD2_PEER ("p.banned", std::tr1::bind(&torrent::Peer::is_banned, std::tr1::placeholders::_1)); + CMD2_PEER_VALUE_V("p.banned.set", std::tr1::bind(&torrent::Peer::set_banned, std::tr1::placeholders::_1, std::tr1::placeholders::_2)); + + CMD2_PEER_V("p.disconnect", std::tr1::bind(&torrent::Peer::disconnect, std::tr1::placeholders::_1, 0)); + CMD2_PEER_V("p.disconnect_delayed", std::tr1::bind(&torrent::Peer::disconnect, std::tr1::placeholders::_1, torrent::ConnectionList::disconnect_delayed)); } diff --git a/src/rpc/command_map.h b/src/rpc/command_map.h index f495b7b5..3148d69a 100644 --- a/src/rpc/command_map.h +++ b/src/rpc/command_map.h @@ -127,7 +127,7 @@ public: const mapped_type call(key_type key, target_type target, const mapped_type& args = mapped_type()) { return call_command(key, args, target); } const mapped_type call_catch(key_type key, target_type target, const mapped_type& args = mapped_type(), const char* err = "Command failed: "); - const mapped_type call_command (key_type key, const mapped_type& arg, target_type target = target_type((int)command_base::target_generic, NULL)); + const mapped_type call_command (key_type key, const mapped_type& arg, target_type target = target_type((int)command_base::target_generic, NULL)); const mapped_type call_command (iterator itr, const mapped_type& arg, target_type target = target_type((int)command_base::target_generic, NULL)); const mapped_type call_command_d(key_type key, core::Download* download, const mapped_type& arg) { return call_command(key, arg, target_type((int)command_base::target_download, download)); } diff --git a/src/rpc/command_scheduler.cc b/src/rpc/command_scheduler.cc index 4affd07a..52317a56 100644 --- a/src/rpc/command_scheduler.cc +++ b/src/rpc/command_scheduler.cc @@ -120,14 +120,6 @@ CommandScheduler::call_item(value_type item) { void CommandScheduler::parse(const std::string& key, const std::string& bufAbsolute, const std::string& bufInterval, const std::string& command) { -// char key[21]; -// char bufAbsolute[21]; -// char bufInterval[21]; -// char command[2048]; - -// if (std::sscanf(arg.c_str(), "%20[^,],%20[^,],%20[^,],%2047[^\n]", key, bufAbsolute, bufInterval, command) != 4) -// throw torrent::input_error("Invalid arguments to command."); - uint32_t absolute = parse_absolute(bufAbsolute.c_str()); uint32_t interval = parse_interval(bufInterval.c_str()); diff --git a/src/rpc/scgi_task.cc b/src/rpc/scgi_task.cc index 91848b2b..7000ac63 100644 --- a/src/rpc/scgi_task.cc +++ b/src/rpc/scgi_task.cc @@ -218,6 +218,9 @@ SCgiTask::event_error() { bool SCgiTask::receive_write(const char* buffer, uint32_t length) { + if (buffer == NULL || length > (100 << 20)) + throw torrent::internal_error("SCgiTask::receive_write(...) received bad input."); + // Need to cast due to a bug in MacOSX gcc-4.0.1. if (length + 256 > std::max(m_bufferSize, (unsigned int)default_buffer_size)) realloc_buffer(length + 256, NULL, 0); diff --git a/src/rpc/xmlrpc.cc b/src/rpc/xmlrpc.cc index cab44f74..b6754409 100644 --- a/src/rpc/xmlrpc.cc +++ b/src/rpc/xmlrpc.cc @@ -41,6 +41,8 @@ #include #endif +#include +#include #include #include @@ -175,29 +177,38 @@ xmlrpc_to_target(xmlrpc_env* env, xmlrpc_value* value) { // Trackers: ":t" int index; - const char* end; + const char* end_ptr = str + 42; switch (str[41]) { case 'f': - end = str + 42; - index = ::strtol(str + 42, (char**)&end, 0); + index = ::strtol(str + 42, (char**)&end_ptr, 0); - if (*str == '\0' || *end != '\0') + if (*str == '\0' || *end_ptr != '\0') throw xmlrpc_error(XMLRPC_TYPE_ERROR, "Invalid index."); target = rpc::make_target(XmlRpc::call_file, xmlrpc.get_slot_find_file()(download, index)); break; case 't': - end = str + 42; - index = ::strtol(str + 42, (char**)&end, 0); + index = ::strtol(str + 42, (char**)&end_ptr, 0); - if (*str == '\0' || *end != '\0') + if (*str == '\0' || *end_ptr != '\0') throw xmlrpc_error(XMLRPC_TYPE_ERROR, "Invalid index."); target = rpc::make_target(XmlRpc::call_tracker, xmlrpc.get_slot_find_tracker()(download, index)); break; + case 'p': + { + torrent::HashString hash; + const char* hash_end = torrent::hash_string_from_hex_c_str(str + 42, hash); + + if (hash_end == end_ptr || *hash_end != '\0') + throw xmlrpc_error(XMLRPC_TYPE_ERROR, "Not a hash string."); + + target = rpc::make_target(XmlRpc::call_peer, xmlrpc.get_slot_find_peer()(download, hash)); + break; + } default: ::free((void*)str); throw xmlrpc_error(XMLRPC_TYPE_ERROR, "Unsupported target type found."); @@ -496,6 +507,9 @@ XmlRpc::process(const char* inBuffer, uint32_t length, slot_write slotWrite) { xmlrpc_mem_block* memblock = xmlrpc_registry_process_call(&localEnv, (xmlrpc_registry*)m_registry, NULL, inBuffer, length); + if (localEnv.fault_occurred && localEnv.fault_code == XMLRPC_INTERNAL_ERROR) + throw torrent::internal_error("Internal error in XMLRPC."); + bool result = slotWrite((const char*)xmlrpc_mem_block_contents(memblock), xmlrpc_mem_block_size(memblock)); diff --git a/src/rpc/xmlrpc.h b/src/rpc/xmlrpc.h index e60a175f..4bf16997 100644 --- a/src/rpc/xmlrpc.h +++ b/src/rpc/xmlrpc.h @@ -38,6 +38,7 @@ #define RTORRENT_RPC_XMLRPC_H #include +#include namespace core { class Download; @@ -56,6 +57,7 @@ public: typedef rak::function1 slot_find_download; typedef rak::function2 slot_find_file; typedef rak::function2 slot_find_tracker; + typedef rak::function2 slot_find_peer; typedef rak::function2 slot_write; static const int dialect_generic = 0; @@ -94,6 +96,9 @@ public: slot_find_tracker& get_slot_find_tracker() { return m_slotFindTracker; } void set_slot_find_tracker(slot_find_tracker::base_type* slot) { m_slotFindTracker.set(slot); } + slot_find_peer& get_slot_find_peer() { return m_slotFindPeer; } + void set_slot_find_peer(slot_find_peer::base_type* slot) { m_slotFindPeer.set(slot); } + static int64_t size_limit(); static void set_size_limit(uint64_t size); @@ -106,6 +111,7 @@ private: slot_find_download m_slotFindDownload; slot_find_file m_slotFindFile; slot_find_tracker m_slotFindTracker; + slot_find_peer m_slotFindPeer; }; } diff --git a/src/ui/element_peer_list.cc b/src/ui/element_peer_list.cc index 84c1538f..7b69f484 100644 --- a/src/ui/element_peer_list.cc +++ b/src/ui/element_peer_list.cc @@ -250,7 +250,7 @@ ElementPeerList::receive_ban_peer() { if (m_listItr == m_list.end()) return; - (*m_listItr)->set_banned(); + (*m_listItr)->set_banned(true); m_download->download()->connection_list()->erase(*m_listItr, torrent::ConnectionList::disconnect_quick); update_itr();