From bebce18368c9d2fd432613851020ad3201d8aaa6 Mon Sep 17 00:00:00 2001 From: rakshasa Date: Wed, 23 May 2007 14:03:02 +0000 Subject: [PATCH] * Added "http_ca{path/cert}" options. Patch by Johan Gunnarsson, public domain. * Minor bugfixes to SCgi. git-svn-id: svn://rakshasa.no/libtorrent/trunk/rtorrent@907 e378c898-3ddf-0310-93e7-cc216c733640 --- src/command_network.cc | 43 ++++++++++++++++++++++++++++++++++-------- src/core/curl_stack.cc | 6 ++++++ src/core/curl_stack.h | 8 ++++++++ src/rpc/scgi.cc | 14 +++++++++++--- src/rpc/scgi.h | 8 +++++--- src/rpc/scgi_task.cc | 26 ++++++++++++++++++------- 6 files changed, 84 insertions(+), 21 deletions(-) diff --git a/src/command_network.cc b/src/command_network.cc index e8f816b0..aa2c02f0 100644 --- a/src/command_network.cc +++ b/src/command_network.cc @@ -37,6 +37,7 @@ #include "config.h" #include +#include #include #include #include @@ -176,9 +177,9 @@ apply_fast_cgi(const std::string& arg) { } void -apply_scgi(const std::string& arg) { +apply_scgi(const std::string& arg, int type) { if (control->fast_cgi() != NULL) - throw torrent::input_error("FastCGI already enabled."); + throw torrent::input_error("SCGI already enabled."); if (control->xmlrpc() == NULL) initialize_xmlrpc(); @@ -189,15 +190,38 @@ apply_scgi(const std::string& arg) { try { int port; char dummy; + char address[1024]; - if (std::sscanf(arg.c_str(), ":%i%c", &port, &dummy) == 1) { - if (port <= 0 || port >= (1 << 16)) - throw torrent::input_error("Invalid port number."); + switch (type) { + case 1: + if (std::sscanf(arg.c_str(), ":%i%c", &port, &dummy) == 1) { + if (port <= 0 || port >= (1 << 16)) + throw torrent::input_error("Invalid port number."); - control->scgi()->open_port(port); + control->scgi()->open_port(port); - } else { + } else if (std::sscanf(arg.c_str(), "%1023[^:]:%i%c", address, &port, &dummy) == 2) { + if (port <= 0 || port >= (1 << 16)) + throw torrent::input_error("Invalid port number."); + + int err; + rak::address_info* ai; + + if ((err = rak::address_info::get_address_info(address, PF_INET, SOCK_STREAM, &ai)) != 0) + throw torrent::input_error("Could not bind address: " + std::string(rak::address_info::strerror(err)) + "."); + + control->scgi()->open(ai->address()->c_sockaddr(), ai->address()->length()); + + } else { + throw torrent::input_error("Could not parse address."); + } + + break; + + case 2: + default: control->scgi()->open_named(rak::path_expand(arg)); + break; } } catch (torrent::local_error& e) { @@ -248,6 +272,8 @@ initialize_command_network() { ADD_COMMAND_STRING_TRI("ip", rak::make_mem_fun(control->core(), &core::Manager::set_local_address), rak::make_mem_fun(control->core(), &core::Manager::local_address)); ADD_COMMAND_STRING_TRI("proxy_address", rak::make_mem_fun(control->core(), &core::Manager::set_proxy_address), rak::make_mem_fun(control->core(), &core::Manager::proxy_address)); ADD_COMMAND_STRING_TRI("http_proxy", rak::make_mem_fun(httpStack, &core::CurlStack::set_http_proxy), rak::make_mem_fun(httpStack, &core::CurlStack::http_proxy)); + ADD_COMMAND_STRING_TRI("http_capath", rak::make_mem_fun(httpStack, &core::CurlStack::set_http_capath), rak::make_mem_fun(httpStack, &core::CurlStack::http_capath)); + ADD_COMMAND_STRING_TRI("http_cacert", rak::make_mem_fun(httpStack, &core::CurlStack::set_http_cacert), rak::make_mem_fun(httpStack, &core::CurlStack::http_cacert)); ADD_COMMAND_VALUE_TRI("send_buffer_size", rak::make_mem_fun(cm, &torrent::ConnectionManager::set_send_buffer_size), rak::make_mem_fun(cm, &torrent::ConnectionManager::send_buffer_size)); ADD_COMMAND_VALUE_TRI("receive_buffer_size", rak::make_mem_fun(cm, &torrent::ConnectionManager::set_receive_buffer_size), rak::make_mem_fun(cm, &torrent::ConnectionManager::receive_buffer_size)); @@ -261,7 +287,8 @@ 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_STRING_UN("scgi_port", rak::bind2nd(std::ptr_fun(&apply_scgi), 1)); + ADD_COMMAND_STRING_UN("scgi_local", rak::bind2nd(std::ptr_fun(&apply_scgi), 2)); 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/core/curl_stack.cc b/src/core/curl_stack.cc index ec1189d9..36acb19c 100644 --- a/src/core/curl_stack.cc +++ b/src/core/curl_stack.cc @@ -121,6 +121,12 @@ CurlStack::add_get(CurlGet* get) { if (!m_bindAddress.empty()) curl_easy_setopt(get->handle(), CURLOPT_INTERFACE, m_bindAddress.c_str()); + if (!m_httpCaPath.empty()) + curl_easy_setopt(get->handle(), CURLOPT_CAPATH, m_httpCaPath.c_str()); + + if (!m_httpCaCert.empty()) + curl_easy_setopt(get->handle(), CURLOPT_CAINFO, m_httpCaCert.c_str()); + base_type::push_back(get); if (m_active >= m_maxActive) diff --git a/src/core/curl_stack.h b/src/core/curl_stack.h index 39bb15b5..31bcb8ba 100644 --- a/src/core/curl_stack.h +++ b/src/core/curl_stack.h @@ -98,6 +98,12 @@ class CurlStack : std::deque { const std::string& bind_address() const { return m_bindAddress; } void set_bind_address(const std::string& s) { m_bindAddress = s; } + + const std::string& http_capath() const { return m_httpCaPath; } + void set_http_capath(const std::string& s) { m_httpCaPath = s; } + + const std::string& http_cacert() const { return m_httpCaCert; } + void set_http_cacert(const std::string& s) { m_httpCaCert = s; } static void global_init(); static void global_cleanup(); @@ -118,6 +124,8 @@ class CurlStack : std::deque { std::string m_userAgent; std::string m_httpProxy; std::string m_bindAddress; + std::string m_httpCaPath; + std::string m_httpCaCert; }; } diff --git a/src/rpc/scgi.cc b/src/rpc/scgi.cc index 08be8120..d7c25f7f 100644 --- a/src/rpc/scgi.cc +++ b/src/rpc/scgi.cc @@ -55,12 +55,19 @@ 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(); + control->poll()->remove_read(this); control->poll()->remove_error(this); control->poll()->close(this); get_fd().close(); get_fd().clear(); + + if (!m_path.empty()) + ::unlink(m_path.c_str()); } void @@ -90,6 +97,7 @@ SCgi::open_named(const std::string& filename) { throw torrent::resource_error("Could not open socket for listening."); open(sa, offsetof(struct sockaddr_un, sun_path) + filename.size() + 1); + m_path = filename; } void @@ -98,7 +106,7 @@ SCgi::open(void* sa, unsigned int length) { if (!get_fd().set_nonblock() || !get_fd().set_reuse_address(true) || !get_fd().bind(*reinterpret_cast(sa), length) || - !get_fd().listen(10)) + !get_fd().listen(max_tasks)) throw torrent::resource_error("Could not prepare socket for listening."); torrent::connection_manager()->inc_socket_count(); @@ -121,9 +129,9 @@ SCgi::event_read() { 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)); + SCgiTask* task = std::find_if(m_task, m_task + max_tasks, std::mem_fun_ref(&SCgiTask::is_available)); - if (task == task + 10) { + if (task == task + max_tasks) { // Ergh... just closing for now. fd.close(); continue; diff --git a/src/rpc/scgi.h b/src/rpc/scgi.h index fed996e8..07f52570 100644 --- a/src/rpc/scgi.h +++ b/src/rpc/scgi.h @@ -54,9 +54,13 @@ public: typedef rak::function2 slot_write; typedef rak::function3 slot_process; + static const int max_tasks = 10; + SCgi() {} virtual ~SCgi(); + void open(void* sa, unsigned int length); + void open_port(uint16_t port); void open_named(const std::string& filename); @@ -73,11 +77,9 @@ public: utils::SocketFd& get_fd() { return *reinterpret_cast(&m_fileDesc); } private: - void open(void* sa, unsigned int length); - std::string m_path; slot_process m_slotProcess; - SCgiTask m_task[10]; + SCgiTask m_task[max_tasks]; }; } diff --git a/src/rpc/scgi_task.cc b/src/rpc/scgi_task.cc index ea33bf9d..afd1e292 100644 --- a/src/rpc/scgi_task.cc +++ b/src/rpc/scgi_task.cc @@ -48,6 +48,12 @@ #include "globals.h" #include "scgi.h" +// Test: +// #include "core/manager.h" +// #include + +// static rak::timer scgiTimer; + namespace rpc { void @@ -60,6 +66,8 @@ SCgiTask::open(SCgi* parent, int fd) { control->poll()->open(this); control->poll()->insert_read(this); control->poll()->insert_error(this); + + scgiTimer = rak::timer::current(); } void @@ -77,6 +85,11 @@ SCgiTask::close() { delete [] m_buffer; m_buffer = NULL; + + // Test +// char buffer[512]; +// sprintf(buffer, "SCgi system call processed: %i", (int)(rak::timer::current() - scgiTimer).usec()); +// control->core()->push_log(std::string(buffer)); } void @@ -162,19 +175,18 @@ SCgiTask::event_error() { bool SCgiTask::receive_write(const char* buffer, uint32_t length) { - if (length + 44 > m_bufferSize) { + if (length + 256 > m_bufferSize) { delete [] m_buffer; - m_buffer = new char[length + 44]; + m_buffer = new char[length + 256]; } - // Try writing as much as possible from here, before copying - // anything. + // Who ever bothers to check the return value? + int headerSize = sprintf(m_buffer, "Status: 200 OK\r\nContent-Type: text/plain\r\nContent-Length: %i\r\n\r\n", length); m_position = m_buffer; - m_bufferSize = length + 44; + m_bufferSize = length + headerSize; - std::memcpy(m_buffer, "Status: 200 OK\r\nContent-Type: text/plain\r\n\r\n", 44); - std::memcpy(m_buffer + 44, buffer, length); + std::memcpy(m_buffer + headerSize, buffer, length); event_write();