#include "conf.h"
#include "logger.h"
#include "responder.h"
#define IDENT_FMT "pyfcgi[%d]"
#define MAX_REQS 1024
#define EARLY_ERR(err_str) write(2, err_str, strlen(err_str))
extern pyfcgi_conf_t PyFCGI_conf;
pid_t pool_handler_pid;
void sighandler(int signum)
{
int ret;
if(signum == SIGINT)
{
pyfcgi_log(LOG_INFO,
"Master process received ctrl+c, exiting...");
}
else
{
pyfcgi_log(LOG_INFO,
"Master process received signal %s(%d), exiting...",
strsignal(signum), signum);
}
if(pool_handler_pid)
{
kill(pool_handler_pid, SIGTERM);
waitpid(pool_handler_pid, &ret, 0);
}
pyfcgi_log(LOG_INFO,
"Master process exiting.");
exit(0);
}
int main(int argc, char **argv)
{
int child_ret;
unsigned int emerg_sleep = 3;
struct sigaction act;
act.sa_handler = sighandler;
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask, SIGTERM);
act.sa_flags = 0;
act.sa_restorer = NULL;
if(sigaction(SIGINT, &act, NULL))
{
perror("Sigaction error");
exit(4);
}
pool_handler_pid = 0;
default_conf();
pyfcgi_logger_init();
pyfcgi_logger_set_ident("pyfcgi(main)");
if(parse_args(argc, argv))
{
return 1;
}
pyfcgi_log(LOG_INFO, "New server started");
while(1)
{
pool_handler_pid = fork();
if(pool_handler_pid == -1)
{
// TODO : Error
pyfcgi_log(LOG_EMERG, "Failed to fork : '%s' sleeping %ds", strerror(errno), emerg_sleep);
sleep(emerg_sleep);
continue;
}
else if(!pool_handler_pid)
{
responder_loop();
exit((unsigned char)-1);
}
waitpid(pool_handler_pid, &child_ret, 0);
pool_handler_pid = 0;
if(child_ret)
{
pyfcgi_log(LOG_ERR, "Responder loop function exits with error code '%d'",
WEXITSTATUS(child_ret));
if(WIFSIGNALED(child_ret))
{
pyfcgi_log(LOG_ERR, "Responder loop function terminated by sig '%d'",
WTERMSIG(child_ret));
}
}
else
{
pyfcgi_log(LOG_NOTICE, "Restarting main process after %d requests", MAX_REQS);
}
}
closelog();
}
/**@mainpage PyFCGI
* @section main_what What is PyFCGI ?
* PyFCGI is a simple python3 fastcgi runner.
*
* Usage : Usage : spawn-fcgi [OPTIONS] -- pyfcgi -e PYMODULE [-E PYFUN] [OPTIONS]
*
* 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 arguments
* to pyfcgi using -- argument of spawnn-fcgi
*
* When called this function will have to send valid CGI data to the webserver
* using sys.stdin (the print() function for exemple) like :
*Content-type: text/html\\r\\n\\r\\nHello world !\\n
*
* 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 pyfcgi_log() to log stuff using a pyfcgi ident.
* PyFCGI logs can be filtered using /etc/rsyslog.d/pyfcgi.conf :
*
if ($programname contains 'pyfcgi') then {
-/var/log/pyfcgi/pyfcgi.log
stop
}
*
* @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 ?)
*/