From 70e6964823a3127c3e1c8c3005fc8d4bfad520d1 Mon Sep 17 00:00:00 2001 From: Jari Sundell Date: Tue, 10 Mar 2026 15:25:28 +0100 Subject: [PATCH] Fixed various SCGI issues. --- src/rpc/scgi.cc | 37 +++++++++++++++++++++++++++++-------- src/rpc/scgi.h | 9 ++++++++- src/rpc/scgi_task.cc | 8 +++----- 3 files changed, 40 insertions(+), 14 deletions(-) diff --git a/src/rpc/scgi.cc b/src/rpc/scgi.cc index 64e9c56c..6555d557 100644 --- a/src/rpc/scgi.cc +++ b/src/rpc/scgi.cc @@ -1,5 +1,6 @@ #include "config.h" +#include #include #include #include @@ -20,6 +21,12 @@ namespace rpc { +SCgi::SCgi() { + std::generate(m_tasks.begin(), m_tasks.end(), []() { return std::make_unique(); }); + + m_current = m_tasks.begin(); +} + SCgi::~SCgi() { assert(!is_open() && "SCgi::~SCgi() called while open"); } @@ -106,9 +113,10 @@ SCgi::stop() { if (!is_open()) return; - for (SCgiTask* itr = m_task, *last = m_task + max_tasks; itr != last; ++itr) + for (auto& itr : m_tasks) { if (itr->is_open()) itr->close(); + } torrent::runtime::socket_manager()->close_event_or_throw(this, [this]() { torrent::this_thread::poll()->remove_and_close(this); @@ -125,10 +133,19 @@ SCgi::stop() { void SCgi::event_read() { - while (true) { - auto* task = std::find_if(m_task, m_task + max_tasks, std::mem_fn(&SCgiTask::is_available)); + if (m_current < m_tasks.begin() || m_current >= m_tasks.end()) + throw torrent::internal_error("SCgi::event_read() m_current is out of bounds"); - if (task == m_task + max_tasks) { + while (true) { + // TODO: Optimize this by keeping track of count. + auto prev = m_current; + + m_current = std::find_if(m_current + 1, m_tasks.end(), [](const auto& task) { return !task->is_open(); }); + + if (m_current == m_tasks.end()) + m_current = std::find_if(m_tasks.begin(), prev, [](const auto& task) { return !task->is_open(); }); + + if (m_current == prev) { // TODO: Currently just close, although we should remove ourselves from read. int fd = torrent::fd_accept(file_descriptor()); @@ -138,11 +155,15 @@ SCgi::event_read() { continue; } - auto open_func = [this, task]() { + auto open_func = [this, task = m_current->get()]() { int fd = torrent::fd_accept(file_descriptor()); if (fd == -1) { - if (errno == EAGAIN || errno == EWOULDBLOCK) + if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) + return; + + // Force a new event_read() call just to be sure we don't enter an infinite loop. + if (errno == ECONNABORTED) return; throw torrent::resource_error("Listener port accept() failed: " + std::string(std::strerror(errno))); @@ -151,11 +172,11 @@ SCgi::event_read() { task->open(this, fd); }; - auto cleanup_func = [task]() { + auto cleanup_func = [task = m_current->get()]() { task->cancel_open(); }; - bool result = torrent::runtime::socket_manager()->open_event_or_cleanup(task, open_func, cleanup_func); + bool result = torrent::runtime::socket_manager()->open_event_or_cleanup(m_current->get(), open_func, cleanup_func); if (!result) break; diff --git a/src/rpc/scgi.h b/src/rpc/scgi.h index 51afe807..5214149e 100644 --- a/src/rpc/scgi.h +++ b/src/rpc/scgi.h @@ -1,7 +1,9 @@ #ifndef RTORRENT_RPC_SCGI_H #define RTORRENT_RPC_SCGI_H +#include #include +#include #include #include "rpc/scgi_task.h" @@ -12,6 +14,7 @@ class SCgi : public torrent::Event { public: static const int max_tasks = 100; + SCgi(); ~SCgi() override; const char* type_name() const override { return "scgi"; } @@ -33,11 +36,15 @@ public: void event_error() override; private: + using task_list = std::array, max_tasks>; + void open(sockaddr* sa, unsigned int length); std::string m_path; int m_logFd{-1}; - SCgiTask m_task[max_tasks]; + + task_list m_tasks; + task_list::iterator m_current; }; } diff --git a/src/rpc/scgi_task.cc b/src/rpc/scgi_task.cc index 1ab8c2ff..089c760c 100644 --- a/src/rpc/scgi_task.cc +++ b/src/rpc/scgi_task.cc @@ -43,12 +43,10 @@ SCgiTask::cancel_open() { if (!is_open()) return; - torrent::runtime::socket_manager()->close_event_or_throw(this, [this]() { - torrent::this_thread::poll()->remove_and_close(this); + torrent::this_thread::poll()->remove_and_close(this); - torrent::fd_close(file_descriptor()); - set_file_descriptor(-1); - }); + torrent::fd_close(file_descriptor()); + set_file_descriptor(-1); }; void