From: Stephan Bosch Date: Tue, 21 Oct 2014 20:34:50 +0000 (+0300) Subject: lib-http: client: If peer is unlinked from queue and no other links remain, close... X-Git-Tag: 2.2.15~38 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4aaec94d5ff8988591f47a51d6dde11862acce1b;p=thirdparty%2Fdovecot%2Fcore.git lib-http: client: If peer is unlinked from queue and no other links remain, close any pending connections. Those pending connections would no longer serve any purpose. --- diff --git a/src/lib-http/http-client-peer.c b/src/lib-http/http-client-peer.c index c5c846c1aa..769b5350de 100644 --- a/src/lib-http/http-client-peer.c +++ b/src/lib-http/http-client-peer.c @@ -157,6 +157,23 @@ bool http_client_peer_is_connected(struct http_client_peer *peer) return FALSE; } +static void +http_client_peer_disconnect(struct http_client_peer *peer) +{ + struct http_client_connection **conn; + ARRAY_TYPE(http_client_connection) conns; + + http_client_peer_debug(peer, "Peer disconnect"); + + /* make a copy of the connection array; freed connections modify it */ + t_array_init(&conns, array_count(&peer->conns)); + array_copy(&conns.arr, 0, &peer->conns.arr, 0, array_count(&peer->conns)); + array_foreach_modifiable(&conns, conn) { + http_client_connection_unref(conn); + } + i_assert(array_count(&peer->conns) == 0); +} + static void http_client_peer_check_idle(struct http_client_peer *peer) { struct http_client_connection *const *conn_idx; @@ -200,6 +217,13 @@ http_client_peer_handle_requests_real(struct http_client_peer *peer) /* FIXME: limit the number of requests handled in one run to prevent I/O starvation. */ + /* disconnect if we're not linked to any queue anymore */ + if (array_count(&peer->queues) == 0) { + i_assert(peer->to_backoff != NULL); + http_client_peer_disconnect(peer); + return; + } + /* don't do anything unless we have pending requests */ num_pending = http_client_peer_requests_pending(peer, &num_urgent); if (num_pending == 0) { @@ -426,8 +450,6 @@ http_client_peer_create(struct http_client *client, void http_client_peer_free(struct http_client_peer **_peer) { struct http_client_peer *peer = *_peer; - struct http_client_connection **conn; - ARRAY_TYPE(http_client_connection) conns; if (peer->destroyed) return; @@ -440,14 +462,7 @@ void http_client_peer_free(struct http_client_peer **_peer) if (peer->to_backoff != NULL) timeout_remove(&peer->to_backoff); - /* make a copy of the connection array; freed connections modify it */ - t_array_init(&conns, array_count(&peer->conns)); - array_copy(&conns.arr, 0, &peer->conns.arr, 0, array_count(&peer->conns)); - array_foreach_modifiable(&conns, conn) { - http_client_connection_unref(conn); - } - - i_assert(array_count(&peer->conns) == 0); + http_client_peer_disconnect(peer); array_free(&peer->conns); array_free(&peer->queues); @@ -502,8 +517,13 @@ void http_client_peer_unlink_queue(struct http_client_peer *peer, array_delete(&peer->queues, array_foreach_idx(&peer->queues, queue_idx), 1); if (array_count(&peer->queues) == 0) { - if (!http_client_peer_start_backoff_timer(peer)) + if (http_client_peer_start_backoff_timer(peer)) { + /* will disconnect any pending connections */ + http_client_peer_trigger_request_handler(peer); + } else { + /* drop peer immediately */ http_client_peer_free(&peer); + } } return; }