[MAJOR] make the client side use stream_sock_process_data()

The client side now relies on stream_sock_process_data(). One
part has not yet been re-implemented, it concerns the calls
to produce_content().

process_session() has been adjusted to correctly check for
changing bits in order not to call useless functions too many
times.

It already appears that stream_sock_process_data() should be
split so that the timeout computations are only performed at
the exit of process_session().
This commit is contained in:
Willy Tarreau 2008-08-27 23:57:16 +02:00
parent 2d2127989c
commit f9839bdffe
2 changed files with 316 additions and 318 deletions

View File

@ -66,6 +66,12 @@
#define BF_SHUTW_NOW 262144 /* the consumer must shut down for writes ASAP */ #define BF_SHUTW_NOW 262144 /* the consumer must shut down for writes ASAP */
#define BF_HIJACK 524288 /* the producer is temporarily replaced */ #define BF_HIJACK 524288 /* the producer is temporarily replaced */
/* masks which define input bits for stream interfaces and stream analysers */
#define BF_MASK_INTERFACE_I (BF_FULL|BF_HIJACK|BF_READ_NULL|BF_SHUTR|BF_SHUTR_NOW|BF_SHUTW)
#define BF_MASK_INTERFACE_O (BF_EMPTY|BF_HIJACK|BF_MAY_FORWARD|BF_SHUTR|BF_SHUTW|BF_SHUTW_NOW)
#define BF_MASK_INTERFACE (BF_MASK_INTF_I | BF_MASK_INTF_O)
#define BF_MASK_ANALYSER (BF_FULL|BF_READ_ERROR|BF_READ_TIMEOUT|BF_WRITE_ERROR|BF_SHUTW|BF_SHUTR|BF_READ_NULL)
/* Analysers (buffer->analysers). /* Analysers (buffer->analysers).
* Those bits indicate that there are some processing to do on the buffer * Those bits indicate that there are some processing to do on the buffer

View File

@ -650,98 +650,45 @@ http_get_path(struct http_txn *txn)
* to be woken up, or TICK_ETERNITY. In order not to call all functions for * to be woken up, or TICK_ETERNITY. In order not to call all functions for
* nothing too many times, the request and response buffers flags are monitored * 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 * 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 * least one flag it is interested in.
* 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;
unsigned resync = PROCESS_ALL; int resync;
unsigned int rqf; unsigned int rqf_cli, rpf_cli;
unsigned int rpf; unsigned int rqf_srv, rpf_srv;
unsigned int rqf_req, rpf_rep;
/* check timeout expiration only once and adjust buffer flags /* force one first pass everywhere */
* accordingly. rqf_cli = rqf_srv = rqf_req = ~s->req->flags;
*/ rpf_cli = rpf_srv = rpf_rep = ~s->rep->flags;
if (unlikely(tick_is_expired(t->expire, now_ms))) {
if (tick_is_expired(s->req->rex, now_ms))
s->req->flags |= BF_READ_TIMEOUT;
//if (tick_is_expired(s->req->wex, now_ms))
// s->req->flags |= BF_WRITE_TIMEOUT;
//
//if (tick_is_expired(s->rep->rex, now_ms))
// s->rep->flags |= BF_READ_TIMEOUT;
if (tick_is_expired(s->rep->wex, now_ms))
s->rep->flags |= BF_WRITE_TIMEOUT;
}
//if (fdtab[s->cli_fd].state == FD_STERROR) {
// fprintf(stderr, "s=%p fd=%d req=%p rep=%p cs=%d ss=%d, term=%08x\n",
// s, s->cli_fd, s->req, s->rep, s->cli_state,
// s->si[1].state, s->term_trace);
// sleep(1);
//}
do { do {
if (resync & PROCESS_REQ) { resync = 0;
resync &= ~PROCESS_REQ;
rqf = s->req->flags;
rpf = s->rep->flags;
/* the analysers must block it themselves */ if (((rqf_cli ^ s->req->flags) & BF_MASK_INTERFACE_I) ||
s->req->flags |= BF_MAY_FORWARD; ((rpf_cli ^ s->rep->flags) & BF_MASK_INTERFACE_O)) {
resync = 1;
if (s->req->analysers) { if (s->rep->cons->state != SI_ST_CLO) {
if (process_request(s)) stream_sock_process_data(s->rep->cons->fd);
resync |= PROCESS_REQ; if (unlikely((s->rep->cons->state == SI_ST_CLO) &&
(global.mode & MODE_DEBUG) &&
if (rqf != s->req->flags || rpf != s->rep->flags) (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE)))) {
resync |= PROCESS_ALL & ~PROCESS_REQ; int len;
len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n",
s->uniq_id, s->be->id, (unsigned short)s->rep->cons->fd, (unsigned short)s->req->cons->fd);
write(1, trash, len);
}
} }
rqf_cli = s->req->flags;
rpf_cli = s->rep->flags;
} }
if (resync & PROCESS_RTR) {
resync &= ~PROCESS_RTR;
rqf = s->req->flags;
rpf = s->rep->flags;
/* the analysers must block it themselves */ if (((rpf_srv ^ s->rep->flags) & BF_MASK_INTERFACE_I) ||
s->rep->flags |= BF_MAY_FORWARD; ((rqf_srv ^ s->req->flags) & BF_MASK_INTERFACE_O)) {
resync = 1;
if (s->rep->analysers) {
if (process_response(s))
resync |= PROCESS_RTR;
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 (s->req->cons->state != SI_ST_CLO) { if (s->req->cons->state != SI_ST_CLO) {
if (s->req->cons->state < SI_ST_EST && s->req->flags & BF_MAY_FORWARD) if (s->req->cons->state < SI_ST_EST && s->req->flags & BF_MAY_FORWARD)
process_srv_conn(s); process_srv_conn(s);
@ -757,8 +704,7 @@ void process_session(struct task *t, int *next)
buffer_shutw_now(s->req); buffer_shutw_now(s->req);
} }
if (stream_sock_process_data(s->req->cons->fd)) stream_sock_process_data(s->req->cons->fd);
resync |= PROCESS_SRV;
/* Count server-side errors (but not timeouts). */ /* Count server-side errors (but not timeouts). */
if (s->req->flags & BF_WRITE_ERROR) { if (s->req->flags & BF_WRITE_ERROR) {
@ -789,12 +735,34 @@ void process_session(struct task *t, int *next)
write(1, trash, len); write(1, trash, len);
} }
} }
if (rqf != s->req->flags || rpf != s->rep->flags) rqf_srv = s->req->flags;
resync |= PROCESS_ALL & ~PROCESS_SRV; rpf_srv = s->rep->flags;
} }
if ((rqf_req ^ s->req->flags) & BF_MASK_ANALYSER) {
resync = 1;
/* the analysers must block it themselves */
s->req->flags |= BF_MAY_FORWARD;
if (s->req->analysers) {
process_request(s);
}
rqf_req = s->req->flags;
}
if ((rpf_rep ^ s->rep->flags) & BF_MASK_ANALYSER) {
resync = 1;
/* the analysers must block it themselves */
s->rep->flags |= BF_MAY_FORWARD;
if (s->rep->analysers) {
process_response(s);
}
rpf_rep = s->rep->flags;
}
} while (resync); } while (resync);
if (likely(s->cli_state != CL_STCLOSE || if (likely((s->rep->cons->state != SI_ST_CLO) ||
(s->req->cons->state != SI_ST_CLO && s->req->cons->state != SI_ST_INI))) { (s->req->cons->state != SI_ST_CLO && s->req->cons->state != SI_ST_INI))) {
if ((s->fe->options & PR_O_CONTSTATS) && (s->flags & SN_BE_ASSIGNED)) if ((s->fe->options & PR_O_CONTSTATS) && (s->flags & SN_BE_ASSIGNED))
@ -1724,7 +1692,7 @@ int process_request(struct session *t)
*/ */
if (req->flags & BF_READ_ERROR) { if (req->flags & BF_READ_ERROR) {
req->analysers = 0; req->analysers = 0;
t->fe->failed_req++; //t->fe->failed_req++;
if (!(t->flags & SN_ERR_MASK)) if (!(t->flags & SN_ERR_MASK))
t->flags |= SN_ERR_CLICL; t->flags |= SN_ERR_CLICL;
if (!(t->flags & SN_FINST_MASK)) if (!(t->flags & SN_FINST_MASK))
@ -1879,14 +1847,12 @@ int process_request(struct session *t)
goto return_bad_req; goto return_bad_req;
} }
/* 2: have we encountered a close ? */ /* 2: have we encountered a read error ? */
else if (req->flags & (BF_READ_NULL | BF_SHUTR)) { else if (req->flags & BF_READ_ERROR) {
txn->status = 400; /* we cannot return any message on error */
client_retnclose(t, error_message(t, HTTP_ERR_400));
msg->msg_state = HTTP_MSG_ERROR; msg->msg_state = HTTP_MSG_ERROR;
req->analysers = 0; req->analysers = 0;
t->fe->failed_req++; //t->fe->failed_req++;
if (!(t->flags & SN_ERR_MASK)) if (!(t->flags & SN_ERR_MASK))
t->flags |= SN_ERR_CLICL; t->flags |= SN_ERR_CLICL;
if (!(t->flags & SN_FINST_MASK)) if (!(t->flags & SN_FINST_MASK))
@ -1909,12 +1875,14 @@ int process_request(struct session *t)
return 0; return 0;
} }
/* 4: have we encountered a read error ? */ /* 4: have we encountered a close ? */
else if (req->flags & BF_READ_ERROR) { else if (req->flags & (BF_READ_NULL | BF_SHUTR)) {
/* we cannot return any message on error */ txn->status = 400;
client_retnclose(t, error_message(t, HTTP_ERR_400));
msg->msg_state = HTTP_MSG_ERROR; msg->msg_state = HTTP_MSG_ERROR;
req->analysers = 0; req->analysers = 0;
t->fe->failed_req++; t->fe->failed_req++;
if (!(t->flags & SN_ERR_MASK)) if (!(t->flags & SN_ERR_MASK))
t->flags |= SN_ERR_CLICL; t->flags |= SN_ERR_CLICL;
if (!(t->flags & SN_FINST_MASK)) if (!(t->flags & SN_FINST_MASK))
@ -2816,18 +2784,22 @@ int process_response(struct session *t)
return 0; return 0;
} }
/* write error to client, read error or close from server */ /* too large response does not fit in buffer. */
if (rep->flags & (BF_WRITE_ERROR|BF_SHUTW|BF_READ_ERROR|BF_SHUTR|BF_READ_NULL)) { else if (rep->flags & BF_FULL) {
goto hdr_response_bad;
}
/* read error */
else if (rep->flags & BF_READ_ERROR) {
buffer_shutr_now(rep); buffer_shutr_now(rep);
buffer_shutw_now(req); buffer_shutw_now(req);
//fd_delete(req->cons->fd); //fd_delete(req->cons->fd);
//req->cons->state = SI_ST_CLO; //req->cons->state = SI_ST_CLO;
if (t->srv) { //if (t->srv) {
//t->srv->cur_sess--; //t->srv->cur_sess--;
t->srv->failed_resp++; //t->srv->failed_resp++;
//sess_change_server(t, NULL); //sess_change_server(t, NULL);
} //}
t->be->failed_resp++; //t->be->failed_resp++;
rep->analysers = 0; rep->analysers = 0;
txn->status = 502; txn->status = 502;
client_return(t, error_message(t, HTTP_ERR_502)); client_return(t, error_message(t, HTTP_ERR_502));
@ -2841,10 +2813,6 @@ int process_response(struct session *t)
return 0; return 0;
} }
/* too large response does not fit in buffer. */
else if (rep->flags & BF_FULL) {
goto hdr_response_bad;
}
/* read timeout : return a 504 to the client. */ /* read timeout : return a 504 to the client. */
else if (rep->flags & BF_READ_TIMEOUT) { else if (rep->flags & BF_READ_TIMEOUT) {
buffer_shutr_now(rep); buffer_shutr_now(rep);
@ -2869,7 +2837,31 @@ int process_response(struct session *t)
// process_srv_queue(t->srv); // process_srv_queue(t->srv);
return 0; return 0;
} }
/* write error to client, or close from server */
else if (rep->flags & (BF_WRITE_ERROR|BF_SHUTW|BF_SHUTR|BF_READ_NULL)) {
buffer_shutr_now(rep);
buffer_shutw_now(req);
//fd_delete(req->cons->fd);
//req->cons->state = SI_ST_CLO;
if (t->srv) {
//t->srv->cur_sess--;
t->srv->failed_resp++;
//sess_change_server(t, NULL);
}
t->be->failed_resp++;
rep->analysers = 0;
txn->status = 502;
client_return(t, error_message(t, HTTP_ERR_502));
if (!(t->flags & SN_ERR_MASK))
t->flags |= SN_ERR_SRVCL;
if (!(t->flags & SN_FINST_MASK))
t->flags |= SN_FINST_H;
//if (t->srv && may_dequeue_tasks(t->srv, t->be))
// process_srv_queue(t->srv);
return 0;
}
rep->flags &= ~BF_MAY_FORWARD; rep->flags &= ~BF_MAY_FORWARD;
return 0; return 0;
} }
@ -3192,219 +3184,219 @@ int process_response(struct session *t)
return 0; return 0;
} }
/* ///*
* Manages the client FSM and its socket. It normally returns zero, but may // * Manages the client FSM and its socket. It normally returns zero, but may
* return 1 if it absolutely wants to be called again. // * return 1 if it absolutely wants to be called again.
* // *
* Note: process_cli 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)
{ //{
struct buffer *req = t->req; // struct buffer *req = t->req;
struct buffer *rep = t->rep; // struct buffer *rep = t->rep;
//
DPRINTF(stderr,"[%u] %s: fd=%d[%d] c=%s set(r,w)=%d,%d exp(r,w)=%u,%u req=%08x rep=%08x rql=%d rpl=%d\n", // DPRINTF(stderr,"[%u] %s: fd=%d[%d] c=%s set(r,w)=%d,%d exp(r,w)=%u,%u req=%08x rep=%08x rql=%d rpl=%d\n",
now_ms, __FUNCTION__, // now_ms, __FUNCTION__,
t->cli_fd, t->cli_fd >= 0 ? fdtab[t->cli_fd].state : 0, /* fd,state*/ // t->cli_fd, t->cli_fd >= 0 ? fdtab[t->cli_fd].state : 0, /* fd,state*/
cli_stnames[t->cli_state], // cli_stnames[t->cli_state],
t->cli_fd >= 0 && fdtab[t->cli_fd].state != FD_STCLOSE ? EV_FD_ISSET(t->cli_fd, DIR_RD) : 0, // t->cli_fd >= 0 && fdtab[t->cli_fd].state != FD_STCLOSE ? EV_FD_ISSET(t->cli_fd, DIR_RD) : 0,
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->rex, rep->wex,
req->flags, rep->flags, // req->flags, rep->flags,
req->l, rep->l); // req->l, rep->l);
//
update_state: // update_state:
/* 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).
*/ // */
if (t->cli_state == CL_STDATA || t->cli_state == CL_STSHUTR) { // if (t->cli_state == CL_STDATA || t->cli_state == CL_STSHUTR) {
/* we can skip most of the tests at once if some conditions are not met */ // /* we can skip most of the tests at once if some conditions are not met */
if (!((fdtab[t->cli_fd].state == FD_STERROR) || // if (!((fdtab[t->cli_fd].state == FD_STERROR) ||
(req->flags & (BF_READ_TIMEOUT|BF_READ_ERROR|BF_SHUTR_NOW)) || // (req->flags & (BF_READ_TIMEOUT|BF_READ_ERROR|BF_SHUTR_NOW)) ||
(rep->flags & (BF_WRITE_TIMEOUT|BF_WRITE_ERROR|BF_SHUTW_NOW)) || // (rep->flags & (BF_WRITE_TIMEOUT|BF_WRITE_ERROR|BF_SHUTW_NOW)) ||
(!(req->flags & BF_SHUTR) && req->flags & (BF_READ_NULL|BF_SHUTW)) || // (!(req->flags & BF_SHUTR) && req->flags & (BF_READ_NULL|BF_SHUTW)) ||
(!(rep->flags & BF_SHUTW) && // (!(rep->flags & BF_SHUTW) &&
(rep->flags & (BF_EMPTY|BF_MAY_FORWARD|BF_SHUTR)) == (BF_EMPTY|BF_MAY_FORWARD|BF_SHUTR)))) // (rep->flags & (BF_EMPTY|BF_MAY_FORWARD|BF_SHUTR)) == (BF_EMPTY|BF_MAY_FORWARD|BF_SHUTR))))
goto update_timeouts; // goto update_timeouts;
//
/* read or write error */ // /* read or write error */
if (fdtab[t->cli_fd].state == FD_STERROR) { // if (fdtab[t->cli_fd].state == FD_STERROR) {
buffer_shutr(req); // buffer_shutr(req);
req->flags |= BF_READ_ERROR; // req->flags |= BF_READ_ERROR;
buffer_shutw(rep); // buffer_shutw(rep);
rep->flags |= BF_WRITE_ERROR; // rep->flags |= BF_WRITE_ERROR;
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_1); // trace_term(t, TT_HTTP_CLI_1);
if (!req->analysers) { // if (!req->analysers) {
if (!(t->flags & SN_ERR_MASK)) // if (!(t->flags & SN_ERR_MASK))
t->flags |= SN_ERR_CLICL; // t->flags |= SN_ERR_CLICL;
if (!(t->flags & SN_FINST_MASK)) { // if (!(t->flags & SN_FINST_MASK)) {
if (req->cons->err_type <= SI_ET_QUEUE_ABRT) // if (req->cons->err_type <= SI_ET_QUEUE_ABRT)
t->flags |= SN_FINST_Q; // t->flags |= SN_FINST_Q;
else if (req->cons->err_type <= SI_ET_CONN_OTHER) // else if (req->cons->err_type <= SI_ET_CONN_OTHER)
t->flags |= SN_FINST_C; // t->flags |= SN_FINST_C;
else // else
t->flags |= SN_FINST_D; // t->flags |= SN_FINST_D;
} // }
} // }
goto update_state; // goto update_state;
} // }
/* last read, or end of server write */ // /* last read, or end of server write */
else if (!(req->flags & BF_SHUTR) && /* not already done */ // else if (!(req->flags & BF_SHUTR) && /* not already done */
req->flags & (BF_READ_NULL|BF_SHUTR_NOW|BF_SHUTW)) { // req->flags & (BF_READ_NULL|BF_SHUTR_NOW|BF_SHUTW)) {
buffer_shutr(req); // buffer_shutr(req);
if (!(rep->flags & BF_SHUTW)) { // if (!(rep->flags & BF_SHUTW)) {
EV_FD_CLR(t->cli_fd, DIR_RD); // EV_FD_CLR(t->cli_fd, DIR_RD);
trace_term(t, TT_HTTP_CLI_2); // trace_term(t, TT_HTTP_CLI_2);
} else { // } else {
/* output was already closed */ // /* output was already closed */
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_3); // trace_term(t, TT_HTTP_CLI_3);
} // }
goto update_state; // 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.
*/ // */
else if (!(rep->flags & BF_SHUTW) && /* not already done */ // else if (!(rep->flags & BF_SHUTW) && /* not already done */
((rep->flags & BF_SHUTW_NOW) || // ((rep->flags & BF_SHUTW_NOW) ||
(rep->flags & BF_EMPTY && rep->flags & BF_MAY_FORWARD && // (rep->flags & BF_EMPTY && rep->flags & BF_MAY_FORWARD &&
rep->flags & BF_SHUTR && !(t->flags & SN_SELF_GEN)))) { // rep->flags & BF_SHUTR && !(t->flags & SN_SELF_GEN)))) {
buffer_shutw(rep); // buffer_shutw(rep);
if (!(req->flags & BF_SHUTR)) { // if (!(req->flags & BF_SHUTR)) {
EV_FD_CLR(t->cli_fd, DIR_WR); // EV_FD_CLR(t->cli_fd, DIR_WR);
shutdown(t->cli_fd, SHUT_WR); // shutdown(t->cli_fd, SHUT_WR);
trace_term(t, TT_HTTP_CLI_4); // trace_term(t, TT_HTTP_CLI_4);
} else { // } else {
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_5); // trace_term(t, TT_HTTP_CLI_5);
} // }
goto update_state; // goto update_state;
} // }
/* read timeout */ // /* read timeout */
else if ((req->flags & (BF_SHUTR|BF_READ_TIMEOUT)) == BF_READ_TIMEOUT) { // else if ((req->flags & (BF_SHUTR|BF_READ_TIMEOUT)) == BF_READ_TIMEOUT) {
buffer_shutr(req); // buffer_shutr(req);
if (!(rep->flags & BF_SHUTW)) { // if (!(rep->flags & BF_SHUTW)) {
EV_FD_CLR(t->cli_fd, DIR_RD); // EV_FD_CLR(t->cli_fd, DIR_RD);
trace_term(t, TT_HTTP_CLI_6); // trace_term(t, TT_HTTP_CLI_6);
} else { // } else {
/* output was already closed */ // /* output was already closed */
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_7); // trace_term(t, TT_HTTP_CLI_7);
} // }
if (!req->analysers) { // if (!req->analysers) {
if (!(t->flags & SN_ERR_MASK)) // if (!(t->flags & SN_ERR_MASK))
t->flags |= SN_ERR_CLITO; // t->flags |= SN_ERR_CLITO;
if (!(t->flags & SN_FINST_MASK)) { // if (!(t->flags & SN_FINST_MASK)) {
if (req->cons->err_type <= SI_ET_QUEUE_ABRT) // if (req->cons->err_type <= SI_ET_QUEUE_ABRT)
t->flags |= SN_FINST_Q; // t->flags |= SN_FINST_Q;
else if (req->cons->err_type <= SI_ET_CONN_OTHER) // else if (req->cons->err_type <= SI_ET_CONN_OTHER)
t->flags |= SN_FINST_C; // t->flags |= SN_FINST_C;
else // else
t->flags |= SN_FINST_D; // t->flags |= SN_FINST_D;
} // }
} // }
goto update_state; // goto update_state;
} // }
/* write timeout */ // /* write timeout */
else if ((rep->flags & (BF_SHUTW|BF_WRITE_TIMEOUT)) == BF_WRITE_TIMEOUT) { // else if ((rep->flags & (BF_SHUTW|BF_WRITE_TIMEOUT)) == BF_WRITE_TIMEOUT) {
buffer_shutw(rep); // buffer_shutw(rep);
if (!(req->flags & BF_SHUTR)) { // if (!(req->flags & BF_SHUTR)) {
EV_FD_CLR(t->cli_fd, DIR_WR); // EV_FD_CLR(t->cli_fd, DIR_WR);
shutdown(t->cli_fd, SHUT_WR); // shutdown(t->cli_fd, SHUT_WR);
trace_term(t, TT_HTTP_CLI_8); // trace_term(t, TT_HTTP_CLI_8);
} else { // } else {
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_9); // trace_term(t, TT_HTTP_CLI_9);
} // }
if (!req->analysers) { // if (!req->analysers) {
if (!(t->flags & SN_ERR_MASK)) // if (!(t->flags & SN_ERR_MASK))
t->flags |= SN_ERR_CLITO; // t->flags |= SN_ERR_CLITO;
if (!(t->flags & SN_FINST_MASK)) { // if (!(t->flags & SN_FINST_MASK)) {
if (req->cons->err_type <= SI_ET_QUEUE_ABRT) // if (req->cons->err_type <= SI_ET_QUEUE_ABRT)
t->flags |= SN_FINST_Q; // t->flags |= SN_FINST_Q;
else if (req->cons->err_type <= SI_ET_CONN_OTHER) // else if (req->cons->err_type <= SI_ET_CONN_OTHER)
t->flags |= SN_FINST_C; // t->flags |= SN_FINST_C;
else // else
t->flags |= SN_FINST_D; // t->flags |= SN_FINST_D;
} // }
} // }
goto update_state; // goto update_state;
} // }
//
update_timeouts: // update_timeouts:
/* manage read timeout */ // /* manage read timeout */
if (!(req->flags & BF_SHUTR)) { // if (!(req->flags & BF_SHUTR)) {
if (req->flags & BF_FULL) { // if (req->flags & BF_FULL) {
/* no room to read more data */ // /* no room to read more data */
if (EV_FD_COND_C(t->cli_fd, DIR_RD)) { // if (EV_FD_COND_C(t->cli_fd, DIR_RD)) {
/* stop reading until we get some space */ // /* stop reading until we get some space */
req->rex = TICK_ETERNITY; // req->rex = TICK_ETERNITY;
} // }
} else { // } else {
EV_FD_COND_S(t->cli_fd, DIR_RD); // EV_FD_COND_S(t->cli_fd, DIR_RD);
req->rex = tick_add_ifset(now_ms, t->fe->timeout.client); // req->rex = tick_add_ifset(now_ms, t->fe->timeout.client);
} // }
} // }
//
/* manage write timeout */ // /* manage write timeout */
if (!(rep->flags & BF_SHUTW)) { // if (!(rep->flags & BF_SHUTW)) {
/* first, we may have to produce data (eg: stats). // /* first, we may have to produce data (eg: stats).
* right now, this is limited to the SHUTR state. // * right now, this is limited to the SHUTR state.
*/ // */
if (req->flags & BF_SHUTR && t->flags & SN_SELF_GEN) { // if (req->flags & BF_SHUTR && t->flags & SN_SELF_GEN) {
produce_content(t); // produce_content(t);
if (rep->flags & BF_EMPTY) { // if (rep->flags & BF_EMPTY) {
buffer_shutw(rep); // buffer_shutw(rep);
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);
goto update_state; // goto update_state;
} // }
} // }
//
/* we don't enable client write if the buffer is empty, nor if the server has to analyze it */ // /* we don't enable client write if the buffer is empty, nor if the server has to analyze it */
if ((rep->flags & (BF_EMPTY|BF_MAY_FORWARD)) != BF_MAY_FORWARD) { // if ((rep->flags & (BF_EMPTY|BF_MAY_FORWARD)) != BF_MAY_FORWARD) {
if (EV_FD_COND_C(t->cli_fd, DIR_WR)) { // if (EV_FD_COND_C(t->cli_fd, DIR_WR)) {
/* stop writing */ // /* stop writing */
rep->wex = TICK_ETERNITY; // rep->wex = TICK_ETERNITY;
} // }
} else { // } else {
/* buffer not empty */ // /* buffer not empty */
EV_FD_COND_S(t->cli_fd, DIR_WR); // EV_FD_COND_S(t->cli_fd, DIR_WR);
if (!tick_isset(rep->wex)) { // if (!tick_isset(rep->wex)) {
/* restart writing */ // /* restart writing */
rep->wex = tick_add_ifset(now_ms, t->fe->timeout.client); // rep->wex = tick_add_ifset(now_ms, t->fe->timeout.client);
if (!(req->flags & BF_SHUTR) && tick_isset(rep->wex) && tick_isset(req->rex)) { // if (!(req->flags & BF_SHUTR) && tick_isset(rep->wex) && tick_isset(req->rex)) {
/* FIXME: to prevent the client from expiring read timeouts during writes, // /* FIXME: to prevent the client from expiring read timeouts during writes,
* we refresh it, except if it was already infinite. */ // * we refresh it, except if it was already infinite. */
req->rex = rep->wex; // req->rex = rep->wex;
} // }
} // }
} // }
} // }
return 0; /* other cases change nothing */ // return 0; /* other cases change nothing */
} // }
else if (t->cli_state == CL_STCLOSE) { /* CL_STCLOSE: nothing to do */ // else if (t->cli_state == CL_STCLOSE) { /* CL_STCLOSE: nothing to do */
if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) { // if ((global.mode & MODE_DEBUG) && (!(global.mode & MODE_QUIET) || (global.mode & MODE_VERBOSE))) {
int len; // int len;
len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n", t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)req->cons->fd); // len = sprintf(trash, "%08x:%s.clicls[%04x:%04x]\n", t->uniq_id, t->be->id, (unsigned short)t->cli_fd, (unsigned short)req->cons->fd);
write(1, trash, len); // write(1, trash, len);
} // }
return 0; // return 0;
} // }
#ifdef DEBUG_DEV //#ifdef DEBUG_DEV
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(); // ABORT_NOW();
#endif //#endif
return 0; // return 0;
} //}
/* Return 1 if the pending connection has failed and should be retried, /* Return 1 if the pending connection has failed and should be retried,