From c0d9d61e3330d4f69a9547cc3d0e62970fb7427e Mon Sep 17 00:00:00 2001 From: Roland Reichwein Date: Fri, 13 Jan 2023 17:40:09 +0100 Subject: Added webapp-runner --- TODO | 1 - debian/changelog | 1 + debian/webserver.manpages | 1 + plugins/fcgi/Makefile | 8 +++- plugins/fcgi/fastcgiprocess.cpp | 84 ++++++++++++++++++++++++----------------- plugins/fcgi/fastcgiprocess.h | 3 ++ plugins/fcgi/webapp-runner.cpp | 54 ++++++++++++++++++++++++++ tests/webserverprocess.cpp | 2 +- webapp-runner.1 | 23 +++++++++++ 9 files changed, 138 insertions(+), 39 deletions(-) create mode 100644 plugins/fcgi/webapp-runner.cpp create mode 100644 webapp-runner.1 diff --git a/TODO b/TODO index 5cc50fd..2e7a58a 100644 --- a/TODO +++ b/TODO @@ -3,7 +3,6 @@ example conf files: Big file bug - dynamic plugin interface (file buffer, ...) -FastCGI from command line stats.png cgi unhandled headers git via smart http / cgi diff --git a/debian/changelog b/debian/changelog index 3f3b762..43a487f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -5,6 +5,7 @@ webserver (1.18~pre1) UNRELEASED; urgency=medium * Added example configurations * FCGI bugfix: IPv6 support * FCGI: Implemented direct application start + * Added webapp-runner for FCGI applications (replacement for spawn-fcgi) -- Roland Reichwein Sun, 08 Jan 2023 15:26:48 +0100 diff --git a/debian/webserver.manpages b/debian/webserver.manpages index 0bf93db..9d38ea1 100644 --- a/debian/webserver.manpages +++ b/debian/webserver.manpages @@ -1 +1,2 @@ webserver.1 +webapp-runner.1 diff --git a/plugins/fcgi/Makefile b/plugins/fcgi/Makefile index e878c5d..81502c4 100644 --- a/plugins/fcgi/Makefile +++ b/plugins/fcgi/Makefile @@ -27,11 +27,14 @@ PROGSRC=\ SRC=$(PROGSRC) -all: $(PROJECTNAME).so +all: $(PROJECTNAME).so webapp-runner $(PROJECTNAME).so: $(SRC:.cpp=.o) $(CXX) $(CXXFLAGS) $^ -shared $(LIBS) -o $@ +webapp-runner: webapp-runner.o fastcgiprocess.o + $(CXX) $(LDFLAGS) $^ $(LDLIBS) $(LIBS) -o $@ + %.d: %.cpp $(CXX) $(CXXFLAGS) -MM -MP -MF $@ -c $< @@ -45,13 +48,14 @@ ADD_DEP=Makefile install: mkdir -p $(DESTDIR)/usr/lib/webserver/plugins cp $(PROJECTNAME).so $(DESTDIR)/usr/lib/webserver/plugins + cp webapp-runner $(DESTDIR)/usr/bin # misc --------------------------------------------------- debs: $(DISTROS) clean: - -rm -f *.o *.so *.d + -rm -f *.o *.so *.d webapp-runner .PHONY: clean install all diff --git a/plugins/fcgi/fastcgiprocess.cpp b/plugins/fcgi/fastcgiprocess.cpp index dd51583..d43fa75 100644 --- a/plugins/fcgi/fastcgiprocess.cpp +++ b/plugins/fcgi/fastcgiprocess.cpp @@ -61,6 +61,51 @@ FastCGIProcess::~FastCGIProcess() stop(); } +void run_fcgi_app(const std::string& command, const std::string& host, unsigned short port) +{ + boost::asio::io_context ioc; + boost::asio::ip::tcp::resolver resolver(ioc); + boost::asio::ip::tcp::acceptor acceptor(ioc); + auto const results = resolver.resolve(host.c_str(), std::to_string(port).c_str()); + if (results.begin() == results.end()) + std::runtime_error("no resolve result"); + boost::asio::ip::tcp::endpoint endpoint{*results.begin()}; + acceptor.open(endpoint.protocol()); + acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + acceptor.bind(endpoint); + acceptor.listen(); + int fd{acceptor.native_handle()}; + if (fd != FCGI_LISTENSOCK_FILENO) { + close(FCGI_LISTENSOCK_FILENO); + dup2(fd, FCGI_LISTENSOCK_FILENO); + close(fd); + } + + execl(command.c_str(), command.c_str(), (const char*)nullptr); +} + +void run_fcgi_app(const std::string& command, const std::filesystem::path& socket_path) +{ + boost::asio::io_context ioc; + boost::asio::local::stream_protocol::acceptor file_acceptor(ioc); + std::error_code ec; + fs::remove(socket_path, ec); // otherwise we get: "bind: Address already in use" + + boost::asio::local::stream_protocol::endpoint endpoint(socket_path); + file_acceptor.open(endpoint.protocol()); + file_acceptor.set_option(boost::asio::local::stream_protocol::acceptor::reuse_address(true)); + file_acceptor.bind(endpoint); + file_acceptor.listen(); + int fd {file_acceptor.native_handle()}; + if (fd != FCGI_LISTENSOCK_FILENO) { + close(FCGI_LISTENSOCK_FILENO); + dup2(fd, FCGI_LISTENSOCK_FILENO); + close(fd); + } + + execl(command.c_str(), command.c_str(), (const char*)nullptr); +} + void FastCGIProcess::start() { if (m_pid != 0) @@ -72,41 +117,10 @@ void FastCGIProcess::start() if (m_pid == 0) { // child process branch try { - int fd{}; - boost::asio::io_context ioc; - boost::asio::ip::tcp::resolver resolver(ioc); - boost::asio::ip::tcp::acceptor acceptor(ioc); - boost::asio::local::stream_protocol::acceptor file_acceptor(ioc); - - if (m_socket_path.empty()) { // tcp connection - auto const results = resolver.resolve(m_host.c_str(), std::to_string(m_port).c_str()); - if (results.begin() == results.end()) - std::runtime_error("no resolve result"); - boost::asio::ip::tcp::endpoint endpoint{*results.begin()}; - acceptor.open(endpoint.protocol()); - acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); - acceptor.bind(endpoint); - acceptor.listen(); - fd = acceptor.native_handle(); - } else { // unix domain socket - std::error_code ec; - fs::remove(m_socket_path, ec); // otherwise we get: "bind: Address already in use" - - boost::asio::local::stream_protocol::endpoint endpoint(m_socket_path); - file_acceptor.open(endpoint.protocol()); - file_acceptor.set_option(boost::asio::local::stream_protocol::acceptor::reuse_address(true)); - file_acceptor.bind(endpoint); - file_acceptor.listen(); - fd = file_acceptor.native_handle(); - } - - if (fd != FCGI_LISTENSOCK_FILENO) { - close(FCGI_LISTENSOCK_FILENO); - dup2(fd, FCGI_LISTENSOCK_FILENO); - close(fd); - } - - execl(m_command.c_str(), m_command.c_str(), (const char*)nullptr); + if (m_socket_path.empty()) + run_fcgi_app(m_command, m_host, m_port); + else + run_fcgi_app(m_command, m_socket_path); } catch (const std::exception& ex) { std::cout << "FastCGI process error: " << ex.what() << std::endl; } diff --git a/plugins/fcgi/fastcgiprocess.h b/plugins/fcgi/fastcgiprocess.h index 07b6539..18a5d5b 100644 --- a/plugins/fcgi/fastcgiprocess.h +++ b/plugins/fcgi/fastcgiprocess.h @@ -10,6 +10,9 @@ #include #include +void run_fcgi_app(const std::string& command, const std::string& host, unsigned short port); +void run_fcgi_app(const std::string& command, const std::filesystem::path& socket_path); + class FastCGIProcess { public: diff --git a/plugins/fcgi/webapp-runner.cpp b/plugins/fcgi/webapp-runner.cpp new file mode 100644 index 0000000..64268f3 --- /dev/null +++ b/plugins/fcgi/webapp-runner.cpp @@ -0,0 +1,54 @@ +#include "plugins/fcgi/fastcgiprocess.h" + +#include +#include + +namespace { + void usage() + { + std::cout << R"(Usage: + webapp-runner + + or: + + webapp-runner + +Description: + +webapp-runner starts the specified executable FastCGI application and connects +it to the specified unix domain socket or local host:port address. Addresses +can be specified in IPv4 or IPv6 format. + +Examples: + +webapp-runner ::1:6543 ./fcgi1 +webapp-runner fcgi-socket0 ./fcgi1 +)" << std::endl; + } +} // namespace + +int main(int argc, char* argv[]) +{ + try { + if (argc == 3) { + std::string address{argv[1]}; + std::string command{argv[2]}; + + if (auto pos{address.find_last_of(':')}; pos != std::string::npos) { + std::string host{address.substr(0, pos)}; + unsigned short port{static_cast(std::stoul(address.substr(pos + 1)))}; + run_fcgi_app(command, host, port); + } else { + run_fcgi_app(command, address); + } + } else { + usage(); + exit(0); + } + } catch (const std::exception& ex) { + std::cout << "webapp-runner caught error: " << ex.what() << std::endl; + } + + return 0; +} + diff --git a/tests/webserverprocess.cpp b/tests/webserverprocess.cpp index edafaaa..f9ecdd3 100644 --- a/tests/webserverprocess.cpp +++ b/tests/webserverprocess.cpp @@ -194,7 +194,7 @@ void WebserverProcess::start() // wait for server to start up if (int port{port_from_config(m_config)}; port >= 0) Process::wait_for_pid_listening_on(m_pid, port); - std::this_thread::sleep_for(std::chrono::milliseconds(10)); + std::this_thread::sleep_for(std::chrono::milliseconds(20)); } void WebserverProcess::stop() diff --git a/webapp-runner.1 b/webapp-runner.1 new file mode 100644 index 0000000..724cff5 --- /dev/null +++ b/webapp-runner.1 @@ -0,0 +1,23 @@ +.TH webapp-runner 1 "12 Jan 2023" "Version 1.18" "Webserver Manual" + +.SH NAME +webapp-runner \- A FastCGI application runner + +.SH SYNOPSIS +webapp-runner + +webapp-runner + +.SH DESCRIPTION +.B webapp-runner +starts the specified executable FastCGI application and connects +it to the specified unix domain socket or local host:port address. Addresses +can be specified in IPv4 or IPv6 format. + +.SH EXAMPLES +webapp-runner ::1:6543 ./fcgi1 + +webapp-runner fcgi-socket0 ./fcgi1 + +.SH AUTHOR +Roland Reichwein -- cgit v1.2.3