diff options
Diffstat (limited to 'plugins')
| -rw-r--r-- | plugins/fcgi/Makefile | 8 | ||||
| -rw-r--r-- | plugins/fcgi/fastcgiprocess.cpp | 84 | ||||
| -rw-r--r-- | plugins/fcgi/fastcgiprocess.h | 3 | ||||
| -rw-r--r-- | plugins/fcgi/webapp-runner.cpp | 54 | 
4 files changed, 112 insertions, 37 deletions
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 <sys/mman.h>  #include <sys/types.h> +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 <iostream> +#include <string> + +namespace { + void usage() + { +  std::cout << R"(Usage: +        webapp-runner <host:port> <executable-command> + +          or: + +        webapp-runner <unix-domain-socket> <executable-command> + +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<unsigned short>(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; +} +  | 
