mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-10-14 13:16:17 +00:00
Moved curl to libtorrent.
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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()
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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{};
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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
@@ -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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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;
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user