summaryrefslogtreecommitdiff
path: root/src/mod_fastcgi.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mod_fastcgi.c')
-rw-r--r--src/mod_fastcgi.c927
1 files changed, 562 insertions, 365 deletions
diff --git a/src/mod_fastcgi.c b/src/mod_fastcgi.c
index 890062c..8b1be0a 100644
--- a/src/mod_fastcgi.c
+++ b/src/mod_fastcgi.c
@@ -69,20 +69,24 @@ typedef struct fcgi_proc {
size_t requests; /* see max_requests */
struct fcgi_proc *prev, *next; /* see first */
- time_t disable_ts; /* replace by host->something */
+ time_t disabled_until; /* this proc is disabled until, use something else until than */
int is_local;
- enum { PROC_STATE_UNSET, /* init-phase */
- PROC_STATE_RUNNING, /* alive */
- PROC_STATE_DIED_WAIT_FOR_PID,
- PROC_STATE_KILLED, /* was killed as we don't have the load anymore */
- PROC_STATE_DIED, /* marked as dead, should be restarted */
- PROC_STATE_DISABLED /* proc disabled as it resulted in an error */
+ enum {
+ PROC_STATE_UNSET, /* init-phase */
+ PROC_STATE_RUNNING, /* alive */
+ PROC_STATE_DIED_WAIT_FOR_PID,
+ PROC_STATE_KILLED, /* was killed as we don't have the load anymore */
+ PROC_STATE_DIED, /* marked as dead, should be restarted */
+ PROC_STATE_DISABLED /* proc disabled as it resulted in an error */
} state;
} fcgi_proc;
typedef struct {
+ /* the key that is used to reference this value */
+ buffer *id;
+
/* list of processes handling this extension
* sorted by lowest load
*
@@ -300,6 +304,8 @@ typedef struct {
buffer *path;
buffer *parse_response;
+
+ buffer *statuskey;
plugin_config **config_storage;
@@ -307,13 +313,19 @@ typedef struct {
} plugin_data;
/* connection specific data */
-typedef enum { FCGI_STATE_INIT, FCGI_STATE_CONNECT, FCGI_STATE_PREPARE_WRITE,
- FCGI_STATE_WRITE, FCGI_STATE_READ
+typedef enum {
+ FCGI_STATE_UNSET,
+ FCGI_STATE_INIT,
+ FCGI_STATE_CONNECT_DELAYED,
+ FCGI_STATE_PREPARE_WRITE,
+ FCGI_STATE_WRITE,
+ FCGI_STATE_READ
} fcgi_connection_state_t;
typedef struct {
fcgi_proc *proc;
fcgi_extension_host *host;
+ fcgi_extension *ext;
fcgi_connection_state_t state;
time_t state_timestamp;
@@ -325,8 +337,6 @@ typedef struct {
buffer *response_header;
- int delayed; /* flag to mark that the connect() is delayed */
-
size_t request_id;
int fd; /* fd to the fastcgi process */
int fde_ndx; /* index into the fd-event buffer */
@@ -348,7 +358,74 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents);
int fcgi_proclist_sort_down(server *srv, fcgi_extension_host *host, fcgi_proc *proc);
+data_integer *status_counter_get_counter(server *srv, const char *s, size_t len) {
+ data_integer *di;
+
+ if (NULL == (di = (data_integer *)array_get_element(srv->status, s))) {
+ /* not found, create it */
+
+ if (NULL == (di = (data_integer *)array_get_unused_element(srv->status, TYPE_INTEGER))) {
+ di = data_integer_init();
+ }
+ buffer_copy_string_len(di->key, s, len);
+ di->value = 0;
+
+ array_insert_unique(srv->status, (data_unset *)di);
+ }
+ return di;
+}
+
+/* dummies of the statistic framework functions
+ * they will be moved to a statistics.c later */
+int status_counter_inc(server *srv, const char *s, size_t len) {
+ data_integer *di = status_counter_get_counter(srv, s, len);
+
+ di->value++;
+
+ return 0;
+}
+
+int status_counter_dec(server *srv, const char *s, size_t len) {
+ data_integer *di = status_counter_get_counter(srv, s, len);
+
+ if (di->value > 0) di->value--;
+
+ return 0;
+}
+
+int status_counter_set(server *srv, const char *s, size_t len, int val) {
+ data_integer *di = status_counter_get_counter(srv, s, len);
+
+ di->value = val;
+ return 0;
+}
+
+int fastcgi_status_copy_procname(buffer *b, fcgi_extension_host *host, fcgi_proc *proc) {
+ buffer_copy_string(b, "fastcgi.backend.");
+ buffer_append_string_buffer(b, host->id);
+ buffer_append_string(b, ".");
+ buffer_append_long(b, proc->id);
+
+ return 0;
+}
+
+int fastcgi_status_init(server *srv, buffer *b, fcgi_extension_host *host, fcgi_proc *proc) {
+#define CLEAN(x) \
+ fastcgi_status_copy_procname(b, host, proc); \
+ buffer_append_string(b, x); \
+ status_counter_set(srv, CONST_BUF_LEN(b), 0);
+
+ CLEAN(".disabled");
+ CLEAN(".died");
+ CLEAN(".overloaded");
+ CLEAN(".connected");
+ CLEAN(".load");
+
+#undef CLEAN
+
+ return 0;
+}
static handler_ctx * handler_ctx_init() {
handler_ctx * hctx;
@@ -366,8 +443,6 @@ static handler_ctx * handler_ctx_init() {
hctx->fd = -1;
- hctx->delayed = 0;
-
hctx->reconnects = 0;
hctx->send_content_body = 1;
@@ -413,6 +488,7 @@ fcgi_extension_host *fastcgi_host_init() {
f = calloc(1, sizeof(*f));
+ f->id = buffer_init();
f->host = buffer_init();
f->unixsocket = buffer_init();
f->docroot = buffer_init();
@@ -427,6 +503,7 @@ fcgi_extension_host *fastcgi_host_init() {
void fastcgi_host_free(fcgi_extension_host *h) {
if (!h) return;
+ buffer_free(h->id);
buffer_free(h->host);
buffer_free(h->unixsocket);
buffer_free(h->docroot);
@@ -540,6 +617,8 @@ INIT_FUNC(mod_fastcgi_init) {
p->path = buffer_init();
p->parse_response = buffer_init();
+
+ p->statuskey = buffer_init();
return p;
}
@@ -556,6 +635,7 @@ FREE_FUNC(mod_fastcgi_free) {
buffer_free(p->fcgi_env);
buffer_free(p->path);
buffer_free(p->parse_response);
+ buffer_free(p->statuskey);
if (p->config_storage) {
size_t i, j, n;
@@ -824,6 +904,7 @@ static int fcgi_spawn_connection(server *srv,
switch ((child = fork())) {
case 0: {
size_t i = 0;
+ char *c;
char_array env;
char_array arg;
@@ -888,6 +969,20 @@ static int fcgi_spawn_connection(server *srv,
parse_binpath(&arg, host->bin_path);
+ /* chdir into the base of the bin-path,
+ * search for the last / */
+ if (NULL != (c = strrchr(arg.ptr[0], '/'))) {
+ *c = '\0';
+
+ /* change to the physical directory */
+ if (-1 == chdir(arg.ptr[0])) {
+ *c = '/';
+ log_error_write(srv, __FILE__, __LINE__, "sss", "chdir failed:", strerror(errno), arg.ptr[0]);
+ }
+ *c = '/';
+ }
+
+
/* exec the cgi */
execve(arg.ptr[0], arg.ptr, env.ptr);
@@ -1058,7 +1153,7 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
for (n = 0; n < da_ext->value->used; n++) {
data_array *da_host = (data_array *)da_ext->value->data[n];
- fcgi_extension_host *df;
+ fcgi_extension_host *host;
config_values_t fcv[] = {
{ "host", NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION }, /* 0 */
@@ -1094,54 +1189,56 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
return HANDLER_ERROR;
}
- df = fastcgi_host_init();
+ host = fastcgi_host_init();
- df->check_local = 1;
- df->min_procs = 4;
- df->max_procs = 4;
- df->max_load_per_proc = 1;
- df->idle_timeout = 60;
- df->mode = FCGI_RESPONDER;
- df->disable_time = 60;
- df->break_scriptfilename_for_php = 0;
- df->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */
+ buffer_copy_string_buffer(host->id, da_host->key);
+
+ host->check_local = 1;
+ host->min_procs = 4;
+ host->max_procs = 4;
+ host->max_load_per_proc = 1;
+ host->idle_timeout = 60;
+ host->mode = FCGI_RESPONDER;
+ host->disable_time = 60;
+ host->break_scriptfilename_for_php = 0;
+ host->allow_xsendfile = 0; /* handle X-LIGHTTPD-send-file */
- fcv[0].destination = df->host;
- fcv[1].destination = df->docroot;
+ fcv[0].destination = host->host;
+ fcv[1].destination = host->docroot;
fcv[2].destination = fcgi_mode;
- fcv[3].destination = df->unixsocket;
- fcv[4].destination = df->bin_path;
+ fcv[3].destination = host->unixsocket;
+ fcv[4].destination = host->bin_path;
- fcv[5].destination = &(df->check_local);
- fcv[6].destination = &(df->port);
- fcv[7].destination = &(df->min_procs);
- fcv[8].destination = &(df->max_procs);
- fcv[9].destination = &(df->max_load_per_proc);
- fcv[10].destination = &(df->idle_timeout);
- fcv[11].destination = &(df->disable_time);
+ fcv[5].destination = &(host->check_local);
+ fcv[6].destination = &(host->port);
+ fcv[7].destination = &(host->min_procs);
+ fcv[8].destination = &(host->max_procs);
+ fcv[9].destination = &(host->max_load_per_proc);
+ fcv[10].destination = &(host->idle_timeout);
+ fcv[11].destination = &(host->disable_time);
- fcv[12].destination = df->bin_env;
- fcv[13].destination = df->bin_env_copy;
- fcv[14].destination = &(df->break_scriptfilename_for_php);
- fcv[15].destination = &(df->allow_xsendfile);
- fcv[16].destination = df->strip_request_uri;
+ fcv[12].destination = host->bin_env;
+ fcv[13].destination = host->bin_env_copy;
+ fcv[14].destination = &(host->break_scriptfilename_for_php);
+ fcv[15].destination = &(host->allow_xsendfile);
+ fcv[16].destination = host->strip_request_uri;
if (0 != config_insert_values_internal(srv, da_host->value, fcv)) {
return HANDLER_ERROR;
}
- if ((!buffer_is_empty(df->host) || df->port) &&
- !buffer_is_empty(df->unixsocket)) {
+ if ((!buffer_is_empty(host->host) || host->port) &&
+ !buffer_is_empty(host->unixsocket)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"either host+port or socket");
return HANDLER_ERROR;
}
- if (!buffer_is_empty(df->unixsocket)) {
+ if (!buffer_is_empty(host->unixsocket)) {
/* unix domain socket */
- if (df->unixsocket->used > UNIX_PATH_MAX - 2) {
+ if (host->unixsocket->used > UNIX_PATH_MAX - 2) {
log_error_write(srv, __FILE__, __LINE__, "s",
"path of the unixdomain socket is too large");
return HANDLER_ERROR;
@@ -1149,8 +1246,8 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
} else {
/* tcp/ip */
- if (buffer_is_empty(df->host) &&
- buffer_is_empty(df->bin_path)) {
+ if (buffer_is_empty(host->host) &&
+ buffer_is_empty(host->bin_path)) {
log_error_write(srv, __FILE__, __LINE__, "sbbbs",
"missing key (string):",
da->key,
@@ -1159,7 +1256,7 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
"host");
return HANDLER_ERROR;
- } else if (df->port == 0) {
+ } else if (host->port == 0) {
log_error_write(srv, __FILE__, __LINE__, "sbbbs",
"missing key (short):",
da->key,
@@ -1170,37 +1267,37 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
}
}
- if (!buffer_is_empty(df->bin_path)) {
+ if (!buffer_is_empty(host->bin_path)) {
/* a local socket + self spawning */
size_t pno;
/* HACK: just to make sure the adaptive spawing is disabled */
- df->min_procs = df->max_procs;
+ host->min_procs = host->max_procs;
- if (df->min_procs > df->max_procs) df->max_procs = df->min_procs;
- if (df->max_load_per_proc < 1) df->max_load_per_proc = 0;
+ if (host->min_procs > host->max_procs) host->max_procs = host->min_procs;
+ if (host->max_load_per_proc < 1) host->max_load_per_proc = 0;
if (s->debug) {
log_error_write(srv, __FILE__, __LINE__, "ssbsdsbsdsd",
"--- fastcgi spawning local",
- "\n\tproc:", df->bin_path,
- "\n\tport:", df->port,
- "\n\tsocket", df->unixsocket,
- "\n\tmin-procs:", df->min_procs,
- "\n\tmax-procs:", df->max_procs);
+ "\n\tproc:", host->bin_path,
+ "\n\tport:", host->port,
+ "\n\tsocket", host->unixsocket,
+ "\n\tmin-procs:", host->min_procs,
+ "\n\tmax-procs:", host->max_procs);
}
- for (pno = 0; pno < df->min_procs; pno++) {
+ for (pno = 0; pno < host->min_procs; pno++) {
fcgi_proc *proc;
proc = fastcgi_process_init();
- proc->id = df->num_procs++;
- df->max_id++;
+ proc->id = host->num_procs++;
+ host->max_id++;
- if (buffer_is_empty(df->unixsocket)) {
- proc->port = df->port + pno;
+ if (buffer_is_empty(host->unixsocket)) {
+ proc->port = host->port + pno;
} else {
- buffer_copy_string_buffer(proc->socket, df->unixsocket);
+ buffer_copy_string_buffer(proc->socket, host->unixsocket);
buffer_append_string(proc->socket, "-");
buffer_append_long(proc->socket, pno);
}
@@ -1208,49 +1305,53 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
if (s->debug) {
log_error_write(srv, __FILE__, __LINE__, "ssdsbsdsd",
"--- fastcgi spawning",
- "\n\tport:", df->port,
- "\n\tsocket", df->unixsocket,
- "\n\tcurrent:", pno, "/", df->min_procs);
+ "\n\tport:", host->port,
+ "\n\tsocket", host->unixsocket,
+ "\n\tcurrent:", pno, "/", host->min_procs);
}
- if (fcgi_spawn_connection(srv, p, df, proc)) {
+ if (fcgi_spawn_connection(srv, p, host, proc)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"[ERROR]: spawning fcgi failed.");
return HANDLER_ERROR;
}
+
+ fastcgi_status_init(srv, p->statuskey, host, proc);
- proc->next = df->first;
- if (df->first) df->first->prev = proc;
+ proc->next = host->first;
+ if (host->first) host->first->prev = proc;
- df->first = proc;
+ host->first = proc;
}
} else {
- fcgi_proc *fp;
+ fcgi_proc *proc;
- fp = fastcgi_process_init();
- fp->id = df->num_procs++;
- df->max_id++;
- df->active_procs++;
- fp->state = PROC_STATE_RUNNING;
+ proc = fastcgi_process_init();
+ proc->id = host->num_procs++;
+ host->max_id++;
+ host->active_procs++;
+ proc->state = PROC_STATE_RUNNING;
- if (buffer_is_empty(df->unixsocket)) {
- fp->port = df->port;
+ if (buffer_is_empty(host->unixsocket)) {
+ proc->port = host->port;
} else {
- buffer_copy_string_buffer(fp->socket, df->unixsocket);
+ buffer_copy_string_buffer(proc->socket, host->unixsocket);
}
- df->first = fp;
+ fastcgi_status_init(srv, p->statuskey, host, proc);
+
+ host->first = proc;
- df->min_procs = 1;
- df->max_procs = 1;
+ host->min_procs = 1;
+ host->max_procs = 1;
}
if (!buffer_is_empty(fcgi_mode)) {
if (strcmp(fcgi_mode->ptr, "responder") == 0) {
- df->mode = FCGI_RESPONDER;
+ host->mode = FCGI_RESPONDER;
} else if (strcmp(fcgi_mode->ptr, "authorizer") == 0) {
- df->mode = FCGI_AUTHORIZER;
- if (buffer_is_empty(df->docroot)) {
+ host->mode = FCGI_AUTHORIZER;
+ if (buffer_is_empty(host->docroot)) {
log_error_write(srv, __FILE__, __LINE__, "s",
"ERROR: docroot is required for authorizer mode.");
return HANDLER_ERROR;
@@ -1261,9 +1362,9 @@ SETDEFAULTS_FUNC(mod_fastcgi_set_defaults) {
fcgi_mode, "(ignored, mode set to responder)");
}
}
-
+
/* if extension already exists, take it */
- fastcgi_extension_insert(s->exts, da_ext->key, df);
+ fastcgi_extension_insert(s->exts, da_ext->key, host);
}
}
}
@@ -1327,7 +1428,6 @@ static int fcgi_requestid_del(server *srv, plugin_data *p, size_t request_id) {
return 0;
}
-
void fcgi_connection_close(server *srv, handler_ctx *hctx) {
plugin_data *p;
connection *con;
@@ -1360,6 +1460,13 @@ void fcgi_connection_close(server *srv, handler_ctx *hctx) {
/* after the connect the process gets a load */
hctx->proc->load--;
+ status_counter_dec(srv, CONST_STR_LEN("fastcgi.active-requests"));
+
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string(p->statuskey, ".load");
+
+ status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
+
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "sddb",
"release proc:",
@@ -1397,11 +1504,13 @@ static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
* we have a connection but the child died by some other reason
*
*/
-
- fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
- fdevent_unregister(srv->ev, hctx->fd);
- close(hctx->fd);
- srv->cur_fds--;
+
+ if (hctx->fd != -1) {
+ fdevent_event_del(srv->ev, &(hctx->fde_ndx), hctx->fd);
+ fdevent_unregister(srv->ev, hctx->fd);
+ close(hctx->fd);
+ srv->cur_fds--;
+ }
fcgi_requestid_del(srv, p, hctx->request_id);
@@ -1416,9 +1525,14 @@ static int fcgi_reconnect(server *srv, handler_ctx *hctx) {
hctx->fd,
hctx->proc->pid, hctx->proc->socket);
}
-
- hctx->proc->load--;
- fcgi_proclist_sort_down(srv, hctx->host, hctx->proc);
+
+ if (hctx->proc) {
+ hctx->proc->load--;
+ fcgi_proclist_sort_down(srv, hctx->host, hctx->proc);
+ }
+
+ /* perhaps another host gives us more luck */
+ hctx->host = NULL;
return 0;
}
@@ -1491,7 +1605,15 @@ static int fcgi_header(FCGI_Header * header, unsigned char type, size_t request_
* 1 not connected yet
*/
-static int fcgi_establish_connection(server *srv, handler_ctx *hctx) {
+typedef enum {
+ CONNECTION_UNSET,
+ CONNECTION_OK,
+ CONNECTION_DELAYED, /* retry after event, take same host */
+ CONNECTION_OVERLOADED, /* disable for 1 seconds, take another backend */
+ CONNECTION_DEAD /* disable for 60 seconds, take another backend */
+} connection_result_t;
+
+static connection_result_t fcgi_establish_connection(server *srv, handler_ctx *hctx) {
struct sockaddr *fcgi_addr;
struct sockaddr_in fcgi_addr_in;
#ifdef HAVE_SYS_UN_H
@@ -1540,57 +1662,37 @@ static int fcgi_establish_connection(server *srv, handler_ctx *hctx) {
errno == EALREADY ||
errno == EINTR) {
if (hctx->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "connect delayed, will continue later:", fcgi_fd);
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "connect delayed, will continue later:", host->host);
}
- return 1;
+ return CONNECTION_DELAYED;
} else if (errno == EAGAIN) {
-#if 0
- if(hctx->delayed == 0) {
- log_error_write(srv, __FILE__, __LINE__, "sdsdsdb",
- "need reconnect, will continue later:", fcgi_fd,
- "reconnects:", hctx->reconnects,
- "load:", host->load,
- host->unixsocket);
+ if (hctx->conf.debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sd",
+ "This means that the you have more incoming requests than your fastcgi-backend can handle in parallel. "
+ "Perhaps it helps to spawn more fastcgi backend or php-children, if not decrease server.max-connections."
+ "The load for this fastcgi backend is:", proc->load);
}
-#endif
- hctx->reconnects++;
- return -1;
+
+ return CONNECTION_OVERLOADED;
} else {
- log_error_write(srv, __FILE__, __LINE__, "sdsddb",
- "connect failed:", fcgi_fd,
- strerror(errno), errno,
+ log_error_write(srv, __FILE__, __LINE__, "ssdb",
+ "connect failed:",
+ strerror(errno),
proc->port, proc->socket);
-#if 0
- if (errno == EAGAIN) {
- log_error_write(srv, __FILE__, __LINE__, "sd",
- "This means that the you have more incoming requests than your fastcgi-backend can handle in parallel. "
- "Perhaps it helps to spawn more fastcgi backend or php-children, if not decrease server.max-connections."
- "The load for this fastcgi backend is:", proc->load);
- }
-#endif
-
- return -1;
+ return CONNECTION_DEAD;
}
}
-#if 0
- if(hctx->delayed == 1) {
- log_error_write(srv, __FILE__, __LINE__, "sdsdsdb",
- "reconnected:", fcgi_fd,
- "reconnects:", hctx->reconnects,
- "load:", host->load,
- host->unixsocket);
- }
-#endif
+
hctx->reconnects = 0;
if (hctx->conf.debug > 1) {
log_error_write(srv, __FILE__, __LINE__, "sd",
"connect succeeded: ", fcgi_fd);
}
- return 0;
+ return CONNECTION_OK;
}
static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_data *p) {
@@ -1639,9 +1741,15 @@ static int fcgi_env_add_request_headers(server *srv, connection *con, plugin_dat
buffer_prepare_append(srv->tmp_buf, ds->key->used + 2);
for (j = 0; j < ds->key->used - 1; j++) {
- srv->tmp_buf->ptr[srv->tmp_buf->used++] =
- isalpha((unsigned char)ds->key->ptr[j]) ?
- toupper((unsigned char)ds->key->ptr[j]) : '_';
+ char c = '_';
+ if (light_isalpha(ds->key->ptr[j])) {
+ /* upper-case */
+ c = ds->key->ptr[j] & ~32;
+ } else if (light_isdigit(ds->key->ptr[j])) {
+ /* copy */
+ c = ds->key->ptr[j];
+ }
+ srv->tmp_buf->ptr[srv->tmp_buf->used++] = c;
}
srv->tmp_buf->ptr[srv->tmp_buf->used++] = '\0';
@@ -2156,7 +2264,7 @@ static int fastcgi_get_packet(server *srv, handler_ctx *hctx, fastcgi_response_p
/* no header */
buffer_free(packet->b);
- log_error_write(srv, __FILE__, __LINE__, "s", "FastCGI: header to small");
+ log_error_write(srv, __FILE__, __LINE__, "s", "FastCGI: header too small");
return -1;
}
@@ -2260,11 +2368,12 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
b->used = r + 1; /* one extra for the fake \0 */
b->ptr[b->used - 1] = '\0';
} else {
- log_error_write(srv, __FILE__, __LINE__, "ssdsdsd",
+ log_error_write(srv, __FILE__, __LINE__, "ssdsbsbsd",
"unexpected end-of-file (perhaps the fastcgi process died):",
"pid:", proc->pid,
- "fcgi-fd:", fcgi_fd,
- "remote-fd:", con->fd);
+ "socket:", proc->socket,
+ "host:", host->host,
+ "port:", proc->port);
return -1;
}
@@ -2279,9 +2388,6 @@ static int fcgi_demux_response(server *srv, handler_ctx *hctx) {
/* check if we have at least one packet */
if (0 != fastcgi_get_packet(srv, hctx, &packet)) {
/* no full packet */
-
- hctx->delayed = 1;
-
break;
}
@@ -2546,7 +2652,7 @@ static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_h
proc->pid);
}
- if (0 == proc->is_local) {
+ if (!proc->is_local) {
/*
* external servers might get disabled
*
@@ -2554,10 +2660,15 @@ static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_h
*/
if ((proc->state == PROC_STATE_DISABLED) &&
- (srv->cur_ts - proc->disable_ts > host->disable_time)) {
+ (srv->cur_ts > proc->disabled_until)) {
proc->state = PROC_STATE_RUNNING;
host->active_procs++;
+ fastcgi_status_copy_procname(p->statuskey, host, proc);
+ buffer_append_string(p->statuskey, ".disabled");
+
+ status_counter_set(srv, CONST_BUF_LEN(p->statuskey), 0);
+
log_error_write(srv, __FILE__, __LINE__, "sbdb",
"fcgi-server re-enabled:",
host->host, host->port,
@@ -2626,7 +2737,6 @@ static int fcgi_restart_dead_procs(server *srv, plugin_data *p, fcgi_extension_h
return 0;
}
-
static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
plugin_data *p = hctx->plugin_data;
fcgi_extension_host *host= hctx->host;
@@ -2645,10 +2755,60 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
host->unixsocket->used);
return HANDLER_ERROR;
}
+
+ /* we can't handle this in the switch as we have to fall through in it */
+ if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
+ int socket_error;
+ socklen_t socket_error_len = sizeof(socket_error);
+
+ /* try to finish the connect() */
+ if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
+ log_error_write(srv, __FILE__, __LINE__, "ss",
+ "getsockopt failed:", strerror(errno));
+
+ return HANDLER_ERROR;
+ }
+ if (socket_error != 0) {
+ if (!hctx->proc->is_local || p->conf.debug) {
+ /* local procs get restarted */
+
+ log_error_write(srv, __FILE__, __LINE__, "sssd",
+ "establishing connection failed:", strerror(socket_error),
+ "port:", hctx->proc->port);
+ }
+ hctx->proc->disabled_until = srv->cur_ts + 10;
+
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string(p->statuskey, ".died");
+
+ status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
+
+ return HANDLER_ERROR;
+ }
+ /* go on with preparing the request */
+ hctx->state = FCGI_STATE_PREPARE_WRITE;
+ }
+
switch(hctx->state) {
+ case FCGI_STATE_CONNECT_DELAYED:
+ /* should never happen */
+ break;
case FCGI_STATE_INIT:
+ /* do we have a running process for this host (max-procs) ? */
+
+ for (hctx->proc = hctx->host->first;
+ hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
+ hctx->proc = hctx->proc->next);
+
+ /* all childs are dead */
+ if (hctx->proc == NULL) {
+ hctx->fde_ndx = -1;
+
+ return HANDLER_ERROR;
+ }
+
ret = host->unixsocket->used ? AF_UNIX : AF_INET;
if (-1 == (hctx->fd = socket(ret, SOCK_STREAM, 0))) {
@@ -2672,80 +2832,88 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
if (-1 == fdevent_fcntl_set(srv->ev, hctx->fd)) {
log_error_write(srv, __FILE__, __LINE__, "ss",
- "fcntl failed: ", strerror(errno));
+ "fcntl failed:", strerror(errno));
return HANDLER_ERROR;
}
-
- /* fall through */
- case FCGI_STATE_CONNECT:
- if (hctx->state == FCGI_STATE_INIT || hctx->delayed == 1) {
- for (hctx->proc = hctx->host->first;
- hctx->proc && hctx->proc->state != PROC_STATE_RUNNING;
- hctx->proc = hctx->proc->next);
-
- /* all childs are dead */
- if (hctx->proc == NULL) {
- hctx->fde_ndx = -1;
-
- return HANDLER_ERROR;
- }
- if (hctx->proc->is_local) {
- hctx->pid = hctx->proc->pid;
- }
+ if (hctx->proc->is_local) {
+ hctx->pid = hctx->proc->pid;
+ }
- switch (fcgi_establish_connection(srv, hctx)) {
- case 1:
- fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT);
-
- /* connection is in progress, wait for an event and call getsockopt() below */
-
- fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
-
- hctx->delayed = 0;
- return HANDLER_WAIT_FOR_EVENT;
- case -1:
- /* if ECONNREFUSED/EAGAIN re-try connect() */
-
- fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT);
- hctx->delayed = 1;
- return HANDLER_WAIT_FOR_EVENT;
- default:
- /* everything is ok, go on */
- break;
- }
+ switch (fcgi_establish_connection(srv, hctx)) {
+ case CONNECTION_DELAYED:
+ /* connection is in progress, wait for an event and call getsockopt() below */
+
+ fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
+
+ fcgi_set_state(srv, hctx, FCGI_STATE_CONNECT_DELAYED);
+ return HANDLER_WAIT_FOR_EVENT;
+ case CONNECTION_OVERLOADED:
+ /* cool down the backend, it is overloaded
+ * -> EAGAIN */
- } else {
- int socket_error;
- socklen_t socket_error_len = sizeof(socket_error);
+ log_error_write(srv, __FILE__, __LINE__, "ssdsdb",
+ "backend is overloaded, we disable it for a 2 seconds and send the request to another backend instead:"
+ "reconnects:", hctx->reconnects,
+ "load:", host->load,
+ host->unixsocket);
+
+
+ hctx->proc->disabled_until = srv->cur_ts + 2;
+
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string(p->statuskey, ".overloaded");
+
+ status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
- /* try to finish the connect() */
- if (0 != getsockopt(hctx->fd, SOL_SOCKET, SO_ERROR, &socket_error, &socket_error_len)) {
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "getsockopt failed:", strerror(errno));
-
- return HANDLER_ERROR;
- }
- if (socket_error != 0) {
- if (!hctx->proc->is_local || p->conf.debug) {
- /* local procs get restarted */
-
- log_error_write(srv, __FILE__, __LINE__, "ss",
- "establishing connection failed:", strerror(socket_error),
- "port:", hctx->proc->port);
- }
-
- return HANDLER_ERROR;
- }
+ return HANDLER_ERROR;
+ case CONNECTION_DEAD:
+ /* we got a hard error from the backend like
+ * - ECONNREFUSED for tcp-ip sockets
+ * - ENOENT for unix-domain-sockets
+ *
+ * for check if the host is back in 10 seconds
+ * */
+
+ hctx->proc->disabled_until = srv->cur_ts + 10;
+
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string(p->statuskey, ".died");
+
+ status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
+
+ return HANDLER_ERROR;
+ case CONNECTION_OK:
+ /* everything is ok, go on */
+
+ fcgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
+
+ break;
+ case CONNECTION_UNSET:
+ break;
}
+ case FCGI_STATE_PREPARE_WRITE:
/* ok, we have the connection */
hctx->proc->load++;
hctx->proc->last_used = srv->cur_ts;
hctx->got_proc = 1;
-
+
+ status_counter_inc(srv, CONST_STR_LEN("fastcgi.requests"));
+ status_counter_inc(srv, CONST_STR_LEN("fastcgi.active-requests"));
+
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string(p->statuskey, ".connected");
+
+ status_counter_inc(srv, CONST_BUF_LEN(p->statuskey));
+
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string(p->statuskey, ".load");
+
+ status_counter_set(srv, CONST_BUF_LEN(p->statuskey), hctx->proc->load);
+
if (p->conf.debug) {
log_error_write(srv, __FILE__, __LINE__, "sddbdd",
"got proc:",
@@ -2766,9 +2934,7 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
"fcgi-request is already in use:", hctx->request_id);
}
- fcgi_set_state(srv, hctx, FCGI_STATE_PREPARE_WRITE);
/* fall through */
- case FCGI_STATE_PREPARE_WRITE:
fcgi_create_env(srv, hctx, hctx->request_id);
fcgi_set_state(srv, hctx, FCGI_STATE_WRITE);
@@ -2847,6 +3013,9 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
return HANDLER_WAIT_FOR_EVENT;
}
+
+/* might be called on fdevent after a connect() is delay too
+ * */
SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
plugin_data *p = p_d;
@@ -2858,83 +3027,118 @@ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
/* not my job */
if (con->mode != p->id) return HANDLER_GO_ON;
+
+ /* we don't have a host yet, choose one
+ * -> this happens in the first round
+ * and when the host died and we have to select a new one */
+ if (hctx->host == NULL) {
+ size_t k;
+ int ndx, used = -1;
+
+ /* get best server */
+ for (k = 0, ndx = -1; k < hctx->ext->used; k++) {
+ host = hctx->ext->hosts[k];
+
+ /* we should have at least one proc that can do somthing */
+ if (host->active_procs == 0) continue;
+
+ if (used == -1 || host->load < used) {
+ used = host->load;
+
+ ndx = k;
+ }
+ }
+ /* found a server */
+ if (ndx == -1) {
+ /* all hosts are down */
+
+ fcgi_connection_close(srv, hctx);
+
+ con->http_status = 500;
+ con->mode = DIRECT;
+
+ return HANDLER_FINISHED;
+ }
+
+ host = hctx->ext->hosts[ndx];
+
+ /*
+ * if check-local is disabled, use the uri.path handler
+ *
+ */
+
+ /* init handler-context */
+ hctx->host = host;
+ hctx->proc = NULL;
+ } else {
+ host = hctx->host;
+ }
+
/* ok, create the request */
switch(fcgi_write_request(srv, hctx)) {
case HANDLER_ERROR:
proc = hctx->proc;
host = hctx->host;
-#if 0
- if (proc &&
- 0 == proc->is_local &&
- proc->state != PROC_STATE_DISABLED) {
- /* only disable remote servers as we don't manage them*/
-
- log_error_write(srv, __FILE__, __LINE__, "sbdb", "fcgi-server disabled:",
- host->host,
- proc->port,
- proc->socket);
-
- /* disable this server */
- proc->disable_ts = srv->cur_ts;
- proc->state = PROC_STATE_DISABLED;
- host->active_procs--;
- }
-#endif
-
if (hctx->state == FCGI_STATE_INIT ||
- hctx->state == FCGI_STATE_CONNECT) {
+ hctx->state == FCGI_STATE_CONNECT_DELAYED) {
/* connect() or getsockopt() failed,
* restart the request-handling
*/
- if (proc && proc->is_local) {
+ if (proc) {
+ if (proc->is_local) {
- if (p->conf.debug) {
- log_error_write(srv, __FILE__, __LINE__, "sbdb", "connect() to fastcgi failed, restarting the request-handling:",
+ if (p->conf.debug) {
+ log_error_write(srv, __FILE__, __LINE__, "sbdb",
+ "connect() to fastcgi failed, restarting the request-handling:",
host->host,
proc->port,
proc->socket);
- }
+ }
- /*
- * several hctx might reference the same proc
- *
- * Only one of them should mark the proc as dead all the other
- * ones should just take a new one.
- *
- * If a new proc was started with the old struct this might lead
- * the mark a perfect proc as dead otherwise
- *
- */
- if (proc->state == PROC_STATE_RUNNING &&
- hctx->pid == proc->pid) {
- proc->state = PROC_STATE_DIED_WAIT_FOR_PID;
+ /*
+ * several hctx might reference the same proc
+ *
+ * Only one of them should mark the proc as dead all the other
+ * ones should just take a new one.
+ *
+ * If a new proc was started with the old struct this might lead
+ * the mark a perfect proc as dead otherwise
+ *
+ */
+ if (proc->state == PROC_STATE_RUNNING &&
+ hctx->pid == proc->pid) {
+ proc->state = PROC_STATE_DIED_WAIT_FOR_PID;
+ }
+ } else {
+ proc->state = PROC_STATE_DISABLED;
}
+ host->active_procs--;
+ fastcgi_status_copy_procname(p->statuskey, hctx->host, hctx->proc);
+ buffer_append_string(p->statuskey, ".disabled");
+
+ status_counter_set(srv, CONST_BUF_LEN(p->statuskey), 1);
}
+
fcgi_restart_dead_procs(srv, p, host);
-
- fcgi_connection_close(srv, hctx);
-
- buffer_reset(con->physical.path);
- con->mode = DIRECT;
- joblist_append(srv, con); /* really ? */
- /* mis-using HANDLER_WAIT_FOR_FD to break out of the loop
- * and hope that the childs will be restarted
- *
- */
-
- /* we might get into a LOOP here
- *
- * but how to handle this ?
- *
- * if we enter a endless loop, we will burn the CPU
- *
- * let this handle by the loop-detection
- */
+ /* cleanup this request and let the request handler start this request again */
+ if (hctx->reconnects < 5) {
+ fcgi_reconnect(srv, hctx);
+ joblist_append(srv, con); /* in case we come from the event-handler */
+
+ return HANDLER_WAIT_FOR_FD;
+ } else {
+ fcgi_connection_close(srv, hctx);
- return HANDLER_WAIT_FOR_FD;
+ buffer_reset(con->physical.path);
+ con->mode = DIRECT;
+ con->http_status = 500;
+ joblist_append(srv, con); /* in case we come from the event-handler */
+
+ return HANDLER_FINISHED;
+ }
} else {
fcgi_connection_close(srv, hctx);
@@ -3054,7 +3258,7 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
fcgi_reconnect(srv, hctx);
log_error_write(srv, __FILE__, __LINE__, "ssdsd",
- "response not sent, request not sent, reconnection.",
+ "response not received, request not sent, reconnecting.",
"connection-fd:", con->fd,
"fcgi-fd:", hctx->fd);
@@ -3062,7 +3266,7 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
}
log_error_write(srv, __FILE__, __LINE__, "sosdsd",
- "response not sent, request sent:", hctx->wb->bytes_out,
+ "response not received, request sent:", hctx->wb->bytes_out,
"connection-fd:", con->fd,
"fcgi-fd:", hctx->fd);
@@ -3093,7 +3297,7 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
}
if (revents & FDEVENT_OUT) {
- if (hctx->state == FCGI_STATE_CONNECT ||
+ if (hctx->state == FCGI_STATE_CONNECT_DELAYED ||
hctx->state == FCGI_STATE_WRITE) {
/* we are allowed to send something out
*
@@ -3110,7 +3314,7 @@ static handler_t fcgi_handle_fdevent(void *s, void *ctx, int revents) {
/* perhaps this issue is already handled */
if (revents & FDEVENT_HUP) {
- if (hctx->state == FCGI_STATE_CONNECT) {
+ if (hctx->state == FCGI_STATE_CONNECT_DELAYED) {
/* getoptsock will catch this one (right ?)
*
* if we are in connect we might get a EINPROGRESS
@@ -3193,16 +3397,15 @@ static int fcgi_patch_connection(server *srv, connection *con, plugin_data *p) {
static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, int uri_path_handler) {
plugin_data *p = p_d;
size_t s_len;
- int used = -1;
- int ndx;
size_t k;
buffer *fn;
fcgi_extension *extension = NULL;
+ fcgi_extension_host *host = NULL;
/* Possibly, we processed already this request */
if (con->file_started == 1) return HANDLER_GO_ON;
-
- fn = con->uri.path;
+
+ fn = uri_path_handler ? con->uri.path : con->physical.path;
if (fn->used == 0) {
return HANDLER_ERROR;
@@ -3237,124 +3440,118 @@ static handler_t fcgi_check_extension(server *srv, connection *con, void *p_d, i
if (k == p->conf.exts->used) {
return HANDLER_GO_ON;
}
-
+
/* get best server */
- for (k = 0, ndx = -1; k < extension->used; k++) {
- fcgi_extension_host *host = extension->hosts[k];
-
+ for (k = 0; k < extension->used; k++) {
+ host = extension->hosts[k];
+
/* we should have at least one proc that can do somthing */
- if (host->active_procs == 0) continue;
+ if (host->active_procs == 0) {
+ host = NULL;
- if (used == -1 || host->load < used) {
- used = host->load;
-
- ndx = k;
+ continue;
}
+
+ /* we found one host that is alive */
+ break;
}
- /* found a server */
- if (ndx != -1) {
- fcgi_extension_host *host = extension->hosts[ndx];
+ if (!host) {
+ /* sorry, we don't have a server alive for this ext */
+ buffer_reset(con->physical.path);
+ con->http_status = 500;
- /*
- * if check-local is disabled, use the uri.path handler
- *
- */
+ log_error_write(srv, __FILE__, __LINE__, "sb",
+ "no fcgi-handler found for:",
+ fn);
- /* init handler-context */
- if (uri_path_handler) {
- if (host->check_local == 0) {
- handler_ctx *hctx;
- char *pathinfo;
-
- hctx = handler_ctx_init();
-
- hctx->remote_conn = con;
- hctx->plugin_data = p;
- hctx->host = host;
- hctx->proc = NULL;
+ return HANDLER_FINISHED;
+ }
- hctx->conf.exts = p->conf.exts;
- hctx->conf.debug = p->conf.debug;
-
- con->plugin_ctx[p->id] = hctx;
-
- host->load++;
-
- con->mode = p->id;
-
- if (con->conf.log_request_handling) {
- log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
- }
-
- /* the prefix is the SCRIPT_NAME,
- * everthing from start to the next slash
- * this is important for check-local = "disable"
- *
- * if prefix = /admin.fcgi
- *
- * /admin.fcgi/foo/bar
- *
- * SCRIPT_NAME = /admin.fcgi
- * PATH_INFO = /foo/bar
- *
- * if prefix = /fcgi-bin/
- *
- * /fcgi-bin/foo/bar
- *
- * SCRIPT_NAME = /fcgi-bin/foo
- * PATH_INFO = /bar
- *
- */
-
- /* the rewrite is only done for /prefix/? matches */
- if (extension->key->ptr[0] == '/' &&
- con->uri.path->used > extension->key->used &&
- NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
- /* rewrite uri.path and pathinfo */
-
- buffer_copy_string(con->request.pathinfo, pathinfo);
-
- con->uri.path->used -= con->request.pathinfo->used - 1;
- con->uri.path->ptr[con->uri.path->used - 1] = '\0';
- }
- }
- return HANDLER_GO_ON;
- } else {
+ /*
+ * if check-local is disabled, use the uri.path handler
+ *
+ */
+
+ /* init handler-context */
+ if (uri_path_handler) {
+ if (host->check_local == 0) {
handler_ctx *hctx;
+ char *pathinfo;
+
hctx = handler_ctx_init();
hctx->remote_conn = con;
hctx->plugin_data = p;
- hctx->host = host;
- hctx->proc = NULL;
-
+ hctx->proc = NULL;
+ hctx->ext = extension;
+
+
hctx->conf.exts = p->conf.exts;
hctx->conf.debug = p->conf.debug;
-
+
con->plugin_ctx[p->id] = hctx;
-
- host->load++;
-
+
con->mode = p->id;
-
+
if (con->conf.log_request_handling) {
- log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
+ log_error_write(srv, __FILE__, __LINE__, "s",
+ "handling it in mod_fastcgi");
}
+
+ /* the prefix is the SCRIPT_NAME,
+ * everthing from start to the next slash
+ * this is important for check-local = "disable"
+ *
+ * if prefix = /admin.fcgi
+ *
+ * /admin.fcgi/foo/bar
+ *
+ * SCRIPT_NAME = /admin.fcgi
+ * PATH_INFO = /foo/bar
+ *
+ * if prefix = /fcgi-bin/
+ *
+ * /fcgi-bin/foo/bar
+ *
+ * SCRIPT_NAME = /fcgi-bin/foo
+ * PATH_INFO = /bar
+ *
+ */
- return HANDLER_GO_ON;
+ /* the rewrite is only done for /prefix/? matches */
+ if (extension->key->ptr[0] == '/' &&
+ con->uri.path->used > extension->key->used &&
+ NULL != (pathinfo = strchr(con->uri.path->ptr + extension->key->used - 1, '/'))) {
+ /* rewrite uri.path and pathinfo */
+
+ buffer_copy_string(con->request.pathinfo, pathinfo);
+
+ con->uri.path->used -= con->request.pathinfo->used - 1;
+ con->uri.path->ptr[con->uri.path->used - 1] = '\0';
+ }
}
} else {
- /* no handler found */
- buffer_reset(con->physical.path);
- con->http_status = 500;
+ handler_ctx *hctx;
+ hctx = handler_ctx_init();
- log_error_write(srv, __FILE__, __LINE__, "sb",
- "no fcgi-handler found for:",
- fn);
+ hctx->remote_conn = con;
+ hctx->plugin_data = p;
+ hctx->proc = NULL;
+ hctx->ext = extension;
- return HANDLER_FINISHED;
+ hctx->conf.exts = p->conf.exts;
+ hctx->conf.debug = p->conf.debug;
+
+ con->plugin_ctx[p->id] = hctx;
+
+ con->mode = p->id;
+
+ if (con->conf.log_request_handling) {
+ log_error_write(srv, __FILE__, __LINE__, "s", "handling it in mod_fastcgi");
+ }
}
+
return HANDLER_GO_ON;
}
@@ -3380,7 +3577,7 @@ JOBLIST_FUNC(mod_fastcgi_handle_joblist) {
fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_IN);
break;
- case FCGI_STATE_CONNECT:
+ case FCGI_STATE_CONNECT_DELAYED:
case FCGI_STATE_WRITE:
fdevent_event_add(srv->ev, &(hctx->fde_ndx), hctx->fd, FDEVENT_OUT);
@@ -3598,7 +3795,7 @@ TRIGGER_FUNC(mod_fastcgi_handle_trigger) {
int mod_fastcgi_plugin_init(plugin *p) {
- p->version = LIGHTTPD_VERSION_ID;
+ p->version = LIGHTTPD_VERSION_ID;
p->name = buffer_init_string("fastcgi");
p->init = mod_fastcgi_init;