Compare commits

...

7 Commits

Author SHA1 Message Date
rakshasa 4463bf418e Release 0.15.5. 2025-06-22 16:44:05 +00:00
Phil Rosenthal 8bd7c79755 Fix file descriptor leak in session file saving
When system.files.session.fdatasync is set to "no", file descriptors
  were not being closed after writing session files, causing a severe
  resource leak. Each save operation would leak one file descriptor.

  With hundreds of torrents, this leads to tens of thousands of leaked
  file descriptors within hours, mostly pointing to deleted session files.
  This can exhaust the system's file descriptor limit and cause rtorrent
  to fail when opening new files.

  The fix moves the close() call outside the fdatasync conditional block,
  ensuring file descriptors are always properly closed regardless of the
  fdatasync setting.
2025-06-18 19:04:45 +02:00
rakshasa f2b83d50e8 Use libtorrent stable-0.15 branch in workflow. 2025-06-08 13:01:36 +02:00
rakshasa ab40059891 Use libtorrent stable-0.15 branch in workflow. 2025-06-08 13:01:36 +02:00
rakshasa b9d880dea3 Properly handle -1 value passed to curl set_timeout. 2025-06-08 13:01:36 +02:00
rakshasa b4c59d2c7a Fixed corrupted stack in curl stack due to wrong argument type. 2025-06-07 13:17:34 +02:00
rakshasa 231606afc1 Fix ExecFile waitpid error handling. 2025-06-01 18:41:22 +02:00
7 changed files with 30 additions and 15 deletions
+2
View File
@@ -14,6 +14,8 @@ jobs:
- name: Fetch libtorrent
run: |
git clone https://github.com/rakshasa/libtorrent
cd libtorrent
git checkout stable-0.15
- name: Build libtorrent
run: |
cd libtorrent
+2
View File
@@ -14,6 +14,8 @@ jobs:
- name: Fetch libtorrent
run: |
git clone https://github.com/rakshasa/libtorrent
cd libtorrent
git checkout stable-0.15
- name: Build libtorrent
run: |
cd libtorrent
+2 -2
View File
@@ -1,6 +1,6 @@
m4_pattern_allow([PKG_CHECK_EXISTS])
AC_INIT([rtorrent],[0.15.4],[sundell.software@gmail.com])
AC_INIT([rtorrent],[0.15.5],[sundell.software@gmail.com])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_MACRO_DIRS([scripts])
@@ -54,7 +54,7 @@ fi
PKG_CHECK_MODULES([LIBCURL], [libcurl],, [LIBCURL_CHECK_CONFIG])
PKG_CHECK_MODULES([CPPUNIT], [cppunit],, [no_cppunit="yes"])
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.15.4])
PKG_CHECK_MODULES([DEPENDENCIES], [libtorrent >= 0.15.5])
AC_LANG_PUSH(C++)
TORRENT_WITH_XMLRPC_C
+6 -2
View File
@@ -233,10 +233,14 @@ CurlStack::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::set_timeout(void*, long timeout_ms, void* userp) {
CurlStack* stack = (CurlStack*)userp;
torrent::this_thread::scheduler()->update_wait_for_ceil_seconds(&stack->m_task_timeout, timeout);
if (timeout_ms == -1)
torrent::this_thread::scheduler()->erase(&stack->m_task_timeout);
else
torrent::this_thread::scheduler()->update_wait_for_ceil_seconds(&stack->m_task_timeout, std::chrono::milliseconds(timeout_ms));
return 0;
}
+1 -1
View File
@@ -79,7 +79,7 @@ public:
void receive_action(CurlSocket* socket, int type);
static int set_timeout(void* handle, std::chrono::microseconds timeout, void* userp);
static int set_timeout(void*, long timeout_ms, void* userp);
void transfer_done(void* handle, const char* msg);
+2 -1
View File
@@ -100,9 +100,10 @@ DownloadStore::write_bencode(const std::string& filename, const torrent::Object&
#else
fdatasync(fd);
#endif
::close(fd);
}
::close(fd);
return true;
download_store_save_error:
+15 -9
View File
@@ -1,6 +1,7 @@
#include "config.h"
#include <cerrno>
#include <cstring>
#include <fcntl.h>
#include <string>
#include <unistd.h>
@@ -18,7 +19,7 @@ namespace rpc {
int
ExecFile::execute(const char* file, char* const* argv, int flags) {
// Write the execued command and its parameters to the log fd.
// Write the executed command and its parameters to the log fd.
[[maybe_unused]] int result;
if (m_log_fd != -1) {
@@ -117,18 +118,23 @@ ExecFile::execute(const char* file, char* const* argv, int flags) {
}
int status;
int wpid;
do {
wpid = waitpid(childPid, &status, 0);
} while (wpid == -1 && WIFEXITED(status) == 0);
if (wpid != childPid)
throw torrent::internal_error("ExecFile::execute(...) waitpid failed.");
while (waitpid(childPid, &status, 0) == -1) {
switch (errno) {
case EINTR:
continue;
case ECHILD:
throw torrent::internal_error("ExecFile::execute(...) waitpid failed with ECHILD, child process not found.");
case EINVAL:
throw torrent::internal_error("ExecFile::execute(...) waitpid failed with EINVAL.");
default:
throw torrent::internal_error("ExecFile::execute(...) waitpid failed with unexpected error: " + std::string(std::strerror(errno)));
}
};
// Check return value?
if (m_log_fd != -1) {
if (status == 0)
if (WIFEXITED(status) && WEXITSTATUS(status) == 0)
result = write(m_log_fd, "\n--- Success ---\n", sizeof("\n--- Success ---\n"));
else
result = write(m_log_fd, "\n--- Error ---\n", sizeof("\n--- Error ---\n"));