#include "fastcgiprocess.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "helper.h" using namespace std::string_literals; namespace fs = std::filesystem; namespace pt = boost::property_tree; using namespace boost::unit_test; using namespace Reichwein; #define FCGI_LISTENSOCK_FILENO 0 FastCGIProcess::FastCGIProcess(const std::filesystem::path& path, const std::string& host, unsigned short port): m_pid{}, m_command{path.generic_string()}, m_host{host}, m_port{port} { start(); } FastCGIProcess::~FastCGIProcess() { stop(); } void FastCGIProcess::start() { if (m_pid != 0) throw std::runtime_error("Process already running, so it can't be started"); m_pid = fork(); if (m_pid < 0) throw std::runtime_error("Fork unsuccessful."); if (m_pid == 0) { // child process branch try { boost::asio::io_context ioc; boost::asio::ip::tcp::resolver resolver(ioc); 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()}; boost::asio::ip::tcp::acceptor acceptor(ioc); 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(m_command.c_str(), m_command.c_str(), (const char*)nullptr); } catch (const std::exception& ex) { std::cout << "FastCGI process error: " << ex.what() << std::endl; } exit(0); } // wait for server to start up wait_for_pid_listening_on(m_pid, m_port); std::this_thread::sleep_for(std::chrono::milliseconds(10)); } void FastCGIProcess::stop() { if (m_pid == 0) throw std::runtime_error("Process not running, so it can't be stopped"); if (kill(m_pid, SIGTERM) != 0) throw std::runtime_error("Unable to kill process"); if (int result = waitpid(m_pid, NULL, 0); result != m_pid) throw std::runtime_error("waitpid returned "s + std::to_string(result)); m_pid = 0; } bool FastCGIProcess::is_running() { if (m_pid == 0) return false; return Reichwein::Process::is_running(m_pid); }