// Standard C++ #include #include #include #include #include #include #include #include #include #include #include #include // FastCGI #include using namespace std; namespace { struct Configuration { int value; string listen_address; }; struct RequestError : runtime_error { RequestError(int status, const string& meldung) : runtime_error(meldung) , status(status) { } int status; }; atomic_bool quit{ false }; atomic_bool reload{ false }; void handler(int signal) { if ( signal == SIGINT || signal == SIGTERM ) { quit = true; } else if ( signal == SIGHUP ) { reload = true; } } void init_signal_handler() { struct sigaction sa; memset(&sa, 0, sizeof sa); sa.sa_handler = handler; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); sigaction(SIGINT, &sa, NULL); sigaction(SIGTERM, &sa, NULL); sigaction(SIGHUP, &sa, NULL); signal(SIGPIPE, SIG_IGN); } bool load_configuration(Configuration& configuration) { cerr << "Load configuration ...\n"; configuration.value = 1; configuration.listen_address = "127.0.0.1:5000"; return true; } void handle_request(char** env, const Configuration&, string_view body, ostream& out) { const char* methode = FCGX_GetParam("REQUEST_METHOD", env); out << "Content-Type: text/html; charset=utf-8\r\n\r\n"; out << "

Verbindung erfolgreich verarbeitet!

"; out << "

Methode: " << (methode ? methode : "?") << ", Body: " << body.size() << " Bytes

"; } void send_error(const FCGX_Request& request, int status, const char* meldung) { FCGX_FPrintF(request.out, "Status: %d\r\n", status); FCGX_FPrintF(request.out, "Content-Type: text/plain; charset=utf-8\r\n\r\n"); FCGX_FPrintF(request.out, "%s\n", meldung); } string read_request_body(const FCGX_Request& request) { string body; char buffer[8192]; int gelesen; while ( (gelesen = FCGX_GetStr(buffer, sizeof buffer, request.in)) > 0 ) { body.append(buffer, gelesen); } return body; } } // namespace int main() { FCGX_Init(); Configuration configuration{}; if ( !load_configuration(configuration) ) { cerr << "Die Konfiguration konnte nicht geladen werden.\n"; return EXIT_FAILURE; } auto socket = FCGX_OpenSocket(configuration.listen_address.c_str(), 20); if ( socket == -1 ) { cerr << "Fehler beim Erstellen des Listen-Sockets...\n"; return EXIT_FAILURE; } FCGX_Request request; if ( FCGX_InitRequest(&request, socket, FCGI_FAIL_ACCEPT_ON_INTR) != 0 ) { cerr << "Fehler beim Initialisieren...\n"; return EXIT_FAILURE; } init_signal_handler(); cout << "Handle Requests...\n"; while ( !quit ) { if ( reload.exchange(false) ) { Configuration new_configuration{}; if ( load_configuration(new_configuration) ) { if ( new_configuration.listen_address != configuration.listen_address ) { cerr << "Listen-Adresse geaendert, wirksam erst nach Neustart.\n"; } configuration = std::move(new_configuration); } else { cerr << "Neue Konfiguration nicht lesbar, die bisherige bleibt in Kraft.\n"; } } if ( FCGX_Accept_r(&request) < 0 ) { if ( errno != EINTR ) { cerr << "Fehler beim Annehmen der Verbindung: " << strerror(errno) << '\n'; break; } continue; } try { const string body = read_request_body(request); ostringstream response; handle_request(request.envp, configuration, body, response); const string_view text = response.view(); FCGX_PutStr(text.data(), static_cast(text.size()), request.out); } catch ( const RequestError& e ) { FCGX_FPrintF(request.err, "Anfrage abgebrochen (%d): %s\n", e.status, e.what()); send_error(request, e.status, e.what()); } catch ( const exception& e ) { FCGX_FPrintF(request.err, "Fehler beim Verarbeiten der Anfrage: %s\n", e.what()); send_error(request, 500, "Die Anfrage konnte nicht verarbeitet werden."); } FCGX_Finish_r(&request); } cout << "shutdown...\n"; }