[MAJOR] process_session: rely only on buffer flags

Instead of calling all functions in a loop, process_session now
calls them according to buffer flags changes. This ensures that
we almost never call functions for nothing. The flags settings
are still quite coarse, but the number of average functions
calls per session has dropped from 31 to 18 (the calls to
process_srv dropped from 13 to 7 and the calls to process_cli
dropped from 13 to 8).

This could still be improved by memorizing which flags each
function uses, but that would add a level of complexity which
is not desirable and maybe even not worth the small gain.
This commit is contained in:
Willy Tarreau 2008-08-17 01:00:46 +02:00
parent e393fe224b
commit dafde43410

View File

@ -645,36 +645,88 @@ http_get_path(struct http_txn *txn)
return ptr; return ptr;
} }
/* Processes the client and server jobs of a session task, then /* Processes the client, server, request and response jobs of a session task,
* puts it back to the wait queue in a clean state, or * then puts it back to the wait queue in a clean state, or cleans up its
* cleans up its resources if it must be deleted. Returns * resources if it must be deleted. Returns in <next> the date the task wants
* the time the task accepts to wait, or TIME_ETERNITY for * to be woken up, or TICK_ETERNITY. In order not to call all functions for
* infinity. * nothing too many times, the request and response buffers flags are monitored
* and each function is called only if at least another function has changed at
* least one flag. If one of the functions called returns non-zero, then it
* will be called once again after all other functions. This permits explicit
* external loops which may be useful for complex state machines.
*/ */
#define PROCESS_CLI 0x1
#define PROCESS_SRV 0x2
#define PROCESS_REQ 0x4
#define PROCESS_RTR 0x8
#define PROCESS_ALL (PROCESS_CLI|PROCESS_SRV|PROCESS_REQ|PROCESS_RTR)
void process_session(struct task *t, int *next) void process_session(struct task *t, int *next)
{ {
struct session *s = t->context; struct session *s = t->context;
int fsm_resync = 0; unsigned resync = PROCESS_ALL;
unsigned int rqf;
unsigned int rpf;
do { do {
fsm_resync = 0; if (resync & PROCESS_REQ) {
resync &= ~PROCESS_REQ;
if (s->analysis & AN_REQ_ANY) {
rqf = s->req->flags;
rpf = s->rep->flags;
//fprintf(stderr,"before_cli:cli=%d, srv=%d, resync=%d\n", s->cli_state, s->srv_state, fsm_resync); if (process_request(s))
fsm_resync |= process_cli(s); resync |= PROCESS_REQ;
//fprintf(stderr,"before_req:cli=%d, srv=%d, resync=%d\n", s->cli_state, s->srv_state, fsm_resync); if (!(s->analysis & AN_REQ_ANY) && !(s->req->flags & BF_MAY_FORWARD))
if (s->analysis & AN_REQ_ANY) s->req->flags |= BF_MAY_FORWARD;
fsm_resync |= process_request(s);
//fprintf(stderr,"before_srv:cli=%d, srv=%d, resync=%d\n", s->cli_state, s->srv_state, fsm_resync); if (rqf != s->req->flags || rpf != s->rep->flags)
fsm_resync |= process_srv(s); resync |= PROCESS_ALL & ~PROCESS_REQ;
}
}
//fprintf(stderr,"before_rep:cli=%d, srv=%d, resync=%d\n", s->cli_state, s->srv_state, fsm_resync); if (resync & PROCESS_RTR) {
if (s->analysis & AN_RTR_ANY) resync &= ~PROCESS_RTR;
fsm_resync |= process_response(s); if (s->analysis & AN_RTR_ANY) {
rqf = s->req->flags;
rpf = s->rep->flags;
//fprintf(stderr,"endof_loop:cli=%d, srv=%d, resync=%d\n", s->cli_state, s->srv_state, fsm_resync); if (process_response(s))
} while (fsm_resync); resync |= PROCESS_RTR;
if (!(s->analysis & AN_RTR_ANY) && !(s->rep->flags & BF_MAY_FORWARD))
s->rep->flags |= BF_MAY_FORWARD;
if (rqf != s->req->flags || rpf != s->rep->flags)
resync |= PROCESS_ALL & ~PROCESS_RTR;
}
}
if (resync & PROCESS_CLI) {
rqf = s->req->flags;
rpf = s->rep->flags;
resync &= ~PROCESS_CLI;
if (process_cli(s))
resync |= PROCESS_CLI;
if (rqf != s->req->flags || rpf != s->rep->flags)
resync |= PROCESS_ALL & ~PROCESS_CLI;
}
if (resync & PROCESS_SRV) {
rqf = s->req->flags;
rpf = s->rep->flags;
resync &= ~PROCESS_SRV;
if (process_srv(s))
resync |= PROCESS_SRV;
if (rqf != s->req->flags || rpf != s->rep->flags)
resync |= PROCESS_ALL & ~PROCESS_SRV;
}
} while (resync);
if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) { if (likely(s->cli_state != CL_STCLOSE || s->srv_state != SV_STCLOSE)) {
@ -1563,15 +1615,14 @@ void http_msg_analyzer(struct buffer *buf, struct http_msg *msg, struct hdr_idx
} }
/* This function performs all the processing enabled for the current request. /* This function performs all the processing enabled for the current request.
* It returns 1 if it changes its state and it believes that another function * It normally returns zero, but may return 1 if it absolutely needs to be
* must be updated, otherwise zero. It might make sense to explode it into * called again after other functions. It relies on buffers flags, and updates
* several other functions. * t->analysis. It might make sense to explode it into several other functions.
*/ */
int process_request(struct session *t) int process_request(struct session *t)
{ {
struct buffer *req = t->req; struct buffer *req = t->req;
struct buffer *rep = t->rep; struct buffer *rep = t->rep;
int fsm_resync = 0;
DPRINTF(stderr,"[%u] process_req: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%u,%u req=%08x rep=%08x analysis=%02x\n", DPRINTF(stderr,"[%u] process_req: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%u,%u req=%08x rep=%08x analysis=%02x\n",
now_ms, now_ms,
@ -1580,6 +1631,7 @@ int process_request(struct session *t)
t->cli_fd >= 0 && fdtab[t->cli_fd].state != FD_STCLOSE ? EV_FD_ISSET(t->cli_fd, DIR_WR) : 0, t->cli_fd >= 0 && fdtab[t->cli_fd].state != FD_STCLOSE ? EV_FD_ISSET(t->cli_fd, DIR_WR) : 0,
req->rex, rep->wex, req->flags, rep->flags, t->analysis); req->rex, rep->wex, req->flags, rep->flags, t->analysis);
update_state:
if (t->analysis & AN_REQ_INSPECT) { if (t->analysis & AN_REQ_INSPECT) {
struct tcp_rule *rule; struct tcp_rule *rule;
int partial; int partial;
@ -1597,7 +1649,7 @@ int process_request(struct session *t)
t->flags |= SN_ERR_CLICL; t->flags |= SN_ERR_CLICL;
if (!(t->flags & SN_FINST_MASK)) if (!(t->flags & SN_FINST_MASK))
t->flags |= SN_FINST_R; t->flags |= SN_FINST_R;
return 1; return 0;
} }
/* Abort if client read timeout has expired */ /* Abort if client read timeout has expired */
@ -1609,7 +1661,7 @@ int process_request(struct session *t)
t->flags |= SN_ERR_CLITO; t->flags |= SN_ERR_CLITO;
if (!(t->flags & SN_FINST_MASK)) if (!(t->flags & SN_FINST_MASK))
t->flags |= SN_FINST_R; t->flags |= SN_FINST_R;
return 1; return 0;
} }
/* We don't know whether we have enough data, so must proceed /* We don't know whether we have enough data, so must proceed
@ -1637,8 +1689,7 @@ int process_request(struct session *t)
/* just set the request timeout once at the beginning of the request */ /* just set the request timeout once at the beginning of the request */
if (!tick_isset(t->inspect_exp)) if (!tick_isset(t->inspect_exp))
t->inspect_exp = tick_add_ifset(now_ms, t->fe->tcp_req.inspect_delay); t->inspect_exp = tick_add_ifset(now_ms, t->fe->tcp_req.inspect_delay);
return 0;
return fsm_resync;
} }
ret = acl_pass(ret); ret = acl_pass(ret);
@ -1660,7 +1711,7 @@ int process_request(struct session *t)
if (!(t->flags & SN_FINST_MASK)) if (!(t->flags & SN_FINST_MASK))
t->flags |= SN_FINST_R; t->flags |= SN_FINST_R;
t->inspect_exp = TICK_ETERNITY; t->inspect_exp = TICK_ETERNITY;
return 1; return 0;
} }
/* otherwise accept */ /* otherwise accept */
break; break;
@ -1672,7 +1723,6 @@ int process_request(struct session *t)
*/ */
t->analysis &= ~AN_REQ_INSPECT; t->analysis &= ~AN_REQ_INSPECT;
t->inspect_exp = TICK_ETERNITY; t->inspect_exp = TICK_ETERNITY;
fsm_resync = 1;
} }
if (t->analysis & AN_REQ_HTTP_HDR) { if (t->analysis & AN_REQ_HTTP_HDR) {
@ -1762,7 +1812,7 @@ int process_request(struct session *t)
t->flags |= SN_ERR_CLICL; t->flags |= SN_ERR_CLICL;
if (!(t->flags & SN_FINST_MASK)) if (!(t->flags & SN_FINST_MASK))
t->flags |= SN_FINST_R; t->flags |= SN_FINST_R;
return 1; return 0;
} }
/* 3: has the read timeout expired ? */ /* 3: has the read timeout expired ? */
@ -1777,7 +1827,7 @@ int process_request(struct session *t)
t->flags |= SN_ERR_CLITO; t->flags |= SN_ERR_CLITO;
if (!(t->flags & SN_FINST_MASK)) if (!(t->flags & SN_FINST_MASK))
t->flags |= SN_FINST_R; t->flags |= SN_FINST_R;
return 1; return 0;
} }
/* 4: have we encountered a read error or did we have to shutdown ? */ /* 4: have we encountered a read error or did we have to shutdown ? */
@ -1790,7 +1840,7 @@ int process_request(struct session *t)
t->flags |= SN_ERR_CLICL; t->flags |= SN_ERR_CLICL;
if (!(t->flags & SN_FINST_MASK)) if (!(t->flags & SN_FINST_MASK))
t->flags |= SN_FINST_R; t->flags |= SN_FINST_R;
return 1; return 0;
} }
/* just set the request timeout once at the beginning of the request */ /* just set the request timeout once at the beginning of the request */
@ -1798,7 +1848,7 @@ int process_request(struct session *t)
t->txn.exp = tick_add_ifset(now_ms, t->fe->timeout.httpreq); t->txn.exp = tick_add_ifset(now_ms, t->fe->timeout.httpreq);
/* we're not ready yet */ /* we're not ready yet */
return fsm_resync; return 0;
} }
@ -2428,7 +2478,6 @@ int process_request(struct session *t)
} }
/* OK let's go on with the BODY now */ /* OK let's go on with the BODY now */
fsm_resync = 1;
goto end_of_headers; goto end_of_headers;
return_bad_req: /* let's centralize all bad requests */ return_bad_req: /* let's centralize all bad requests */
@ -2442,7 +2491,7 @@ int process_request(struct session *t)
t->flags |= SN_ERR_PRXCOND; t->flags |= SN_ERR_PRXCOND;
if (!(t->flags & SN_FINST_MASK)) if (!(t->flags & SN_FINST_MASK))
t->flags |= SN_FINST_R; t->flags |= SN_FINST_R;
return 1; return 0;
end_of_headers: end_of_headers:
; // to keep gcc happy ; // to keep gcc happy
} }
@ -2506,17 +2555,19 @@ int process_request(struct session *t)
/* The situation will not evolve, so let's give up on the analysis. */ /* The situation will not evolve, so let's give up on the analysis. */
t->logs.tv_request = now; /* update the request timer to reflect full request */ t->logs.tv_request = now; /* update the request timer to reflect full request */
t->analysis &= ~AN_REQ_HTTP_BODY; t->analysis &= ~AN_REQ_HTTP_BODY;
fsm_resync = 1;
} }
} }
return fsm_resync; /* we want to leave with that clean */
if (unlikely(t->analysis & AN_REQ_ANY))
goto update_state;
return 0;
} }
/* This function performs all the processing enabled for the current response. /* This function performs all the processing enabled for the current response.
* It returns 1 if it changes its state and it believes that another function * It normally returns zero, but may return 1 if it absolutely needs to be
* must be updated, otherwise zero. It might make sense to explode it into * called again after other functions. It relies on buffers flags, and updates
* several other functions. * t->analysis. It might make sense to explode it into several other functions.
*/ */
int process_response(struct session *t) int process_response(struct session *t)
{ {
@ -2531,6 +2582,7 @@ int process_response(struct session *t)
t->srv_fd >= 0 && fdtab[t->srv_fd].state != FD_STCLOSE ? EV_FD_ISSET(t->srv_fd, DIR_WR) : 0, t->srv_fd >= 0 && fdtab[t->srv_fd].state != FD_STCLOSE ? EV_FD_ISSET(t->srv_fd, DIR_WR) : 0,
req->rex, rep->wex, req->flags, rep->flags, t->analysis); req->rex, rep->wex, req->flags, rep->flags, t->analysis);
update_state:
if (t->analysis & AN_RTR_HTTP_HDR) { /* receiving server headers */ if (t->analysis & AN_RTR_HTTP_HDR) { /* receiving server headers */
/* /*
* Now parse the partial (or complete) lines. * Now parse the partial (or complete) lines.
@ -2614,7 +2666,7 @@ int process_response(struct session *t)
if (t->srv && may_dequeue_tasks(t->srv, t->be)) if (t->srv && may_dequeue_tasks(t->srv, t->be))
process_srv_queue(t->srv); process_srv_queue(t->srv);
return 1; return 0;
} }
/* write error to client, read error or close from server */ /* write error to client, read error or close from server */
if (req->flags & BF_WRITE_ERROR || if (req->flags & BF_WRITE_ERROR ||
@ -2640,7 +2692,7 @@ int process_response(struct session *t)
if (t->srv && may_dequeue_tasks(t->srv, t->be)) if (t->srv && may_dequeue_tasks(t->srv, t->be))
process_srv_queue(t->srv); process_srv_queue(t->srv);
return 1; return 0;
} }
/* too large response does not fit in buffer. */ /* too large response does not fit in buffer. */
else if (rep->flags & BF_FULL) { else if (rep->flags & BF_FULL) {
@ -2668,7 +2720,7 @@ int process_response(struct session *t)
if (t->srv && may_dequeue_tasks(t->srv, t->be)) if (t->srv && may_dequeue_tasks(t->srv, t->be))
process_srv_queue(t->srv); process_srv_queue(t->srv);
return 1; return 0;
} }
return 0; return 0;
} }
@ -2768,7 +2820,7 @@ int process_response(struct session *t)
*/ */
if (t->srv && may_dequeue_tasks(t->srv, cur_proxy)) if (t->srv && may_dequeue_tasks(t->srv, cur_proxy))
process_srv_queue(t->srv); process_srv_queue(t->srv);
return 1; return 0;
} }
} }
@ -2974,16 +3026,20 @@ int process_response(struct session *t)
* otherwise we would not let the client side wake up. * otherwise we would not let the client side wake up.
*/ */
return 1; return 0;
} }
/* we want to leave with that clean */
if (unlikely(t->analysis & AN_RTR_ANY))
goto update_state;
return 0; return 0;
} }
/* /*
* manages the client FSM and its socket. BTW, it also tries to handle the * Manages the client FSM and its socket. It normally returns zero, but may
* cookie. It returns 1 if a state has changed (and a resync may be needed), * return 1 if it absolutely wants to be called again.
* 0 else. *
* Note: process_srv is the ONLY function allowed to set cli_state to anything * Note: process_cli is the ONLY function allowed to set cli_state to anything
* but CL_STCLOSE. * but CL_STCLOSE.
*/ */
int process_cli(struct session *t) int process_cli(struct session *t)
@ -3000,10 +3056,7 @@ int process_cli(struct session *t)
req->flags, rep->flags, req->flags, rep->flags,
req->l, rep->l); req->l, rep->l);
/* if no analysis remains, it's time to forward the connection */ update_state:
if (!(t->analysis & AN_REQ_ANY) && !(req->flags & BF_MAY_FORWARD))
req->flags |= BF_MAY_FORWARD;
/* FIXME: we still have to check for CL_STSHUTR because client_retnclose /* FIXME: we still have to check for CL_STSHUTR because client_retnclose
* still set this state (and will do until unix sockets are converted). * still set this state (and will do until unix sockets are converted).
*/ */
@ -3027,7 +3080,7 @@ int process_cli(struct session *t)
else else
t->flags |= SN_FINST_D; t->flags |= SN_FINST_D;
} }
return 1; goto update_state;
} }
/* last read, or end of server write */ /* last read, or end of server write */
else if (!(req->flags & BF_SHUTR) && /* already done */ else if (!(req->flags & BF_SHUTR) && /* already done */
@ -3042,7 +3095,7 @@ int process_cli(struct session *t)
t->cli_state = CL_STCLOSE; t->cli_state = CL_STCLOSE;
trace_term(t, TT_HTTP_CLI_3); trace_term(t, TT_HTTP_CLI_3);
} }
return 1; goto update_state;
} }
/* last server read and buffer empty : we only check them when we're /* last server read and buffer empty : we only check them when we're
* allowed to forward the data. * allowed to forward the data.
@ -3064,7 +3117,7 @@ int process_cli(struct session *t)
t->cli_state = CL_STCLOSE; t->cli_state = CL_STCLOSE;
trace_term(t, TT_HTTP_CLI_5); trace_term(t, TT_HTTP_CLI_5);
} }
return 1; goto update_state;
} }
/* read timeout */ /* read timeout */
else if (tick_is_expired(req->rex, now_ms)) { else if (tick_is_expired(req->rex, now_ms)) {
@ -3091,7 +3144,7 @@ int process_cli(struct session *t)
else else
t->flags |= SN_FINST_D; t->flags |= SN_FINST_D;
} }
return 1; goto update_state;
} }
/* write timeout */ /* write timeout */
else if (tick_is_expired(rep->wex, now_ms)) { else if (tick_is_expired(rep->wex, now_ms)) {
@ -3123,7 +3176,7 @@ int process_cli(struct session *t)
else else
t->flags |= SN_FINST_D; t->flags |= SN_FINST_D;
} }
return 1; goto update_state;
} }
/* manage read timeout */ /* manage read timeout */
@ -3152,7 +3205,7 @@ int process_cli(struct session *t)
fd_delete(t->cli_fd); fd_delete(t->cli_fd);
t->cli_state = CL_STCLOSE; t->cli_state = CL_STCLOSE;
trace_term(t, TT_HTTP_CLI_10); trace_term(t, TT_HTTP_CLI_10);
return 1; goto update_state;
} }
} }
@ -3186,19 +3239,18 @@ int process_cli(struct session *t)
} }
return 0; return 0;
} }
#ifdef DEBUG_FULL #ifdef DEBUG_DEV
else { fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, t->cli_state);
fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, t->cli_state); ABORT_NOW();
exit(1);
}
#endif #endif
return 0; return 0;
} }
/* /*
* manages the server FSM and its socket. It returns 1 if a state has changed * Manages the server FSM and its socket. It normally returns zero, but may
* (and a resync may be needed), 0 else. * return 1 if it absolutely wants to be called again.
*
* Note: process_srv is the ONLY function allowed to set srv_state to anything * Note: process_srv is the ONLY function allowed to set srv_state to anything
* but SV_STCLOSE. The only exception is for functions called from this * but SV_STCLOSE. The only exception is for functions called from this
* one (eg: those in backend.c). * one (eg: those in backend.c).
@ -3219,10 +3271,7 @@ int process_srv(struct session *t)
req->flags, rep->flags, req->flags, rep->flags,
req->l, rep->l); req->l, rep->l);
/* if no analysis remains, we have to let the data pass */ update_state:
if (!(t->analysis & AN_RTR_ANY) && !(rep->flags & BF_MAY_FORWARD))
rep->flags |= BF_MAY_FORWARD;
if (t->srv_state == SV_STIDLE) { if (t->srv_state == SV_STIDLE) {
if ((rep->flags & BF_SHUTW) || if ((rep->flags & BF_SHUTW) ||
((req->flags & BF_SHUTR) && ((req->flags & BF_SHUTR) &&
@ -3239,7 +3288,7 @@ int process_srv(struct session *t)
srv_close_with_err(t, SN_ERR_CLICL, t->pend_pos ? SN_FINST_Q : SN_FINST_C, 0, NULL); srv_close_with_err(t, SN_ERR_CLICL, t->pend_pos ? SN_FINST_Q : SN_FINST_C, 0, NULL);
trace_term(t, TT_HTTP_SRV_1); trace_term(t, TT_HTTP_SRV_1);
return 1; goto update_state;
} }
else if (req->flags & BF_MAY_FORWARD) { else if (req->flags & BF_MAY_FORWARD) {
/* the client allows the server to connect */ /* the client allows the server to connect */
@ -3262,7 +3311,7 @@ int process_srv(struct session *t)
srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T, srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_T,
500, error_message(t, HTTP_ERR_500)); 500, error_message(t, HTTP_ERR_500));
trace_term(t, TT_HTTP_SRV_2); trace_term(t, TT_HTTP_SRV_2);
return 1; goto update_state;
} }
/* Right now, we will need to create a connection to the server. /* Right now, we will need to create a connection to the server.
@ -3283,7 +3332,7 @@ int process_srv(struct session *t)
if (t->srv) if (t->srv)
t->srv->failed_conns++; t->srv->failed_conns++;
t->be->failed_conns++; t->be->failed_conns++;
return 1; goto update_state;
} }
} }
@ -3292,8 +3341,11 @@ int process_srv(struct session *t)
if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD) if (txn->meth == HTTP_METH_GET || txn->meth == HTTP_METH_HEAD)
t->flags |= SN_REDIRECTABLE; t->flags |= SN_REDIRECTABLE;
if (srv_redispatch_connect(t)) if (srv_redispatch_connect(t)) {
return t->srv_state != SV_STIDLE; if (t->srv_state == SV_STIDLE)
return 0;
goto update_state;
}
if ((t->flags & SN_REDIRECTABLE) && t->srv && t->srv->rdr_len) { if ((t->flags & SN_REDIRECTABLE) && t->srv && t->srv->rdr_len) {
/* Server supporting redirection and it is possible. /* Server supporting redirection and it is possible.
@ -3335,14 +3387,14 @@ int process_srv(struct session *t)
/* FIXME: we should increase a counter of redirects per server and per backend. */ /* FIXME: we should increase a counter of redirects per server and per backend. */
if (t->srv) if (t->srv)
t->srv->cum_sess++; t->srv->cum_sess++;
return 1; goto update_state;
cancel_redir: cancel_redir:
txn->status = 400; txn->status = 400;
t->fe->failed_req++; t->fe->failed_req++;
srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_C, srv_close_with_err(t, SN_ERR_PRXCOND, SN_FINST_C,
400, error_message(t, HTTP_ERR_400)); 400, error_message(t, HTTP_ERR_400));
trace_term(t, TT_HTTP_SRV_4); trace_term(t, TT_HTTP_SRV_4);
return 1; goto update_state;
} }
/* try to (re-)connect to the server, and fail if we expire the /* try to (re-)connect to the server, and fail if we expire the
@ -3350,10 +3402,13 @@ int process_srv(struct session *t)
*/ */
if (srv_retryable_connect(t)) { if (srv_retryable_connect(t)) {
t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now); t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
return t->srv_state != SV_STIDLE; if (t->srv_state == SV_STIDLE)
return 0;
goto update_state;
} }
} while (1); } while (1);
} } /* end if may_forward */
return 0;
} }
else if (t->srv_state == SV_STCONN) { /* connection in progress */ else if (t->srv_state == SV_STCONN) { /* connection in progress */
if ((rep->flags & BF_SHUTW) || if ((rep->flags & BF_SHUTW) ||
@ -3375,7 +3430,7 @@ int process_srv(struct session *t)
*/ */
srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, NULL); srv_close_with_err(t, SN_ERR_CLICL, SN_FINST_C, 0, NULL);
trace_term(t, TT_HTTP_SRV_5); trace_term(t, TT_HTTP_SRV_5);
return 1; goto update_state;
} }
if (!(req->flags & BF_WRITE_STATUS) && !tick_is_expired(req->cex, now_ms)) { if (!(req->flags & BF_WRITE_STATUS) && !tick_is_expired(req->cex, now_ms)) {
return 0; /* nothing changed */ return 0; /* nothing changed */
@ -3401,8 +3456,9 @@ int process_srv(struct session *t)
conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error. conn_err = SN_ERR_SRVCL; // it was an asynchronous connect error.
/* ensure that we have enough retries left */ /* ensure that we have enough retries left */
if (srv_count_retry_down(t, conn_err)) if (srv_count_retry_down(t, conn_err)) {
return 1; goto update_state;
}
if (req->flags & BF_WRITE_ERROR) { if (req->flags & BF_WRITE_ERROR) {
/* we encountered an immediate connection error, and we /* we encountered an immediate connection error, and we
@ -3430,8 +3486,11 @@ int process_srv(struct session *t)
t->prev_srv = t->srv; t->prev_srv = t->srv;
/* first, get a connection */ /* first, get a connection */
if (srv_redispatch_connect(t)) if (srv_redispatch_connect(t)) {
return t->srv_state != SV_STCONN; if (t->srv_state == SV_STCONN)
return 0;
goto update_state;
}
} else { } else {
if (t->srv) if (t->srv)
t->srv->retries++; t->srv->retries++;
@ -3446,12 +3505,17 @@ int process_srv(struct session *t)
*/ */
if (srv_retryable_connect(t)) { if (srv_retryable_connect(t)) {
t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now); t->logs.t_queue = tv_ms_elapsed(&t->logs.tv_accept, &now);
return t->srv_state != SV_STCONN; if (t->srv_state == SV_STCONN)
return 0;
goto update_state;
} }
/* we need to redispatch the connection to another server */ /* we need to redispatch the connection to another server */
if (srv_redispatch_connect(t)) if (srv_redispatch_connect(t)) {
return t->srv_state != SV_STCONN; if (t->srv_state == SV_STCONN)
return 0;
goto update_state;
}
} while (1); } while (1);
} }
else { /* no error or write 0 */ else { /* no error or write 0 */
@ -3473,7 +3537,6 @@ int process_srv(struct session *t)
if (t->be->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */ if (t->be->mode == PR_MODE_TCP) { /* let's allow immediate data connection in this case */
EV_FD_SET(t->srv_fd, DIR_RD); EV_FD_SET(t->srv_fd, DIR_RD);
rep->rex = tick_add_ifset(now_ms, t->be->timeout.server); rep->rex = tick_add_ifset(now_ms, t->be->timeout.server);
t->srv_state = SV_STDATA;
buffer_set_rlim(rep, BUFSIZE); /* no rewrite needed */ buffer_set_rlim(rep, BUFSIZE); /* no rewrite needed */
/* if the user wants to log as soon as possible, without counting /* if the user wants to log as soon as possible, without counting
@ -3490,7 +3553,6 @@ int process_srv(struct session *t)
#endif #endif
} }
else { else {
t->srv_state = SV_STDATA;
t->analysis |= AN_RTR_HTTP_HDR; t->analysis |= AN_RTR_HTTP_HDR;
buffer_set_rlim(rep, BUFSIZE - MAXREWRITE); /* rewrite needed */ buffer_set_rlim(rep, BUFSIZE - MAXREWRITE); /* rewrite needed */
t->txn.rsp.msg_state = HTTP_MSG_RPBEFORE; t->txn.rsp.msg_state = HTTP_MSG_RPBEFORE;
@ -3499,9 +3561,13 @@ int process_srv(struct session *t)
* hdr_idx_init(&t->txn.hdr_idx); * hdr_idx_init(&t->txn.hdr_idx);
*/ */
} }
t->srv_state = SV_STDATA;
if (!(t->analysis & AN_RTR_ANY))
t->rep->flags |= BF_MAY_FORWARD;
req->cex = TICK_ETERNITY; req->cex = TICK_ETERNITY;
return 1; goto update_state;
} } /* else no error or write 0 */
} }
else if (t->srv_state == SV_STDATA) { else if (t->srv_state == SV_STDATA) {
/* read or write error */ /* read or write error */
@ -3526,7 +3592,7 @@ int process_srv(struct session *t)
if (may_dequeue_tasks(t->srv, t->be)) if (may_dequeue_tasks(t->srv, t->be))
process_srv_queue(t->srv); process_srv_queue(t->srv);
return 1; goto update_state;
} }
/* last read, or end of client write */ /* last read, or end of client write */
else if (!(rep->flags & BF_SHUTR) && /* not already done */ else if (!(rep->flags & BF_SHUTR) && /* not already done */
@ -3548,7 +3614,7 @@ int process_srv(struct session *t)
if (may_dequeue_tasks(t->srv, t->be)) if (may_dequeue_tasks(t->srv, t->be))
process_srv_queue(t->srv); process_srv_queue(t->srv);
} }
return 1; goto update_state;
} }
/* end of client read and no more data to send. We can forward /* end of client read and no more data to send. We can forward
* the close when we're allowed to forward data (anytime right * the close when we're allowed to forward data (anytime right
@ -3581,7 +3647,7 @@ int process_srv(struct session *t)
if (may_dequeue_tasks(t->srv, t->be)) if (may_dequeue_tasks(t->srv, t->be))
process_srv_queue(t->srv); process_srv_queue(t->srv);
} }
return 1; goto update_state;
} }
/* read timeout */ /* read timeout */
else if (tick_is_expired(rep->rex, now_ms)) { else if (tick_is_expired(rep->rex, now_ms)) {
@ -3606,7 +3672,8 @@ int process_srv(struct session *t)
t->flags |= SN_ERR_SRVTO; t->flags |= SN_ERR_SRVTO;
if (!(t->flags & SN_FINST_MASK)) if (!(t->flags & SN_FINST_MASK))
t->flags |= SN_FINST_D; t->flags |= SN_FINST_D;
return 1;
goto update_state;
} }
/* write timeout */ /* write timeout */
else if (tick_is_expired(req->wex, now_ms)) { else if (tick_is_expired(req->wex, now_ms)) {
@ -3636,7 +3703,8 @@ int process_srv(struct session *t)
t->flags |= SN_ERR_SRVTO; t->flags |= SN_ERR_SRVTO;
if (!(t->flags & SN_FINST_MASK)) if (!(t->flags & SN_FINST_MASK))
t->flags |= SN_FINST_D; t->flags |= SN_FINST_D;
return 1;
goto update_state;
} }
/* manage read timeout */ /* manage read timeout */
@ -3682,11 +3750,9 @@ int process_srv(struct session *t)
} }
return 0; return 0;
} }
#ifdef DEBUG_FULL #ifdef DEBUG_DEV
else { fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, t->srv_state);
fprintf(stderr, "FIXME !!!! impossible state at %s:%d = %d\n", __FILE__, __LINE__, t->srv_state); ABORT_NOW();
exit(1);
}
#endif #endif
return 0; return 0;
} }