From e36e38e7572edec6a504a258eb4f3ae0b24af8ab Mon Sep 17 00:00:00 2001 From: Taras Taranenko Date: Thu, 24 Mar 2016 12:30:51 +0100 Subject: [PATCH 1/4] added timeout parameter to fcgiwrap --- fcgiwrap.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 2 deletions(-) diff --git a/fcgiwrap.c b/fcgiwrap.c index b44d8aa..671b8af 100644 --- a/fcgiwrap.c +++ b/fcgiwrap.c @@ -84,9 +84,15 @@ static const char * blacklisted_env_vars[] = { static int stderr_to_fastcgi = 0; - +#define TIMEOUT_MAX 3600 /* an hour timeout */ #define FCGI_BUF_SIZE 4096 +/* timeout related data */ +static int timed_out; +static int term_signal = SIGTERM; /* same default as kill command. */ +static int monitored_pid; +static int timeout; + static int write_all(int fd, char *buf, size_t size) { size_t nleft = size; @@ -514,6 +520,49 @@ static void cgi_error(const char *message, const char *reason, const char *filen _exit(99); } +static void unblock_signal (int sig) +{ + sigset_t unblock_set; + sigemptyset (&unblock_set); + sigaddset (&unblock_set, sig); + sigprocmask (SIG_UNBLOCK, &unblock_set, NULL); +} + +/* Start the timeout after which we'll receive a SIGALRM. + '0' means don't timeout. */ +static void settimeout (int duration) +{ + /* We configure timers below so that SIGALRM is sent on expiry. + Therefore ensure we don't inherit a mask blocking SIGALRM. */ + unblock_signal (SIGALRM); + + if (TIMEOUT_MAX <= duration) + timeout = TIMEOUT_MAX; + else { + timeout = duration; + } + alarm (timeout); +} + +static void cleanup (int sig) +{ + if (sig == SIGALRM) + { + timed_out = 1; + sig = term_signal; + } + if (monitored_pid) + { + /* Send the signal directly to the monitored child */ + kill (monitored_pid, sig); + //FCGI_puts("Status: 504 Gateway Timeout\nContent-type: text/plain\n"); + //FCGI_puts("CGI script execution timeout"); + } + else /* we're the child or the child is not exec'd yet. */ + _exit (128 + sig); +} + + static void handle_fcgi_request(void) { int pipe_in[2]; @@ -551,6 +600,7 @@ static void handle_fcgi_request(void) signal(SIGCHLD, SIG_DFL); signal(SIGPIPE, SIG_DFL); + signal(SIGALRM, SIG_DFL); filename = get_cgi_filename(); inherit_environment(); @@ -591,6 +641,10 @@ static void handle_fcgi_request(void) fc.reply_state = REPLY_STATE_INIT; fc.cgi_pid = pid; + if (timeout>0) { + monitored_pid = pid; + settimeout (timeout); + } fcgi_pass(&fc); } return; @@ -626,13 +680,23 @@ static void fcgiwrap_main(void) signal(SIGCHLD, SIG_IGN); signal(SIGPIPE, SIG_IGN); + sigint_received = 0; + // Use sigaction for SIGINT so we can avoid SA_RESTART and actually react a.sa_handler = sigint_handler; a.sa_flags = 0; + sigemptyset( &a.sa_mask ); sigaction( SIGINT, &a, NULL ); sigaction( SIGTERM, &a, NULL ); + struct sigaction sa; + sigemptyset (&sa.sa_mask); /* Allow concurrent calls to handler */ + sa.sa_handler = cleanup; + sa.sa_flags = SA_RESTART; /* Restart syscalls if possible, as that's + more likely to work cleanly. */ + sigaction (SIGALRM, &sa, NULL); /* our timeout. */ + inherited_environ = environ; while (FCGI_Accept() >= 0 && !sigint_received) { @@ -805,8 +869,9 @@ int main(int argc, char **argv) char *socket_url = NULL; int fd = 0; int c; + timeout = 0; - while ((c = getopt(argc, argv, "c:hfs:p:")) != -1) { + while ((c = getopt(argc, argv, "c:t:hfs:p:")) != -1) { switch (c) { case 'f': stderr_to_fastcgi++; @@ -817,6 +882,7 @@ int main(int argc, char **argv) "Options are:\n" " -f\t\t\tSend CGI's stderr over FastCGI\n" " -c \t\tNumber of processes to prefork\n" + " -t \t\tNumber of seconds after those CGI process would be killed\n" " -s \tSocket to bind to (say -s help for help)\n" " -h\t\t\tShow this help message and exit\n" " -p \t\tRestrict execution to this script. (repeated options will be merged)\n" @@ -828,6 +894,9 @@ int main(int argc, char **argv) case 'c': nchildren = atoi(optarg); break; + case 't': + timeout = atoi(optarg); + break; case 's': socket_url = strdup(optarg); break; From 2efccfdf1df2eca2e7e5eec8b6cc74f9ed0b2574 Mon Sep 17 00:00:00 2001 From: Taras Taranenko Date: Thu, 24 Mar 2016 12:45:42 +0100 Subject: [PATCH 2/4] added timeout parameter to fcgiwrap, optimization --- fcgiwrap.c | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/fcgiwrap.c b/fcgiwrap.c index 671b8af..570b4f1 100644 --- a/fcgiwrap.c +++ b/fcgiwrap.c @@ -533,7 +533,7 @@ static void unblock_signal (int sig) static void settimeout (int duration) { /* We configure timers below so that SIGALRM is sent on expiry. - Therefore ensure we don't inherit a mask blocking SIGALRM. */ + Therefore ensure we don't inherit a mask blocking SIGALRM. */ unblock_signal (SIGALRM); if (TIMEOUT_MAX <= duration) @@ -548,21 +548,15 @@ static void cleanup (int sig) { if (sig == SIGALRM) { - timed_out = 1; sig = term_signal; + if (monitored_pid) + { + /* Send the signal directly to the monitored child */ + kill (monitored_pid, sig); + } } - if (monitored_pid) - { - /* Send the signal directly to the monitored child */ - kill (monitored_pid, sig); - //FCGI_puts("Status: 504 Gateway Timeout\nContent-type: text/plain\n"); - //FCGI_puts("CGI script execution timeout"); - } - else /* we're the child or the child is not exec'd yet. */ - _exit (128 + sig); } - static void handle_fcgi_request(void) { int pipe_in[2]; @@ -579,6 +573,8 @@ static void handle_fcgi_request(void) if (pipe(pipe_out) < 0) goto err_pipeout; if (pipe(pipe_err) < 0) goto err_pipeerr; + monitored_pid = 0; + switch((pid = fork())) { case -1: goto err_fork; From 32004d88a0438218e02445d901cc32b7c934271b Mon Sep 17 00:00:00 2001 From: Taras Taranenko Date: Thu, 24 Mar 2016 13:08:30 +0100 Subject: [PATCH 3/4] added timeout parameter to fcgiwrap, optimization 2 --- fcgiwrap.c | 1 - 1 file changed, 1 deletion(-) diff --git a/fcgiwrap.c b/fcgiwrap.c index 570b4f1..f160a1d 100644 --- a/fcgiwrap.c +++ b/fcgiwrap.c @@ -88,7 +88,6 @@ static int stderr_to_fastcgi = 0; #define FCGI_BUF_SIZE 4096 /* timeout related data */ -static int timed_out; static int term_signal = SIGTERM; /* same default as kill command. */ static int monitored_pid; static int timeout; From 7089c13e31217ac63e30366f0b3bd49d5834a2a8 Mon Sep 17 00:00:00 2001 From: Taras Taranenko Date: Thu, 24 Mar 2016 13:26:47 +0100 Subject: [PATCH 4/4] added timeout parameter to fcgiwrap, final --- fcgiwrap.c | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/fcgiwrap.c b/fcgiwrap.c index f160a1d..1165f23 100644 --- a/fcgiwrap.c +++ b/fcgiwrap.c @@ -531,29 +531,28 @@ static void unblock_signal (int sig) '0' means don't timeout. */ static void settimeout (int duration) { - /* We configure timers below so that SIGALRM is sent on expiry. - Therefore ensure we don't inherit a mask blocking SIGALRM. */ - unblock_signal (SIGALRM); - - if (TIMEOUT_MAX <= duration) - timeout = TIMEOUT_MAX; - else { - timeout = duration; - } - alarm (timeout); + /* We configure timers below so that SIGALRM is sent on expiry. + Therefore ensure we don't inherit a mask blocking SIGALRM. */ + unblock_signal (SIGALRM); + + if (TIMEOUT_MAX <= duration) + timeout = TIMEOUT_MAX; + else + timeout = duration; + + alarm(timeout); } static void cleanup (int sig) { if (sig == SIGALRM) - { - sig = term_signal; - if (monitored_pid) - { + { + sig = term_signal; + if (monitored_pid) { /* Send the signal directly to the monitored child */ - kill (monitored_pid, sig); - } - } + kill (monitored_pid, sig); + } + } } static void handle_fcgi_request(void)