Fix #1575: spawn-fcgi: only try to connect to unix socket (not tcp) before spawning

- we do not need to check for a tcp socket this way as bind will fail if the socket is in use;
   this does not apply to unix sockets as they are not bound to a filename but to the file, which
   we delete before spawning.


git-svn-id: svn://svn.lighttpd.net/lighttpd/branches/lighttpd-1.4.x@2106 152afb58-edef-0310-8abb-c4023f1b3aa9
This commit is contained in:
Stefan Bühler 2008-02-28 12:19:34 +00:00
parent c5a1cac202
commit 0adc0af5fd
2 changed files with 138 additions and 135 deletions

1
NEWS
View File

@ -44,6 +44,7 @@ NEWS
* do not generate a "Content-Length: 0" header for HEAD requests, added test too
* remove compress cache file if compression or write failed (#1150)
* fixed body handling of status 300 requests
* spawn-fcgi: only try to connect to unix socket (not tcp) before spawning (#1575)
- 1.4.18 - 2007-09-09

View File

@ -48,6 +48,9 @@ int fcgi_spawn_connection(char *appPath, char **appArgv, char *addr, unsigned sh
socklen_t servlen;
pid_t child;
int val;
if (child_count < 2) {
child_count = 5;
}
@ -71,6 +74,25 @@ int fcgi_spawn_connection(char *appPath, char **appArgv, char *addr, unsigned sh
#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, "%s.%d\n",
__FILE__, __LINE__);
return -1;
}
if (-1 != connect(fcgi_fd, fcgi_addr, servlen)) {
fprintf(stderr, "%s.%d: socket is already used, can't spawn\n",
__FILE__, __LINE__);
return -1;
}
/* cleanup previous socket if it exists */
unlink(unixsocket);
close(fcgi_fd);
} else {
fcgi_addr_in.sin_family = AF_INET;
if (addr != NULL) {
@ -85,150 +107,130 @@ int fcgi_spawn_connection(char *appPath, char **appArgv, char *addr, unsigned sh
fcgi_addr = (struct sockaddr *) &fcgi_addr_in;
}
/* open socket */
if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
fprintf(stderr, "%s.%d\n",
__FILE__, __LINE__);
return -1;
}
if (-1 == connect(fcgi_fd, fcgi_addr, servlen)) {
/* server is not up, spawn in */
pid_t child;
int val;
if (unixsocket) unlink(unixsocket);
close(fcgi_fd);
/* reopen socket */
if (-1 == (fcgi_fd = socket(socket_type, SOCK_STREAM, 0))) {
fprintf(stderr, "%s.%d\n",
__FILE__, __LINE__);
return -1;
}
val = 1;
if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
fprintf(stderr, "%s.%d\n",
__FILE__, __LINE__);
return -1;
}
/* create socket */
if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
fprintf(stderr, "%s.%d: bind failed: %s\n",
__FILE__, __LINE__,
strerror(errno));
return -1;
}
if (-1 == listen(fcgi_fd, 1024)) {
fprintf(stderr, "%s.%d: fd = -1\n",
__FILE__, __LINE__);
return -1;
}
if (!nofork) {
child = fork();
} else {
child = 0;
}
switch (child) {
case 0: {
char cgi_childs[64];
int i = 0;
/* is safe as we limit to 256 childs */
sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count);
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 < 256; i++) {
close(i);
}
/* create environment */
putenv(cgi_childs);
/* fork and replace shell */
if (appArgv) {
execv(appArgv[0], appArgv);
} else {
char *b = malloc(strlen("exec ") + strlen(appPath) + 1);
strcpy(b, "exec ");
strcat(b, appPath);
/* exec the cgi */
execl("/bin/sh", "sh", "-c", b, (char *)NULL);
}
exit(errno);
break;
}
case -1:
/* error */
break;
default:
/* father */
/* wait */
select(0, NULL, NULL, NULL, &tv);
switch (waitpid(child, &status, WNOHANG)) {
case 0:
fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n",
__FILE__, __LINE__,
child);
/* write pid file */
if (pid_fd != -1) {
/* assume a 32bit pid_t */
char pidbuf[12];
snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child);
write(pid_fd, pidbuf, strlen(pidbuf));
close(pid_fd);
pid_fd = -1;
}
break;
case -1:
break;
default:
if (WIFEXITED(status)) {
fprintf(stderr, "%s.%d: child exited with: %d, %s\n",
__FILE__, __LINE__,
WEXITSTATUS(status), strerror(WEXITSTATUS(status)));
} else if (WIFSIGNALED(status)) {
fprintf(stderr, "%s.%d: child signaled: %d\n",
__FILE__, __LINE__,
WTERMSIG(status));
} else {
fprintf(stderr, "%s.%d: child died somehow: %d\n",
__FILE__, __LINE__,
status);
}
}
break;
}
} else {
fprintf(stderr, "%s.%d: socket is already used, can't spawn\n",
val = 1;
if (setsockopt(fcgi_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0) {
fprintf(stderr, "%s.%d\n",
__FILE__, __LINE__);
return -1;
}
/* create socket */
if (-1 == bind(fcgi_fd, fcgi_addr, servlen)) {
fprintf(stderr, "%s.%d: bind failed: %s\n",
__FILE__, __LINE__,
strerror(errno));
return -1;
}
if (-1 == listen(fcgi_fd, 1024)) {
fprintf(stderr, "%s.%d: fd = -1\n",
__FILE__, __LINE__);
return -1;
}
if (!nofork) {
child = fork();
} else {
child = 0;
}
switch (child) {
case 0: {
char cgi_childs[64];
int i = 0;
/* is safe as we limit to 256 childs */
sprintf(cgi_childs, "PHP_FCGI_CHILDREN=%d", child_count);
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 < 256; i++) {
close(i);
}
/* create environment */
putenv(cgi_childs);
/* fork and replace shell */
if (appArgv) {
execv(appArgv[0], appArgv);
} else {
char *b = malloc(strlen("exec ") + strlen(appPath) + 1);
strcpy(b, "exec ");
strcat(b, appPath);
/* exec the cgi */
execl("/bin/sh", "sh", "-c", b, (char *)NULL);
}
exit(errno);
break;
}
case -1:
/* error */
break;
default:
/* father */
/* wait */
select(0, NULL, NULL, NULL, &tv);
switch (waitpid(child, &status, WNOHANG)) {
case 0:
fprintf(stderr, "%s.%d: child spawned successfully: PID: %d\n",
__FILE__, __LINE__,
child);
/* write pid file */
if (pid_fd != -1) {
/* assume a 32bit pid_t */
char pidbuf[12];
snprintf(pidbuf, sizeof(pidbuf) - 1, "%d", child);
write(pid_fd, pidbuf, strlen(pidbuf));
close(pid_fd);
pid_fd = -1;
}
break;
case -1:
break;
default:
if (WIFEXITED(status)) {
fprintf(stderr, "%s.%d: child exited with: %d, %s\n",
__FILE__, __LINE__,
WEXITSTATUS(status), strerror(WEXITSTATUS(status)));
} else if (WIFSIGNALED(status)) {
fprintf(stderr, "%s.%d: child signaled: %d\n",
__FILE__, __LINE__,
WTERMSIG(status));
} else {
fprintf(stderr, "%s.%d: child died somehow: %d\n",
__FILE__, __LINE__,
status);
}
}
break;
}
close(fcgi_fd);
return 0;
@ -285,7 +287,7 @@ int main(int argc, char **argv) {
while(-1 != (o = getopt(argc, argv, "c:f:g:hna:p:u:vC:s:P:"))) {
switch(o) {
case 'f': fcgi_app = optarg; break;
case 'a': addr = optarg;/* ip addr */ break;
case 'a': addr = optarg;/* ip addr */ break;
case 'p': port = strtol(optarg, NULL, 10);/* port */ break;
case 'C': child_count = strtol(optarg, NULL, 10);/* */ break;
case 's': unixsocket = optarg; /* unix-domain socket */ break;