changeset 19960:5f32b22684ee

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.
author Stephan Bosch <stephan@rename-it.nl>
date Fri, 25 Mar 2016 02:47:28 +0900
parents 9d1ca7caf268
children 3f6a74b9ce54
files src/lib-http/http-client-peer.c
diffstat 1 files changed, 20 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-http/http-client-peer.c	Fri Mar 25 00:45:54 2016 +0900
+++ b/src/lib-http/http-client-peer.c	Fri Mar 25 02:47:28 2016 +0900
@@ -275,17 +275,22 @@
 	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 @@
 					}
 				}
 				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;