diff --git a/configure.ac b/configure.ac index 88cad8da..8c1f5658 100644 --- a/configure.ac +++ b/configure.ac @@ -29,6 +29,10 @@ TORRENT_WITHOUT_NCURSESW() TORRENT_WITHOUT_STATVFS() TORRENT_WITHOUT_STATFS() +ACX_PTHREAD(CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS"; + LIBS="$PTHREAD_LIBS $LIBS" +) + PKG_CHECK_MODULES(sigc, sigc++-2.0, CXXFLAGS="$CXXFLAGS $sigc_CFLAGS"; LIBS="$LIBS $sigc_LIBS") diff --git a/scripts/acx_pthread.m4 b/scripts/acx_pthread.m4 new file mode 100644 index 00000000..ceb161a5 --- /dev/null +++ b/scripts/acx_pthread.m4 @@ -0,0 +1,227 @@ +dnl PGSGL: When updating, comment out port-specific part below; +dnl see the comment below with the word "PostgreSQL". +dnl +dnl Available from the GNU Autoconf Macro Archive at: +dnl http://www.gnu.org/software/ac-archive/htmldoc/acx_pthread.html +dnl +AC_DEFUN([ACX_PTHREAD], [ +AC_REQUIRE([AC_CANONICAL_HOST]) +AC_LANG_SAVE +AC_LANG_C +acx_pthread_ok=no + +# We used to check for pthread.h first, but this fails if pthread.h +# requires special compiler flags (e.g. on True64 or Sequent). +# It gets checked for in the link test anyway. + +# First of all, check if the user has set any of the PTHREAD_LIBS, +# etcetera environment variables, and if threads linking works using +# them: +if test x"$PTHREAD_LIBS$PTHREAD_CFLAGS" != x; then + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + AC_MSG_CHECKING([for pthread_join in LIBS=$PTHREAD_LIBS with CFLAGS=$PTHREAD_CFLAGS]) + AC_TRY_LINK_FUNC(pthread_join, acx_pthread_ok=yes) + AC_MSG_RESULT($acx_pthread_ok) + if test x"$acx_pthread_ok" = xno; then + PTHREAD_LIBS="" + PTHREAD_CFLAGS="" + fi + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" +fi + +# We must check for the threads library under a number of different +# names; the ordering is very important because some systems +# (e.g. DEC) have both -lpthread and -lpthreads, where one of the +# libraries is broken (non-POSIX). + +# Create a list of thread flags to try. Items starting with a "-" are +# C compiler flags, and other items are library names, except for "none" +# which indicates that we try without any flags at all, and "pthread-config" +# which is a program returning the flags for the Pth emulation library. + +acx_pthread_flags="pthreads none -Kthread -kthread lthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config pthreadGC2" + +# The ordering *is* (sometimes) important. Some notes on the +# individual items follow: + +# pthreads: AIX (must check this before -lpthread) +# none: in case threads are in libc; should be tried before -Kthread and +# other compiler flags to prevent continual compiler warnings +# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h) +# -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able) +# lthread: LinuxThreads port on FreeBSD (also preferred to -pthread) +# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads) +# -pthreads: Solaris/gcc +# -mthreads: Mingw32/gcc, Lynx/gcc +# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it +# doesn't hurt to check since this sometimes defines pthreads too; +# also defines -D_REENTRANT) +# pthread: Linux, etcetera +# --thread-safe: KAI C++ +# pthread-config: use pthread-config program (for GNU Pth library) + +case "${host_cpu}-${host_os}" in + *solaris*) + + # On Solaris (at least, for some versions), libc contains stubbed + # (non-functional) versions of the pthreads routines, so link-based + # tests will erroneously succeed. (We need to link with -pthread or + # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather + # a function called by this macro, so we could check for that, but + # who knows whether they'll stub that too in a future libc.) So, + # we'll just look for -pthreads and -lpthread first: + + acx_pthread_flags="-pthread -pthreads pthread -mt $acx_pthread_flags" + ;; +esac + +if test x"$acx_pthread_ok" = xno; then +for flag in $acx_pthread_flags; do + + tryPTHREAD_CFLAGS="" + tryPTHREAD_LIBS="" + case $flag in + none) + AC_MSG_CHECKING([whether pthreads work without any flags]) + ;; + + -*) + AC_MSG_CHECKING([whether pthreads work with $flag]) + tryPTHREAD_CFLAGS="$flag" + ;; + + pthread-config) + # skip this if we already have flags defined, for PostgreSQL + if test x"$PTHREAD_CFLAGS" != x -o x"$PTHREAD_LIBS" != x; then continue; fi + AC_CHECK_PROG(acx_pthread_config, pthread-config, yes, no) + if test x"$acx_pthread_config" = xno; then continue; fi + tryPTHREAD_CFLAGS="`pthread-config --cflags`" + tryPTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`" + ;; + + *) + AC_MSG_CHECKING([for the pthreads library -l$flag]) + tryPTHREAD_LIBS="-l$flag" + ;; + esac + + save_LIBS="$LIBS" + save_CFLAGS="$CFLAGS" + LIBS="$tryPTHREAD_LIBS $PTHREAD_LIBS $LIBS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS $tryPTHREAD_CFLAGS" + + # Check for various functions. We must include pthread.h, + # since some functions may be macros. (On the Sequent, we + # need a special flag -Kthread to make this header compile.) + # We check for pthread_join because it is in -lpthread on IRIX + # while pthread_create is in libc. We check for pthread_attr_init + # due to DEC craziness with -lpthreads. We check for + # pthread_cleanup_push because it is one of the few pthread + # functions on Solaris that doesn't have a non-functional libc stub. + # We try pthread_create on general principles. + AC_TRY_LINK([#include ], + [pthread_t th; pthread_join(th, 0); + pthread_attr_init(0); pthread_cleanup_push(0, 0); + pthread_create(0,0,0,0); pthread_cleanup_pop(0); ], + [acx_pthread_ok=yes], [acx_pthread_ok=no]) + + if test "x$acx_pthread_ok" = xyes; then + # Don't use options that are ignored by the compiler. + # We find them by checking stderror. + cat >conftest.$ac_ext <<_ACEOF +int +main (int argc, char **argv) +{ + (void) argc; + (void) argv; + return 0; +} +_ACEOF + rm -f conftest.$ac_objext conftest$ac_exeext + if test "`(eval $ac_link 2>&1 1>&5)`" = ""; then + # we continue with more flags because Linux needs -lpthread + # for libpq builds on PostgreSQL. The test above only + # tests for building binaries, not shared libraries. + PTHREAD_LIBS=" $tryPTHREAD_LIBS $PTHREAD_LIBS" + PTHREAD_CFLAGS="$PTHREAD_CFLAGS $tryPTHREAD_CFLAGS" + else acx_pthread_ok=no + fi + fi + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + + AC_MSG_RESULT($acx_pthread_ok) +done +fi + +# Various other checks: +if test "x$acx_pthread_ok" = xyes; then + save_LIBS="$LIBS" + LIBS="$PTHREAD_LIBS $LIBS" + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $PTHREAD_CFLAGS" + + # Detect AIX lossage: threads are created detached by default + # and the JOINABLE attribute has a nonstandard name (UNDETACHED). + AC_MSG_CHECKING([for joinable pthread attribute]) + AC_TRY_LINK([#include ], + [int attr=PTHREAD_CREATE_JOINABLE;], + ok=PTHREAD_CREATE_JOINABLE, ok=unknown) + if test x"$ok" = xunknown; then + AC_TRY_LINK([#include ], + [int attr=PTHREAD_CREATE_UNDETACHED;], + ok=PTHREAD_CREATE_UNDETACHED, ok=unknown) + fi + if test x"$ok" != xPTHREAD_CREATE_JOINABLE; then + AC_DEFINE(PTHREAD_CREATE_JOINABLE, $ok, + [Define to the necessary symbol if this constant + uses a non-standard name on your system.]) + fi + AC_MSG_RESULT(${ok}) + if test x"$ok" = xunknown; then + AC_MSG_WARN([we do not know how to create joinable pthreads]) + fi + + AC_MSG_CHECKING([if more special flags are required for pthreads]) + flag=no +# We always add these in PostgreSQL +# case "${host_cpu}-${host_os}" in +# *-aix* | *-freebsd* | *-darwin*) flag="-D_THREAD_SAFE";; +# *solaris* | *-osf* | *-hpux*) flag="-D_REENTRANT";; +# esac + AC_MSG_RESULT(${flag}) + if test "x$flag" != xno; then + PTHREAD_CFLAGS="$flag $PTHREAD_CFLAGS" + fi + + LIBS="$save_LIBS" + CFLAGS="$save_CFLAGS" + +# Supporting cc_r would require a special CC in all places that +# use libpq, and that is ugly, so we don't do it. Users can still +# define their compiler as cc_r to do thread builds of everything. + # More AIX lossage: must compile with cc_r + AC_CHECK_PROG(PTHREAD_CC, cc_r, cc_r, ${CC}) +else + PTHREAD_CC="$CC" +fi + +AC_SUBST(PTHREAD_LIBS) +AC_SUBST(PTHREAD_CFLAGS) +AC_SUBST(PTHREAD_CC) + +# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND: +if test x"$acx_pthread_ok" = xyes; then + ifelse([$1],,AC_DEFINE(HAVE_PTHREAD,1,[Define if you have POSIX threads libraries and header files.]),[$1]) + : +else + acx_pthread_ok=no + $2 +fi +AC_LANG_RESTORE +])dnl ACX_PTHREAD diff --git a/scripts/common.m4 b/scripts/common.m4 index ec0463e0..f875c71a 100644 --- a/scripts/common.m4 +++ b/scripts/common.m4 @@ -212,11 +212,11 @@ dnl AC_DEFINE(lt_cacheline_aligned, __cacheline_aligned, LibTorrent defined dnl Need to fix this so that it uses the stuff defined by the system. - AC_DEFINE(LT_SMP_CACHE_BYTES, 128, Largest L1 cache size we know of, should work on all archs.) + AC_DEFINE(LT_SMP_CACHE_BYTES, 128, Largest L1 cache size we know of should work on all archs.) AC_DEFINE(lt_cacheline_aligned, __attribute__((__aligned__(LT_SMP_CACHE_BYTES))), LibTorrent defined cacheline aligned.) ], [ AC_MSG_RESULT(using default 128 bytes) - AC_DEFINE(LT_SMP_CACHE_BYTES, 128, Largest L1 cache size we know of, should work on all archs.) + AC_DEFINE(LT_SMP_CACHE_BYTES, 128, Largest L1 cache size we know of should work on all archs.) AC_DEFINE(lt_cacheline_aligned, __attribute__((__aligned__(LT_SMP_CACHE_BYTES))), LibTorrent defined cacheline aligned.) ]) ]) diff --git a/src/Makefile.am b/src/Makefile.am index d61fb484..33ab8891 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -13,6 +13,7 @@ libsub_root_a_SOURCES = \ command_dynamic.cc \ command_events.cc \ command_file.cc \ + command_ip.cc \ command_helpers.cc \ command_helpers.h \ command_groups.cc \ diff --git a/src/command_helpers.cc b/src/command_helpers.cc index 8a716757..59892f13 100644 --- a/src/command_helpers.cc +++ b/src/command_helpers.cc @@ -46,6 +46,7 @@ void initialize_command_dynamic(); void initialize_command_download(); void initialize_command_events(); void initialize_command_file(); +void initialize_command_ip(); void initialize_command_peer(); void initialize_command_local(); void initialize_command_network(); @@ -65,6 +66,7 @@ initialize_commands() { initialize_command_ui(); initialize_command_download(); initialize_command_file(); + initialize_command_ip(); initialize_command_peer(); initialize_command_throttle(); initialize_command_tracker(); diff --git a/src/command_ip.cc b/src/command_ip.cc new file mode 100644 index 00000000..b92547df --- /dev/null +++ b/src/command_ip.cc @@ -0,0 +1,245 @@ +// 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 +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "globals.h" +#include "command_helpers.h" + +void +ipv4_filter_parse(const char* address, int value) { + uint32_t ip_values[4] = { 0, 0, 0, 0 }; + unsigned int block = rpc::ipv4_table::mask_bits; + + char ip_dot; + int values_read; + + if ((values_read = sscanf(address, "%u%1[.]%u%1[.]%u%1[.]%u/%u", + ip_values + 0, &ip_dot, + ip_values + 1, &ip_dot, + ip_values + 2, &ip_dot, + ip_values + 3, + &block)) < 2 || + + // Make sure the dot is included. + (values_read < 7 && values_read % 2) || + + ip_values[0] >= 256 || + ip_values[1] >= 256 || + ip_values[2] >= 256 || + ip_values[3] >= 256 || + + block > rpc::ipv4_table::mask_bits) + throw torrent::input_error("Invalid address format."); + + // E.g. '10.10.' will be '10.10.0.0/16'. + if (values_read < 7) + block = 8 * (values_read / 2); + + torrent::PeerList::ipv4_filter()->insert((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3], + rpc::ipv4_table::mask_bits - block, value); +} + +torrent::Object +apply_ip_tables_insert_table(const std::string& args) { + if (ip_tables.find(args) != ip_tables.end()) + throw torrent::input_error("IP table already exists."); + + ip_tables.insert(args); + return torrent::Object(); +} + +torrent::Object +apply_ip_tables_get(const torrent::Object::list_type& args) { + if (args.size() != 2) + throw torrent::input_error("Incorrect number of arguments."); + + torrent::Object::list_const_iterator args_itr = args.begin(); + + const std::string& name = (args_itr++)->as_string(); + const std::string& address = (args_itr++)->as_string(); + + // Move to a helper function, add support for addresses. + uint32_t ip_values[4]; + + if (sscanf(address.c_str(), "%u.%u.%u.%u", + ip_values + 0, ip_values + 1, ip_values + 2, ip_values + 3) != 4) + throw torrent::input_error("Invalid address format."); + + rpc::ip_table_list::iterator table_itr = ip_tables.find(name); + + if (table_itr == ip_tables.end()) + throw torrent::input_error("Could not find ip table."); + + return table_itr->table.at((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3]); +} + +torrent::Object +apply_ip_tables_add_address(const torrent::Object::list_type& args) { + if (args.size() != 3) + throw torrent::input_error("Incorrect number of arguments."); + + torrent::Object::list_const_iterator args_itr = args.begin(); + + const std::string& name = (args_itr++)->as_string(); + const std::string& address = (args_itr++)->as_string(); + const std::string& value_str = (args_itr++)->as_string(); + + // Move to a helper function, add support for addresses. + uint32_t ip_values[4]; + unsigned int block = rpc::ipv4_table::mask_bits; + + if (sscanf(address.c_str(), "%u.%u.%u.%u/%u", + ip_values + 0, ip_values + 1, ip_values + 2, ip_values + 3, &block) < 4 || + block > rpc::ipv4_table::mask_bits) + throw torrent::input_error("Invalid address format."); + + int value; + + if (value_str == "block") + value = 1; + else + throw torrent::input_error("Invalid value."); + + rpc::ip_table_list::iterator table_itr = ip_tables.find(name); + + if (table_itr == ip_tables.end()) + throw torrent::input_error("Could not find ip table."); + + table_itr->table.insert((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3], + rpc::ipv4_table::mask_bits - block, value); + + return torrent::Object(); +} + +// +// IPv4 filter functions: +// + +torrent::Object +apply_ipv4_filter_size_data() { + return torrent::PeerList::ipv4_filter()->sizeof_data(); +} + +torrent::Object +apply_ipv4_filter_get(const std::string& args) { + // Move to a helper function, add support for addresses. + uint32_t ip_values[4]; + + if (sscanf(args.c_str(), "%u.%u.%u.%u", + ip_values + 0, ip_values + 1, ip_values + 2, ip_values + 3) != 4) + throw torrent::input_error("Invalid address format."); + + return torrent::PeerList::ipv4_filter()->at((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3]); +} + +torrent::Object +apply_ipv4_filter_add_address(const torrent::Object::list_type& args) { + if (args.size() != 2) + throw torrent::input_error("Incorrect number of arguments."); + + ipv4_filter_parse(args.front().as_string().c_str(), + torrent::option_find_string(torrent::OPTION_IP_FILTER, args.back().as_string().c_str())); + return torrent::Object(); +} + +torrent::Object +apply_ipv4_filter_load(const torrent::Object::list_type& args) { + if (args.size() != 2) + throw torrent::input_error("Incorrect number of arguments."); + + std::fstream file(rak::path_expand(args.front().as_string()).c_str(), std::ios::in); + + if (!file.is_open()) + throw torrent::input_error("Could not open ip filter file: " + args.front().as_string()); + + int value = torrent::option_find_string(torrent::OPTION_IP_FILTER, args.back().as_string().c_str()); + + char buffer[4096]; + unsigned int lineNumber = 0; + + try { + while (file.good() && !file.getline(buffer, 4096).fail()) { + if (file.gcount() == 0) + throw torrent::internal_error("parse_command_file(...) file.gcount() == 0."); + + int lineLength = file.gcount() - 1; + // In case we are at the end of the file and the last character is + // not a line feed, we'll just increase the read character count so + // that the last would also be included in option line. + if (file.eof() && file.get() != '\n') + lineLength++; + + lineNumber++; + + if (buffer[0] == '\0' || buffer[0] == '#') + continue; + + ipv4_filter_parse(buffer, value); + } + + } catch (torrent::input_error& e) { + snprintf(buffer, 2048, "Error in ip filter file: %s:%u: %s", args.front().as_string().c_str(), lineNumber, e.what()); + + throw torrent::input_error(buffer); + } + + lt_log_print(torrent::LOG_CONNECTION_INFO, "Loaded %u %s address blocks (%u kb in-memory) from '%s'.", + lineNumber, + args.back().as_string().c_str(), + torrent::PeerList::ipv4_filter()->sizeof_data() / 1024, + args.front().as_string().c_str()); + + return torrent::Object(); +} + +void +initialize_command_ip() { + CMD2_ANY_STRING ("ip_tables.insert_table", std::bind(&apply_ip_tables_insert_table, std::placeholders::_2)); + CMD2_ANY_LIST ("ip_tables.get", std::bind(&apply_ip_tables_get, std::placeholders::_2)); + CMD2_ANY_LIST ("ip_tables.add_address", std::bind(&apply_ip_tables_add_address, std::placeholders::_2)); + + CMD2_ANY ("ipv4_filter.size_data", std::bind(&apply_ipv4_filter_size_data)); + CMD2_ANY_STRING ("ipv4_filter.get", std::bind(&apply_ipv4_filter_get, std::placeholders::_2)); + CMD2_ANY_LIST ("ipv4_filter.add_address", std::bind(&apply_ipv4_filter_add_address, std::placeholders::_2)); + CMD2_ANY_LIST ("ipv4_filter.load", std::bind(&apply_ipv4_filter_load, std::placeholders::_2)); +} diff --git a/src/command_network.cc b/src/command_network.cc index 4bf6c553..5a27975a 100644 --- a/src/command_network.cc +++ b/src/command_network.cc @@ -37,24 +37,20 @@ #include "config.h" #include -#include #include #include #include #include #include -#include #include #include #include #include #include #include -#include #include #include -#include "core/dht_manager.h" #include "core/download.h" #include "core/manager.h" #include "rpc/scgi.h" @@ -66,6 +62,8 @@ #include "control.h" #include "command_helpers.h" +namespace tr1 { using namespace std::tr1; } + torrent::Object apply_encryption(const torrent::Object::list_type& args) { uint32_t options_mask = torrent::ConnectionManager::encryption_none; @@ -100,56 +98,6 @@ torrent::Object apply_hash_read_ahead(int arg) { torrent::set_hash_ torrent::Object apply_hash_interval(int arg) { torrent::set_hash_interval(arg * 1000); return torrent::Object(); } torrent::Object apply_encoding_list(const std::string& arg) { torrent::encoding_list()->push_back(arg); return torrent::Object(); } -struct call_add_node_t { - call_add_node_t(int port) : m_port(port) { } - - void operator() (const sockaddr* sa, int err) { - if (sa == NULL) { - lt_log_print(torrent::LOG_DHT_WARN, "Could not resolve host."); - } else { - torrent::dht_manager()->add_node(sa, m_port); - } - } - - int m_port; -}; - -torrent::Object -apply_dht_add_node(const std::string& arg) { - if (!torrent::dht_manager()->is_valid()) - throw torrent::input_error("DHT not enabled."); - - int port, ret; - char dummy; - char host[1024]; - - ret = std::sscanf(arg.c_str(), "%1023[^:]:%i%c", host, &port, &dummy); - - if (ret == 1) - port = 6881; - else if (ret != 2) - throw torrent::input_error("Could not parse host."); - - if (port < 1 || port > 65535) - throw torrent::input_error("Invalid port number."); - - torrent::connection_manager()->resolver()(host, (int)rak::socket_address::pf_inet, SOCK_DGRAM, call_add_node_t(port)); - return torrent::Object(); -} - -torrent::Object -apply_enable_trackers(int64_t arg) { - for (core::Manager::DListItr itr = control->core()->download_list()->begin(), last = control->core()->download_list()->end(); itr != last; ++itr) { - std::for_each((*itr)->tracker_list()->begin(), (*itr)->tracker_list()->end(), - arg ? std::mem_fun(&torrent::Tracker::enable) : std::mem_fun(&torrent::Tracker::disable)); - - if (arg && !rpc::call_command_value("trackers.use_udp")) - (*itr)->enable_udp_trackers(false); - } - - return torrent::Object(); -} - torrent::File* xmlrpc_find_file(core::Download* download, uint32_t index) { if (index >= download->file_list()->size_files()) @@ -180,10 +128,10 @@ xmlrpc_find_peer(core::Download* download, const torrent::HashString& hash) { void initialize_xmlrpc() { rpc::xmlrpc.initialize(); - rpc::xmlrpc.slot_find_download() = std::tr1::bind(&core::DownloadList::find_hex_ptr, control->core()->download_list(), std::tr1::placeholders::_1); - rpc::xmlrpc.slot_find_file() = std::tr1::bind(&xmlrpc_find_file, std::tr1::placeholders::_1, std::tr1::placeholders::_2); - rpc::xmlrpc.slot_find_tracker() = std::tr1::bind(&xmlrpc_find_tracker, std::tr1::placeholders::_1, std::tr1::placeholders::_2); - rpc::xmlrpc.slot_find_peer() = std::tr1::bind(&xmlrpc_find_peer, std::tr1::placeholders::_1, std::tr1::placeholders::_2); + rpc::xmlrpc.slot_find_download() = tr1::bind(&core::DownloadList::find_hex_ptr, control->core()->download_list(), tr1::placeholders::_1); + rpc::xmlrpc.slot_find_file() = tr1::bind(&xmlrpc_find_file, tr1::placeholders::_1, tr1::placeholders::_2); + rpc::xmlrpc.slot_find_tracker() = tr1::bind(&xmlrpc_find_tracker, tr1::placeholders::_1, tr1::placeholders::_2); + rpc::xmlrpc.slot_find_peer() = tr1::bind(&xmlrpc_find_peer, tr1::placeholders::_1, tr1::placeholders::_2); unsigned int count = 0; @@ -284,197 +232,6 @@ apply_xmlrpc_dialect(const std::string& arg) { return torrent::Object(); } -// -// IP filter stuff: -// - -void -ipv4_filter_parse(const char* address, int value) { - uint32_t ip_values[4] = { 0, 0, 0, 0 }; - unsigned int block = rpc::ipv4_table::mask_bits; - - char ip_dot; - int values_read; - - if ((values_read = sscanf(address, "%u%1[.]%u%1[.]%u%1[.]%u/%u", - ip_values + 0, &ip_dot, - ip_values + 1, &ip_dot, - ip_values + 2, &ip_dot, - ip_values + 3, - &block)) < 2 || - - // Make sure the dot is included. - (values_read < 7 && values_read % 2) || - - ip_values[0] >= 256 || - ip_values[1] >= 256 || - ip_values[2] >= 256 || - ip_values[3] >= 256 || - - block > rpc::ipv4_table::mask_bits) - throw torrent::input_error("Invalid address format."); - - // E.g. '10.10.' will be '10.10.0.0/16'. - if (values_read < 7) - block = 8 * (values_read / 2); - - torrent::PeerList::ipv4_filter()->insert((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3], - rpc::ipv4_table::mask_bits - block, value); -} - -torrent::Object -apply_ip_tables_insert_table(const std::string& args) { - if (ip_tables.find(args) != ip_tables.end()) - throw torrent::input_error("IP table already exists."); - - ip_tables.insert(args); - return torrent::Object(); -} - -torrent::Object -apply_ip_tables_get(const torrent::Object::list_type& args) { - if (args.size() != 2) - throw torrent::input_error("Incorrect number of arguments."); - - torrent::Object::list_const_iterator args_itr = args.begin(); - - const std::string& name = (args_itr++)->as_string(); - const std::string& address = (args_itr++)->as_string(); - - // Move to a helper function, add support for addresses. - uint32_t ip_values[4]; - - if (sscanf(address.c_str(), "%u.%u.%u.%u", - ip_values + 0, ip_values + 1, ip_values + 2, ip_values + 3) != 4) - throw torrent::input_error("Invalid address format."); - - rpc::ip_table_list::iterator table_itr = ip_tables.find(name); - - if (table_itr == ip_tables.end()) - throw torrent::input_error("Could not find ip table."); - - return table_itr->table.at((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3]); -} - -torrent::Object -apply_ip_tables_add_address(const torrent::Object::list_type& args) { - if (args.size() != 3) - throw torrent::input_error("Incorrect number of arguments."); - - torrent::Object::list_const_iterator args_itr = args.begin(); - - const std::string& name = (args_itr++)->as_string(); - const std::string& address = (args_itr++)->as_string(); - const std::string& value_str = (args_itr++)->as_string(); - - // Move to a helper function, add support for addresses. - uint32_t ip_values[4]; - unsigned int block = rpc::ipv4_table::mask_bits; - - if (sscanf(address.c_str(), "%u.%u.%u.%u/%u", - ip_values + 0, ip_values + 1, ip_values + 2, ip_values + 3, &block) < 4 || - block > rpc::ipv4_table::mask_bits) - throw torrent::input_error("Invalid address format."); - - int value; - - if (value_str == "block") - value = 1; - else - throw torrent::input_error("Invalid value."); - - rpc::ip_table_list::iterator table_itr = ip_tables.find(name); - - if (table_itr == ip_tables.end()) - throw torrent::input_error("Could not find ip table."); - - table_itr->table.insert((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3], - rpc::ipv4_table::mask_bits - block, value); - - return torrent::Object(); -} - -// -// IPv4 filter functions: -// - -torrent::Object -apply_ipv4_filter_size_data() { - return torrent::PeerList::ipv4_filter()->sizeof_data(); -} - -torrent::Object -apply_ipv4_filter_get(const std::string& args) { - // Move to a helper function, add support for addresses. - uint32_t ip_values[4]; - - if (sscanf(args.c_str(), "%u.%u.%u.%u", - ip_values + 0, ip_values + 1, ip_values + 2, ip_values + 3) != 4) - throw torrent::input_error("Invalid address format."); - - return torrent::PeerList::ipv4_filter()->at((ip_values[0] << 24) + (ip_values[1] << 16) + (ip_values[2] << 8) + ip_values[3]); -} - -torrent::Object -apply_ipv4_filter_add_address(const torrent::Object::list_type& args) { - if (args.size() != 2) - throw torrent::input_error("Incorrect number of arguments."); - - ipv4_filter_parse(args.front().as_string().c_str(), - torrent::option_find_string(torrent::OPTION_IP_FILTER, args.back().as_string().c_str())); - return torrent::Object(); -} - -torrent::Object -apply_ipv4_filter_load(const torrent::Object::list_type& args) { - if (args.size() != 2) - throw torrent::input_error("Incorrect number of arguments."); - - std::fstream file(rak::path_expand(args.front().as_string()).c_str(), std::ios::in); - - if (!file.is_open()) - throw torrent::input_error("Could not open ip filter file: " + args.front().as_string()); - - int value = torrent::option_find_string(torrent::OPTION_IP_FILTER, args.back().as_string().c_str()); - - char buffer[4096]; - unsigned int lineNumber = 0; - - try { - while (file.good() && !file.getline(buffer, 4096).fail()) { - if (file.gcount() == 0) - throw torrent::internal_error("parse_command_file(...) file.gcount() == 0."); - - int lineLength = file.gcount() - 1; - // In case we are at the end of the file and the last character is - // not a line feed, we'll just increase the read character count so - // that the last would also be included in option line. - if (file.eof() && file.get() != '\n') - lineLength++; - - lineNumber++; - - if (buffer[0] == '\0' || buffer[0] == '#') - continue; - - ipv4_filter_parse(buffer, value); - } - - } catch (torrent::input_error& e) { - snprintf(buffer, 2048, "Error in ip filter file: %s:%u: %s", args.front().as_string().c_str(), lineNumber, e.what()); - - throw torrent::input_error(buffer); - } - - lt_log_print(torrent::LOG_CONNECTION_INFO, "Loaded %u %s address blocks (%u kb in-memory) from '%s'.", - lineNumber, - args.back().as_string().c_str(), - torrent::PeerList::ipv4_filter()->sizeof_data() / 1024, - args.front().as_string().c_str()); - - return torrent::Object(); -} - void initialize_command_network() { torrent::ConnectionManager* cm = torrent::connection_manager(); @@ -555,27 +312,4 @@ initialize_command_network() { CMD2_ANY_VALUE_V ("system.hash.interval.set", std::bind(&apply_hash_interval, std::placeholders::_2)); CMD2_ANY ("system.hash.max_tries", std::bind(&torrent::hash_max_tries)); CMD2_ANY_VALUE_V ("system.hash.max_tries.set", std::bind(&torrent::set_hash_max_tries, std::placeholders::_2)); - - CMD2_ANY_VALUE ("trackers.enable", std::bind(&apply_enable_trackers, int64_t(1))); - CMD2_ANY_VALUE ("trackers.disable", std::bind(&apply_enable_trackers, int64_t(0))); - CMD2_VAR_VALUE ("trackers.numwant", -1); - CMD2_VAR_BOOL ("trackers.use_udp", true); - - CMD2_ANY_STRING ("ip_tables.insert_table", std::bind(&apply_ip_tables_insert_table, std::placeholders::_2)); - CMD2_ANY_LIST ("ip_tables.get", std::bind(&apply_ip_tables_get, std::placeholders::_2)); - CMD2_ANY_LIST ("ip_tables.add_address", std::bind(&apply_ip_tables_add_address, std::placeholders::_2)); - - CMD2_ANY ("ipv4_filter.size_data", std::bind(&apply_ipv4_filter_size_data)); - CMD2_ANY_STRING ("ipv4_filter.get", std::bind(&apply_ipv4_filter_get, std::placeholders::_2)); - CMD2_ANY_LIST ("ipv4_filter.add_address", std::bind(&apply_ipv4_filter_add_address, std::placeholders::_2)); - CMD2_ANY_LIST ("ipv4_filter.load", std::bind(&apply_ipv4_filter_load, std::placeholders::_2)); - -// CMD2_ANY_V ("dht.enable", std::bind(&core::DhtManager::set_start, control->dht_manager())); -// CMD2_ANY_V ("dht.disable", std::bind(&core::DhtManager::set_stop, control->dht_manager())); - CMD2_ANY_STRING_V("dht.mode.set", std::bind(&core::DhtManager::set_mode, control->dht_manager(), std::placeholders::_2)); - CMD2_VAR_VALUE ("dht.port", int64_t(6881)); - CMD2_ANY_STRING ("dht.add_node", std::bind(&apply_dht_add_node, std::placeholders::_2)); - CMD2_ANY ("dht.statistics", std::bind(&core::DhtManager::dht_statistics, control->dht_manager())); - CMD2_ANY ("dht.throttle.name", std::bind(&core::DhtManager::throttle_name, control->dht_manager())); - CMD2_ANY_STRING_V("dht.throttle.name.set", std::bind(&core::DhtManager::set_throttle_name, control->dht_manager(), std::placeholders::_2)); } diff --git a/src/command_tracker.cc b/src/command_tracker.cc index 1af9b616..e6f226aa 100644 --- a/src/command_tracker.cc +++ b/src/command_tracker.cc @@ -36,14 +36,20 @@ #include "config.h" +#include +#include #include +#include #include +#include +#include "core/download.h" #include "core/manager.h" #include "globals.h" #include "control.h" #include "command_helpers.h" +#include "core/dht_manager.h" void tracker_set_enabled(torrent::Tracker* tracker, bool state) { @@ -53,6 +59,56 @@ tracker_set_enabled(torrent::Tracker* tracker, bool state) { tracker->disable(); } +struct call_add_node_t { + call_add_node_t(int port) : m_port(port) { } + + void operator() (const sockaddr* sa, int err) { + if (sa == NULL) { + lt_log_print(torrent::LOG_DHT_WARN, "Could not resolve host."); + } else { + torrent::dht_manager()->add_node(sa, m_port); + } + } + + int m_port; +}; + +torrent::Object +apply_dht_add_node(const std::string& arg) { + if (!torrent::dht_manager()->is_valid()) + throw torrent::input_error("DHT not enabled."); + + int port, ret; + char dummy; + char host[1024]; + + ret = std::sscanf(arg.c_str(), "%1023[^:]:%i%c", host, &port, &dummy); + + if (ret == 1) + port = 6881; + else if (ret != 2) + throw torrent::input_error("Could not parse host."); + + if (port < 1 || port > 65535) + throw torrent::input_error("Invalid port number."); + + torrent::connection_manager()->resolver()(host, (int)rak::socket_address::pf_inet, SOCK_DGRAM, call_add_node_t(port)); + return torrent::Object(); +} + +torrent::Object +apply_enable_trackers(int64_t arg) { + for (core::Manager::DListItr itr = control->core()->download_list()->begin(), last = control->core()->download_list()->end(); itr != last; ++itr) { + std::for_each((*itr)->tracker_list()->begin(), (*itr)->tracker_list()->end(), + arg ? std::mem_fun(&torrent::Tracker::enable) : std::mem_fun(&torrent::Tracker::disable)); + + if (arg && !rpc::call_command_value("trackers.use_udp")) + (*itr)->enable_udp_trackers(false); + } + + return torrent::Object(); +} + void initialize_command_tracker() { CMD2_TRACKER ("t.is_open", std::bind(&torrent::Tracker::is_busy, std::placeholders::_1)); @@ -66,6 +122,10 @@ initialize_command_tracker() { CMD2_TRACKER ("t.type", std::bind(&torrent::Tracker::type, std::placeholders::_1)); CMD2_TRACKER ("t.id", std::bind(&torrent::Tracker::tracker_id, std::placeholders::_1)); + CMD2_TRACKER ("t.latest_event", std::bind(&torrent::Tracker::latest_event, std::placeholders::_1)); + CMD2_TRACKER ("t.latest_new_peers", std::bind(&torrent::Tracker::latest_new_peers, std::placeholders::_1)); + CMD2_TRACKER ("t.latest_sum_peers", std::bind(&torrent::Tracker::latest_sum_peers, std::placeholders::_1)); + // Time since last connection, connection attempt. CMD2_TRACKER ("t.normal_interval", std::bind(&torrent::Tracker::normal_interval, std::placeholders::_1)); @@ -83,4 +143,16 @@ initialize_command_tracker() { CMD2_TRACKER ("t.scrape_complete", std::bind(&torrent::Tracker::scrape_complete, std::placeholders::_1)); CMD2_TRACKER ("t.scrape_incomplete", std::bind(&torrent::Tracker::scrape_incomplete, std::placeholders::_1)); CMD2_TRACKER ("t.scrape_downloaded", std::bind(&torrent::Tracker::scrape_downloaded, std::placeholders::_1)); + + CMD2_ANY_VALUE ("trackers.enable", std::bind(&apply_enable_trackers, int64_t(1))); + CMD2_ANY_VALUE ("trackers.disable", std::bind(&apply_enable_trackers, int64_t(0))); + CMD2_VAR_VALUE ("trackers.numwant", -1); + CMD2_VAR_BOOL ("trackers.use_udp", true); + + CMD2_ANY_STRING_V ("dht.mode.set", std::bind(&core::DhtManager::set_mode, control->dht_manager(), std::placeholders::_2)); + CMD2_VAR_VALUE ("dht.port", int64_t(6881)); + CMD2_ANY_STRING ("dht.add_node", std::bind(&apply_dht_add_node, std::placeholders::_2)); + CMD2_ANY ("dht.statistics", std::bind(&core::DhtManager::dht_statistics, control->dht_manager())); + CMD2_ANY ("dht.throttle.name", std::bind(&core::DhtManager::throttle_name, control->dht_manager())); + CMD2_ANY_STRING_V ("dht.throttle.name.set", std::bind(&core::DhtManager::set_throttle_name, control->dht_manager(), std::placeholders::_2)); } diff --git a/src/display/window_tracker_list.cc b/src/display/window_tracker_list.cc index 729f4524..ac2d78dc 100644 --- a/src/display/window_tracker_list.cc +++ b/src/display/window_tracker_list.cc @@ -41,6 +41,7 @@ #include #include #include +#include #include "core/download.h" @@ -62,8 +63,13 @@ WindowTrackerList::redraw() { unsigned int pos = 0; torrent::TrackerList* tl = m_download->tracker_list(); + torrent::TrackerController* tc = m_download->tracker_controller(); - m_canvas->print(2, pos, "Trackers: [Key: %08x]", tl->key()); + m_canvas->print(2, pos, "Trackers: [Key: %08x] [%s %s %s]", + tl->key(), + tc->is_requesting() ? "req" : " ", + tc->is_promiscuous_mode() ? "prom" : " ", + tc->is_failure_mode() ? "fail" : " "); ++pos; if (tl->size() == 0 || *m_focus >= tl->size()) @@ -89,16 +95,18 @@ WindowTrackerList::redraw() { tracker->url().c_str()); if (pos < m_canvas->height()) - m_canvas->print(4, pos++, "Id: %s Counters: %uf / %us (%u) Enabled: %s Open: %s S/L/D: %u/%u/%u", + m_canvas->print(4, pos++, "Id: %s Counters: %uf / %us (%u) %s %s S/L/D: %u/%u/%u (%u/%u)", rak::copy_escape_html(tracker->tracker_id()).c_str(), tracker->failed_counter(), tracker->success_counter(), tracker->scrape_counter(), - tracker->is_usable() ? "yes" : tracker->is_enabled() ? "off" : " no", - tracker->is_busy() ? "yes" : " no", + tracker->is_usable() ? " on" : tracker->is_enabled() ? "err" : "off", + tracker->is_busy() ? "req" : " ", tracker->scrape_complete(), tracker->scrape_incomplete(), - tracker->scrape_downloaded()); + tracker->scrape_downloaded(), + tracker->latest_new_peers(), + tracker->latest_sum_peers()); // m_canvas->print(4, pos++, "Id: %s Focus: %s Enabled: %s Open: %s Timer: %u/%u", // rak::copy_escape_html(tracker->tracker_id()).c_str(),