Remove obsolete SocketFd class.

This commit is contained in:
Jari Sundell
2026-01-26 11:13:03 +01:00
committed by GitHub
parent f4b718f685
commit 2fa7568165
8 changed files with 97 additions and 319 deletions
-2
View File
@@ -172,8 +172,6 @@ libsub_root_a_SOURCES = \
utils/list_focus.h \
utils/lockfile.cc \
utils/lockfile.h \
utils/socket_fd.cc \
utils/socket_fd.h \
\
command_download.cc \
command_dynamic.cc \
+51 -43
View File
@@ -1,6 +1,7 @@
#include "config.h"
#include <cassert>
#include <unistd.h>
#include <sys/un.h>
#include <torrent/connection_manager.h>
#include <torrent/torrent.h>
@@ -12,7 +13,6 @@
#include "control.h"
#include "globals.h"
#include "rpc/scgi_task.h"
#include "utils/socket_fd.h"
// TODO: Figure out why moving this to the top causes a build error.
#include "rpc/scgi.h"
@@ -20,30 +20,26 @@
namespace rpc {
SCgi::~SCgi() {
if (!get_fd().is_valid())
return;
for (SCgiTask* itr = m_task, *last = m_task + max_tasks; itr != last; ++itr)
if (itr->is_open())
itr->close();
deactivate();
torrent::connection_manager()->dec_socket_count();
get_fd().close();
get_fd().clear();
if (!m_path.empty())
::unlink(m_path.c_str());
assert(!is_open() && "SCgi::~SCgi() called while open");
}
void
SCgi::open_port(void* sa, unsigned int length, bool dontRoute) {
if (!get_fd().open_stream() ||
(dontRoute && !get_fd().set_dont_route(true)))
SCgi::open_port(sockaddr* sa, unsigned int length, bool dont_route) {
int fd = torrent::fd_open_family(torrent::fd_flag_stream | torrent::fd_flag_nonblock | torrent::fd_flag_reuse_address,
reinterpret_cast<sockaddr*>(sa)->sa_family);
if (fd == -1)
throw torrent::resource_error("Could not open socket for listening: " + std::string(std::strerror(errno)));
open(sa, length);
if (dont_route && !torrent::fd_set_dont_route(fd, true)) {
torrent::fd_close(fd);
throw torrent::resource_error("Could not set socket option IP_DONTROUTE: " + std::string(std::strerror(errno)));
}
set_file_descriptor(fd);
open(reinterpret_cast<sockaddr*>(sa), length);
torrent::connection_manager()->inc_socket_count();
}
void
@@ -51,45 +47,42 @@ SCgi::open_named(const std::string& filename) {
if (filename.empty() || filename.size() > 4096)
throw torrent::resource_error("Invalid filename length.");
auto buffer = std::make_unique<char[]>(sizeof(sockaddr_un) + filename.size());
auto buffer = std::make_unique<char[]>(sizeof(sockaddr_un) + filename.size() + 1);
sockaddr_un* sa = reinterpret_cast<sockaddr_un*>(buffer.get());
#ifdef __sun__
sa->sun_family = AF_UNIX;
#else
sa->sun_family = AF_LOCAL;
#endif
std::memcpy(sa->sun_path, filename.c_str(), filename.size() + 1);
if (!get_fd().open_local())
throw torrent::resource_error("Could not open socket for listening.");
int fd = torrent::fd_open_local(torrent::fd_flag_stream | torrent::fd_flag_nonblock | torrent::fd_flag_reuse_address);
if (fd == -1)
throw torrent::resource_error("Could not open socket for listening: " + std::string(std::strerror(errno)));
set_file_descriptor(fd);
open(reinterpret_cast<sockaddr*>(sa), offsetof(struct sockaddr_un, sun_path) + filename.size() + 1);
torrent::connection_manager()->inc_socket_count();
open(sa, offsetof(struct sockaddr_un, sun_path) + filename.size() + 1);
m_path = filename;
}
void
SCgi::open(void* sa, unsigned int length) {
SCgi::open(sockaddr* sa, unsigned int length) {
try {
if (!get_fd().set_nonblock() ||
!get_fd().set_reuse_address(true) ||
!get_fd().bind_sa(reinterpret_cast<sockaddr*>(sa), length) ||
!get_fd().listen(max_tasks))
if (::bind(file_descriptor(), sa, length) == -1)
throw torrent::resource_error("Could not bind socket for listening: " + std::string(std::strerror(errno)));
if (!torrent::fd_listen(file_descriptor(), max_tasks))
throw torrent::resource_error("Could not prepare socket for listening: " + std::string(std::strerror(errno)));
torrent::connection_manager()->inc_socket_count();
} catch (torrent::resource_error& e) {
get_fd().close();
get_fd().clear();
torrent::fd_close(file_descriptor());
set_file_descriptor(-1);
throw e;
}
}
// TODO: Verify this is run in correct thread, also only ever call poll methods from thread_self.
void
SCgi::activate() {
assert(torrent::this_thread::thread() == scgi_thread::thread());
@@ -100,16 +93,31 @@ SCgi::activate() {
}
void
SCgi::deactivate() {
SCgi::stop() {
assert(torrent::this_thread::thread() == scgi_thread::thread());
if (!is_open())
return;
for (SCgiTask* itr = m_task, *last = m_task + max_tasks; itr != last; ++itr)
if (itr->is_open())
itr->close();
torrent::this_thread::poll()->remove_and_close(this);
torrent::fd_close(file_descriptor());
set_file_descriptor(-1);
torrent::connection_manager()->dec_socket_count();
if (!m_path.empty())
::unlink(m_path.c_str());
}
void
SCgi::event_read() {
while (true) {
int fd = torrent::fd_accept(get_fd().get_fd());
int fd = torrent::fd_accept(file_descriptor());
if (fd == -1) {
if (errno == EAGAIN || errno == EWOULDBLOCK)
+4 -10
View File
@@ -5,11 +5,6 @@
#include <torrent/event.h>
#include "rpc/scgi_task.h"
#include "utils/socket_fd.h"
namespace utils {
class SocketFd;
}
namespace rpc {
@@ -21,11 +16,12 @@ public:
const char* type_name() const override { return "scgi"; }
void open_port(void* sa, unsigned int length, bool dontRoute);
void open_port(sockaddr* sa, unsigned int length, bool dont_route);
void open_named(const std::string& filename);
void activate();
void deactivate();
void stop();
const std::string& path() const { return m_path; }
@@ -36,10 +32,8 @@ public:
void event_write() override;
void event_error() override;
utils::SocketFd& get_fd() { return *reinterpret_cast<utils::SocketFd*>(&m_fileDesc); }
private:
void open(void* sa, unsigned int length);
void open(sockaddr* sa, unsigned int length);
std::string m_path;
int m_logFd{-1};
+33 -37
View File
@@ -3,11 +3,13 @@
#include "rpc/scgi_task.h"
#include <cstdio>
#include <unistd.h>
#include <vector>
#include <sys/types.h>
#include <sys/socket.h>
#include <torrent/exceptions.h>
#include <torrent/torrent.h>
#include <torrent/net/fd.h>
#include <torrent/net/poll.h>
#include <torrent/utils/log.h>
#include <torrent/utils/thread.h>
@@ -16,7 +18,6 @@
#include "globals.h"
#include "scgi.h"
#include "rpc/parse_commands.h"
#include "utils/socket_fd.h"
namespace rpc {
@@ -24,10 +25,12 @@ void
SCgiTask::open(SCgi* parent, int fd) {
m_parent = parent;
m_fileDesc = fd;
m_buffer = new char[default_buffer_size + 1];
m_buffer.reset(new char[default_buffer_size + 1]);
m_buffer_size = default_buffer_size;
m_position = m_buffer;
m_body = NULL;
m_position = m_buffer.get();
m_body = nullptr;
torrent::this_thread::poll()->open(this);
torrent::this_thread::poll()->insert_read(this);
@@ -36,7 +39,7 @@ SCgiTask::open(SCgi* parent, int fd) {
void
SCgiTask::close() {
if (!get_fd().is_valid())
if (!is_open())
return;
torrent::main_thread::thread()->cancel_callback_and_wait(this);
@@ -44,18 +47,17 @@ SCgiTask::close() {
torrent::this_thread::poll()->remove_and_close(this);
get_fd().close();
get_fd().clear();
torrent::fd_close(file_descriptor());
set_file_descriptor(-1);
auto lock = std::lock_guard<std::mutex>(m_result_mutex);
delete[] m_buffer;
m_buffer = NULL;
m_buffer = nullptr;
}
void
SCgiTask::event_read() {
int bytes = ::recv(m_fileDesc, m_position, m_buffer_size - (m_position - m_buffer), 0);
int bytes = ::recv(m_fileDesc, m_position, m_buffer_size - (m_position - m_buffer.get()), 0);
if (bytes <= 0) {
if (bytes == 0 || !(errno == EAGAIN || errno == EINTR))
@@ -73,14 +75,14 @@ SCgiTask::event_read() {
// receive all the data we need the first time.
char* current;
int header_size = strtol(m_buffer, &current, 0);
int header_size = strtol(m_buffer.get(), &current, 0);
if (current == m_position)
return;
// If the request doesn't start with an integer or if it didn't
// end in ':', then close the connection.
if (current == m_buffer || *current != ':' || header_size < 17 || header_size > max_header_size)
if (current == m_buffer.get() || *current != ':' || header_size < 17 || header_size > max_header_size)
goto event_read_failed;
if (std::distance(++current, m_position) < header_size + 1)
@@ -135,7 +137,7 @@ SCgiTask::event_read() {
goto event_read_failed;
m_body = current + 1;
header_size = std::distance(m_buffer, m_body);
header_size = std::distance(m_buffer.get(), m_body);
if (!detect_content_type(content_type))
goto event_read_failed;
@@ -146,19 +148,19 @@ SCgiTask::event_read() {
} else if ((unsigned int)content_length <= default_buffer_size) {
m_buffer_size = content_length;
std::memmove(m_buffer, m_body, std::distance(m_body, m_position));
m_position = m_buffer + std::distance(m_body, m_position);
m_body = m_buffer;
std::memmove(m_buffer.get(), m_body, std::distance(m_body, m_position));
m_position = m_buffer.get() + std::distance(m_body, m_position);
m_body = m_buffer.get();
} else {
realloc_buffer((m_buffer_size = content_length) + 1, m_body, std::distance(m_body, m_position));
m_position = m_buffer + std::distance(m_body, m_position);
m_body = m_buffer;
m_position = m_buffer.get() + std::distance(m_body, m_position);
m_body = m_buffer.get();
}
}
if ((unsigned int)std::distance(m_buffer, m_position) != m_buffer_size)
if ((unsigned int)std::distance(m_buffer.get(), m_position) != m_buffer_size)
return;
torrent::this_thread::poll()->remove_read(this);
@@ -168,13 +170,13 @@ SCgiTask::event_read() {
// Clean up logging, this is just plain ugly...
// write(m_logFd, "\n---\n", sizeof("\n---\n"));
result = write(m_parent->log_fd(), m_buffer, m_buffer_size);
result = write(m_parent->log_fd(), "\n---\n", sizeof("\n---\n"));
result = ::write(m_parent->log_fd(), m_buffer.get(), m_buffer_size);
result = ::write(m_parent->log_fd(), "\n---\n", sizeof("\n---\n"));
}
lt_log_print_dump(torrent::LOG_RPC_DUMP, m_body, m_buffer_size - std::distance(m_buffer, m_body), "scgi", "RPC read.", 0);
lt_log_print_dump(torrent::LOG_RPC_DUMP, m_body, m_buffer_size - std::distance(m_buffer.get(), m_body), "scgi", "RPC read.", 0);
receive_call(m_body, m_buffer_size - std::distance(m_buffer, m_body));
receive_call(m_body, m_buffer_size - std::distance(m_buffer.get(), m_body));
return;
event_read_failed:
@@ -184,13 +186,7 @@ event_read_failed:
void
SCgiTask::event_write() {
// Apple and Solaris do not support MSG_NOSIGNAL,
// so disable this fix until we find a better solution
#if defined(__APPLE__) || defined(__sun__)
int bytes = ::send(m_fileDesc, m_position, m_buffer_size, 0);
#else
int bytes = ::send(m_fileDesc, m_position, m_buffer_size, MSG_NOSIGNAL);
#endif
if (bytes == -1) {
if (!(errno == EAGAIN || errno == EINTR))
@@ -248,11 +244,11 @@ SCgiTask::detect_content_type(const std::string& content_type) {
// If bufferSize is zero then memcpy won't do anything.
void
SCgiTask::realloc_buffer(uint32_t size, const char* buffer, uint32_t bufferSize) {
char* tmp = new char[size];
auto tmp = new char[size];
std::memcpy(tmp, buffer, bufferSize);
::free(m_buffer);
m_buffer = tmp;
m_buffer.reset(tmp);
}
void
@@ -317,20 +313,20 @@ SCgiTask::receive_write(const char* buffer, uint32_t length) {
: "Status: 200 OK\r\nContent-Type: text/xml\r\nContent-Length: %i\r\n\r\n";
// Who ever bothers to check the return value?
int headerSize = snprintf(m_buffer, m_buffer_size, header, length);
int headerSize = snprintf(m_buffer.get(), m_buffer_size, header, length);
m_position = m_buffer;
m_position = m_buffer.get();
m_buffer_size = length + headerSize;
std::memcpy(m_buffer + headerSize, buffer, length);
std::memcpy(m_buffer.get() + headerSize, buffer, length);
if (m_parent->log_fd() >= 0) {
[[maybe_unused]] int result;
result = write(m_parent->log_fd(), m_buffer, m_buffer_size);
result = write(m_parent->log_fd(), m_buffer.get(), m_buffer_size);
result = write(m_parent->log_fd(), "\n---\n", sizeof("\n---\n"));
}
lt_log_print_dump(torrent::LOG_RPC_DUMP, m_buffer, m_buffer_size, "scgi", "RPC write.", 0);
lt_log_print_dump(torrent::LOG_RPC_DUMP, m_buffer.get(), m_buffer_size, "scgi", "RPC write.", 0);
}
} // namespace rpc
+4 -10
View File
@@ -5,10 +5,6 @@
#include <mutex>
#include <torrent/event.h>
namespace utils {
class SocketFd;
}
namespace rpc {
class SCgi;
@@ -37,8 +33,6 @@ public:
void event_write() override;
void event_error() override;
utils::SocketFd& get_fd() { return *reinterpret_cast<utils::SocketFd*>(&m_fileDesc); }
private:
bool detect_content_type(const std::string& content_type);
void realloc_buffer(uint32_t size, const char* buffer, uint32_t bufferSize);
@@ -46,13 +40,13 @@ private:
void receive_call(const char* buffer, uint32_t length);
void receive_write(const char* buffer, uint32_t length);
SCgi* m_parent;
SCgi* m_parent{};
std::mutex m_result_mutex;
char* m_buffer{nullptr};
char* m_position{nullptr};
char* m_body{nullptr};
std::unique_ptr<char[]> m_buffer;
char* m_position{};
char* m_body{};
unsigned int m_buffer_size{0};
+5 -3
View File
@@ -41,7 +41,7 @@ ThreadScgi::thread_scgi() {
void
ThreadScgi::cleanup_thread() {
if (m_scgi != nullptr)
m_scgi.load()->deactivate();
m_scgi.load()->stop();
}
rpc::SCgi*
@@ -49,6 +49,8 @@ ThreadScgi::scgi() {
return m_scgi;
}
// TODO: Disable changing SCGI once set?
bool
ThreadScgi::set_scgi(rpc::SCgi* scgi) {
rpc::SCgi* expected = nullptr;
@@ -59,7 +61,7 @@ ThreadScgi::set_scgi(rpc::SCgi* scgi) {
change_rpc_log();
callback(nullptr, [this]() {
if (m_scgi == NULL)
if (m_scgi == nullptr)
throw torrent::internal_error("Tried to start SCGI but object was not present.");
m_scgi.load()->activate();
@@ -78,7 +80,7 @@ ThreadScgi::set_rpc_log(const std::string& filename) {
void
ThreadScgi::change_rpc_log() {
if (scgi() == NULL)
if (scgi() == nullptr)
return;
if (scgi()->log_fd() != -1) {
-159
View File
@@ -1,159 +0,0 @@
#include "config.h"
#include <errno.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <torrent/exceptions.h>
#include <torrent/net/socket_address.h>
#include "socket_fd.h"
namespace utils {
inline void
SocketFd::check_valid() const {
if (!is_valid())
throw torrent::internal_error("SocketFd function called on an invalid fd.");
}
bool
SocketFd::set_nonblock() {
check_valid();
return fcntl(m_fd, F_SETFL, O_NONBLOCK) == 0;
}
bool
SocketFd::set_priority(priority_type p) {
check_valid();
int opt = p;
if (m_ipv6_socket)
return setsockopt(m_fd, IPPROTO_IPV6, IPV6_TCLASS, &opt, sizeof(opt)) == 0;
else
return setsockopt(m_fd, IPPROTO_IP, IP_TOS, &opt, sizeof(opt)) == 0;
}
bool
SocketFd::set_reuse_address(bool state) {
check_valid();
int opt = state;
return setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)) == 0;
}
bool
SocketFd::set_dont_route(bool state) {
check_valid();
int opt = state;
return setsockopt(m_fd, SOL_SOCKET, SO_DONTROUTE, &opt, sizeof(opt)) == 0;
}
// bool
// SocketFd::set_bind_to_device(const char* device) {
// check_valid();
// struct ifreq ifr;
// strlcpy(ifr.ifr_name, device, IFNAMSIZ);
// return setsockopt(m_fd, SOL_SOCKET, SO_BINDTODEVICE, &ifr, sizeof(ifr)) == 0;
// }
bool
SocketFd::set_send_buffer_size(uint32_t s) {
check_valid();
int opt = s;
return setsockopt(m_fd, SOL_SOCKET, SO_SNDBUF, &opt, sizeof(opt)) == 0;
}
bool
SocketFd::set_receive_buffer_size(uint32_t s) {
check_valid();
int opt = s;
return setsockopt(m_fd, SOL_SOCKET, SO_RCVBUF, &opt, sizeof(opt)) == 0;
}
int
SocketFd::get_error() const {
check_valid();
int err;
socklen_t length = sizeof(err);
if (getsockopt(m_fd, SOL_SOCKET, SO_ERROR, &err, &length) == -1)
throw torrent::internal_error("SocketFd::get_error() could not get error");
return err;
}
bool
SocketFd::open_stream() {
m_fd = socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP);
if (m_fd == -1) {
m_ipv6_socket = false;
return (m_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1;
}
m_ipv6_socket = true;
int zero = 0;
return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1;
}
bool
SocketFd::open_datagram() {
m_fd = socket(AF_INET6, SOCK_DGRAM, 0);
if (m_fd == -1) {
m_ipv6_socket = false;
return (m_fd = socket(AF_INET, SOCK_DGRAM, 0)) != -1;
}
m_ipv6_socket = true;
int zero = 0;
return setsockopt(m_fd, IPPROTO_IPV6, IPV6_V6ONLY, &zero, sizeof(zero)) != -1;
}
bool
SocketFd::open_local() {
return (m_fd = socket(AF_LOCAL, SOCK_STREAM, 0)) != -1;
}
void
SocketFd::close() {
if (::close(m_fd) && errno == EBADF)
throw torrent::internal_error("SocketFd::close() called on an invalid file descriptor");
}
bool
SocketFd::bind_sa(const sockaddr* sa, unsigned int length) {
check_valid();
if (m_ipv6_socket && sa->sa_family == AF_INET) {
if (length < sizeof(sockaddr_in))
throw torrent::input_error("SocketFd::bind_sa: invalid sockaddr length for AF_INET");
auto mapped_sa = torrent::sin6_to_v4mapped_in(reinterpret_cast<const sockaddr_in*>(sa));
return !::bind(m_fd, reinterpret_cast<const sockaddr*>(mapped_sa.get()), sizeof(sockaddr_in6));
}
return !::bind(m_fd, sa, length);
}
bool
SocketFd::listen(int size) {
check_valid();
return !::listen(m_fd, size);
}
}
-55
View File
@@ -1,55 +0,0 @@
#ifndef RTORRENT_UTILS_SOCKET_FD_H
#define RTORRENT_UTILS_SOCKET_FD_H
#include <cinttypes>
#include <unistd.h>
#include <sys/socket.h>
namespace utils {
class SocketFd {
public:
typedef uint8_t priority_type;
SocketFd() : m_fd(-1) {}
explicit SocketFd(int fd) : m_fd(fd) {}
bool is_valid() const { return m_fd >= 0; }
int get_fd() const { return m_fd; }
void set_fd(int fd) { m_fd = fd; }
bool set_nonblock();
bool set_reuse_address(bool state);
bool set_dont_route(bool state);
bool set_bind_to_device(const char* device);
bool set_priority(priority_type p);
bool set_send_buffer_size(uint32_t s);
bool set_receive_buffer_size(uint32_t s);
int get_error() const;
bool open_stream();
bool open_datagram();
bool open_local();
void close();
void clear() { m_fd = -1; }
bool bind_sa(const sockaddr* sa, unsigned int length);
bool listen(int size);
private:
inline void check_valid() const;
int m_fd;
bool m_ipv6_socket;
};
}
#endif