diff --git a/src/command_network.cc b/src/command_network.cc index cbb70e3d..e8f816b0 100644 --- a/src/command_network.cc +++ b/src/command_network.cc @@ -38,6 +38,7 @@ #include #include +#include #include #include #include @@ -184,7 +185,25 @@ apply_scgi(const std::string& arg) { // Fix this... control->set_scgi(new rpc::SCgi); - control->scgi()->open(5000); + + try { + int port; + char dummy; + + 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); + + } else { + control->scgi()->open_named(rak::path_expand(arg)); + } + + } catch (torrent::local_error& e) { + throw torrent::input_error(e.what()); + } + control->scgi()->set_slot_process(rak::mem_fn(control->xmlrpc(), &rpc::XmlRpc::process)); } diff --git a/src/rpc/scgi.cc b/src/rpc/scgi.cc index caac900c..08be8120 100644 --- a/src/rpc/scgi.cc +++ b/src/rpc/scgi.cc @@ -36,10 +36,11 @@ #include "config.h" +#include +#include #include #include #include -#include #include #include "utils/socket_fd.h" @@ -62,21 +63,43 @@ SCgi::~SCgi() { get_fd().clear(); } -bool -SCgi::open(uint16_t port) { +void +SCgi::open_port(uint16_t port) { + rak::socket_address sa; + sa.sa_inet()->clear(); + sa.sa_inet()->set_port(port); + if (!get_fd().open_stream()) - throw torrent::resource_error("Could not allocate socket for listening."); + throw torrent::resource_error("Could not open socket for listening."); + open(sa.c_sockaddr(), sa.length()); +} + +void +SCgi::open_named(const std::string& filename) { + if (filename.empty() || filename.size() > 4096) + throw torrent::resource_error("Invalid filename length."); + + char buffer[sizeof(sockaddr_un) + filename.size()]; + sockaddr_un* sa = reinterpret_cast(buffer); + + sa->sun_family = AF_LOCAL; + 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."); + + open(sa, offsetof(struct sockaddr_un, sun_path) + filename.size() + 1); +} + +void +SCgi::open(void* sa, unsigned int length) { 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().bind(*reinterpret_cast(sa), length) || !get_fd().listen(10)) - throw torrent::resource_error("Could not allocate socket for listening."); + throw torrent::resource_error("Could not prepare socket for listening."); torrent::connection_manager()->inc_socket_count(); @@ -90,8 +113,6 @@ SCgi::open(uint16_t port) { throw e; } - - return true; } void diff --git a/src/rpc/scgi.h b/src/rpc/scgi.h index 708f014a..fed996e8 100644 --- a/src/rpc/scgi.h +++ b/src/rpc/scgi.h @@ -57,7 +57,8 @@ public: SCgi() {} virtual ~SCgi(); - bool open(uint16_t port); + void open_port(uint16_t port); + void open_named(const std::string& filename); const std::string path() const { return m_path; } @@ -72,10 +73,10 @@ 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]; }; diff --git a/src/rpc/scgi_task.cc b/src/rpc/scgi_task.cc index 03942d4d..ea33bf9d 100644 --- a/src/rpc/scgi_task.cc +++ b/src/rpc/scgi_task.cc @@ -96,7 +96,10 @@ SCgiTask::event_read() { // Don't bother caching the parsed values, as we're likely to // receive all the data we need the first time. char* current; + char* contentPos; + int headerSize = strtol(m_buffer, ¤t, 0); + int contentSize; if (current == m_buffer || current == m_position) // Need to validate the header size. @@ -111,8 +114,7 @@ SCgiTask::event_read() { if (std::memcmp(current, "CONTENT_LENGTH", 15) != 0) goto event_read_failed; - char* contentPos; - int contentSize = strtol(current + 15, &contentPos, 0); + contentSize = strtol(current + 15, &contentPos, 0); if (*contentPos != '\0' || contentSize <= 0) goto event_read_failed; diff --git a/src/utils/socket_fd.cc b/src/utils/socket_fd.cc index 10f466bb..8319a345 100644 --- a/src/utils/socket_fd.cc +++ b/src/utils/socket_fd.cc @@ -120,6 +120,11 @@ SocketFd::open_datagram() { return (m_fd = socket(PF_INET, SOCK_DGRAM, 0)) != -1; } +bool +SocketFd::open_local() { + return (m_fd = socket(PF_LOCAL, SOCK_DGRAM, 0)) != -1; +} + void SocketFd::close() { if (::close(m_fd) && errno == EBADF) @@ -133,6 +138,13 @@ SocketFd::bind(const rak::socket_address& sa) { return !::bind(m_fd, sa.c_sockaddr(), sa.length()); } +bool +SocketFd::bind(const rak::socket_address& sa, unsigned int length) { + check_valid(); + + return !::bind(m_fd, sa.c_sockaddr(), length); +} + bool SocketFd::connect(const rak::socket_address& sa) { check_valid(); diff --git a/src/utils/socket_fd.h b/src/utils/socket_fd.h index a4d9549b..2d72336f 100644 --- a/src/utils/socket_fd.h +++ b/src/utils/socket_fd.h @@ -69,11 +69,13 @@ public: bool open_stream(); bool open_datagram(); + bool open_local(); void close(); void clear() { m_fd = -1; } bool bind(const rak::socket_address& sa); + bool bind(const rak::socket_address& sa, unsigned int length); bool connect(const rak::socket_address& sa); bool listen(int size);