|
|
|
@ -69,16 +69,17 @@ 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;
|
|
|
|
|
|
|
|
|
@ -307,13 +308,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 +332,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 */
|
|
|
|
@ -349,6 +354,21 @@ 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);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* 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) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int status_counter_dec(server *srv, const char *s, size_t len) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int status_counter_set(server *srv, const char *s, size_t len, int val) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static handler_ctx * handler_ctx_init() {
|
|
|
|
|
handler_ctx * hctx;
|
|
|
|
@ -366,8 +386,6 @@ static handler_ctx * handler_ctx_init() {
|
|
|
|
|
|
|
|
|
|
hctx->fd = -1;
|
|
|
|
|
|
|
|
|
|
hctx->delayed = 0;
|
|
|
|
|
|
|
|
|
|
hctx->reconnects = 0;
|
|
|
|
|
hctx->send_content_body = 1;
|
|
|
|
|
|
|
|
|
@ -1397,11 +1415,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 +1436,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 +1516,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,27 +1573,17 @@ 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);
|
|
|
|
|
}
|
|
|
|
|
#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
|
|
|
|
@ -1572,25 +1595,17 @@ static int fcgi_establish_connection(server *srv, handler_ctx *hctx) {
|
|
|
|
|
}
|
|
|
|
|
#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) {
|
|
|
|
@ -2279,9 +2294,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 +2558,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 +2566,12 @@ 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++;
|
|
|
|
|
|
|
|
|
|
status_counter_set(srv, CONST_STR_LEN("fastcgi.backend.<hostid>.disable"), 0);
|
|
|
|
|
|
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sbdb",
|
|
|
|
|
"fcgi-server re-enabled:",
|
|
|
|
|
host->host, host->port,
|
|
|
|
@ -2626,7 +2640,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 +2658,59 @@ static handler_t fcgi_write_request(server *srv, handler_ctx *hctx) {
|
|
|
|
|
host->unixsocket->used);
|
|
|
|
|
return HANDLER_ERROR;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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->state = PROC_STATE_DISABLED;
|
|
|
|
|
hctx->proc->disabled_until = srv->cur_ts + 10;
|
|
|
|
|
host->active_procs--;
|
|
|
|
|
|
|
|
|
|
status_counter_inc(srv, CONST_STR_LEN("fastcgi.backend.<hostid>.died"));
|
|
|
|
|
status_counter_set(srv, CONST_STR_LEN("fastcgi.backend.<hostid>.disable"), 1);
|
|
|
|
|
|
|
|
|
|
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 +2734,79 @@ 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__, "sdsdsdb",
|
|
|
|
|
"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->state = PROC_STATE_DISABLED;
|
|
|
|
|
hctx->proc->disabled_until = srv->cur_ts + 2;
|
|
|
|
|
host->active_procs--;
|
|
|
|
|
status_counter_inc(srv, CONST_STR_LEN("fastcgi.backend.<hostid>.overloaded"));
|
|
|
|
|
status_counter_set(srv, CONST_STR_LEN("fastcgi.backend.<hostid>.disable"), 1);
|
|
|
|
|
|
|
|
|
|
/* 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->state = PROC_STATE_DISABLED;
|
|
|
|
|
hctx->proc->disabled_until = srv->cur_ts + 10;
|
|
|
|
|
host->active_procs--;
|
|
|
|
|
|
|
|
|
|
status_counter_inc(srv, CONST_STR_LEN("fastcgi.backend.<hostid>.died"));
|
|
|
|
|
status_counter_set(srv, CONST_STR_LEN("fastcgi.backend.<hostid>.disable"), 1);
|
|
|
|
|
|
|
|
|
|
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"));
|
|
|
|
|
status_counter_inc(srv, CONST_STR_LEN("fastcgi.backend.<hostid>.connected"));
|
|
|
|
|
status_counter_set(srv, CONST_STR_LEN("fastcgi.backend.<hostid>.load"), hctx->proc->load);
|
|
|
|
|
|
|
|
|
|
if (p->conf.debug) {
|
|
|
|
|
log_error_write(srv, __FILE__, __LINE__, "sddbdd",
|
|
|
|
|
"got proc:",
|
|
|
|
@ -2766,9 +2827,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 +2906,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,33 +2920,62 @@ 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
|
|
|
|
|
*/
|
|
|
|
@ -2913,28 +3004,23 @@ SUBREQUEST_FUNC(mod_fastcgi_handle_subrequest) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
@ -3093,7 +3179,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 +3196,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,11 +3279,10 @@ 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;
|
|
|
|
@ -3237,124 +3322,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 +3459,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 +3677,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;
|
|
|
|
|