From 3acd1bf80d742120b74498ff784a2988c4ecf82d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20B=C3=BChler?= Date: Wed, 18 Feb 2009 16:14:11 +0000 Subject: [PATCH] Only try to connect to unix socket (not tcp) before spawning (fixes again #1575) git-svn-id: svn://svn.lighttpd.net/spawn-fcgi/trunk@11 4a9f3682-ca7b-49a8-9a55-ba4640e46f83 --- NEWS | 3 + src/spawn-fcgi.c | 249 +++++++++++++++++++++++++---------------------- 2 files changed, 133 insertions(+), 119 deletions(-) diff --git a/NEWS b/NEWS index ebe2215..314cd4b 100644 --- a/NEWS +++ b/NEWS @@ -6,3 +6,6 @@ NEWS - 1.6.0 - * Separated spawn-fcgi from lighttpd + * Remove limits für php children; per default the PHP_FCGI_CHILDREN var is not changed (php defaults to no children, one worker) + * Modified the log messages format (more details on errors, no source line) + * Only try to connect to unix socket (not tcp) before spawning (fixes again #1575) diff --git a/src/spawn-fcgi.c b/src/spawn-fcgi.c index c2c6488..1dd61f5 100644 --- a/src/spawn-fcgi.c +++ b/src/spawn-fcgi.c @@ -69,6 +69,9 @@ static int fcgi_spawn_connection(char *appPath, char **appArgv, char *addr, unsi socklen_t servlen; + pid_t child; + int val; + if (unixsocket) { memset(&fcgi_addr_un, 0, sizeof(fcgi_addr_un)); @@ -83,6 +86,30 @@ static int fcgi_spawn_connection(char *appPath, char **appArgv, char *addr, unsi #endif socket_type = AF_UNIX; fcgi_addr = (struct sockaddr *) &fcgi_addr_un; + + /* check if some backend is listening on the socket + * as if we delete the socket-file and rebind there will be no "socket already in use" error + */ + if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { + fprintf(stderr, "spawn-fcgi: couldn't create socket: %s\n", strerror(errno)); + return -1; + } + + if (-1 != connect(fcgi_fd, fcgi_addr, servlen)) { + switch (errno) { + case EADDRINUSE: + fprintf(stderr, "spawn-fcgi: socket is already in use, can't spawn\n"); + break; + default: + fprintf(stderr, "spawn-fcgi: connect failed: %s\n", strerror(errno)); + break; + } + return -1; + } + + /* cleanup previous socket if it exists */ + unlink(unixsocket); + close(fcgi_fd); } else { memset(&fcgi_addr_in, 0, sizeof(fcgi_addr_in)); fcgi_addr_in.sin_family = AF_INET; @@ -98,159 +125,141 @@ static int fcgi_spawn_connection(char *appPath, char **appArgv, char *addr, unsi fcgi_addr = (struct sockaddr *) &fcgi_addr_in; } + if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { - fprintf(stderr, "spawn-fcgi: couldn't create socket: %s", strerror(errno)); + fprintf(stderr, "spawn-fcgi: couldn't create socket: %s\n", strerror(errno)); return -1; } - if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) { - /* server is not up, spawn in */ - pid_t child; - int val; + val = 1; + if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) { + fprintf(stderr, "spawn-fcgi: couldn't set SO_REUSEADDR: %s\n", strerror(errno)); + return -1; + } - if (unixsocket) unlink(unixsocket); + if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) { + fprintf(stderr, "spawn-fcgi: bind failed: %s\n", strerror(errno)); + return -1; + } - close(fcgi_fd); + if (-1 == listen(fcgi_fd, 1024)) { + fprintf(stderr, "spawn-fcgi: listen failed: %s\n", strerror(errno)); + return -1; + } - /* reopen socket */ - if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) { - fprintf(stderr, "spawn-fcgi: couldn't create socket: %s", strerror(errno)); - return -1; - } + while (fork_count-- > 0) { - val = 1; - if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) { - fprintf(stderr, "spawn-fcgi: couldn't set SO_REUSEADDR: %s", strerror(errno)); - return -1; + if (!nofork) { + child = fork(); + } else { + child = 0; } - /* create socket */ - if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) { - fprintf(stderr, "spawn-fcgi: bind failed: %s", strerror(errno)); - return -1; - } + switch (child) { + case 0: { + char cgi_childs[64]; + int max_fd = 0; - if (-1 == listen(fcgi_fd, 1024)) { - fprintf(stderr, "spawn-fcgi: listen failed: %s", strerror(errno)); - return -1; - } + int i = 0; - while (fork_count-- > 0) { + /* loose control terminal */ + setsid(); - if (!nofork) { - child = fork(); - } else { - child = 0; + if (child_count >= 0) { + snprintf(cgi_childs, sizeof(cgi_childs), "PHP_FCGI_CHILDREN=%d", child_count); + putenv(cgi_childs); } - switch (child) { - case 0: { - char cgi_childs[64]; - int max_fd = 0; - - int i = 0; - - /* loose control terminal */ - setsid(); - - if (child_count >= 0) { - snprintf(cgi_childs, sizeof(cgi_childs), "PHP_FCGI_CHILDREN=%d", child_count); - putenv(cgi_childs); - } - - if(fcgi_fd != FCGI_LISTENSOCK_FILENO) { - close(FCGI_LISTENSOCK_FILENO); - dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO); - close(fcgi_fd); - } - - max_fd = open("/dev/null", O_RDWR); - close(STDERR_FILENO); - dup2(max_fd, STDERR_FILENO); - close(max_fd); - - max_fd = open("/dev/null", O_RDWR); - close(STDOUT_FILENO); - dup2(max_fd, STDOUT_FILENO); - close(max_fd); + if(fcgi_fd != FCGI_LISTENSOCK_FILENO) { + close(FCGI_LISTENSOCK_FILENO); + dup2(fcgi_fd, FCGI_LISTENSOCK_FILENO); + close(fcgi_fd); + } - /* we don't need the client socket */ - for (i = 3; i < max_fd; i++) { - if (i != FCGI_LISTENSOCK_FILENO) close(i); - } + max_fd = open("/dev/null", O_RDWR); + close(STDERR_FILENO); + dup2(max_fd, STDERR_FILENO); + close(max_fd); - /* fork and replace shell */ - if (appArgv) { - execv(appArgv[0], appArgv); + max_fd = open("/dev/null", O_RDWR); + close(STDOUT_FILENO); + dup2(max_fd, STDOUT_FILENO); + close(max_fd); - } else { - char *b = malloc(strlen("exec ") + strlen(appPath) + 1); - strcpy(b, "exec "); - strcat(b, appPath); + /* we don't need the client socket */ + for (i = 3; i < max_fd; i++) { + if (i != FCGI_LISTENSOCK_FILENO) close(i); + } - /* exec the cgi */ - execl("/bin/sh", "sh", "-c", b, (char *)NULL); - } + /* fork and replace shell */ + if (appArgv) { + execv(appArgv[0], appArgv); - exit(errno); + } else { + char *b = malloc(strlen("exec ") + strlen(appPath) + 1); + strcpy(b, "exec "); + strcat(b, appPath); - break; + /* exec the cgi */ + execl("/bin/sh", "sh", "-c", b, (char *)NULL); } - case -1: - /* error */ - break; - default: - /* father */ - /* wait */ - select(0, NULL, NULL, NULL, &tv); + exit(errno); + + break; + } + case -1: + /* error */ + fprintf(stderr, "spawn-fcgi: fork failed: %s\n", strerror(errno)); + break; + default: + /* father */ - switch (waitpid(child, &status, WNOHANG)) { - case 0: - fprintf(stdout, "spawn-fcgi: child spawned successfully: PID: %d\n", child); + /* wait */ + select(0, NULL, NULL, NULL, &tv); - /* write pid file */ - if (pid_fd != -1) { - /* assume a 32bit pid_t */ - char pidbuf[12]; + switch (waitpid(child, &status, WNOHANG)) { + case 0: + fprintf(stdout, "spawn-fcgi: child spawned successfully: PID: %d\n", child); - snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child); + /* write pid file */ + if (pid_fd != -1) { + /* assume a 32bit pid_t */ + char pidbuf[12]; - write(pid_fd, pidbuf, strlen(pidbuf)); - /* avoid eol for the last one */ - if (fork_count != 0) { - write(pid_fd, "\n", 1); - } - } + snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child); - break; - case -1: - break; - default: - if (WIFEXITED(status)) { - fprintf(stderr, "spawn-fcgi: child exited with: %d\n", - WEXITSTATUS(status)); - rc = WEXITSTATUS(status); - } else if (WIFSIGNALED(status)) { - fprintf(stderr, "spawn-fcgi: child signaled: %d\n", - WTERMSIG(status)); - rc = 1; - } else { - fprintf(stderr, "spawn-fcgi: child died somehow: exit status = %d\n", - status); - rc = status; + write(pid_fd, pidbuf, strlen(pidbuf)); + /* avoid eol for the last one */ + if (fork_count != 0) { + write(pid_fd, "\n", 1); } } break; + case -1: + break; + default: + if (WIFEXITED(status)) { + fprintf(stderr, "spawn-fcgi: child exited with: %d\n", + WEXITSTATUS(status)); + rc = WEXITSTATUS(status); + } else if (WIFSIGNALED(status)) { + fprintf(stderr, "spawn-fcgi: child signaled: %d\n", + WTERMSIG(status)); + rc = 1; + } else { + fprintf(stderr, "spawn-fcgi: child died somehow: exit status = %d\n", + status); + rc = status; + } } + + break; } - close(pid_fd); - pid_fd = -1; - } else { - fprintf(stderr, "spawn-fcgi: socket is already used, can't spawn\n"); - return -1; } + close(pid_fd); + pid_fd = -1; close(fcgi_fd); @@ -422,7 +431,9 @@ int main(int argc, char **argv) { return -1; } - /* do the change before we do the chroot() */ + /* Change group before chroot, when we have access + * to /etc/group + */ setgid(grp->gr_gid); setgroups(0, NULL);