Moved curl to libtorrent.

This commit is contained in:
Jari Sundell
2025-06-05 13:29:43 +02:00
committed by GitHub
parent 231606afc1
commit 6c25e64c26
23 changed files with 167 additions and 911 deletions
+6 -3
View File
@@ -11,6 +11,12 @@ jobs:
- name: Update Packages - name: Update Packages
run: | run: |
sudo apt-get update sudo apt-get update
- name: Install Dependencies
run: |
sudo apt-get install -y \
bear \
clang-tidy \
libcurl4-openssl-dev
- name: Fetch libtorrent - name: Fetch libtorrent
run: | run: |
git clone https://github.com/rakshasa/libtorrent git clone https://github.com/rakshasa/libtorrent
@@ -35,9 +41,6 @@ jobs:
run: | run: |
git remote add upstream "https://github.com/${{ github.event.pull_request.base.repo.full_name }}" git remote add upstream "https://github.com/${{ github.event.pull_request.base.repo.full_name }}"
git fetch --no-tags --no-recurse-submodules upstream "${{ github.event.pull_request.base.ref }}" git fetch --no-tags --no-recurse-submodules upstream "${{ github.event.pull_request.base.ref }}"
- name: Install Dependencies
run: |
sudo apt-get install -y bear clang-tidy libcurl4-openssl-dev
- name: Configure Project - name: Configure Project
run: | run: |
libtoolize libtoolize
+13 -5
View File
@@ -11,6 +11,11 @@ jobs:
- name: Update Packages - name: Update Packages
run: | run: |
sudo apt-get update sudo apt-get update
- name: Install Dependencies
run: |
sudo apt-get install -y \
libcppunit-dev \
libcurl4-openssl-dev
- name: Fetch libtorrent - name: Fetch libtorrent
run: | run: |
git clone https://github.com/rakshasa/libtorrent git clone https://github.com/rakshasa/libtorrent
@@ -35,11 +40,6 @@ jobs:
run: | run: |
git remote add upstream "https://github.com/${{ github.event.pull_request.base.repo.full_name }}" git remote add upstream "https://github.com/${{ github.event.pull_request.base.repo.full_name }}"
git fetch --no-tags --no-recurse-submodules upstream "${{ github.event.pull_request.base.ref }}" git fetch --no-tags --no-recurse-submodules upstream "${{ github.event.pull_request.base.ref }}"
- name: Install Dependencies
run: |
sudo apt-get install -y \
libcppunit-dev \
libcurl4-openssl-dev
- name: Configure Project - name: Configure Project
run: | run: |
libtoolize libtoolize
@@ -53,4 +53,12 @@ jobs:
make make
- name: Run Unit Tests - name: Run Unit Tests
run: | run: |
ls /usr/local/lib/
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib"
make check make check
- name: Archive test/test-suite.log
if: success() || failure()
uses: actions/upload-artifact@v4
with:
name: test-suite.log
path: test/test-suite.log
+3 -4
View File
@@ -52,7 +52,6 @@ if test "x$ax_cv_ncursesw" != xyes && test "x$ax_cv_ncurses" != xyes; then
AC_MSG_ERROR([requires either NcursesW or Ncurses library]) AC_MSG_ERROR([requires either NcursesW or Ncurses library])
fi fi
PKG_CHECK_MODULES([LIBCURL], [libcurl],, [LIBCURL_CHECK_CONFIG])
PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"]) PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"])
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.15.4]) PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.15.4])
@@ -74,9 +73,9 @@ AC_CHECK_FUNCS(posix_memalign)
dnl Only update global build variables immediately before generating the output, dnl Only update global build variables immediately before generating the output,
dnl to avoid affecting the global build environment for other autoconf checks. dnl to avoid affecting the global build environment for other autoconf checks.
LIBS="$PTHREAD_LIBS $CURSES_LIB $CURSES_LIBS $LIBCURL $LIBCURL_LIBS $DEPENDENCIES_LIBS $LIBS" LIBS="$PTHREAD_LIBS $CURSES_LIB $CURSES_LIBS $DEPENDENCIES_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS $LIBCURL_CPPFLAGS $LIBCURL_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS" CFLAGS="$CFLAGS $PTHREAD_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS"
CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $LIBCURL_CPPFLAGS $LIBCURL_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS" CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS $DEPENDENCIES_CFLAGS $CURSES_CFLAGS"
TORRENT_CHECK_CACHELINE() TORRENT_CHECK_CACHELINE()
TORRENT_CHECK_POPCOUNT() TORRENT_CHECK_POPCOUNT()
-6
View File
@@ -5,12 +5,6 @@ rtorrent_LDADD = libsub_root.a @PTHREAD_LIBS@
rtorrent_SOURCES = main.cc rtorrent_SOURCES = main.cc
libsub_root_a_SOURCES = \ libsub_root_a_SOURCES = \
core/curl_get.cc \
core/curl_get.h \
core/curl_socket.cc \
core/curl_socket.h \
core/curl_stack.cc \
core/curl_stack.h \
core/dht_manager.cc \ core/dht_manager.cc \
core/dht_manager.h \ core/dht_manager.h \
core/download.cc \ core/download.cc \
+21 -21
View File
@@ -5,16 +5,16 @@
#include <unistd.h> #include <unistd.h>
#include <rak/address_info.h> #include <rak/address_info.h>
#include <rak/path.h> #include <rak/path.h>
#include <torrent/connection_manager.h>
#include <torrent/tracker/tracker.h>
#include <torrent/torrent.h> #include <torrent/torrent.h>
#include <torrent/rate.h> #include <torrent/rate.h>
#include <torrent/connection_manager.h>
#include <torrent/data/file_manager.h> #include <torrent/data/file_manager.h>
#include <torrent/download/resource_manager.h> #include <torrent/download/resource_manager.h>
#include <torrent/net/http_stack.h>
#include <torrent/tracker/tracker.h>
#include <torrent/utils/log.h> #include <torrent/utils/log.h>
#include <torrent/utils/option_strings.h> #include <torrent/utils/option_strings.h>
#include "core/curl_stack.h"
#include "core/download.h" #include "core/download.h"
#include "core/manager.h" #include "core/manager.h"
#include "rpc/scgi.h" #include "rpc/scgi.h"
@@ -189,9 +189,9 @@ apply_xmlrpc_dialect(const std::string& arg) {
void void
initialize_command_network() { initialize_command_network() {
torrent::ConnectionManager* cm = torrent::connection_manager(); auto cm = torrent::connection_manager();
torrent::FileManager* fileManager = torrent::file_manager(); auto fileManager = torrent::file_manager();
core::CurlStack* httpStack = control->core()->http_stack(); auto http_stack = torrent::net_thread::http_stack();
CMD2_ANY_STRING ("encoding.add", std::bind(&apply_encoding_list, std::placeholders::_2)); CMD2_ANY_STRING ("encoding.add", std::bind(&apply_encoding_list, std::placeholders::_2));
@@ -215,21 +215,21 @@ initialize_command_network() {
CMD2_VAR_STRING ("protocol.choke_heuristics.down.leech", "download_leech"); CMD2_VAR_STRING ("protocol.choke_heuristics.down.leech", "download_leech");
CMD2_VAR_STRING ("protocol.choke_heuristics.down.seed", "download_leech"); CMD2_VAR_STRING ("protocol.choke_heuristics.down.seed", "download_leech");
CMD2_ANY ("network.http.cacert", std::bind(&core::CurlStack::http_cacert, httpStack)); CMD2_ANY ("network.http.cacert", [http_stack](auto, auto) { return http_stack->http_cacert(); });
CMD2_ANY_STRING_V("network.http.cacert.set", std::bind(&core::CurlStack::set_http_cacert, httpStack, std::placeholders::_2)); CMD2_ANY_STRING_V("network.http.cacert.set", [http_stack](auto, auto& str) { return http_stack->set_http_cacert(str); });
CMD2_ANY ("network.http.capath", std::bind(&core::CurlStack::http_capath, httpStack)); CMD2_ANY ("network.http.capath", [http_stack](auto, auto) { return http_stack->http_capath(); });
CMD2_ANY_STRING_V("network.http.capath.set", std::bind(&core::CurlStack::set_http_capath, httpStack, std::placeholders::_2)); CMD2_ANY_STRING_V("network.http.capath.set", [http_stack](auto, auto& str) { return http_stack->set_http_capath(str); });
CMD2_ANY ("network.http.dns_cache_timeout", std::bind(&core::CurlStack::dns_timeout, httpStack)); CMD2_ANY ("network.http.dns_cache_timeout", [http_stack](auto, auto) { return http_stack->dns_timeout(); });
CMD2_ANY_VALUE_V ("network.http.dns_cache_timeout.set", std::bind(&core::CurlStack::set_dns_timeout, httpStack, std::placeholders::_2)); CMD2_ANY_VALUE_V ("network.http.dns_cache_timeout.set", [http_stack](auto, auto& value) { return http_stack->set_dns_timeout(value); });
CMD2_ANY ("network.http.current_open", std::bind(&core::CurlStack::active, httpStack)); CMD2_ANY ("network.http.current_open", [http_stack](auto, auto) { return http_stack->active(); });
CMD2_ANY ("network.http.max_open", std::bind(&core::CurlStack::max_active, httpStack)); CMD2_ANY ("network.http.max_open", [http_stack](auto, auto) { return http_stack->max_active(); });
CMD2_ANY_VALUE_V ("network.http.max_open.set", std::bind(&core::CurlStack::set_max_active, httpStack, std::placeholders::_2)); CMD2_ANY_VALUE_V ("network.http.max_open.set", [http_stack](auto, auto& value) { return http_stack->set_max_active(value); });
CMD2_ANY ("network.http.proxy_address", std::bind(&core::CurlStack::http_proxy, httpStack)); CMD2_ANY ("network.http.proxy_address", [http_stack](auto, auto) { return http_stack->http_proxy(); });
CMD2_ANY_STRING_V("network.http.proxy_address.set", std::bind(&core::CurlStack::set_http_proxy, httpStack, std::placeholders::_2)); CMD2_ANY_STRING_V("network.http.proxy_address.set", [http_stack](auto, auto& str) { return http_stack->set_http_proxy(str); });
CMD2_ANY ("network.http.ssl_verify_host", std::bind(&core::CurlStack::ssl_verify_host, httpStack)); CMD2_ANY ("network.http.ssl_verify_host", [http_stack](auto, auto) { return http_stack->ssl_verify_host(); });
CMD2_ANY_VALUE_V ("network.http.ssl_verify_host.set", std::bind(&core::CurlStack::set_ssl_verify_host, httpStack, std::placeholders::_2)); CMD2_ANY_VALUE_V ("network.http.ssl_verify_host.set", [http_stack](auto, auto& value) { return http_stack->set_ssl_verify_host(value); });
CMD2_ANY ("network.http.ssl_verify_peer", std::bind(&core::CurlStack::ssl_verify_peer, httpStack)); CMD2_ANY ("network.http.ssl_verify_peer", [http_stack](auto, auto) { return http_stack->ssl_verify_peer(); });
CMD2_ANY_VALUE_V ("network.http.ssl_verify_peer.set", std::bind(&core::CurlStack::set_ssl_verify_peer, httpStack, std::placeholders::_2)); CMD2_ANY_VALUE_V ("network.http.ssl_verify_peer.set", [http_stack](auto, auto& value) { return http_stack->set_ssl_verify_peer(value); });
CMD2_ANY ("network.send_buffer.size", std::bind(&torrent::ConnectionManager::send_buffer_size, cm)); CMD2_ANY ("network.send_buffer.size", std::bind(&torrent::ConnectionManager::send_buffer_size, cm));
CMD2_ANY_VALUE_V ("network.send_buffer.size.set", std::bind(&torrent::ConnectionManager::set_send_buffer_size, cm, std::placeholders::_2)); CMD2_ANY_VALUE_V ("network.send_buffer.size.set", std::bind(&torrent::ConnectionManager::set_send_buffer_size, cm, std::placeholders::_2));
+17 -25
View File
@@ -1,11 +1,13 @@
#include "config.h" #include "config.h"
#include "control.h"
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <torrent/connection_manager.h> #include <torrent/connection_manager.h>
#include <torrent/net/http_stack.h>
#include <torrent/utils/directory_events.h> #include <torrent/utils/directory_events.h>
#include "core/curl_stack.h"
#include "core/dht_manager.h" #include "core/dht_manager.h"
#include "core/download_store.h" #include "core/download_store.h"
#include "core/http_queue.h" #include "core/http_queue.h"
@@ -26,10 +28,8 @@
#include "rpc/object_storage.h" #include "rpc/object_storage.h"
#include "ui/root.h" #include "ui/root.h"
#include "control.h" Control::Control()
: m_ui(new ui::Root()),
Control::Control() :
m_ui(new ui::Root()),
m_display(new display::Manager()), m_display(new display::Manager()),
m_input(new input::Manager()), m_input(new input::Manager()),
m_inputStdin(new input::InputEvent(STDIN_FILENO)), m_inputStdin(new input::InputEvent(STDIN_FILENO)),
@@ -38,11 +38,11 @@ Control::Control() :
m_lua_engine(new rpc::LuaEngine()), m_lua_engine(new rpc::LuaEngine()),
m_directory_events(new torrent::directory_events()) { m_directory_events(new torrent::directory_events()) {
m_core = new core::Manager(); m_core = std::make_unique<core::Manager>();
m_viewManager = new core::ViewManager(); m_viewManager = std::make_unique<core::ViewManager>();
m_dhtManager = new core::DhtManager(); m_dhtManager = std::make_unique<core::DhtManager>();
m_inputStdin->slot_pressed(std::bind(&input::Manager::pressed, m_input, std::placeholders::_1)); m_inputStdin->slot_pressed(std::bind(&input::Manager::pressed, m_input.get(), std::placeholders::_1));
m_task_shutdown.slot() = std::bind(&Control::handle_shutdown, this); m_task_shutdown.slot() = std::bind(&Control::handle_shutdown, this);
@@ -50,20 +50,10 @@ Control::Control() :
} }
Control::~Control() { Control::~Control() {
delete m_inputStdin; m_viewManager.reset();
delete m_input;
delete m_viewManager; m_ui.reset();
m_display.reset();
delete m_ui;
delete m_display;
delete m_core;
delete m_dhtManager;
delete m_directory_events;
delete m_commandScheduler;
delete m_objectStorage;
delete m_lua_engine;
} }
void void
@@ -73,9 +63,8 @@ Control::initialize() {
display::Window::slot_unschedule([this](display::Window* w) { m_display->unschedule(w); }); display::Window::slot_unschedule([this](display::Window* w) { m_display->unschedule(w); });
display::Window::slot_adjust([this]() { m_display->adjust_layout(); }); display::Window::slot_adjust([this]() { m_display->adjust_layout(); });
m_core->http_stack()->set_user_agent(USER_AGENT); torrent::net_thread::http_stack()->set_user_agent(USER_AGENT);
m_core->initialize_second();
m_core->listen_open(); m_core->listen_open();
m_core->download_store()->enable(rpc::call_command_value("session.use_lock")); m_core->download_store()->enable(rpc::call_command_value("session.use_lock"));
@@ -122,7 +111,10 @@ Control::is_shutdown_completed() {
// Tracker requests can be disowned, so wait for these to // Tracker requests can be disowned, so wait for these to
// finish. The edge case of torrent http downloads may delay // finish. The edge case of torrent http downloads may delay
// shutdown. // shutdown.
if (!core()->http_stack()->empty() || !core()->http_queue()->empty())
// TODO: We keep http requests in the queue for a while after, so improve this check to ignore
// those.
if (torrent::net_thread::http_stack()->active() != 0 || !core()->http_queue()->empty())
return false; return false;
return torrent::is_inactive(); return torrent::is_inactive();
+23 -22
View File
@@ -3,6 +3,7 @@
#include <atomic> #include <atomic>
#include <cinttypes> #include <cinttypes>
#include <memory>
#include <sys/types.h> #include <sys/types.h>
#include <torrent/torrent.h> #include <torrent/torrent.h>
#include <torrent/utils/scheduler.h> #include <torrent/utils/scheduler.h>
@@ -55,20 +56,20 @@ public:
void receive_normal_shutdown() { m_shutdownReceived = true; } void receive_normal_shutdown() { m_shutdownReceived = true; }
void receive_quick_shutdown() { m_shutdownReceived = true; m_shutdownQuick = true; } void receive_quick_shutdown() { m_shutdownReceived = true; m_shutdownQuick = true; }
core::Manager* core() { return m_core; } core::Manager* core() { return m_core.get(); }
core::ViewManager* view_manager() { return m_viewManager; } core::ViewManager* view_manager() { return m_viewManager.get(); }
core::DhtManager* dht_manager() { return m_dhtManager; } core::DhtManager* dht_manager() { return m_dhtManager.get(); }
ui::Root* ui() { return m_ui; } ui::Root* ui() { return m_ui.get(); }
display::Manager* display() { return m_display; } display::Manager* display() { return m_display.get(); }
input::Manager* input() { return m_input; } input::Manager* input() { return m_input.get(); }
input::InputEvent* input_stdin() { return m_inputStdin; } input::InputEvent* input_stdin() { return m_inputStdin.get(); }
rpc::CommandScheduler* command_scheduler() { return m_commandScheduler; } rpc::CommandScheduler* command_scheduler() { return m_commandScheduler.get(); }
rpc::object_storage* object_storage() { return m_objectStorage; } rpc::object_storage* object_storage() { return m_objectStorage.get(); }
rpc::LuaEngine* lua_engine() { return m_lua_engine; } rpc::LuaEngine* lua_engine() { return m_lua_engine.get(); }
torrent::directory_events* directory_events() { return m_directory_events; } torrent::directory_events* directory_events() { return m_directory_events.get(); }
uint64_t tick() const { return m_tick; } uint64_t tick() const { return m_tick; }
void inc_tick() { m_tick++; } void inc_tick() { m_tick++; }
@@ -80,19 +81,19 @@ private:
Control(const Control&); Control(const Control&);
void operator = (const Control&); void operator = (const Control&);
core::Manager* m_core; std::unique_ptr<core::Manager> m_core;
core::ViewManager* m_viewManager; std::unique_ptr<core::ViewManager> m_viewManager;
core::DhtManager* m_dhtManager; std::unique_ptr<core::DhtManager> m_dhtManager;
ui::Root* m_ui; std::unique_ptr<ui::Root> m_ui;
display::Manager* m_display; std::unique_ptr<display::Manager> m_display;
input::Manager* m_input; std::unique_ptr<input::Manager> m_input;
input::InputEvent* m_inputStdin; std::unique_ptr<input::InputEvent> m_inputStdin;
rpc::CommandScheduler* m_commandScheduler; std::unique_ptr<rpc::CommandScheduler> m_commandScheduler;
rpc::object_storage* m_objectStorage; std::unique_ptr<rpc::object_storage> m_objectStorage;
rpc::LuaEngine* m_lua_engine; std::unique_ptr<rpc::LuaEngine> m_lua_engine;
torrent::directory_events* m_directory_events; std::unique_ptr<torrent::directory_events> m_directory_events;
uint64_t m_tick{}; uint64_t m_tick{};
-122
View File
@@ -1,122 +0,0 @@
#include "config.h"
#include "core/curl_get.h"
#include <iostream>
#include <curl/curl.h>
#include <curl/easy.h>
#include <torrent/exceptions.h>
#include "globals.h"
#include "core/curl_stack.h"
namespace core {
size_t
curl_get_receive_write(void* data, size_t size, size_t nmemb, void* handle) {
if (!((CurlGet*)handle)->stream()->write((const char*)data, size * nmemb).fail())
return size * nmemb;
else
return 0;
}
CurlGet::CurlGet(CurlStack* s) :
m_stack(s) {
m_task_timeout.slot() = [this]() { receive_timeout(); };
}
CurlGet::~CurlGet() {
close();
}
void
CurlGet::start() {
if (is_busy())
throw torrent::internal_error("Tried to call CurlGet::start on a busy object.");
if (m_stream == NULL)
throw torrent::internal_error("Tried to call CurlGet::start without a valid output stream.");
if (!m_stack->is_running())
return;
m_handle = curl_easy_init();
if (m_handle == NULL)
throw torrent::internal_error("Call to curl_easy_init() failed.");
curl_easy_setopt(m_handle, CURLOPT_URL, m_url.c_str());
curl_easy_setopt(m_handle, CURLOPT_WRITEFUNCTION, &curl_get_receive_write);
curl_easy_setopt(m_handle, CURLOPT_WRITEDATA, this);
if (m_timeout != 0) {
curl_easy_setopt(m_handle, CURLOPT_CONNECTTIMEOUT, (long)60);
curl_easy_setopt(m_handle, CURLOPT_TIMEOUT, (long)m_timeout);
// Normally libcurl should handle the timeout. But sometimes that doesn't
// work right so we do a fallback timeout that just aborts the transfer.
torrent::this_thread::scheduler()->update_wait_for_ceil_seconds(&m_task_timeout, 5s + 1s*m_timeout);
}
curl_easy_setopt(m_handle, CURLOPT_FORBID_REUSE, (long)1);
curl_easy_setopt(m_handle, CURLOPT_NOSIGNAL, (long)1);
curl_easy_setopt(m_handle, CURLOPT_FOLLOWLOCATION, (long)1);
curl_easy_setopt(m_handle, CURLOPT_MAXREDIRS, (long)5);
curl_easy_setopt(m_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER);
curl_easy_setopt(m_handle, CURLOPT_ENCODING, "");
m_ipv6 = false;
m_stack->add_get(this);
}
void
CurlGet::close() {
torrent::this_thread::scheduler()->erase(&m_task_timeout);
if (!is_busy())
return;
m_stack->remove_get(this);
curl_easy_cleanup(m_handle);
m_handle = NULL;
}
void
CurlGet::retry_ipv6() {
CURL* nhandle = curl_easy_duphandle(m_handle);
curl_easy_setopt(nhandle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6);
curl_easy_cleanup(m_handle);
m_handle = nhandle;
m_ipv6 = true;
}
void
CurlGet::receive_timeout() {
return m_stack->transfer_done(m_handle, "Timed out");
}
curl_off_t
CurlGet::size_done() {
curl_off_t d = 0;
curl_easy_getinfo(m_handle, CURLINFO_SIZE_DOWNLOAD_T, &d);
return d;
}
curl_off_t
CurlGet::size_total() {
curl_off_t d = 0;
curl_easy_getinfo(m_handle, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &d);
return d;
}
}
-54
View File
@@ -1,54 +0,0 @@
#ifndef RTORRENT_CORE_CURL_GET_H
#define RTORRENT_CORE_CURL_GET_H
#include <iosfwd>
#include <string>
#include <curl/curl.h>
#include <torrent/http.h>
#include <torrent/utils/scheduler.h>
namespace core {
class CurlStack;
class CurlGet : public torrent::Http {
public:
CurlGet(CurlStack* s);
virtual ~CurlGet();
void start();
void close();
bool is_using_ipv6() { return m_ipv6; }
void retry_ipv6();
bool is_busy() const { return m_handle; }
bool is_active() const { return m_active; }
void set_active(bool a) { m_active = a; }
curl_off_t size_done();
curl_off_t size_total();
CURL* handle() { return m_handle; }
private:
friend class CurlStack;
CurlGet(const CurlGet&) = delete;
void operator = (const CurlGet&) = delete;
void receive_timeout();
bool m_active{};
bool m_ipv6;
torrent::utils::SchedulerEntry m_task_timeout;
CURL* m_handle{};
CurlStack* m_stack;
};
}
#endif
-99
View File
@@ -1,99 +0,0 @@
#include "config.h"
#include "curl_socket.h"
#include <cassert>
#include <curl/multi.h>
#include <torrent/poll.h>
#include <torrent/exceptions.h>
#include <torrent/utils/thread.h>
#include "control.h"
#include "core/curl_stack.h"
namespace core {
int
CurlSocket::receive_socket([[maybe_unused]] void* easy_handle, curl_socket_t fd, int what, void* userp, void* socketp) {
CurlStack* stack = (CurlStack*)userp;
CurlSocket* socket = (CurlSocket*)socketp;
if (!stack->is_running())
return 0;
if (what == CURL_POLL_REMOVE) {
// We also probably need the special code here as we're not
// guaranteed that the fd will be closed, afaik.
if (socket != NULL)
socket->close();
// TODO: Consider the possibility that we'll need to set the
// fd-associated pointer curl holds to NULL.
delete socket;
return 0;
}
if (socket == NULL) {
socket = stack->new_socket(fd);
torrent::this_thread::poll()->open(socket);
// No interface for libcurl to signal when it's interested in error events.
// Assume that hence it must always be interested in them.
torrent::this_thread::poll()->insert_error(socket);
}
if (what == CURL_POLL_NONE || what == CURL_POLL_OUT)
torrent::this_thread::poll()->remove_read(socket);
else
torrent::this_thread::poll()->insert_read(socket);
if (what == CURL_POLL_NONE || what == CURL_POLL_IN)
torrent::this_thread::poll()->remove_write(socket);
else
torrent::this_thread::poll()->insert_write(socket);
return 0;
}
CurlSocket::~CurlSocket() {
assert(m_fileDesc == -1 && "CurlSocket::~CurlSocket() m_fileDesc != -1.");
}
void
CurlSocket::close() {
if (m_fileDesc == -1)
throw torrent::internal_error("CurlSocket::close() m_fileDesc == -1.");
torrent::this_thread::poll()->closed(this);
m_fileDesc = -1;
}
void
CurlSocket::event_read() {
#if (LIBCURL_VERSION_NUM >= 0x071003)
return m_stack->receive_action(this, CURL_CSELECT_IN);
#else
return m_stack->receive_action(this, 0);
#endif
}
void
CurlSocket::event_write() {
#if (LIBCURL_VERSION_NUM >= 0x071003)
return m_stack->receive_action(this, CURL_CSELECT_OUT);
#else
return m_stack->receive_action(this, 0);
#endif
}
void
CurlSocket::event_error() {
#if (LIBCURL_VERSION_NUM >= 0x071003)
return m_stack->receive_action(this, CURL_CSELECT_ERR);
#else
return m_stack->receive_action(this, 0);
#endif
}
}
-37
View File
@@ -1,37 +0,0 @@
#ifndef RTORRENT_CORE_CURL_SOCKET_H
#define RTORRENT_CORE_CURL_SOCKET_H
#include <curl/curl.h>
#include <torrent/event.h>
#include "globals.h"
namespace core {
class CurlStack;
class CurlSocket : public torrent::Event {
public:
CurlSocket(int fd, CurlStack* stack) : m_stack(stack) { m_fileDesc = fd; }
~CurlSocket();
const char* type_name() const { return "curl"; }
void close();
static int receive_socket(void* easy_handle, curl_socket_t fd, int what, void* userp, void* socketp);
private:
CurlSocket(const CurlSocket&);
void operator = (const CurlSocket&);
virtual void event_read();
virtual void event_write();
virtual void event_error();
CurlStack* m_stack;
};
}
#endif
-243
View File
@@ -1,243 +0,0 @@
#include "config.h"
#include <algorithm>
#include <curl/multi.h>
#include <torrent/exceptions.h>
#include "curl_get.h"
#include "curl_socket.h"
#include "curl_stack.h"
namespace core {
CurlStack::CurlStack() {
m_handle = (void*)curl_multi_init();
m_task_timeout.slot() = std::bind(&CurlStack::receive_timeout, this);
#if (LIBCURL_VERSION_NUM >= 0x071000)
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_TIMERDATA, this);
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_TIMERFUNCTION, &CurlStack::set_timeout);
#endif
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_SOCKETDATA, this);
curl_multi_setopt((CURLM*)m_handle, CURLMOPT_SOCKETFUNCTION, &CurlSocket::receive_socket);
}
CurlStack::~CurlStack() {
shutdown();
}
void
CurlStack::shutdown() {
if (!m_running)
return;
m_running = false;
while (!empty())
front()->close();
curl_multi_cleanup((CURLM*)m_handle);
torrent::this_thread::scheduler()->erase(&m_task_timeout);
}
CurlGet*
CurlStack::new_object() {
return new CurlGet(this);
}
CurlSocket*
CurlStack::new_socket(int fd) {
if (!m_running)
throw torrent::internal_error("CurlStack::new_socket() called when not running.");
CurlSocket* socket = new CurlSocket(fd, this);
curl_multi_assign((CURLM*)m_handle, fd, socket);
return socket;
}
void
CurlStack::receive_action(CurlSocket* socket, int events) {
CURLMcode code;
do {
int count;
#if (LIBCURL_VERSION_NUM >= 0x071003)
code = curl_multi_socket_action((CURLM*)m_handle,
socket != NULL ? socket->file_descriptor() : CURL_SOCKET_TIMEOUT,
events,
&count);
#else
code = curl_multi_socket((CURLM*)m_handle,
socket != NULL ? socket->file_descriptor() : CURL_SOCKET_TIMEOUT,
&count);
#endif
if (code > 0)
throw torrent::internal_error("Error calling curl_multi_socket_action.");
// Socket might be removed when cleaning handles below, future
// calls should not use it.
socket = NULL;
events = 0;
if ((unsigned int)count != size()) {
while (process_done_handle())
; // Do nothing.
if (empty())
torrent::this_thread::scheduler()->erase(&m_task_timeout);
}
} while (code == CURLM_CALL_MULTI_PERFORM);
}
bool
CurlStack::process_done_handle() {
int remaining_msgs = 0;
CURLMsg* msg = curl_multi_info_read((CURLM*)m_handle, &remaining_msgs);
if (msg == NULL)
return false;
if (msg->msg != CURLMSG_DONE)
throw torrent::internal_error("CurlStack::receive_action() msg->msg != CURLMSG_DONE.");
if (msg->data.result == CURLE_COULDNT_RESOLVE_HOST) {
iterator itr = std::find_if(begin(), end(), [&msg](CurlGet* get) { return get->handle() == msg->easy_handle; });
if (itr == end())
throw torrent::internal_error("Could not find CurlGet when calling CurlStack::receive_action.");
if (!(*itr)->is_using_ipv6()) {
(*itr)->retry_ipv6();
if (curl_multi_add_handle((CURLM*)m_handle, (*itr)->handle()) > 0)
throw torrent::internal_error("Error calling curl_multi_add_handle.");
}
} else {
transfer_done(msg->easy_handle,
msg->data.result == CURLE_OK ? NULL : curl_easy_strerror(msg->data.result));
}
return remaining_msgs != 0;
}
void
CurlStack::transfer_done(void* handle, const char* msg) {
iterator itr = std::find_if(begin(), end(), [&handle](CurlGet* get) { return get->handle() == handle; });
if (itr == end())
throw torrent::internal_error("Could not find CurlGet with the right easy_handle.");
if (msg == NULL)
(*itr)->trigger_done();
else
(*itr)->trigger_failed(msg);
}
void
CurlStack::receive_timeout() {
receive_action(NULL, 0);
if (!empty() && !m_task_timeout.is_scheduled()) {
// Sometimes libcurl forgets to reset the timeout. Try to poll the value in that case, or use 10
// seconds max.
long timeout_ms;
curl_multi_timeout((CURLM*)m_handle, &timeout_ms);
auto timeout = std::max<std::chrono::microseconds>(std::chrono::milliseconds(timeout_ms), 10s);
torrent::this_thread::scheduler()->wait_for_ceil_seconds(&m_task_timeout, timeout);
}
}
void
CurlStack::add_get(CurlGet* get) {
if (!m_user_agent.empty())
curl_easy_setopt(get->handle(), CURLOPT_USERAGENT, m_user_agent.c_str());
if (!m_http_proxy.empty())
curl_easy_setopt(get->handle(), CURLOPT_PROXY, m_http_proxy.c_str());
if (!m_bind_address.empty())
curl_easy_setopt(get->handle(), CURLOPT_INTERFACE, m_bind_address.c_str());
if (!m_http_ca_path.empty())
curl_easy_setopt(get->handle(), CURLOPT_CAPATH, m_http_ca_path.c_str());
if (!m_http_ca_cert.empty())
curl_easy_setopt(get->handle(), CURLOPT_CAINFO, m_http_ca_cert.c_str());
curl_easy_setopt(get->handle(), CURLOPT_SSL_VERIFYHOST, (long)(m_ssl_verify_host ? 2 : 0));
curl_easy_setopt(get->handle(), CURLOPT_SSL_VERIFYPEER, (long)(m_ssl_verify_peer ? 1 : 0));
curl_easy_setopt(get->handle(), CURLOPT_DNS_CACHE_TIMEOUT, m_dns_timeout);
base_type::push_back(get);
if (m_active >= m_max_active)
return;
m_active++;
get->set_active(true);
if (curl_multi_add_handle((CURLM*)m_handle, get->handle()) > 0)
throw torrent::internal_error("Error calling curl_multi_add_handle.");
#if (LIBCURL_VERSION_NUM < 0x071000)
receive_timeout();
#endif
}
void
CurlStack::remove_get(CurlGet* get) {
iterator itr = std::find(begin(), end(), get);
if (itr == end())
throw torrent::internal_error("Could not find CurlGet when calling CurlStack::remove.");
base_type::erase(itr);
// The CurlGet object was never activated, so we just skip this one.
if (!get->is_active())
return;
get->set_active(false);
if (curl_multi_remove_handle((CURLM*)m_handle, get->handle()) > 0)
throw torrent::internal_error("Error calling curl_multi_remove_handle.");
if (m_active == m_max_active &&
(itr = std::find_if(begin(), end(), [](CurlGet* get) { return !get->is_active(); })) != end()) {
(*itr)->set_active(true);
if (curl_multi_add_handle((CURLM*)m_handle, (*itr)->handle()) > 0)
throw torrent::internal_error("Error calling curl_multi_add_handle.");
} else {
m_active--;
}
}
void
CurlStack::global_init() {
curl_global_init(CURL_GLOBAL_ALL);
}
void
CurlStack::global_cleanup() {
curl_global_cleanup();
}
// TODO: Is this function supposed to set a per-handle timeout, or is
// it the shortest timeout amongst all handles?
int
CurlStack::set_timeout([[maybe_unused]] void* handle, std::chrono::microseconds timeout, void* userp) {
CurlStack* stack = (CurlStack*)userp;
torrent::this_thread::scheduler()->update_wait_for_ceil_seconds(&stack->m_task_timeout, timeout);
return 0;
}
}
-120
View File
@@ -1,120 +0,0 @@
#ifndef RTORRENT_CORE_CURL_STACK_H
#define RTORRENT_CORE_CURL_STACK_H
#include <deque>
#include <string>
#include <torrent/utils/scheduler.h>
namespace core {
class CurlGet;
class CurlSocket;
// By using a deque instead of vector we allow for cheaper removal of
// the oldest elements, those that will be first in the in the
// deque.
//
// This should fit well with the use-case of a http stack, thus
// we get most of the cache locality benefits of a vector with fast
// removal of elements.
class CurlStack : std::deque<CurlGet*> {
public:
friend class CurlGet;
typedef std::deque<CurlGet*> base_type;
using base_type::value_type;
using base_type::iterator;
using base_type::const_iterator;
using base_type::reverse_iterator;
using base_type::const_reverse_iterator;
using base_type::begin;
using base_type::end;
using base_type::rbegin;
using base_type::rend;
using base_type::back;
using base_type::front;
using base_type::size;
using base_type::empty;
CurlStack();
~CurlStack();
void shutdown();
bool is_running() const { return m_running; }
CurlGet* new_object();
CurlSocket* new_socket(int fd);
unsigned int active() const { return m_active; }
unsigned int max_active() const { return m_max_active; }
void set_max_active(unsigned int a) { m_max_active = a; }
const std::string& user_agent() const { return m_user_agent; }
const std::string& http_proxy() const { return m_http_proxy; }
const std::string& bind_address() const { return m_bind_address; }
const std::string& http_capath() const { return m_http_ca_path; }
const std::string& http_cacert() const { return m_http_ca_cert; }
void set_user_agent(const std::string& s) { m_user_agent = s; }
void set_http_proxy(const std::string& s) { m_http_proxy = s; }
void set_bind_address(const std::string& s) { m_bind_address = s; }
void set_http_capath(const std::string& s) { m_http_ca_path = s; }
void set_http_cacert(const std::string& s) { m_http_ca_cert = s; }
bool ssl_verify_host() const { return m_ssl_verify_host; }
bool ssl_verify_peer() const { return m_ssl_verify_peer; }
void set_ssl_verify_host(bool s) { m_ssl_verify_host = s; }
void set_ssl_verify_peer(bool s) { m_ssl_verify_peer = s; }
long dns_timeout() const { return m_dns_timeout; }
void set_dns_timeout(long timeout) { m_dns_timeout = timeout; }
static void global_init();
static void global_cleanup();
void receive_action(CurlSocket* socket, int type);
static int set_timeout(void* handle, std::chrono::microseconds timeout, void* userp);
void transfer_done(void* handle, const char* msg);
protected:
void add_get(CurlGet* get);
void remove_get(CurlGet* get);
private:
CurlStack(const CurlStack&) = delete;
void operator = (const CurlStack&) = delete;
void receive_timeout();
bool process_done_handle();
void* m_handle;
bool m_running{true};
unsigned int m_active{0};
unsigned int m_max_active{32};
torrent::utils::SchedulerEntry m_task_timeout;
std::string m_user_agent;
std::string m_http_proxy;
std::string m_bind_address;
std::string m_http_ca_path;
std::string m_http_ca_cert;
bool m_ssl_verify_host{true};
bool m_ssl_verify_peer{true};
long m_dns_timeout{60};
};
}
#endif
+11 -12
View File
@@ -1,11 +1,12 @@
#include "config.h" #include "config.h"
#include "download_factory.h"
#include <cstdlib> #include <cstdlib>
#include <fstream> #include <fstream>
#include <functional> #include <functional>
#include <sstream> #include <sstream>
#include <stdexcept> #include <stdexcept>
#include <rak/path.h> #include <rak/path.h>
#include <torrent/utils/log.h> #include <torrent/utils/log.h>
#include <torrent/utils/resume.h> #include <torrent/utils/resume.h>
@@ -14,18 +15,15 @@
#include <torrent/exceptions.h> #include <torrent/exceptions.h>
#include <torrent/rate.h> #include <torrent/rate.h>
#include <torrent/data/file_utils.h> #include <torrent/data/file_utils.h>
#include <torrent/net/http_stack.h>
#include "rpc/parse_commands.h"
#include "curl_get.h"
#include "control.h" #include "control.h"
#include "http_queue.h"
#include "globals.h" #include "globals.h"
#include "manager.h" #include "core/download.h"
#include "core/download_store.h"
#include "download.h" #include "core/http_queue.h"
#include "download_factory.h" #include "core/manager.h"
#include "download_store.h" #include "rpc/parse_commands.h"
namespace core { namespace core {
@@ -111,10 +109,11 @@ DownloadFactory::receive_load() {
if (is_network_uri(m_uri)) { if (is_network_uri(m_uri)) {
// Http handling here. // Http handling here.
m_stream = new std::stringstream; m_stream = new std::stringstream;
HttpQueue::iterator itr = m_manager->http_queue()->insert(m_uri, m_stream); HttpQueue::iterator itr = m_manager->http_queue()->insert(m_uri, m_stream);
(*itr)->signal_done().push_front(std::bind(&DownloadFactory::receive_loaded, this)); itr->add_done_slot([this]() { receive_loaded(); });
(*itr)->signal_failed().push_front(std::bind(&DownloadFactory::receive_failed, this, std::placeholders::_1)); itr->add_failed_slot([this](const std::string& error) { receive_failed(error); });
m_variables["tied_to_file"] = (int64_t)false; m_variables["tied_to_file"] = (int64_t)false;
+12 -25
View File
@@ -1,43 +1,32 @@
#include "config.h" #include "config.h"
#include <memory>
#include <sstream>
#include <torrent/http.h>
#include "http_queue.h" #include "http_queue.h"
#include "curl_get.h"
#include <torrent/net/http_get.h>
#include <torrent/net/http_stack.h>
namespace core { namespace core {
HttpQueue::iterator HttpQueue::iterator
HttpQueue::insert(const std::string& url, std::iostream* s) { HttpQueue::insert(const std::string& url, std::iostream* s) {
std::unique_ptr<CurlGet> h(m_slot_factory()); auto itr = base_type::insert(end(), torrent::net_thread::http_stack()->create(url, s));
h->set_url(url); itr->add_done_slot([this, itr]() { erase(itr); });
h->set_stream(s); itr->add_failed_slot([this, itr](auto) { erase(itr); });
h->set_timeout(5 * 60);
iterator signal_itr = base_type::insert(end(), h.get()); itr->start();
h->signal_done().push_back(std::bind(&HttpQueue::erase, this, signal_itr)); for (auto& slot : m_signal_insert)
h->signal_failed().push_back(std::bind(&HttpQueue::erase, this, signal_itr)); slot(*itr);
(*signal_itr)->start(); return itr;
h.release();
for (signal_curl_get::iterator itr = m_signal_insert.begin(), last = m_signal_insert.end(); itr != last; itr++)
(*itr)(*signal_itr);
return signal_itr;
} }
void void
HttpQueue::erase(iterator signal_itr) { HttpQueue::erase(iterator signal_itr) {
for (signal_curl_get::iterator itr = m_signal_erase.begin(), last = m_signal_erase.end(); itr != last; itr++) for (const auto& slot : m_signal_erase)
(*itr)(*signal_itr); slot(*signal_itr);
delete *signal_itr;
base_type::erase(signal_itr); base_type::erase(signal_itr);
} }
@@ -45,8 +34,6 @@ void
HttpQueue::clear() { HttpQueue::clear() {
while (!empty()) while (!empty())
erase(begin()); erase(begin());
base_type::clear();
} }
} }
+7 -9
View File
@@ -4,17 +4,18 @@
#include <functional> #include <functional>
#include <iosfwd> #include <iosfwd>
#include <list> #include <list>
#include <string>
#include <torrent/net/http_get.h>
namespace core { namespace core {
class CurlGet; // TODO: Remove this.
class HttpQueue : private std::list<CurlGet*> { class HttpQueue : private std::list<torrent::net::HttpGet> {
public: public:
typedef std::list<CurlGet*> base_type; using base_type = std::list<torrent::net::HttpGet>;
typedef std::function<CurlGet* ()> slot_factory; using slot_curl_get = std::function<void (torrent::net::HttpGet)>;
typedef std::function<void (CurlGet*)> slot_curl_get; using signal_curl_get = std::list<slot_curl_get>;
typedef std::list<slot_curl_get> signal_curl_get;
using base_type::iterator; using base_type::iterator;
using base_type::const_iterator; using base_type::const_iterator;
@@ -42,13 +43,10 @@ public:
void clear(); void clear();
void set_slot_factory(slot_factory s) { m_slot_factory = s; }
signal_curl_get& signal_insert() { return m_signal_insert; } signal_curl_get& signal_insert() { return m_signal_insert; }
signal_curl_get& signal_erase() { return m_signal_erase; } signal_curl_get& signal_erase() { return m_signal_erase; }
private: private:
slot_factory m_slot_factory;
signal_curl_get m_signal_insert; signal_curl_get m_signal_insert;
signal_curl_get m_signal_erase; signal_curl_get m_signal_erase;
}; };
+11 -27
View File
@@ -18,6 +18,7 @@
#include <torrent/exceptions.h> #include <torrent/exceptions.h>
#include <torrent/object_stream.h> #include <torrent/object_stream.h>
#include <torrent/throttle.h> #include <torrent/throttle.h>
#include <torrent/net/http_stack.h>
#include <torrent/utils/log.h> #include <torrent/utils/log.h>
#include "rpc/parse_commands.h" #include "rpc/parse_commands.h"
@@ -26,15 +27,13 @@
#include "utils/file_status_cache.h" #include "utils/file_status_cache.h"
#include "globals.h" #include "globals.h"
#include "curl_get.h"
#include "curl_stack.h"
#include "control.h" #include "control.h"
#include "download.h" #include "core/download.h"
#include "download_factory.h" #include "core/download_factory.h"
#include "download_store.h" #include "core/download_store.h"
#include "http_queue.h" #include "core/http_queue.h"
#include "manager.h" #include "core/manager.h"
#include "view.h" #include "core/view.h"
namespace core { namespace core {
@@ -57,7 +56,6 @@ Manager::Manager() :
m_download_list = std::make_unique<DownloadList>(); m_download_list = std::make_unique<DownloadList>();
m_file_status_cache = std::make_unique<FileStatusCache>(); m_file_status_cache = std::make_unique<FileStatusCache>();
m_http_queue = std::make_unique<HttpQueue>(); m_http_queue = std::make_unique<HttpQueue>();
m_http_stack = std::make_unique<CurlStack>();
torrent::Throttle* unthrottled = torrent::Throttle::create_throttle(); torrent::Throttle* unthrottled = torrent::Throttle::create_throttle();
unthrottled->set_max_rate(0); unthrottled->set_max_rate(0);
@@ -131,31 +129,14 @@ Manager::retrieve_throttle_value(const torrent::Object::string_type& name, bool
} }
} }
// Most of this should be possible to move out.
void
Manager::initialize_second() {
torrent::Http::slot_factory() = std::bind(&CurlStack::new_object, m_http_stack.get());
m_http_queue->set_slot_factory(std::bind(&CurlStack::new_object, m_http_stack.get()));
CurlStack::global_init();
}
void void
Manager::cleanup() { Manager::cleanup() {
m_http_stack->shutdown();
// Need to disconnect log signals? Not really since we won't receive // Need to disconnect log signals? Not really since we won't receive
// any more. // any more.
m_download_list->clear(); m_download_list->clear();
// When we implement asynchronous DNS lookups, we need to cancel them
// here before the torrent::* objects are deleted.
torrent::cleanup(); torrent::cleanup();
m_http_stack.reset();
CurlStack::global_cleanup();
} }
void void
@@ -229,7 +210,10 @@ Manager::set_bind_address(const std::string& addr) {
torrent::connection_manager()->set_bind_address(ai->address()->c_sockaddr()); torrent::connection_manager()->set_bind_address(ai->address()->c_sockaddr());
} }
m_http_stack->set_bind_address(!ai->address()->is_address_any() ? ai->address()->address_str() : std::string()); if (ai->address()->is_address_any())
torrent::net_thread::http_stack()->set_bind_address(std::string());
else
torrent::net_thread::http_stack()->set_bind_address(ai->address()->address_str());
rak::address_info::free_address_info(ai); rak::address_info::free_address_info(ai);
-5
View File
@@ -21,7 +21,6 @@ class FileStatusCache;
namespace core { namespace core {
class CurlStack;
class DownloadStore; class DownloadStore;
class HttpQueue; class HttpQueue;
@@ -42,7 +41,6 @@ public:
FileStatusCache* file_status_cache() { return m_file_status_cache.get(); } FileStatusCache* file_status_cache() { return m_file_status_cache.get(); }
HttpQueue* http_queue() { return m_http_queue.get(); } HttpQueue* http_queue() { return m_http_queue.get(); }
CurlStack* http_stack() { return m_http_stack.get(); }
View* hashing_view() { return m_hashingView; } View* hashing_view() { return m_hashingView; }
void set_hashing_view(View* v); void set_hashing_view(View* v);
@@ -59,8 +57,6 @@ public:
void set_address_throttle(uint32_t begin, uint32_t end, torrent::ThrottlePair throttles); void set_address_throttle(uint32_t begin, uint32_t end, torrent::ThrottlePair throttles);
torrent::ThrottlePair get_address_throttle(const sockaddr* addr); torrent::ThrottlePair get_address_throttle(const sockaddr* addr);
// Really should find a more descriptive name.
void initialize_second();
void cleanup(); void cleanup();
void listen_open(); void listen_open();
@@ -109,7 +105,6 @@ private:
std::unique_ptr<DownloadStore> m_download_store; std::unique_ptr<DownloadStore> m_download_store;
std::unique_ptr<FileStatusCache> m_file_status_cache; std::unique_ptr<FileStatusCache> m_file_status_cache;
std::unique_ptr<HttpQueue> m_http_queue; std::unique_ptr<HttpQueue> m_http_queue;
std::unique_ptr<CurlStack> m_http_stack;
View* m_hashingView{}; View* m_hashingView{};
+10 -10
View File
@@ -1,5 +1,7 @@
#include "config.h" #include "config.h"
#include "display/utils.h"
#include <cstring> #include <cstring>
#include <cstdio> #include <cstdio>
#include <sstream> #include <sstream>
@@ -14,18 +16,16 @@
#include <torrent/data/file_list.h> #include <torrent/data/file_list.h>
#include <torrent/data/file_manager.h> #include <torrent/data/file_manager.h>
#include <torrent/download/resource_manager.h> #include <torrent/download/resource_manager.h>
#include <torrent/net/http_stack.h>
#include <torrent/peer/client_info.h> #include <torrent/peer/client_info.h>
#include "core/curl_stack.h" #include "control.h"
#include "globals.h"
#include "core/download.h" #include "core/download.h"
#include "core/manager.h" #include "core/manager.h"
#include "rpc/parse_commands.h" #include "rpc/parse_commands.h"
#include "ui/root.h" #include "ui/root.h"
#include "control.h"
#include "globals.h"
#include "utils.h"
namespace display { namespace display {
char* char*
@@ -111,7 +111,7 @@ print_download_info_full(char* first, char* last, core::Download* d) {
first = print_buffer(first, last, "%6.1f / %6.1f MB", first = print_buffer(first, last, "%6.1f / %6.1f MB",
(double)d->download()->bytes_done() / (double)(1 << 20), (double)d->download()->bytes_done() / (double)(1 << 20),
(double)d->download()->file_list()->size_bytes() / (double)(1 << 20)); (double)d->download()->file_list()->size_bytes() / (double)(1 << 20));
first = print_buffer(first, last, " Rate: %5.1f / %5.1f KB Uploaded: %7.1f MB", first = print_buffer(first, last, " Rate: %5.1f / %5.1f KB Uploaded: %7.1f MB",
(double)d->info()->up_rate()->rate() / (1 << 10), (double)d->info()->up_rate()->rate() / (1 << 10),
(double)d->info()->down_rate()->rate() / (1 << 10), (double)d->info()->down_rate()->rate() / (1 << 10),
@@ -391,7 +391,7 @@ print_status_info(char* first, char* last) {
first = print_address(first, last, torrent::connection_manager()->local_address()); first = print_address(first, last, torrent::connection_manager()->local_address());
first = print_buffer(first, last, "]"); first = print_buffer(first, last, "]");
} }
if (first > last) if (first > last)
throw torrent::internal_error("print_status_info(...) wrote past end of the buffer."); throw torrent::internal_error("print_status_info(...) wrote past end of the buffer.");
@@ -415,14 +415,14 @@ print_status_extra(char* first, char* last) {
torrent::resource_manager()->max_download_unchoked()); torrent::resource_manager()->max_download_unchoked());
first = print_buffer(first, last, " [H %u/%u]", first = print_buffer(first, last, " [H %u/%u]",
control->core()->http_stack()->active(), torrent::net_thread::http_stack()->active(),
control->core()->http_stack()->max_active()); torrent::net_thread::http_stack()->max_active());
first = print_buffer(first, last, " [S %i/%i/%i]", first = print_buffer(first, last, " [S %i/%i/%i]",
torrent::total_handshakes(), torrent::total_handshakes(),
torrent::connection_manager()->size(), torrent::connection_manager()->size(),
torrent::connection_manager()->max_size()); torrent::connection_manager()->max_size());
first = print_buffer(first, last, " [F %i/%i]", first = print_buffer(first, last, " [F %i/%i]",
torrent::file_manager()->open_files(), torrent::file_manager()->open_files(),
torrent::file_manager()->max_open_files()); torrent::file_manager()->max_open_files());
+1 -36
View File
@@ -1,45 +1,10 @@
// 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
#ifndef RTORRENT_DISPLAY_UTILS_H #ifndef RTORRENT_DISPLAY_UTILS_H
#define RTORRENT_DISPLAY_UTILS_H #define RTORRENT_DISPLAY_UTILS_H
#include <ctime> #include <ctime>
#include <cstdio> #include <cstdio>
#include <string> #include <string>
#include <vector>
namespace core { namespace core {
class Download; class Download;
+17 -14
View File
@@ -3,8 +3,8 @@
#include "display/window_http_queue.h" #include "display/window_http_queue.h"
#include <stdexcept> #include <stdexcept>
#include <torrent/net/http_get.h>
#include "core/curl_get.h"
#include "core/http_queue.h" #include "core/http_queue.h"
#include "display/canvas.h" #include "display/canvas.h"
@@ -17,8 +17,9 @@ WindowHttpQueue::WindowHttpQueue(core::HttpQueue* q) :
m_queue(q) { m_queue(q) {
set_active(false); set_active(false);
m_conn_insert = m_queue->signal_insert().insert(m_queue->signal_insert().end(), [this](auto* h) { receive_insert(h); });
m_conn_erase = m_queue->signal_erase().insert(m_queue->signal_insert().end(), [this](auto* h) { receive_erase(h); }); m_conn_insert = m_queue->signal_insert().insert(m_queue->signal_insert().end(), [this](auto h) { receive_insert(h); });
m_conn_erase = m_queue->signal_erase().insert(m_queue->signal_insert().end(), [this](auto h) { receive_erase(h); });
m_task_deactivate.slot() = [this] { m_task_deactivate.slot() = [this] {
if (!m_container.empty()) if (!m_container.empty())
@@ -55,14 +56,14 @@ WindowHttpQueue::redraw() {
Container::iterator itr = m_container.begin(); Container::iterator itr = m_container.begin();
while (itr != m_container.end() && pos + 10 < m_canvas->width()) { while (itr != m_container.end() && pos + 10 < m_canvas->width()) {
if (itr->m_http == NULL) if (!itr->m_http.is_valid())
m_canvas->print(pos, 0, "[%s done]", itr->m_name.c_str()); m_canvas->print(pos, 0, "[%s done]", itr->m_name.c_str());
else if (itr->m_http->size_total() == 0) else if (itr->m_http.size_total() == 0)
m_canvas->print(pos, 0, "[%s ---%%]", itr->m_name.c_str()); m_canvas->print(pos, 0, "[%s ---%%]", itr->m_name.c_str());
else else
m_canvas->print(pos, 0, "[%s %3i%%]", itr->m_name.c_str(), (int)(100.0 * itr->m_http->size_done() / itr->m_http->size_total())); m_canvas->print(pos, 0, "[%s %3i%%]", itr->m_name.c_str(), (int)(100.0 * itr->m_http.size_done() / itr->m_http.size_total()));
pos += itr->m_name.size() + 6; pos += itr->m_name.size() + 6;
++itr; ++itr;
@@ -72,7 +73,7 @@ WindowHttpQueue::redraw() {
void void
WindowHttpQueue::cleanup_list() { WindowHttpQueue::cleanup_list() {
for (Container::iterator itr = m_container.begin(); itr != m_container.end(); ) { for (Container::iterator itr = m_container.begin(); itr != m_container.end(); ) {
if (itr->m_http == nullptr && itr->m_timer < torrent::this_thread::cached_time()) { if (!itr->m_http.is_valid() && itr->m_timer < torrent::this_thread::cached_time()) {
itr = m_container.erase(itr); itr = m_container.erase(itr);
continue; continue;
} }
@@ -82,10 +83,10 @@ WindowHttpQueue::cleanup_list() {
} }
std::string std::string
WindowHttpQueue::create_name(core::CurlGet* h) { WindowHttpQueue::create_name(torrent::net::HttpGet http_get) {
size_t p = h->url().rfind('/', h->url().size() - std::min<int>(10, h->url().size())); size_t p = http_get.url().rfind('/', http_get.url().size() - std::min<int>(10, http_get.url().size()));
std::string n = p != std::string::npos ? h->url().substr(p) : h->url(); std::string n = p != std::string::npos ? http_get.url().substr(p) : http_get.url();
if (n.empty()) if (n.empty())
throw std::logic_error("WindowHttpQueue::create_name(...) made a bad string"); throw std::logic_error("WindowHttpQueue::create_name(...) made a bad string");
@@ -105,8 +106,8 @@ WindowHttpQueue::create_name(core::CurlGet* h) {
} }
void void
WindowHttpQueue::receive_insert(core::CurlGet* h) { WindowHttpQueue::receive_insert(torrent::net::HttpGet http_get) {
m_container.push_back(Node(h, create_name(h))); m_container.push_back(Node(http_get, create_name(http_get)));
if (!is_active()) { if (!is_active()) {
set_active(true); set_active(true);
@@ -117,8 +118,10 @@ WindowHttpQueue::receive_insert(core::CurlGet* h) {
} }
void void
WindowHttpQueue::receive_erase(core::CurlGet* h) { WindowHttpQueue::receive_erase(torrent::net::HttpGet http_get) {
Container::iterator itr = std::find_if(m_container.begin(), m_container.end(), [h](Node& n) { return h == n.m_http; }); Container::iterator itr = std::find_if(m_container.begin(),
m_container.end(),
[http_get](Node& n) { return http_get == n.m_http; });
if (itr == m_container.end()) if (itr == m_container.end())
throw std::logic_error("WindowHttpQueue::receive_erase(...) tried to remove an object we don't have"); throw std::logic_error("WindowHttpQueue::receive_erase(...) tried to remove an object we don't have");
+9 -9
View File
@@ -3,20 +3,20 @@
#include <functional> #include <functional>
#include <list> #include <list>
#include <torrent/net/http_get.h>
#include "window.h" #include "window.h"
namespace core { namespace core {
class CurlGet; class HttpQueue;
class HttpQueue;
} }
namespace display { namespace display {
class WindowHttpQueue : public Window { class WindowHttpQueue : public Window {
public: public:
typedef std::function<void (core::CurlGet*)> slot_curl_get; typedef std::function<void (torrent::net::HttpGet)> slot_curl_get;
typedef std::list<slot_curl_get> signal_curl_get; typedef std::list<slot_curl_get> signal_curl_get;
WindowHttpQueue(core::HttpQueue* q); WindowHttpQueue(core::HttpQueue* q);
~WindowHttpQueue() override; ~WindowHttpQueue() override;
@@ -25,9 +25,9 @@ public:
private: private:
struct Node { struct Node {
Node(core::CurlGet* h, const std::string& n) : m_http(h), m_name(n) {} Node(torrent::net::HttpGet h, const std::string& n) : m_http(h), m_name(n) {}
core::CurlGet* m_http{}; torrent::net::HttpGet m_http{};
std::string m_name; std::string m_name;
std::chrono::microseconds m_timer{}; std::chrono::microseconds m_timer{};
}; };
@@ -36,10 +36,10 @@ private:
void cleanup_list(); void cleanup_list();
void receive_insert(core::CurlGet* h); void receive_insert(torrent::net::HttpGet h);
void receive_erase(core::CurlGet* h); void receive_erase(torrent::net::HttpGet h);
static std::string create_name(core::CurlGet* h); static std::string create_name(torrent::net::HttpGet h);
core::HttpQueue* m_queue; core::HttpQueue* m_queue;
Container m_container; Container m_container;
+6 -3
View File
@@ -7,8 +7,8 @@
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <inttypes.h> #include <inttypes.h>
#include <typeinfo>
#include <unistd.h> #include <unistd.h>
#include <torrent/http.h>
#include <torrent/torrent.h> #include <torrent/torrent.h>
#include <torrent/exceptions.h> #include <torrent/exceptions.h>
#include <torrent/data/chunk_utils.h> #include <torrent/data/chunk_utils.h>
@@ -454,8 +454,10 @@ main(int argc, char** argv) {
} catch (torrent::internal_error& e) { } catch (torrent::internal_error& e) {
control->cleanup_exception(); control->cleanup_exception();
std::cout << "Caught internal_error: " << e.what() << std::endl std::cout << "rtorrent: caught torrent::internal_error: "
<< e.what() << std::endl
<< e.backtrace(); << e.backtrace();
lt_log_print_dump(torrent::LOG_CRITICAL, e.backtrace().c_str(), e.backtrace().size(), lt_log_print_dump(torrent::LOG_CRITICAL, e.backtrace().c_str(), e.backtrace().size(),
"Caught internal_error: '%s'.", e.what()); "Caught internal_error: '%s'.", e.what());
return -1; return -1;
@@ -463,7 +465,8 @@ main(int argc, char** argv) {
} catch (std::exception& e) { } catch (std::exception& e) {
control->cleanup_exception(); control->cleanup_exception();
std::cout << "rtorrent: " << e.what() << std::endl; std::cout << "rtorrent: caught" << typeid(e).name() << " : " << e.what() << std::endl;
lt_log_print(torrent::LOG_CRITICAL, "Caught exception: '%s'.", e.what()); lt_log_print(torrent::LOG_CRITICAL, "Caught exception: '%s'.", e.what());
return -1; return -1;
} }