From: Stephan Bosch Date: Thu, 24 Mar 2016 17:47:28 +0000 (+0900) Subject: lib-http: client: Fixed handling of stalled connections that emerge when the client... X-Git-Tag: 2.2.23~12 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bbbf8a9b7eb491b54b4720d1ff7fe8aebdc63428;p=thirdparty%2Fdovecot%2Fcore.git lib-http: client: Fixed handling of stalled connections that emerge when the client ioloop hasn't run for a long time. 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. --- diff --git a/src/lib-http/http-client-peer.c b/src/lib-http/http-client-peer.c index 53aebfcaa5..ed4e305dd3 100644 --- a/src/lib-http/http-client-peer.c +++ b/src/lib-http/http-client-peer.c @@ -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;