diff options
| -rw-r--r-- | fcgiwrap.8 | 23 | ||||
| -rw-r--r-- | fcgiwrap.c | 125 | 
2 files changed, 144 insertions, 4 deletions
@@ -1,5 +1,5 @@  .\"                                      Hey, EMACS: -*- nroff -*- -.TH FCGIWRAP 8 "Jun 2, 2010" +.TH FCGIWRAP 8 "Jun 3, 2010"  .\" Please adjust this date whenever revising the manpage.  .\"  .\" Some roff macros, for reference: @@ -28,6 +28,14 @@ that may need it).  .B \-c \fInumber\fP  Number of fcgiwrap processes to prefork.  .TP +.B \-s \fIsocket_url\fP +A URL for the listen socket to bind to. By default \fBfcgiwrap\fP expects +a listen socket to be passed on file descriptor 0, matching the FastCGI convention. +The recommended way to deploy \fBfcgiwrap\fP is to run it under a process manager that +takes care of opening the socket. However, for simple configurations and one-off +tests this option may be used. Valid socket_urls include \fIunix:/path/to/unix/socket\fP, +\fItcp:dot.ted.qu.ad:port\fP and \fItcp6:[ipv6_addr]:port\fP. +.TP  .B \-h  Show a help message and exit. @@ -53,6 +61,14 @@ SCRIPT_FILENAME  complete path to CGI script. When set, overrides DOCUMENT_ROOT and SCRIPT_NAME  .SH EXAMPLE +The fastest way to see \fBfcgiwrap\fP do something is to launch it at the command line +like this: +.br +fcgiwrap -s unix:/var/run/fcgiwrap.sock +.br +Apart from potential permission problems etc., it should be ready to accept FastCGI +requests and run CGI scripts. +  Most probably you will want to launch \fBfcgiwrap\fP by   .I spawn-fcgi  using a configuration like this: @@ -80,11 +96,14 @@ location / {  .br  	fastcgi_param SCRIPT_NAME   cgit;  .br +	fastcgi_pass unix:/var/run/fastcgi.sock; +.br  }  .SH AUTHOR  fcgiwrap was written by Grzegorz Nosek <root@localdomain.pl>  with contributions by W-Mark Kubacki <wmark@hurrikane.de>.  .PP -This manual page was written by Jordi Mallach <jordi@debian.org>, +This manual page was written by Jordi Mallach <jordi@debian.org> +(with contributions by Grzegorz Nosek)  for the Debian project (and may be used by others). @@ -42,6 +42,15 @@  #include <sys/wait.h>  #include <ctype.h> +#include <arpa/inet.h> +#include <sys/socket.h> +#include <sys/un.h> + +/* glibc doesn't seem to export it */ +#ifndef UNIX_PATH_MAX +#define UNIX_PATH_MAX 108 +#endif +  extern char **environ;  static char * const * inherited_environ; @@ -623,18 +632,120 @@ static void prefork(int nchildren)  	}  } +int setup_socket(char *url) { +	char *p = url; +	char *q; +	int fd; +	int port; +	size_t sockaddr_size; +	int one = 1; + +	union { +		struct sockaddr sa; +		struct sockaddr_un sa_un; +		struct sockaddr_in sa_in; +		struct sockaddr_in6 sa_in6; +	} sa; + +	if (!strncmp(p, "unix:", sizeof("unix:") - 1)) { +		p += sizeof("unix:") - 1; + +		if (strlen(p) >= UNIX_PATH_MAX) { +			fprintf(stderr, "Socket path too long, exceeds %d characters\n", +			        UNIX_PATH_MAX); +			return -1; +		} + +		sockaddr_size = sizeof sa.sa_un; +		sa.sa_un.sun_family = AF_UNIX; +		strcpy(sa.sa_un.sun_path, p); +	} else if (!strncmp(p, "tcp:", sizeof("tcp:") - 1)) { +		p += sizeof("tcp:") - 1; + +		q = strchr(p, ':'); +		if (!q) { +			goto invalid_url; +		} +		port = atoi(q+1); +		if (port <= 0 || port > 65535) { +			goto invalid_url; +		} +		sockaddr_size = sizeof sa.sa_in; +		sa.sa_in.sin_family = AF_INET; +		sa.sa_in.sin_port = htons(port); +		*q = 0; +		if (inet_pton(AF_INET, p, &sa.sa_in.sin_addr) < 1) { +			goto invalid_url; +		} +	} else if (!strncmp(p, "tcp6:[", sizeof("tcp6:[") - 1)) { +		p += sizeof("tcp6:[") - 1; +		q = strchr(p, ']'); +		if (!q || !q[0] || q[1] != ':') { +			goto invalid_url; +		} +		port = atoi(q+2); +		if (port <= 0 || port > 65535) { +			goto invalid_url; +		} +		sockaddr_size = sizeof sa.sa_in6; +		sa.sa_in6.sin6_family = AF_INET6; +		sa.sa_in6.sin6_port = htons(port); +		*q = 0; +		if (inet_pton(AF_INET6, p, &sa.sa_in6.sin6_addr) < 1) { +			goto invalid_url; +		} +	} else { +invalid_url: +		fprintf(stderr, "Valid socket URLs are:\n" +		                "unix:/path/to/socket for Unix sockets\n" +		                "tcp:dot.ted.qu.ad:port for IPv4 sockets\n" +		                "tcp6:[ipv6_addr]:port for IPv6 sockets\n"); +		return -1; +	} + +	fd = socket(sa.sa.sa_family, SOCK_STREAM, 0); +	if (fd < 0) { +		perror("Failed to create socket"); +		return -1; +	} +	if (bind(fd, &sa.sa, sockaddr_size) < 0) { +		perror("Failed to bind"); +		return -1; +	} +	if (listen(fd, 511) < 0) { +		perror("Failed to listen"); +		return -1; +	} +	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof one) < 0) { +		perror("Failed to enable SO_REUSEADDR"); +		return -1; +	} +	if (dup2(fd, 0) < 0) { +		perror("Failed to move socket to fd 0"); +		return -1; +	} +	if (close(fd) < 0) { +		perror("Failed to close original socket"); +		return -1; +	} + +	return 0; +} +  int main(int argc, char **argv)  {  	int nchildren = 1; +	char *socket_url = NULL;  	int c; -	while ((c = getopt(argc, argv, "c:h")) != -1) { +	while ((c = getopt(argc, argv, "c:hs:")) != -1) {  		switch (c) {  			case 'h':  				printf("Usage: %s [OPTION]\nInvokes CGI scripts as FCGI.\n\n"  					PACKAGE_NAME" version "PACKAGE_VERSION"\n\n"  					"Options are:\n"  					"  -c <number>\t\tNumber of processes to prefork\n" +					"  -s <socket_url>\tSocket to bind to (say -s help for help)\n"  					"  -h\t\t\tShow this help message and exit\n"  					"\nReport bugs to Grzegorz Nosek <"PACKAGE_BUGREPORT">.\n"  					PACKAGE_NAME" home page: <http://nginx.localdomain.pl/wiki/FcgiWrap>\n", @@ -644,8 +755,11 @@ int main(int argc, char **argv)  			case 'c':  				nchildren = atoi(optarg);  				break; +			case 's': +				socket_url = strdup(optarg); +				break;  			case '?': -				if (optopt == 'c') +				if (optopt == 'c' || optopt == 's')  					fprintf(stderr, "Option -%c requires an argument.\n", optopt);  				else if (isprint(optopt))  					fprintf(stderr, "Unknown option `-%c'.\n", optopt); @@ -659,6 +773,13 @@ int main(int argc, char **argv)  		}  	} +	if (socket_url) { +		if (setup_socket(socket_url) < 0) { +			return 1; +		} +		free(socket_url); +	} +  	prefork(nchildren);  	fcgiwrap_main();  	return 0;  | 
