* Fix potential buffer overflows in case snprintf buffer is too

small. Patch by Josef Drexler.

* Added 'view.persistance' command that makes downloads inserted into
that view persist across sessions. Only call on user-created views.

* Added 'ratio.*' commands that call the 'group.seeding.ratio.*'
equivalents.


git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@1080 e378c898-3ddf-0310-93e7-cc216c733640
This commit is contained in:
rakshasa
2008-11-16 07:54:45 +00:00
parent de8a11c4fd
commit 7600a51039
13 changed files with 161 additions and 25 deletions
+1
View File
@@ -25,6 +25,7 @@ rtorrent_SOURCES = \
command_helpers.h \
command_local.cc \
command_network.cc \
command_object.cc \
command_peer.cc \
command_tracker.cc \
command_scheduler.cc \
+57
View File
@@ -384,6 +384,57 @@ p_multicall(core::Download* download, const torrent::Object& rawArgs) {
return resultRaw;
}
inline torrent::Object&
d_object_wrapper(const std::pair<const char*, const char*> keyPair, core::Download* download) {
if (keyPair.first == NULL)
return download->bencode()->get_key(keyPair.second);
else
return download->bencode()->get_key(keyPair.first).get_key(keyPair.second);
}
torrent::Object
d_object_get(const std::pair<const char*, const char*> keyPair, core::Download* download, __UNUSED const torrent::Object& rawArgs) {
return d_object_wrapper(keyPair, download);
}
torrent::Object
d_list_push_back(const std::pair<const char*, const char*> keyPair, core::Download* download, const torrent::Object& rawArgs) {
d_object_wrapper(keyPair, download).as_list().push_back(rawArgs);
return torrent::Object();
}
torrent::Object
d_list_push_back_unique(const std::pair<const char*, const char*> keyPair, core::Download* download, const torrent::Object& rawArgs) {
const torrent::Object& args = (rawArgs.is_list() && !rawArgs.as_list().empty()) ? rawArgs.as_list().front() : rawArgs;
torrent::Object::list_type& list = d_object_wrapper(keyPair, download).as_list();
if (std::find_if(list.begin(), list.end(),
rak::bind1st(std::ptr_fun(&torrent::object_equal), args)) == list.end())
list.push_back(rawArgs);
return torrent::Object();
}
torrent::Object
d_list_has(const std::pair<const char*, const char*> keyPair, core::Download* download, const torrent::Object& rawArgs) {
const torrent::Object& args = (rawArgs.is_list() && !rawArgs.as_list().empty()) ? rawArgs.as_list().front() : rawArgs;
torrent::Object::list_type& list = d_object_wrapper(keyPair, download).as_list();
return (int64_t)(std::find_if(list.begin(), list.end(),
rak::bind1st(std::ptr_fun(&torrent::object_equal), args)) != list.end());
}
torrent::Object
d_list_remove(const std::pair<const char*, const char*> keyPair, core::Download* download, const torrent::Object& rawArgs) {
const torrent::Object& args = (rawArgs.is_list() && !rawArgs.as_list().empty()) ? rawArgs.as_list().front() : rawArgs;
torrent::Object::list_type& list = d_object_wrapper(keyPair, download).as_list();
list.erase(std::remove_if(list.begin(), list.end(), rak::bind1st(std::ptr_fun(&torrent::object_equal), args)), list.end());
return torrent::Object();
}
#define ADD_CD_SLOT(key, function, slot, parm, doc) \
commandDownloadSlotsItr->set_slot(slot); \
rpc::commands.insert_type(key, commandDownloadSlotsItr++, &rpc::CommandSlot<core::Download*>::function, rpc::CommandMap::flag_dont_delete, parm, doc);
@@ -547,6 +598,12 @@ initialize_command_download() {
ADD_CD_VALUE_BI("hashing_failed", std::mem_fun(&core::Download::set_hash_failed), std::mem_fun(&core::Download::is_hash_failed));
CMD_D("d.views", rak::bind_ptr_fn(&d_object_get, std::make_pair("rtorrent", "views")));
CMD_D("d.views.has", rak::bind_ptr_fn(&d_list_has, std::make_pair("rtorrent", "views")));
CMD_D("d.views.remove", rak::bind_ptr_fn(&d_list_remove, std::make_pair("rtorrent", "views")));
CMD_D("d.views.push_back", rak::bind_ptr_fn(&d_list_push_back, std::make_pair("rtorrent", "views")));
CMD_D("d.views.push_back_unique", rak::bind_ptr_fn(&d_list_push_back_unique, std::make_pair("rtorrent", "views")));
// This command really needs to be improved, so we have proper
// logging support.
ADD_CD_STRING_BI("message", std::mem_fun(&core::Download::set_message), std::mem_fun(&core::Download::message));
+2 -2
View File
@@ -122,7 +122,7 @@ apply_on_ratio(const torrent::Object& rawArgs) {
if (!(*itr)->is_seeding() || rpc::call_command_value("d.get_ignore_commands", rpc::make_target(*itr)) != 0)
continue;
rpc::parse_command_single(rpc::make_target(*itr), "print={Checked ratio of download.}");
// rpc::parse_command_single(rpc::make_target(*itr), "print={Checked ratio of download.}");
int64_t totalDone = (*itr)->download()->bytes_done();
int64_t totalUpload = (*itr)->download()->up_rate()->total();
@@ -137,7 +137,7 @@ apply_on_ratio(const torrent::Object& rawArgs) {
std::strcpy(bufferStart, "command");
for (std::vector<core::Download*>::iterator itr = downloads.begin(), last = downloads.end(); itr != last; itr++) {
rpc::commands.call("print", rpc::make_target(*itr), "Calling ratio command.");
// rpc::commands.call("print", rpc::make_target(*itr), "Calling ratio command.");
rpc::commands.call_catch(buffer, rpc::make_target(*itr), torrent::Object(), "Ratio reached, but command failed: ");
}
+2
View File
@@ -64,6 +64,7 @@ rpc::CommandSlot<torrent::Tracker*>* commandTrackerSlotsItr = commandTr
rpc::CommandSlot<rpc::target_type> commandAnySlots[COMMAND_ANY_SLOTS_SIZE];
rpc::CommandSlot<rpc::target_type>* commandAnySlotsItr = commandAnySlots;
void initialize_command_object();
void initialize_command_dynamic();
void initialize_command_download();
void initialize_command_events();
@@ -77,6 +78,7 @@ void initialize_command_ui();
void
initialize_commands() {
initialize_command_object();
initialize_command_dynamic();
initialize_command_events();
initialize_command_network();
+5 -1
View File
@@ -213,7 +213,11 @@ add_variable(key, NULL, NULL, &rpc::CommandVariable::get_string, NULL, std::stri
#define CMD_D_SLOT(key, function, slot, parm, doc) \
commandDownloadSlotsItr->set_slot(slot); \
rpc::commands.insert_type(key, commandDownloadSlotsItr++, &rpc::CommandSlot<core::Download*>::function, rpc::CommandMap::flag_dont_delete | rpc::CommandMap::flag_public_xmlrpc, parm, doc);
rpc::commands.insert_type(key, commandDownloadSlotsItr++, &rpc::CommandSlot<core::Download*>::function, \
rpc::CommandMap::flag_dont_delete | rpc::CommandMap::flag_public_xmlrpc, parm, doc);
#define CMD_D(key, slot) \
CMD_D_SLOT(key, call_unknown, slot, "i:", "")
#define CMD_D_ANY(key, slot) \
CMD_D_SLOT(key, call_unknown, slot, "i:", "")
+50
View File
@@ -0,0 +1,50 @@
// rTorrent - BitTorrent client
// Copyright (C) 2005-2007, 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 <algorithm>
#include "globals.h"
#include "control.h"
#include "command_helpers.h"
#include "rpc/command_variable.h"
void
initialize_command_object() {
// CMD_N ("system.method.insert", rak::ptr_fn(&system_method_insert));
// CMD_N_STRING("system.method.erase", rak::ptr_fn(&system_method_erase));
}
+17
View File
@@ -394,6 +394,21 @@ cmd_view_size_not_visible(__UNUSED rpc::target_type target, const torrent::Objec
return (*control->view_manager()->find_throw(rawArgs.as_string()))->size_not_visible();
}
torrent::Object
cmd_view_persistent(__UNUSED rpc::target_type target, const torrent::Object& rawArgs) {
const std::string& args = rawArgs.as_string();
core::View* view = *control->view_manager()->find_throw(args);
if (!view->get_filter().empty() || !view->get_event_added().empty() || !view->get_event_removed().empty())
throw torrent::input_error("Cannot set modified views as persitent.");
view->set_filter("d.views.has=" + args);
view->set_event_added("d.views.push_back_unique=" + args);
view->set_event_removed("d.views.remove=" + args);
return torrent::Object();
}
torrent::Object
cmd_ui_set_view(__UNUSED rpc::target_type target, const torrent::Object& rawArgs) {
control->ui()->download_list()->set_current_view(rawArgs.as_string());
@@ -451,6 +466,8 @@ initialize_command_ui() {
CMD_G_STRING("view.size", rak::ptr_fn(&cmd_view_size));
CMD_G_STRING("view.size_not_visible", rak::ptr_fn(&cmd_view_size_not_visible));
CMD_G_STRING("view.persistent", rak::ptr_fn(&cmd_view_persistent));
CMD_D_STRING("view.filter_download", rak::ptr_fn(&cmd_view_filter_download));
CMD_D_STRING("view.set_visible", rak::ptr_fn(&cmd_view_set_visible));
CMD_D_STRING("view.set_not_visible", rak::ptr_fn(&cmd_view_set_not_visible));
+1
View File
@@ -337,6 +337,7 @@ DownloadFactory::initialize_rtorrent(Download* download, torrent::Object* rtorre
download->download()->file_list()->size_chunks()));
rtorrent->insert_preserve_copy("ignore_commands", (int64_t)0);
rtorrent->insert_preserve_copy("views", torrent::Object::create_list());
rtorrent->insert_preserve_type("connection_leech", m_variables["connection_leech"]);
rtorrent->insert_preserve_type("connection_seed", m_variables["connection_seed"]);
+3
View File
@@ -122,11 +122,14 @@ public:
void filter();
void filter_download(core::Download* download);
const std::string& get_filter() const { return m_filter; }
void set_filter(const std::string& s) { m_filter = s; }
void set_filter_on_event(const std::string& event);
void clear_filter_on();
const std::string& get_event_added() const { return m_eventAdded; }
const std::string& get_event_removed() const { return m_eventRemoved; }
void set_event_added(const std::string& cmd) { m_eventAdded = cmd; }
void set_event_removed(const std::string& cmd) { m_eventRemoved = cmd; }
+1 -1
View File
@@ -122,7 +122,7 @@ TextElementCommand::print(char* first, char* last, Canvas::attributes_list* attr
}
case torrent::Object::TYPE_VALUE:
{
first += std::max(snprintf(first, last - first + 1, "%lld", result.as_value()), 0);
first += std::min(std::max(snprintf(first, last - first + 1, "%lld", result.as_value()), 0), last - first + 1);
break;
}
default:
+11 -11
View File
@@ -82,28 +82,28 @@ TextElementValueBase::print(char* first, char* last, Canvas::attributes_list* at
} else if (m_flags & flag_kb) {
// Just use a default width of 5 for now.
first += std::max(snprintf(first, last - first + 1, "%5.1f", (double)val / (1 << 10)), 0);
first += std::min(std::max(snprintf(first, last - first + 1, "%5.1f", (double)val / (1 << 10)), 0), last - first + 1);
} else if (m_flags & flag_mb) {
// Just use a default width of 8 for now.
first += std::max(snprintf(first, last - first + 1, "%8.1f", (double)val / (1 << 20)), 0);
first += std::min(std::max(snprintf(first, last - first + 1, "%8.1f", (double)val / (1 << 20)), 0), last - first + 1);
} else if (m_flags & flag_xb) {
if (val < (int64_t(1000) << 10))
first += std::max(snprintf(first, last - first + 1, "%5.1f KB", (double)val / (int64_t(1) << 10)), 0);
first += std::min(std::max(snprintf(first, last - first + 1, "%5.1f KB", (double)val / (int64_t(1) << 10)), 0), last - first + 1);
else if (val < (int64_t(1000) << 20))
first += std::max(snprintf(first, last - first + 1, "%5.1f MB", (double)val / (int64_t(1) << 20)), 0);
first += std::min(std::max(snprintf(first, last - first + 1, "%5.1f MB", (double)val / (int64_t(1) << 20)), 0), last - first + 1);
else if (val < (int64_t(1000) << 30))
first += std::max(snprintf(first, last - first + 1, "%5.1f GB", (double)val / (int64_t(1) << 30)), 0);
first += std::min(std::max(snprintf(first, last - first + 1, "%5.1f GB", (double)val / (int64_t(1) << 30)), 0), last - first + 1);
else
first += std::max(snprintf(first, last - first + 1, "%5.1f TB", (double)val / (int64_t(1) << 40)), 0);
first += std::min(std::max(snprintf(first, last - first + 1, "%5.1f TB", (double)val / (int64_t(1) << 40)), 0), last - first + 1);
} else if (m_flags & flag_timer) {
if (val == 0)
first += std::max(snprintf(first, last - first + 1, "--:--:--"), 0);
first += std::min(std::max(snprintf(first, last - first + 1, "--:--:--"), 0), last - first + 1);
else
first += std::max(snprintf(first, last - first + 1, "%2d:%02d:%02d", (int)(val / 3600), (int)((val / 60) % 60), (int)(val % 60)), 0);
first += std::min(std::max(snprintf(first, last - first + 1, "%2d:%02d:%02d", (int)(val / 3600), (int)((val / 60) % 60), (int)(val % 60)), 0), last - first + 1);
} else if (m_flags & flag_date) {
time_t t = val;
@@ -112,7 +112,7 @@ TextElementValueBase::print(char* first, char* last, Canvas::attributes_list* at
if (u == NULL)
return first;
first += std::max(snprintf(first, last - first + 1, "%02u/%02u/%04u", u->tm_mday, (u->tm_mon + 1), (1900 + u->tm_year)), 0);
first += std::min(std::max(snprintf(first, last - first + 1, "%02u/%02u/%04u", u->tm_mday, (u->tm_mon + 1), (1900 + u->tm_year)), 0), last - first + 1);;
} else if (m_flags & flag_time) {
time_t t = val;
@@ -121,10 +121,10 @@ TextElementValueBase::print(char* first, char* last, Canvas::attributes_list* at
if (u == NULL)
return first;
first += std::max(snprintf(first, last - first + 1, "%2d:%02d:%02d", u->tm_hour, u->tm_min, u->tm_sec), 0);
first += std::min(std::max(snprintf(first, last - first + 1, "%2d:%02d:%02d", u->tm_hour, u->tm_min, u->tm_sec), 0), last - first + 1);
} else {
first += std::max(snprintf(first, last - first + 1, "%lld", val), 0);
first += std::min(std::max(snprintf(first, last - first + 1, "%lld", val), 0), last - first + 1);
}
push_attribute(attributes, Attributes(first, baseAttribute));
+2 -2
View File
@@ -68,7 +68,7 @@ WindowDownloadStatusbar::redraw() {
position = print_download_info(buffer, last, m_download);
m_canvas->print(0, 0, "%s", buffer);
position = buffer + std::max(snprintf(buffer, last - buffer, "Peers: %i(%i) Min/Max: %i/%i Uploads: %i U/I/C/A: %i/%i/%i/%i Failed: %i",
position = buffer + std::min(std::max(snprintf(buffer, last - buffer, "Peers: %i(%i) Min/Max: %i/%i Uploads: %i U/I/C/A: %i/%i/%i/%i Failed: %i",
(int)m_download->download()->connection_list()->size(),
(int)m_download->download()->peer_list()->available_list_size(),
(int)m_download->download()->connection_list()->min_size(),
@@ -79,7 +79,7 @@ WindowDownloadStatusbar::redraw() {
(int)m_download->download()->peers_complete(),
(int)m_download->download()->peers_accounted(),
(int)m_download->chunks_failed()),
0);
0), last - buffer);
m_canvas->print(0, 1, "%s", buffer);
+9 -8
View File
@@ -212,14 +212,15 @@ main(int argc, char** argv) {
"group.insert = seeding,seeding\n"
// "system.method.insert = group.seeding.view,string|static|const,seeding\n"
// "system.method.insert = group.seeding.ratio.enable ,simple,\"schedule=group.seeding.ratio,5,60,on_ratio=seeding\"\n"
// "system.method.insert = group.seeding.ratio.disable,simple,\"schedule_remove=group.seeding.ratio\"\n"
// "system.method.insert = group.seeding.ratio.command,simple|static,\"d.try_close= ;d.set_ignore_commands=1\"\n"
// "system.method.insert = group.seeding.ratio.min,value,200\n"
// "system.method.insert = group.seeding.ratio.max,value,300\n"
// "system.method.insert = group.seeding.ratio.upload,value,20M\n"
"system.method.insert = ratio.enable, simple|static|const,group.seeding.ratio.enable=\n"
"system.method.insert = ratio.disable,simple|static|const,group.seeding.ratio.disable=\n"
"system.method.insert = ratio.command,simple|static|const,group.seeding.ratio.command=\n"
"system.method.insert = ratio.min, simple|static|const,group.seeding.ratio.min=\n"
"system.method.insert = ratio.max, simple|static|const,group.seeding.ratio.max=\n"
"system.method.insert = ratio.upload, simple|static|const,group.seeding.ratio.upload=\n"
"system.method.insert = ratio.min.set, simple|static|const,group.seeding.ratio.min.set=$argument.0=\n"
"system.method.insert = ratio.max.set, simple|static|const,group.seeding.ratio.max.set=$argument.0=\n"
"system.method.insert = ratio.upload.set,simple|static|const,group.seeding.ratio.upload.set=$argument.0=\n"
"set_name = \"$cat=$system.hostname=,:,$system.pid=\"\n"