]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
[BUG] process_response: do not touch srv_state
authorWilly Tarreau <w@1wt.eu>
Sat, 16 Aug 2008 16:40:18 +0000 (18:40 +0200)
committerWilly Tarreau <w@1wt.eu>
Sat, 16 Aug 2008 16:40:18 +0000 (18:40 +0200)
process_response is not allowed to touch srv_state (this is an
incident which has survived the code migration). This bug was
causing connection exhaustion on frontend due to some closed
sockets marked SV_STDATA again.

src/proto_http.c

index 1f7f035d6b1bf51afe0e483a5d9b7b149cf95278..c4c527663362041c4cbde775fb2b043cf87d4c08 100644 (file)
@@ -709,6 +709,11 @@ void process_session(struct task *t, int *next)
                /* restore t to its place in the task list */
                task_queue(t);
 
+#ifdef DEBUG_DEV
+               /* this may only happen when no timeout is set or in case of an FSM bug */
+               if (!t->expire)
+                       ABORT_NOW();
+#endif
                *next = t->expire;
                return; /* nothing more to do */
        }
@@ -1571,7 +1576,8 @@ int process_request(struct session *t)
        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,
                cli_stnames[t->cli_state], srv_stnames[t->srv_state],
-               EV_FD_ISSET(t->cli_fd, DIR_RD), EV_FD_ISSET(t->cli_fd, DIR_WR),
+               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,
                req->rex, rep->wex, req->flags, rep->flags, t->analysis);
 
        if (t->analysis & AN_REQ_INSPECT) {
@@ -2522,7 +2528,8 @@ int process_response(struct session *t)
        DPRINTF(stderr,"[%u] process_rep: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%u,%u req=%08x rep=%08x analysis=%02x\n",
                now_ms,
                cli_stnames[t->cli_state], srv_stnames[t->srv_state],
-               EV_FD_ISSET(t->srv_fd, DIR_RD), EV_FD_ISSET(t->srv_fd, DIR_WR),
+               t->srv_fd >= 0 && fdtab[t->srv_fd].state != FD_STCLOSE ? EV_FD_ISSET(t->srv_fd, DIR_RD) : 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);
 
        if (t->analysis & AN_RTR_HTTP_HDR) { /* receiving server headers */
@@ -2674,6 +2681,8 @@ int process_response(struct session *t)
                 * of each header's length, so we can parse them quickly.        *
                 ****************************************************************/
 
+               t->analysis &= ~AN_RTR_HTTP_HDR;
+
                /* ensure we keep this pointer to the beginning of the message */
                msg->sol = rep->data + msg->som;
 
@@ -2939,8 +2948,6 @@ int process_response(struct session *t)
                 * could. Let's switch to the DATA state.                    *
                 ************************************************************/
 
-               t->srv_state = SV_STDATA;
-               t->analysis &= ~AN_RTR_ANY;
                rep->rlim = rep->data + BUFSIZE; /* no more rewrite needed */
                t->logs.t_data = tv_ms_elapsed(&t->logs.tv_accept, &now);
 
@@ -2977,6 +2984,8 @@ int process_response(struct session *t)
  * manages the client FSM and its socket. BTW, it also tries to handle the
  * cookie. It returns 1 if a state has changed (and a resync may be needed),
  * 0 else.
+ * Note: process_srv is the ONLY function allowed to set cli_state to anything
+ *       but CL_STCLOSE.
  */
 int process_cli(struct session *t)
 {
@@ -2986,7 +2995,8 @@ int process_cli(struct session *t)
        DPRINTF(stderr,"[%u] process_cli: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%u,%u req=%08x rep=%08x rql=%d rpl=%d\n",
                now_ms,
                cli_stnames[t->cli_state], srv_stnames[t->srv_state],
-               EV_FD_ISSET(t->cli_fd, DIR_RD), EV_FD_ISSET(t->cli_fd, DIR_WR),
+               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,
                req->rex, rep->wex,
                req->flags, rep->flags,
                req->l, rep->l);
@@ -3190,6 +3200,9 @@ int process_cli(struct session *t)
 /*
  * manages the server FSM and its socket. It returns 1 if a state has changed
  * (and a resync may be needed), 0 else.
+ * 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
+ *       one (eg: those in backend.c).
  */
 int process_srv(struct session *t)
 {
@@ -3201,7 +3214,8 @@ int process_srv(struct session *t)
        DPRINTF(stderr,"[%u] process_srv: c=%s s=%s set(r,w)=%d,%d exp(r,w)=%u,%u req=%08x rep=%08x rql=%d rpl=%d\n",
                now_ms,
                cli_stnames[t->cli_state], srv_stnames[t->srv_state],
-               EV_FD_ISSET(t->srv_fd, DIR_RD), EV_FD_ISSET(t->srv_fd, DIR_WR),
+               t->srv_fd >= 0 && fdtab[t->srv_fd].state != FD_STCLOSE ? EV_FD_ISSET(t->srv_fd, DIR_RD) : 0,
+               t->srv_fd >= 0 && fdtab[t->srv_fd].state != FD_STCLOSE ? EV_FD_ISSET(t->srv_fd, DIR_WR) : 0,
                rep->rex, req->wex,
                req->flags, rep->flags,
                req->l, rep->l);