http-client-peer.c revision 94d1b08c9e20d637db568a3eab3dfc2b9e96e62a
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny/* Copyright (c) 2013-2014 Dovecot authors, see the included COPYING file */
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "lib.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "net.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "time-util.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "str.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "hash.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "array.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "llist.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "istream.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "ostream.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "iostream-ssl.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "http-response-parser.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny#include "http-client-private.h"
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny/*
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny * Logging
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny */
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenystatic inline void
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenyhttp_client_peer_debug(struct http_client_peer *peer,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny const char *format, ...) ATTR_FORMAT(2, 3);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenystatic inline void
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozekhttp_client_peer_debug(struct http_client_peer *peer,
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek const char *format, ...)
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek{
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek va_list args;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek if (peer->client->set.debug) {
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek va_start(args, format);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek i_debug("http-client: peer %s: %s",
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek http_client_peer_label(peer), t_strdup_vprintf(format, args));
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek va_end(args);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek }
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek}
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek/*
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek * Peer address
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek */
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozekunsigned int http_client_peer_addr_hash
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek(const struct http_client_peer_addr *peer)
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek{
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek switch (peer->type) {
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek case HTTP_CLIENT_PEER_ADDR_RAW:
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek return net_ip_hash(&peer->ip) + peer->port + 1;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek case HTTP_CLIENT_PEER_ADDR_HTTP:
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek return net_ip_hash(&peer->ip) + peer->port;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek case HTTP_CLIENT_PEER_ADDR_HTTPS:
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek case HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL:
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek return net_ip_hash(&peer->ip) + peer->port +
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek (peer->https_name == NULL ? 0 : str_hash(peer->https_name));
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek }
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek i_unreached();
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek return 0;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek}
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozekint http_client_peer_addr_cmp
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek(const struct http_client_peer_addr *peer1,
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek const struct http_client_peer_addr *peer2)
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek{
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek int ret;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek if (peer1->type != peer2->type)
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek return (peer1->type > peer2->type ? 1 : -1);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek if ((ret=net_ip_cmp(&peer1->ip, &peer2->ip)) != 0)
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek return ret;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek if (peer1->port != peer2->port)
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek return (peer1->port > peer2->port ? 1 : -1);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek if (peer1->type != HTTP_CLIENT_PEER_ADDR_HTTPS)
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek return 0;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek return null_strcmp(peer1->https_name, peer2->https_name);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek}
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek/*
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek * Peer
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek */
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozekstatic void
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozekhttp_client_peer_do_connect(struct http_client_peer *peer,
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek unsigned int count)
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek{
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek unsigned int i;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek for (i = 0; i < count; i++) {
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek http_client_peer_debug(peer,
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek "Making new connection %u of %u", i+1, count);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek (void)http_client_connection_create(peer);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek }
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek}
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozekstatic void
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozekhttp_client_peer_connect_backoff(struct http_client_peer *peer)
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek{
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek i_assert(peer->to_backoff != NULL);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek http_client_peer_debug(peer,
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek "Backoff timer expired");
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek timeout_remove(&peer->to_backoff);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek if (array_count(&peer->queues) == 0) {
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek http_client_peer_free(&peer);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek return;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek }
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek http_client_peer_do_connect(peer, 1);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek}
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozekstatic bool
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozekhttp_client_peer_start_backoff_timer(struct http_client_peer *peer)
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek{
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek if (peer->to_backoff != NULL)
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek return TRUE;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek if (peer->last_failure.tv_sec > 0) {
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek int backoff_time_spent =
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek timeval_diff_msecs(&ioloop_timeval, &peer->last_failure);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek if (backoff_time_spent < (int)peer->backoff_time_msecs) {
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek http_client_peer_debug(peer,
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek "Starting backoff timer for %d msecs",
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek peer->backoff_time_msecs - backoff_time_spent);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek peer->to_backoff = timeout_add
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek ((unsigned int)(peer->backoff_time_msecs - backoff_time_spent),
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek http_client_peer_connect_backoff, peer);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek return TRUE;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek }
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek http_client_peer_debug(peer,
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek "Backoff time already exceeded by %d msecs",
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek backoff_time_spent - peer->backoff_time_msecs);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek }
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek return FALSE;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek}
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozekstatic void
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozekhttp_client_peer_connect(struct http_client_peer *peer, unsigned int count)
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek{
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek if (http_client_peer_start_backoff_timer(peer))
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek return;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek http_client_peer_do_connect(peer, count);
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek}
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozekbool http_client_peer_is_connected(struct http_client_peer *peer)
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek{
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek struct http_client_connection *const *conn_idx;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek array_foreach(&peer->conns, conn_idx) {
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek if ((*conn_idx)->connected)
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek return TRUE;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek }
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek return FALSE;
50936fc7230a9b3f01e285e72c4182013542f53eJakub Hrozek}
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenystatic void
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenyhttp_client_peer_disconnect(struct http_client_peer *peer)
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny{
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny struct http_client_connection **conn;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny ARRAY_TYPE(http_client_connection) conns;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce http_client_peer_debug(peer, "Peer disconnect");
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny /* make a copy of the connection array; freed connections modify it */
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose t_array_init(&conns, array_count(&peer->conns));
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek array_copy(&conns.arr, 0, &peer->conns.arr, 0, array_count(&peer->conns));
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose array_foreach_modifiable(&conns, conn) {
ea224c3813a537639778f91ac762732b3c289603Jakub Hrozek http_client_connection_unref(conn);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce i_assert(array_count(&peer->conns) == 0);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny}
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bosestatic void http_client_peer_check_idle(struct http_client_peer *peer)
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose{
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose struct http_client_connection *const *conn_idx;
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose array_foreach(&peer->conns, conn_idx) {
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek http_client_connection_check_idle(*conn_idx);
ea224c3813a537639778f91ac762732b3c289603Jakub Hrozek }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny}
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenystatic unsigned int
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenyhttp_client_peer_requests_pending(struct http_client_peer *peer,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny unsigned int *num_urgent_r)
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny{
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny struct http_client_queue *const *queue;
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce unsigned int num_requests = 0, num_urgent = 0, requests, urgent;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny array_foreach(&peer->queues, queue) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny requests = http_client_queue_requests_pending(*queue, &urgent);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce num_requests += requests;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny num_urgent += urgent;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny *num_urgent_r = num_urgent;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny return num_requests;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny}
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zelenystatic void
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorcehttp_client_peer_handle_requests_real(struct http_client_peer *peer)
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce{
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce struct _conn_available {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce struct http_client_connection *conn;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce unsigned int pending_requests;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce };
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce struct http_client_connection *const *conn_idx;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce ARRAY(struct _conn_available) conns_avail;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny struct _conn_available *conn_avail_idx;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny unsigned int connecting, closing, idle;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny unsigned int num_pending, num_urgent, new_connections, working_conn_count;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny bool statistics_dirty = TRUE;
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce /* FIXME: limit the number of requests handled in one run to prevent
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce I/O starvation. */
7fe69bb6ec70bce439c6b975a9a0044c98ff502bSimo Sorce
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* disconnect if we're not linked to any queue anymore */
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov if (array_count(&peer->queues) == 0) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny i_assert(peer->to_backoff != NULL);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny http_client_peer_disconnect(peer);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny return;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce /* don't do anything unless we have pending requests */
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny num_pending = http_client_peer_requests_pending(peer, &num_urgent);
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce if (num_pending == 0) {
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce http_client_peer_check_idle(peer);
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce return;
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce }
aab938c5975f0e3b85c7c79a5d718e5fefed7217Simo Sorce
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny t_array_init(&conns_avail, array_count(&peer->conns));
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose do {
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose array_clear(&conns_avail);
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose connecting = closing = idle = 0;
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek /* gather connection statistics */
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek array_foreach(&peer->conns, conn_idx) {
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose if (http_client_connection_is_ready(*conn_idx)) {
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose struct _conn_available *conn_avail;
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose unsigned int insert_idx, pending_requests;
ea224c3813a537639778f91ac762732b3c289603Jakub Hrozek
ea224c3813a537639778f91ac762732b3c289603Jakub Hrozek /* compile sorted availability list */
ea224c3813a537639778f91ac762732b3c289603Jakub Hrozek pending_requests = http_client_connection_count_pending(*conn_idx);
ea224c3813a537639778f91ac762732b3c289603Jakub Hrozek if (array_count(&conns_avail) == 0) {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce insert_idx = 0;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce } else {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce insert_idx = array_count(&conns_avail);
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce array_foreach_modifiable(&conns_avail, conn_avail_idx) {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce if (conn_avail_idx->pending_requests > pending_requests) {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce insert_idx = array_foreach_idx(&conns_avail, conn_avail_idx);
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce break;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov }
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov }
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce }
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce conn_avail = array_insert_space(&conns_avail, insert_idx);
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce conn_avail->conn = *conn_idx;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce conn_avail->pending_requests = pending_requests;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce if (pending_requests == 0)
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce idle++;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce }
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce /* count the number of connecting and closing connections */
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce if ((*conn_idx)->closing)
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov closing++;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov else if (!(*conn_idx)->connected)
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce connecting++;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce }
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce working_conn_count = array_count(&peer->conns) - closing;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce statistics_dirty = FALSE;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce /* use idle connections right away */
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce if (idle > 0) {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce http_client_peer_debug(peer,
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "Using %u idle connections to handle %u requests "
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov "(%u total connections ready)",
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce idle, num_pending > idle ? idle : num_pending,
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce array_count(&conns_avail));
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce array_foreach_modifiable(&conns_avail, conn_avail_idx) {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce if (num_pending == 0 || conn_avail_idx->pending_requests > 0)
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce break;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce idle--;
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose if (http_client_connection_next_request(conn_avail_idx->conn) <= 0) {
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose /* no longer available (probably connection error/closed) */
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose statistics_dirty = TRUE;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov conn_avail_idx->conn = NULL;
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose } else {
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov /* update statistics */
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose conn_avail_idx->pending_requests++;
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose if (num_urgent > 0)
9822d4d468ec74e4e173f5adf0db12d02974cd18Sumit Bose num_urgent--;
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek num_pending--;
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek }
ea224c3813a537639778f91ac762732b3c289603Jakub Hrozek }
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek }
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek /* don't continue unless we have more pending requests */
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek num_pending = http_client_peer_requests_pending(peer, &num_urgent);
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek if (num_pending == 0) {
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose http_client_peer_check_idle(peer);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose return;
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose }
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose } while (statistics_dirty);
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov i_assert(idle == 0);
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose /* determine how many new connections we can set up */
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose if (peer->last_failure.tv_sec > 0 && working_conn_count > 0 &&
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose working_conn_count == connecting) {
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose /* don't create new connections until the existing ones have
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose finished connecting successfully. */
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose new_connections = 0;
c5711b0279ea85d69fe3c77dfb194360c346e1d7Sumit Bose } else {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if (working_conn_count - connecting + num_urgent >=
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose peer->client->set.max_parallel_connections) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /* only create connections for urgent requests */
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose new_connections = (num_urgent > connecting ? num_urgent - connecting : 0);
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose } else if (num_pending <= connecting) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /* there are already enough connections being made */
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose new_connections = 0;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose } else if (working_conn_count == connecting) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /* no connections succeeded so far, don't hammer the server with more
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose than one connection attempt unless its urgent */
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if (num_urgent > 0) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose new_connections =
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose (num_urgent > connecting ? num_urgent - connecting : 0);
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose } else {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose new_connections = (connecting == 0 ? 1 : 0);
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose }
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose } else if (num_pending - connecting >
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose peer->client->set.max_parallel_connections - working_conn_count) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /* create maximum allowed connections */
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose new_connections =
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose peer->client->set.max_parallel_connections - working_conn_count;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose } else {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /* create as many connections as we need */
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose new_connections = num_pending - connecting;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose }
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose }
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /* create connections */
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if (new_connections > 0) {
ea224c3813a537639778f91ac762732b3c289603Jakub Hrozek http_client_peer_debug(peer,
ea224c3813a537639778f91ac762732b3c289603Jakub Hrozek "Creating %u new connections to handle requests "
ea224c3813a537639778f91ac762732b3c289603Jakub Hrozek "(already %u usable, connecting to %u, closing %u)",
ea224c3813a537639778f91ac762732b3c289603Jakub Hrozek new_connections, working_conn_count - connecting,
ea224c3813a537639778f91ac762732b3c289603Jakub Hrozek connecting, closing);
ea224c3813a537639778f91ac762732b3c289603Jakub Hrozek http_client_peer_connect(peer, new_connections);
ea224c3813a537639778f91ac762732b3c289603Jakub Hrozek return;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce }
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce /* cannot create new connections for normal request; attempt pipelining */
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce if (working_conn_count - connecting >=
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce peer->client->set.max_parallel_connections) {
a6cca9c284724fafd670a3163812f248ba53ad97Jakub Hrozek unsigned int pipeline_level = 0, total_handled = 0, handled;
ea224c3813a537639778f91ac762732b3c289603Jakub Hrozek
ea224c3813a537639778f91ac762732b3c289603Jakub Hrozek if (!peer->allows_pipelining) {
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce http_client_peer_debug(peer,
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce "Will not pipeline until peer has shown support");
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce return;
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce }
bba1a5fd62cffcae076d1351df5a83fbc4a6ec17Simo Sorce
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny /* fill pipelines */
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny do {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny handled = 0;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny /* fill smallest pipelines first,
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny until all pipelines are filled to the same level */
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny array_foreach_modifiable(&conns_avail, conn_avail_idx) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (conn_avail_idx->conn == NULL)
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny continue;
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny if (pipeline_level == 0) {
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny pipeline_level = conn_avail_idx->pending_requests;
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce } else if (conn_avail_idx->pending_requests > pipeline_level) {
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny pipeline_level = conn_avail_idx->pending_requests;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny break; /* restart from least busy connection */
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny /* pipeline it */
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if (http_client_connection_next_request(conn_avail_idx->conn) <= 0) {
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny /* connection now unavailable */
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny conn_avail_idx->conn = NULL;
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce } else {
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny /* successfully pipelined */
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny conn_avail_idx->pending_requests++;
17195241500e46272018d7897d6e87249870caf2Pavel Reichl num_pending--;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny handled++;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny total_handled += handled;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny } while (num_pending > num_urgent && handled > 0);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny http_client_peer_debug(peer,
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce "Pipelined %u requests (filled pipelines up to %u requests)",
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce total_handled, pipeline_level);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny /* still waiting for connections to finish */
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce http_client_peer_debug(peer,
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce "No request handled; waiting for new connections");
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny}
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zelenystatic void http_client_peer_handle_requests(struct http_client_peer *peer)
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny{
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce if (peer->to_req_handling != NULL)
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce timeout_remove(&peer->to_req_handling);
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce T_BEGIN {
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce http_client_peer_handle_requests_real(peer);
cb388d52f49f54963379cc20a25e14d17fe6e9a3Simo Sorce } T_END;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov}
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zelenyvoid http_client_peer_trigger_request_handler(struct http_client_peer *peer)
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny{
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny /* trigger request handling through timeout */
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if (peer->to_req_handling == NULL) {
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce peer->to_req_handling =
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce timeout_add_short(0, http_client_peer_handle_requests, peer);
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce }
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce}
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorcestatic struct http_client_peer *
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorcehttp_client_peer_create(struct http_client *client,
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce const struct http_client_peer_addr *addr)
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce{
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce struct http_client_peer *peer;
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce
204cfc89a076fd32bf34f2abb3f809304aaa88abSimo Sorce i_assert(addr->https_name == NULL || client->ssl_ctx != NULL);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny peer = i_new(struct http_client_peer, 1);
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce peer->client = client;
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce peer->addr = *addr;
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce peer->https_name = i_strdup(addr->https_name);
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce peer->addr.https_name = peer->https_name;
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce i_array_init(&peer->queues, 16);
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce i_array_init(&peer->conns, 16);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny hash_table_insert
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny (client->peers, (const struct http_client_peer_addr *)&peer->addr, peer);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny DLLIST_PREPEND(&client->peers_list, peer);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny http_client_peer_debug(peer, "Peer created");
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return peer;
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce}
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorcevoid http_client_peer_free(struct http_client_peer **_peer)
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce{
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce struct http_client_peer *peer = *_peer;
65393a294e635822c1d7a15fe5853dc457ad8a2aSimo Sorce
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if (peer->destroyed)
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny peer->destroyed = TRUE;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny http_client_peer_debug(peer, "Peer destroy");
17195241500e46272018d7897d6e87249870caf2Pavel Reichl
17195241500e46272018d7897d6e87249870caf2Pavel Reichl if (peer->to_req_handling != NULL)
17195241500e46272018d7897d6e87249870caf2Pavel Reichl timeout_remove(&peer->to_req_handling);
17195241500e46272018d7897d6e87249870caf2Pavel Reichl if (peer->to_backoff != NULL)
17195241500e46272018d7897d6e87249870caf2Pavel Reichl timeout_remove(&peer->to_backoff);
17195241500e46272018d7897d6e87249870caf2Pavel Reichl
17195241500e46272018d7897d6e87249870caf2Pavel Reichl http_client_peer_disconnect(peer);
17195241500e46272018d7897d6e87249870caf2Pavel Reichl array_free(&peer->conns);
17195241500e46272018d7897d6e87249870caf2Pavel Reichl array_free(&peer->queues);
17195241500e46272018d7897d6e87249870caf2Pavel Reichl
17195241500e46272018d7897d6e87249870caf2Pavel Reichl hash_table_remove
17195241500e46272018d7897d6e87249870caf2Pavel Reichl (peer->client->peers, (const struct http_client_peer_addr *)&peer->addr);
17195241500e46272018d7897d6e87249870caf2Pavel Reichl DLLIST_REMOVE(&peer->client->peers_list, peer);
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose i_free(peer->https_name);
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose i_free(peer);
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose *_peer = NULL;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose}
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bosestruct http_client_peer *
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bosehttp_client_peer_get(struct http_client *client,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose const struct http_client_peer_addr *addr)
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose{
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose struct http_client_peer *peer;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose peer = hash_table_lookup(client->peers, addr);
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if (peer == NULL)
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose peer = http_client_peer_create(client, addr);
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose return peer;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose}
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bosebool http_client_peer_have_queue(struct http_client_peer *peer,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose struct http_client_queue *queue)
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose{
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose struct http_client_queue *const *queue_idx;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose array_foreach(&peer->queues, queue_idx) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if (*queue_idx == queue)
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose return TRUE;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose }
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose return FALSE;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose}
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bosevoid http_client_peer_link_queue(struct http_client_peer *peer,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose struct http_client_queue *queue)
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose{
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if (!http_client_peer_have_queue(peer, queue))
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose array_append(&peer->queues, &queue, 1);
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose}
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bosevoid http_client_peer_unlink_queue(struct http_client_peer *peer,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose struct http_client_queue *queue)
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose{
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose struct http_client_queue *const *queue_idx;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose array_foreach(&peer->queues, queue_idx) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if (*queue_idx == queue) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose array_delete(&peer->queues,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose array_foreach_idx(&peer->queues, queue_idx), 1);
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if (array_count(&peer->queues) == 0) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if (http_client_peer_start_backoff_timer(peer)) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /* will disconnect any pending connections */
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose http_client_peer_trigger_request_handler(peer);
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose } else {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose /* drop peer immediately */
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose http_client_peer_free(&peer);
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose }
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose }
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose return;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose }
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose }
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose}
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bosestruct http_client_request *
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bosehttp_client_peer_claim_request(struct http_client_peer *peer, bool no_urgent)
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose{
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose struct http_client_queue *const *queue_idx;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose struct http_client_request *req;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose array_foreach(&peer->queues, queue_idx) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose if ((req=http_client_queue_claim_request
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose (*queue_idx, &peer->addr, no_urgent)) != NULL) {
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose req->peer = peer;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose return req;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose }
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose }
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose return NULL;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose}
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bosevoid http_client_peer_connection_success(struct http_client_peer *peer)
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose{
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose struct http_client_queue *const *queue;
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose http_client_peer_debug(peer,
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose "Successfully connected (connections=%u)",
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose array_count(&peer->conns));
9f734d4c122e37cc3080974342ed9586d05d5f83Sumit Bose
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny peer->last_failure.tv_sec = peer->last_failure.tv_usec = 0;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny peer->backoff_time_msecs = 0;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if (peer->to_backoff != NULL)
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny timeout_remove(&peer->to_backoff);
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce
17195241500e46272018d7897d6e87249870caf2Pavel Reichl array_foreach(&peer->queues, queue) {
17195241500e46272018d7897d6e87249870caf2Pavel Reichl http_client_queue_connection_success(*queue, &peer->addr);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny http_client_peer_trigger_request_handler(peer);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny}
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zelenyvoid http_client_peer_connection_failure(struct http_client_peer *peer,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny const char *reason)
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny{
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny const struct http_client_settings *set = &peer->client->set;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny struct http_client_queue *const *queue;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny unsigned int pending;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny peer->last_failure = ioloop_timeval;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny /* count number of pending connections */
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny pending = http_client_peer_pending_connections(peer);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny i_assert(pending > 0);
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce
0754ff886f909f0404038eb9c99dd61be1acf5b9Simo Sorce http_client_peer_debug(peer,
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny "Failed to make connection "
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny "(connections=%u, connecting=%u)",
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny array_count(&peer->conns), pending);
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny /* manage backoff timer only when this was the only attempt */
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce if (pending == 1) {
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce if (peer->backoff_time_msecs == 0)
7fe69bb6ec70bce439c6b975a9a0044c98ff502bSimo Sorce peer->backoff_time_msecs = set->connect_backoff_time_msecs;
7fe69bb6ec70bce439c6b975a9a0044c98ff502bSimo Sorce else
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny peer->backoff_time_msecs *= 2;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if (peer->backoff_time_msecs > set->connect_backoff_max_time_msecs)
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny peer->backoff_time_msecs = set->connect_backoff_max_time_msecs;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce if (pending > 1) {
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny /* if there are other connections attempting to connect, wait
c03b28a38b14fdb59f74864ae4dc56affe256508Simo Sorce for them before failing the requests. remember that we had
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny trouble with connecting so in future we don't try to create
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny more than one connection until connects work again. */
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny } else {
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny /* this was the only/last connection and connecting to it
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny failed. a second connect will probably also fail, so just
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny try another IP for the hosts(s) or abort all requests if this
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce was the only/last option. */
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce array_foreach(&peer->queues, queue) {
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce http_client_queue_connection_failure(*queue, &peer->addr, reason);
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny}
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zelenyvoid http_client_peer_connection_lost(struct http_client_peer *peer)
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny{
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce unsigned int num_urgent;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
c03b28a38b14fdb59f74864ae4dc56affe256508Simo Sorce /* we get here when an already connected connection fails. if the
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny connect itself fails, http_client_peer_connection_failure() is
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny called instead. */
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if (peer->destroyed)
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
17195241500e46272018d7897d6e87249870caf2Pavel Reichl http_client_peer_debug(peer, "Lost a connection (%d connections left)",
17195241500e46272018d7897d6e87249870caf2Pavel Reichl array_count(&peer->conns));
17195241500e46272018d7897d6e87249870caf2Pavel Reichl
17195241500e46272018d7897d6e87249870caf2Pavel Reichl /* if there are pending requests for this peer, create a new connection
17195241500e46272018d7897d6e87249870caf2Pavel Reichl for them. */
17195241500e46272018d7897d6e87249870caf2Pavel Reichl http_client_peer_trigger_request_handler(peer);
17195241500e46272018d7897d6e87249870caf2Pavel Reichl
17195241500e46272018d7897d6e87249870caf2Pavel Reichl if (array_count(&peer->conns) == 0 &&
17195241500e46272018d7897d6e87249870caf2Pavel Reichl http_client_peer_requests_pending(peer, &num_urgent) == 0)
17195241500e46272018d7897d6e87249870caf2Pavel Reichl http_client_peer_free(&peer);
17195241500e46272018d7897d6e87249870caf2Pavel Reichl}
17195241500e46272018d7897d6e87249870caf2Pavel Reichl
17195241500e46272018d7897d6e87249870caf2Pavel Reichlunsigned int
17195241500e46272018d7897d6e87249870caf2Pavel Reichlhttp_client_peer_idle_connections(struct http_client_peer *peer)
17195241500e46272018d7897d6e87249870caf2Pavel Reichl{
17195241500e46272018d7897d6e87249870caf2Pavel Reichl struct http_client_connection *const *conn_idx;
17195241500e46272018d7897d6e87249870caf2Pavel Reichl unsigned int idle = 0;
17195241500e46272018d7897d6e87249870caf2Pavel Reichl
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny /* find idle connections */
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny array_foreach(&peer->conns, conn_idx) {
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny if (http_client_connection_is_idle(*conn_idx))
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny idle++;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return idle;
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashov}
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce
a3c8390d19593b1e5277d95bfb4ab206d4785150Nikolai Kondrashovunsigned int
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zelenyhttp_client_peer_pending_connections(struct http_client_peer *peer)
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny{
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny struct http_client_connection *const *conn_idx;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny unsigned int pending = 0;
3b0e0352d8076909608d04750d3ea6b0d9ba33f6Jakub Hrozek
3b0e0352d8076909608d04750d3ea6b0d9ba33f6Jakub Hrozek /* find idle connections */
3b0e0352d8076909608d04750d3ea6b0d9ba33f6Jakub Hrozek array_foreach(&peer->conns, conn_idx) {
3b0e0352d8076909608d04750d3ea6b0d9ba33f6Jakub Hrozek if (!(*conn_idx)->closing && !(*conn_idx)->connected)
3b0e0352d8076909608d04750d3ea6b0d9ba33f6Jakub Hrozek pending++;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny }
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny return pending;
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny}
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zelenyvoid http_client_peer_switch_ioloop(struct http_client_peer *peer)
84c611c1b7c04cc7735ab54d4e5f48284b79e6fbJan Zeleny{
3912262270a6449ebe1d3e92c27c217b4044f894Simo Sorce if (peer->to_req_handling != NULL) {
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce peer->to_req_handling =
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce io_loop_move_timeout(&peer->to_req_handling);
09d7c105839bfc7447ea0f766413ed86675ca075Sumit Bose }
ea224c3813a537639778f91ac762732b3c289603Jakub Hrozek if (peer->to_backoff != NULL) {
ea224c3813a537639778f91ac762732b3c289603Jakub Hrozek peer->to_backoff =
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny io_loop_move_timeout(&peer->to_backoff);
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny }
e76d78338026fa47dca32eaf7f5c15eabb1b951aJan Zeleny}
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce
1187a07ed4207c1c326fdf83915dddfe472b8620Simo Sorce