diff --git a/src/command_network.cc b/src/command_network.cc index a2ea43d4..cbb70e3d 100644 --- a/src/command_network.cc +++ b/src/command_network.cc @@ -48,6 +48,7 @@ #include "core/download_store.h" #include "core/manager.h" #include "rpc/fast_cgi.h" +#include "rpc/scgi.h" #include "rpc/xmlrpc.h" #include "ui/root.h" #include "utils/command_slot.h" @@ -141,34 +142,52 @@ apply_enable_trackers(int64_t arg) { } } +void +initialize_xmlrpc() { + control->set_xmlrpc(new rpc::XmlRpc); + control->xmlrpc()->set_slot_call_command(rak::mem_fn(control->variable(), &utils::VariableMap::call_command)); + + unsigned int count = 0; + + for (utils::VariableMap::const_iterator itr = control->variable()->begin(), last = control->variable()->end(); itr != last; itr++) + if (itr->second.m_flags & utils::VariableMap::flag_public_xmlrpc) { + control->xmlrpc()->insert_command(itr->first, itr->second.m_parm, itr->second.m_doc); + + count++; + } + + char buffer[128]; + sprintf(buffer, "XMLRPC initialized with %u functions.", count); + + control->core()->push_log(buffer); +} + void apply_fast_cgi(const std::string& arg) { if (control->fast_cgi() != NULL) throw torrent::input_error("FastCGI already enabled."); - if (control->xmlrpc() == NULL) { - control->set_xmlrpc(new rpc::XmlRpc); - control->xmlrpc()->set_slot_call_command(rak::mem_fn(control->variable(), &utils::VariableMap::call_command)); - - unsigned int count = 0; - - for (utils::VariableMap::const_iterator itr = control->variable()->begin(), last = control->variable()->end(); itr != last; itr++) - if (itr->second.m_flags & utils::VariableMap::flag_public_xmlrpc) { - control->xmlrpc()->insert_command(itr->first, itr->second.m_parm, itr->second.m_doc); - - count++; - } - - char buffer[128]; - sprintf(buffer, "FastCGI initialized with %u functions.", count); - - control->core()->push_log(buffer); - } + if (control->xmlrpc() == NULL) + initialize_xmlrpc(); control->set_fast_cgi(new rpc::FastCgi(arg)); control->fast_cgi()->set_slot_process(rak::mem_fn(control->xmlrpc(), &rpc::XmlRpc::process)); } +void +apply_scgi(const std::string& arg) { + if (control->fast_cgi() != NULL) + throw torrent::input_error("FastCGI already enabled."); + + if (control->xmlrpc() == NULL) + initialize_xmlrpc(); + + // Fix this... + control->set_scgi(new rpc::SCgi); + control->scgi()->open(5000); + control->scgi()->set_slot_process(rak::mem_fn(control->xmlrpc(), &rpc::XmlRpc::process)); +} + void initialize_command_network() { utils::VariableMap* variables = control->variable(); @@ -223,6 +242,7 @@ initialize_command_network() { ADD_COMMAND_VALUE_TRI("max_open_http", rak::make_mem_fun(httpStack, &core::CurlStack::set_max_active), rak::make_mem_fun(httpStack, &core::CurlStack::max_active)); ADD_COMMAND_STRING_UN("fast_cgi", std::ptr_fun(&apply_fast_cgi)); + ADD_COMMAND_STRING_UN("scgi", std::ptr_fun(&apply_scgi)); ADD_COMMAND_VALUE_TRI("hash_read_ahead", std::ptr_fun(&apply_hash_read_ahead), rak::ptr_fun(torrent::hash_read_ahead)); ADD_COMMAND_VALUE_TRI("hash_interval", std::ptr_fun(&apply_hash_interval), rak::ptr_fun(torrent::hash_interval)); diff --git a/src/control.cc b/src/control.cc index 682aca83..87eb08f9 100644 --- a/src/control.cc +++ b/src/control.cc @@ -51,6 +51,7 @@ #include "input/manager.h" #include "input/input_event.h" #include "rpc/fast_cgi.h" +#include "rpc/scgi.h" #include "rpc/xmlrpc.h" #include "ui/root.h" #include "utils/variable_map.h" @@ -73,6 +74,7 @@ Control::Control() : m_downloadVariables(new utils::VariableMap()), m_fastCgi(NULL), + m_scgi(NULL), m_xmlrpc(NULL), m_tick(0) { @@ -129,6 +131,7 @@ Control::initialize() { void Control::cleanup() { delete m_fastCgi; m_fastCgi = NULL; + delete m_scgi; m_scgi = NULL; delete m_xmlrpc; m_xmlrpc = NULL; priority_queue_erase(&taskScheduler, &m_taskShutdown); @@ -163,6 +166,11 @@ Control::handle_shutdown() { m_shutdownReceived = false; } +torrent::Poll* +Control::poll() { + return m_core->get_poll_manager()->get_torrent_poll(); +} + void Control::set_umask(mode_t m) { ::umask(m); diff --git a/src/control.h b/src/control.h index df1bc8a9..002041a1 100644 --- a/src/control.h +++ b/src/control.h @@ -64,6 +64,7 @@ namespace input { namespace rpc { class FastCgi; + class SCgi; class XmlRpc; } @@ -94,6 +95,8 @@ public: core::ViewManager* view_manager() { return m_viewManager; } core::Scheduler* scheduler() { return m_scheduler; } + torrent::Poll* poll(); + ui::Root* ui() { return m_ui; } display::Manager* display() { return m_display; } input::Manager* input() { return m_input; } @@ -107,6 +110,9 @@ public: rpc::FastCgi* fast_cgi() { return m_fastCgi; } void set_fast_cgi(rpc::FastCgi* f) { m_fastCgi = f; } + rpc::SCgi* scgi() { return m_scgi; } + void set_scgi(rpc::SCgi* f) { m_scgi = f; } + rpc::XmlRpc* xmlrpc() { return m_xmlrpc; } void set_xmlrpc(rpc::XmlRpc* f) { m_xmlrpc = f; } @@ -140,6 +146,7 @@ private: utils::VariableMap* m_downloadVariables; rpc::FastCgi* m_fastCgi; + rpc::SCgi* m_scgi; rpc::XmlRpc* m_xmlrpc; uint64_t m_tick; diff --git a/src/rpc/Makefile.am b/src/rpc/Makefile.am index efb50dad..b7219749 100644 --- a/src/rpc/Makefile.am +++ b/src/rpc/Makefile.am @@ -3,6 +3,10 @@ noinst_LIBRARIES = libsub_rpc.a libsub_rpc_a_SOURCES = \ fast_cgi.cc \ fast_cgi.h \ + scgi.cc \ + scgi.h \ + scgi_task.cc \ + scgi_task.h \ xmlrpc.h \ xmlrpc.cc diff --git a/src/rpc/fast_cgi.cc b/src/rpc/fast_cgi.cc index 1c4e8335..4cd0f179 100644 --- a/src/rpc/fast_cgi.cc +++ b/src/rpc/fast_cgi.cc @@ -113,6 +113,11 @@ FastCgi::event_read() { return; } +// int flags = fcntl(((FCGX_Request*)m_request)->ipcFd, F_GETFL); + +// if (fcntl(((FCGX_Request*)m_request)->ipcFd, F_SETFL, flags & ~O_NONBLOCK) != 0) +// throw torrent::internal_error("FastCgi::event_read() could not set socket flags."); + int length; char* endPtr; char* buffer = NULL; diff --git a/src/rpc/scgi.cc b/src/rpc/scgi.cc new file mode 100644 index 00000000..caac900c --- /dev/null +++ b/src/rpc/scgi.cc @@ -0,0 +1,133 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005-2006, 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 +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "utils/socket_fd.h" + +#include "control.h" +#include "globals.h" +#include "scgi.h" + +namespace rpc { + +SCgi::~SCgi() { + if (!get_fd().is_valid()) + return; + + control->poll()->remove_read(this); + control->poll()->remove_error(this); + control->poll()->close(this); + + get_fd().close(); + get_fd().clear(); +} + +bool +SCgi::open(uint16_t port) { + if (!get_fd().open_stream()) + throw torrent::resource_error("Could not allocate socket for listening."); + + try { + rak::socket_address sa; + sa.sa_inet()->clear(); + sa.sa_inet()->set_port(port); + + if (!get_fd().set_nonblock() || + !get_fd().set_reuse_address(true) || + !get_fd().bind(sa) || + !get_fd().listen(10)) + throw torrent::resource_error("Could not allocate socket for listening."); + + torrent::connection_manager()->inc_socket_count(); + + control->poll()->open(this); + control->poll()->insert_read(this); + control->poll()->insert_error(this); + + } catch (torrent::resource_error& e) { + get_fd().close(); + get_fd().clear(); + + throw e; + } + + return true; +} + +void +SCgi::event_read() { + rak::socket_address sa; + utils::SocketFd fd; + + while ((fd = get_fd().accept(&sa)).is_valid()) { + SCgiTask* task = std::find_if(m_task, m_task + 10, std::mem_fun_ref(&SCgiTask::is_available)); + + if (task == task + 10) { + // Ergh... just closing for now. + fd.close(); + continue; + } + + task->open(this, fd.get_fd()); + } +} + +void +SCgi::event_write() { + throw torrent::internal_error("Listener does not support write()."); +} + +void +SCgi::event_error() { + throw torrent::internal_error("SCGI listener port received an error event."); +} + +bool +SCgi::receive_call(SCgiTask* task, const char* buffer, uint32_t length) { + slot_write slotWrite; + slotWrite.set(rak::mem_fn(task, &SCgiTask::receive_write)); + + return m_slotProcess(buffer, length, slotWrite); +} + +} diff --git a/src/rpc/scgi.h b/src/rpc/scgi.h new file mode 100644 index 00000000..708f014a --- /dev/null +++ b/src/rpc/scgi.h @@ -0,0 +1,84 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005-2006, 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 +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#ifndef RTORRENT_RPC_SCGI_H +#define RTORRENT_RPC_SCGI_H + +#include +#include +#include + +#include "scgi_task.h" + +namespace utils { + class SocketFd; +} + +namespace rpc { + +class SCgi : public torrent::Event { +public: + typedef rak::function2 slot_write; + typedef rak::function3 slot_process; + + SCgi() {} + virtual ~SCgi(); + + bool open(uint16_t port); + + const std::string path() const { return m_path; } + + void set_slot_process(slot_process::base_type* s) { m_slotProcess.set(s); } + + virtual void event_read(); + virtual void event_write(); + virtual void event_error(); + + bool receive_call(SCgiTask* task, const char* buffer, uint32_t length); + + utils::SocketFd& get_fd() { return *reinterpret_cast(&m_fileDesc); } + +private: + std::string m_path; + + slot_process m_slotProcess; + + SCgiTask m_task[10]; +}; + +} + +#endif diff --git a/src/rpc/scgi_task.cc b/src/rpc/scgi_task.cc new file mode 100644 index 00000000..03942d4d --- /dev/null +++ b/src/rpc/scgi_task.cc @@ -0,0 +1,182 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005-2006, 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 +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#include "config.h" + +#include +#include +#include +#include +#include + +#include "utils/socket_fd.h" + +#include "control.h" +#include "globals.h" +#include "scgi.h" + +namespace rpc { + +void +SCgiTask::open(SCgi* parent, int fd) { + m_parent = parent; + m_fileDesc = fd; + m_buffer = new char[(m_bufferSize = 2048)]; + m_position = m_buffer; + + control->poll()->open(this); + control->poll()->insert_read(this); + control->poll()->insert_error(this); +} + +void +SCgiTask::close() { + if (!get_fd().is_valid()) + return; + + control->poll()->remove_read(this); + control->poll()->remove_write(this); + control->poll()->remove_error(this); + control->poll()->close(this); + + get_fd().close(); + get_fd().clear(); + + delete [] m_buffer; + m_buffer = NULL; +} + +void +SCgiTask::event_read() { + int bytes = ::recv(m_fileDesc, m_position, m_bufferSize - 1 - (m_position - m_buffer), 0); + + if (bytes == -1) { + if (!rak::error_number::current().is_blocked_momentary()) + close(); + + return; + } + + m_position += bytes; + *m_position = '\0'; + + // Don't bother caching the parsed values, as we're likely to + // receive all the data we need the first time. + char* current; + int headerSize = strtol(m_buffer, ¤t, 0); + + if (current == m_buffer || current == m_position) + // Need to validate the header size. + return; + + if (*current != ':' || headerSize < 17) + goto event_read_failed; + + if (std::distance(++current, m_position) < headerSize + 1) + return; + + if (std::memcmp(current, "CONTENT_LENGTH", 15) != 0) + goto event_read_failed; + + char* contentPos; + int contentSize = strtol(current + 15, &contentPos, 0); + + if (*contentPos != '\0' || contentSize <= 0) + goto event_read_failed; + + // Start of the data. + current += headerSize + 1; + + if (std::distance(current, m_position) < contentSize) + return; + + control->poll()->remove_read(this); + control->poll()->insert_write(this); + + if (!m_parent->receive_call(this, current, contentSize)) + close(); + + return; + + event_read_failed: + throw torrent::internal_error("SCgiTask::event_read() fault not handled."); +} + +void +SCgiTask::event_write() { + int bytes = ::send(m_fileDesc, m_position, m_bufferSize, 0); + + if (bytes == -1) { + if (!rak::error_number::current().is_blocked_momentary()) + close(); + + return; + } + + m_position += bytes; + m_bufferSize -= bytes; + + if (bytes == 0 || m_bufferSize == 0) + return close(); +} + +void +SCgiTask::event_error() { + close(); +} + +bool +SCgiTask::receive_write(const char* buffer, uint32_t length) { + if (length + 44 > m_bufferSize) { + delete [] m_buffer; + m_buffer = new char[length + 44]; + } + + // Try writing as much as possible from here, before copying + // anything. + + m_position = m_buffer; + m_bufferSize = length + 44; + + std::memcpy(m_buffer, "Status: 200 OK\r\nContent-Type: text/plain\r\n\r\n", 44); + std::memcpy(m_buffer + 44, buffer, length); + + event_write(); + + return true; +} + +} diff --git a/src/rpc/scgi_task.h b/src/rpc/scgi_task.h new file mode 100644 index 00000000..05feb422 --- /dev/null +++ b/src/rpc/scgi_task.h @@ -0,0 +1,78 @@ +// rTorrent - BitTorrent client +// Copyright (C) 2005-2006, 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 +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#ifndef RTORRENT_RPC_SCGI_TASK_H +#define RTORRENT_RPC_SCGI_TASK_H + +#include + +namespace utils { + class SocketFd; +} + +namespace rpc { + +class SCgi; + +class SCgiTask : public torrent::Event { +public: + SCgiTask() { m_fileDesc = -1; } + + bool is_open() const { return m_fileDesc != -1; } + bool is_available() const { return m_fileDesc == -1; } + + void open(SCgi* parent, int fd); + void close(); + + virtual void event_read(); + virtual void event_write(); + virtual void event_error(); + + bool receive_write(const char* buffer, uint32_t length); + + utils::SocketFd& get_fd() { return *reinterpret_cast(&m_fileDesc); } + +private: + SCgi* m_parent; + + char* m_buffer; + char* m_position; + unsigned int m_bufferSize; +}; + +} + +#endif diff --git a/src/utils/Makefile.am b/src/utils/Makefile.am index 594de484..b6e4a077 100644 --- a/src/utils/Makefile.am +++ b/src/utils/Makefile.am @@ -14,6 +14,8 @@ libsub_utils_a_SOURCES = \ lockfile.h \ parse.cc \ parse.h \ + socket_fd.cc \ + socket_fd.h \ variable.cc \ variable.h \ variable_generic.cc \ diff --git a/src/utils/socket_fd.cc b/src/utils/socket_fd.cc new file mode 100644 index 00000000..10f466bb --- /dev/null +++ b/src/utils/socket_fd.cc @@ -0,0 +1,178 @@ +// libTorrent - BitTorrent library +// Copyright (C) 2005-2006, 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 +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#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; + + 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_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() { + return (m_fd = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP)) != -1; +} + +bool +SocketFd::open_datagram() { + return (m_fd = socket(PF_INET, SOCK_DGRAM, 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(const rak::socket_address& sa) { + check_valid(); + + return !::bind(m_fd, sa.c_sockaddr(), sa.length()); +} + +bool +SocketFd::connect(const rak::socket_address& sa) { + check_valid(); + + return !::connect(m_fd, sa.c_sockaddr(), sa.length()) || errno == EINPROGRESS; +} + +bool +SocketFd::listen(int size) { + check_valid(); + + return !::listen(m_fd, size); +} + +SocketFd +SocketFd::accept(rak::socket_address* sa) { + check_valid(); + socklen_t len = sizeof(rak::socket_address); + + return SocketFd(::accept(m_fd, sa != NULL ? sa->c_sockaddr() : NULL, &len)); +} + +// unsigned int +// SocketFd::get_read_queue_size() const { +// unsigned int v; + +// if (!is_valid() || ioctl(m_fd, SIOCINQ, &v) < 0) +// throw internal_error("SocketFd::get_read_queue_size() could not be performed"); + +// return v; +// } + +// unsigned int +// SocketFd::get_write_queue_size() const { +// unsigned int v; + +// if (!is_valid() || ioctl(m_fd, SIOCOUTQ, &v) < 0) +// throw internal_error("SocketFd::get_write_queue_size() could not be performed"); + +// return v; +// } + +} diff --git a/src/utils/socket_fd.h b/src/utils/socket_fd.h new file mode 100644 index 00000000..a4d9549b --- /dev/null +++ b/src/utils/socket_fd.h @@ -0,0 +1,93 @@ +// libTorrent - BitTorrent library +// Copyright (C) 2005-2006, 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 +// +// Skomakerveien 33 +// 3185 Skoppum, NORWAY + +#ifndef RTORRENT_UTILS_SOCKET_FD_H +#define RTORRENT_UTILS_SOCKET_FD_H + +#include + +namespace rak { + class socket_address; +} + +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_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(); + void close(); + + void clear() { m_fd = -1; } + + bool bind(const rak::socket_address& sa); + bool connect(const rak::socket_address& sa); + + bool listen(int size); + SocketFd accept(rak::socket_address* sa); + +// unsigned int get_read_queue_size() const; +// unsigned int get_write_queue_size() const; + +private: + inline void check_valid() const; + + int m_fd; +}; + +} + +#endif