]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: client: Fixed handling of stalled connections that emerge when the client...
authorStephan Bosch <stephan@rename-it.nl>
Thu, 24 Mar 2016 17:47:28 +0000 (02:47 +0900)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Tue, 29 Mar 2016 08:21:43 +0000 (11:21 +0300)
Inside the peer's request handler routine, the connections are verified
after the ioloop continues. If they turn out to be broken, they
self-destruct while the handler routine is active, leading to problems.

Solved by referencing the connection and retrying the connection statistics
loop when a connection is lost in the process.

src/lib-http/http-client-peer.c

index 53aebfcaa5299dca3f2d7927dbcf5b78c1fe0600..ed4e305dd357a6781f71a5e159c9883ef870b115 100644 (file)
@@ -275,17 +275,22 @@ http_client_peer_handle_requests_real(struct http_client_peer *peer)
        peer->handling_requests = TRUE;
        t_array_init(&conns_avail, array_count(&peer->conns));
        do {
+               bool conn_lost = FALSE;
+
                array_clear(&conns_avail);
                connecting = closing = idle = 0;
 
                /* gather connection statistics */
                array_foreach(&peer->conns, conn_idx) {
-                       if (http_client_connection_is_ready(*conn_idx)) {                       
+                       struct http_client_connection *conn = *conn_idx;
+
+                       http_client_connection_ref(conn);
+                       if (http_client_connection_is_ready(conn)) {
                                struct _conn_available *conn_avail;
                                unsigned int insert_idx, pending_requests;
 
                                /* compile sorted availability list */
-                               pending_requests = http_client_connection_count_pending(*conn_idx);
+                               pending_requests = http_client_connection_count_pending(conn);
                                if (array_count(&conns_avail) == 0) {
                                        insert_idx = 0;
                                } else {
@@ -298,18 +303,28 @@ http_client_peer_handle_requests_real(struct http_client_peer *peer)
                                        }
                                }
                                conn_avail = array_insert_space(&conns_avail, insert_idx);
-                               conn_avail->conn = *conn_idx;
+                               conn_avail->conn = conn;
                                conn_avail->pending_requests = pending_requests;
                                if (pending_requests == 0)
                                        idle++;
                        }
+                       if (!http_client_connection_unref(&conn)) {
+                               conn_lost = TRUE;
+                               break;
+                       }
+                       conn = *conn_idx;
                        /* count the number of connecting and closing connections */
-                       if ((*conn_idx)->closing)
+                       if (conn->closing)
                                closing++;
-                       else if (!(*conn_idx)->connected)
+                       else if (!conn->connected)
                                connecting++;
                }
 
+               if (conn_lost) {
+                       /* connection array changed while iterating; retry */
+                       continue;
+               }
+
                working_conn_count = array_count(&peer->conns) - closing;
                statistics_dirty = FALSE;