123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169 |
- /*
- * Copyright (C) 2019 Weber Yann
- *
- * This file is part of PyFCGI.
- *
- * PyFCGI is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * any later version.
- *
- * PyFCGI is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with PyFCGI. If not, see <http://www.gnu.org/licenses/>.
- */
-
- /**@defgroup processes Process organisation of PyFCGI
- *
- * PyFCGI is organised in three layer :
- * A @ref main_proc : simple, that keep running and spawn a
- * @ref work_master_proc . This process handles @ref worker_process creation
- * and try to maintain a pool able to reply efficiently to CGI requests.
- */
- /**@defgroup main_proc Main process
- * @brief The main process in the @ref main() function
- * @ingroup processes
- */
-
- #include <fcgi_stdio.h> /* fcgi library; put it first*/
-
- #include <unistd.h>
- #include <stdlib.h>
- #include <syslog.h>
- #include <string.h>
- #include <errno.h>
- #include <sys/types.h>
- #include <sys/wait.h>
-
- #include "responder.h"
-
- #define IDENT_FMT "pyfcgi[%d]"
- #define MAX_REQS 50
-
- #define EARLY_ERR(err_str) write(2, err_str, strlen(err_str))
-
- int main(int argc, char **argv)
- {
- char *ident, *py_entrypoint;
- size_t ident_len;
- pid_t child;
- int child_ret;
- unsigned int emerg_sleep = 3;
-
- py_entrypoint = getenv("PY_ENTRYPOINT");
- if(argc > 1 || !py_entrypoint)
- {
- EARLY_ERR("Usage : PY_ENTRYPOINT='PATH.py' spawn-fcgi [OPTIONS] ");
- EARLY_ERR(argv[0]);
- EARLY_ERR("\n");
- return 1;
- }
-
- ident_len = snprintf(NULL, 0, IDENT_FMT, getpid());
- ident_len++;
- ident = malloc(sizeof(char)*ident_len);
- if(ident == NULL)
- {
- EARLY_ERR("Unable to allocate memory for ident string...\n");
- return -1;
- }
-
- snprintf(ident, ident_len, IDENT_FMT, getpid());
-
- openlog(ident, LOG_CONS | LOG_PERROR, LOG_DAEMON | LOG_USER);
- syslog(LOG_INFO, "New server started");
-
- while(1)
- {
- child = fork();
- if(child == -1)
- {
- // TODO : Error
- syslog(LOG_EMERG, "Failed to fork : '%s' sleeping %ds", strerror(errno), emerg_sleep);
- sleep(emerg_sleep);
- continue;
- }
- else if(!child)
- {
- responder_loop(py_entrypoint, MAX_REQS, 1, 30);
- exit((unsigned char)-1);
- }
- waitpid(child, &child_ret, 0);
- if(child_ret)
- {
- syslog(LOG_ERR, "Responder loop function exits with error code '%d'",
- WEXITSTATUS(child_ret));
- }
- else
- {
- syslog(LOG_NOTICE, "Restarting main process after %d requests", MAX_REQS);
- }
- }
-
- closelog();
- free(ident);
- }
-
- /**@mainpage PyFCGI
- * @section main_what What is PyFCGI ?
- * PyFCGI is a simple python3 fastcgi runner.
- *
- * Usage : *PY_ENTRYPOINT='foo' spawn-fcgi -d . -n src/pyfcgi -p 9000 -a 127.0.0.1*
- *
- * To run foo.entrypoint() python function.
- *
- * @subsection main_how_use How to use it ?
- *
- * @warning For the moment PyFCGI is under heavy developpement and in early
- * stage. Everything will change ;o)
- *
- * PyFCGI should be runned with spawn-fcgi (or something similar), allowing
- * to configure & forward environnement variables to libFCGI.
- *
- * For the moment no configuration files exists. You have to pass a
- * PY_ENTRYPOINT containing an importable python module containing an
- * entrypoint() (no arguments for the moment) function.
- *
- * When called this function will have to send valid CGI data to the webserver
- * using sys.stdin (the print() function for exemple) like :
- *<code>Content-type: text/html\\r\\n\\r\\nHello world !\\n</code>
- *
- * The function will have access to updated CGI os.environ containing
- * all informations about a request
- *
- * @subsubsection main_how_use_syslog Logging, using syslog
- *
- * Right now PyFCGI uses syslog() to log stuff using a pyfcgi ident.
- * PyFCGI logs can be filtered using /etc/rsyslog.d/pyfcgi.conf :
- *
- <pre>
- if ($programname contains 'pyfcgi') then {
- -/var/log/pyfcgi/pyfcgi.log
- stop
- }
- </pre>
- *
- * @subsubsection main_how_use_hardcode Hardcoded stuffs
- *
- * Right now there is a lot of hardcodd stuff. Fortunatly a vast majority
- * is in @ref main.c like the minimum and maximum number of workers, or
- * the number of requests before a worker restart. Some timers and stuff
- * are harcoded but should not in @ref pyworker.c & @ref responder.c
- *
- * @subsection main_how_works How it works ?
- *
- * - @ref processes
- * - @ref main_proc
- * - @ref work_master_proc
- * - @ref worker_process
- *
- * @subsection main_how_todo TODO
- * @todo Add another logging facility
- * @todo Add a configuration mecanism
- * @todo Implement a watchdog (request too long, or too much memory ?)
- */
|