]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MEDIUM: connection: always update connection flags prior to computing polling
authorWilly Tarreau <w@1wt.eu>
Sun, 16 Dec 2012 18:19:13 +0000 (19:19 +0100)
committerWilly Tarreau <w@1wt.eu>
Mon, 17 Dec 2012 00:14:25 +0000 (01:14 +0100)
stream_int_chk_rcv_conn() did not clear connection flags before updating them. It
is unsure whether this could have caused the stalled transfers that have been
reported since dev15.

In order to avoid such further issues, we now use a simple inline function to do
all the job.

include/proto/connection.h
src/connection.c
src/stream_interface.c

index ddfb89e4eff04b92d6d33235bed8d42cc2e1c3f2..0c07f8c334657a6b84d6c82a3811786cd05da6a0 100644 (file)
@@ -114,6 +114,24 @@ void conn_update_data_polling(struct connection *c);
  */
 int conn_local_send_proxy(struct connection *conn, unsigned int flag);
 
+/* Refresh the connection's polling flags from its file descriptor status.
+ * This should be called at the beginning of a connection handler.
+ */
+static inline void conn_refresh_polling_flags(struct connection *conn)
+{
+       conn->flags &= ~(CO_FL_WAIT_ROOM | CO_FL_WAIT_RD | CO_FL_WAIT_DATA | CO_FL_WAIT_WR);
+
+       if (conn->ctrl) {
+               unsigned int flags = conn->flags & ~(CO_FL_CURR_RD_ENA | CO_FL_CURR_WR_ENA);
+
+               if (fd_ev_is_set(conn->t.sock.fd, DIR_RD))
+                       flags |= CO_FL_CURR_RD_ENA;
+               if (fd_ev_is_set(conn->t.sock.fd, DIR_WR))
+                       flags |= CO_FL_CURR_WR_ENA;
+               conn->flags = flags;
+       }
+}
+
 /* inspects c->flags and returns non-zero if DATA ENA changes from the CURR ENA
  * or if the WAIT flags are set with their respective ENA flags. Additionally,
  * non-zero is also returned if an error was reported on the connection. This
index 519a8f9cadc036ac2939e2e54cc9943c1837c610..f86afde816114a0301c9a58a1e416738aba0fa0d 100644 (file)
@@ -46,18 +46,8 @@ int conn_fd_handler(int fd)
        if (unlikely(!conn))
                return 0;
 
-       /* before engaging there, we clear the new WAIT_* flags so that we can
-        * more easily detect an EAGAIN condition from anywhere.
-        */
-       flags = conn->flags &= ~(CO_FL_WAIT_DATA|CO_FL_WAIT_ROOM|CO_FL_WAIT_RD|CO_FL_WAIT_WR);
-       flags &= ~CO_FL_ERROR; /* ensure to call the wake handler upon error */
-
-       /* adjust current polling status if it has been updated below us */
-       if (fd_ev_is_set(conn->t.sock.fd, DIR_RD))
-               conn->flags |= CO_FL_CURR_RD_ENA;
-
-       if (fd_ev_is_set(conn->t.sock.fd, DIR_WR))
-               conn->flags |= CO_FL_CURR_WR_ENA;
+       conn_refresh_polling_flags(conn);
+       flags = conn->flags & ~CO_FL_ERROR; /* ensure to call the wake handler upon error */
 
        if (unlikely(conn->flags & CO_FL_ERROR))
                goto leave;
index 5f6d85d65e591c6c4965c6d16ab75e040de34b84..bba52e7e86f2c22fb7ac7041ad2b1e28a53e1b5b 100644 (file)
@@ -765,17 +765,20 @@ static void stream_int_chk_rcv_conn(struct stream_interface *si)
        if (unlikely(si->state > SI_ST_EST || (ib->flags & CF_SHUTR)))
                return;
 
+       conn_refresh_polling_flags(si->conn);
+
        if ((ib->flags & CF_DONT_READ) || channel_full(ib)) {
                /* stop reading */
                if (!(ib->flags & CF_DONT_READ)) /* full */
                        si->flags |= SI_FL_WAIT_ROOM;
-               conn_data_stop_recv(si->conn);
+               __conn_data_stop_recv(si->conn);
        }
        else {
                /* (re)start reading */
                si->flags &= ~SI_FL_WAIT_ROOM;
-               conn_data_want_recv(si->conn);
+               __conn_data_want_recv(si->conn);
        }
+       conn_cond_update_data_polling(si->conn);
 }
 
 
@@ -804,9 +807,8 @@ static void stream_int_chk_snd_conn(struct stream_interface *si)
                 */
                if (si->conn->ctrl)
                        fd_want_send(si->conn->t.sock.fd);
-               si->conn->flags &= ~(CO_FL_WAIT_DATA|CO_FL_WAIT_ROOM|CO_FL_WAIT_RD|CO_FL_WAIT_WR);
-               if (fd_ev_is_set(si->conn->t.sock.fd, DIR_WR))
-                       si->conn->flags |= CO_FL_CURR_WR_ENA;
+
+               conn_refresh_polling_flags(si->conn);
 
                if (si_conn_send_loop(si->conn) < 0) {
                        /* Write error on the file descriptor */