summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--fcgiwrap.823
-rw-r--r--fcgiwrap.c125
2 files changed, 144 insertions, 4 deletions
diff --git a/fcgiwrap.8 b/fcgiwrap.8
index 0383b19..15c8523 100644
--- a/fcgiwrap.8
+++ b/fcgiwrap.8
@@ -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).
diff --git a/fcgiwrap.c b/fcgiwrap.c
index d62e37f..416f609 100644
--- a/fcgiwrap.c
+++ b/fcgiwrap.c
@@ -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;