mirror of
https://github.com/rakshasa/rtorrent.git
synced 2026-08-05 17:52:29 +00:00
Remove obsolete SocketFd class.
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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, ¤t, 0);
|
||||
int header_size = strtol(m_buffer.get(), ¤t, 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
@@ -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};
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user