bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2013-2018 Dovecot authors, see the included COPYING file */
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch#include "lib.h"
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch#include "net.h"
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch#include "str.h"
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch#include "hash.h"
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch#include "array.h"
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch#include "bsearch-insert-pos.h"
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch#include "llist.h"
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch#include "ioloop.h"
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch#include "istream.h"
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch#include "ostream.h"
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch#include "time-util.h"
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch#include "dns-lookup.h"
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch#include "http-response-parser.h"
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch#include "http-client-private.h"
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
06d1b658d0f6840204bf1487b8bcad829d33b726Stephan Bosch#define TIMEOUT_CMP_MARGIN_USECS 2000
06d1b658d0f6840204bf1487b8bcad829d33b726Stephan Bosch
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Boschstatic void
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Boschhttp_client_queue_fail(struct http_client_queue *queue,
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch unsigned int status, const char *error);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Boschstatic void
b66def5dadd3e7c250313a938d26ad113663f86bStephan Boschhttp_client_queue_set_delay_timer(struct http_client_queue *queue,
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch struct timeval time);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Boschstatic void
b66def5dadd3e7c250313a938d26ad113663f86bStephan Boschhttp_client_queue_set_request_timer(struct http_client_queue *queue,
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch const struct timeval *time);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch/*
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch * Queue object
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch */
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Boschstatic struct http_client_queue *
de96afeeaa5242cffe89f1966457e935806b5746Stephan Boschhttp_client_queue_find(struct http_client_host *host,
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch const struct http_client_peer_addr *addr)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch{
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch struct http_client_queue *const *queue_idx;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch array_foreach_modifiable(&host->queues, queue_idx) {
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch struct http_client_queue *queue = *queue_idx;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch if (http_client_peer_addr_cmp(&queue->addr, addr) == 0)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch return queue;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch }
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch return NULL;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch}
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Boschstatic struct http_client_queue *
de96afeeaa5242cffe89f1966457e935806b5746Stephan Boschhttp_client_queue_create(struct http_client_host *host,
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch const struct http_client_peer_addr *addr)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch{
e48102389fb49deadfc685600dc2e56177fd0d7cStephan Bosch const char *hostname = host->shared->name;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch struct http_client_queue *queue;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch queue = i_new(struct http_client_queue, 1);
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch queue->client = host->client;
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch queue->host = host;
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch queue->addr = *addr;
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch switch (addr->type) {
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch case HTTP_CLIENT_PEER_ADDR_RAW:
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch queue->name =
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch i_strdup_printf("raw://%s:%u", hostname, addr->a.tcp.port);
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch queue->addr.a.tcp.https_name = NULL;
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch break;
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch case HTTP_CLIENT_PEER_ADDR_HTTPS_TUNNEL:
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch case HTTP_CLIENT_PEER_ADDR_HTTPS:
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch queue->name =
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch i_strdup_printf("https://%s:%u", hostname, addr->a.tcp.port);
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch queue->addr_name = i_strdup(addr->a.tcp.https_name);
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch queue->addr.a.tcp.https_name = queue->addr_name;
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch break;
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch case HTTP_CLIENT_PEER_ADDR_HTTP:
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch queue->name =
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch i_strdup_printf("http://%s:%u", hostname, addr->a.tcp.port);
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch queue->addr.a.tcp.https_name = NULL;
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch break;
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch case HTTP_CLIENT_PEER_ADDR_UNIX:
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch queue->name = i_strdup_printf("unix:%s", addr->a.un.path);
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch queue->addr_name = i_strdup(addr->a.un.path);
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch queue->addr.a.un.path = queue->addr_name;
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch break;
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch default:
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch i_unreached();
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch }
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen queue->event = event_create(queue->client->event);
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen event_set_append_log_prefix(queue->event,
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen t_strdup_printf("queue %s: ", queue->name));
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch queue->ips_connect_idx = 0;
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch i_array_init(&queue->pending_peers, 8);
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch i_array_init(&queue->requests, 16);
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch i_array_init(&queue->queued_requests, 16);
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch i_array_init(&queue->queued_urgent_requests, 16);
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch i_array_init(&queue->delayed_requests, 4);
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch array_append(&host->queues, &queue, 1);
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch return queue;
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch}
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Boschstruct http_client_queue *
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Boschhttp_client_queue_get(struct http_client_host *host,
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch const struct http_client_peer_addr *addr)
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch{
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch struct http_client_queue *queue;
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch queue = http_client_queue_find(host, addr);
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch if (queue == NULL)
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch queue = http_client_queue_create(host, addr);
8149ed57ae5abbb0c4ccfe88c1d7c58255dc85cfStephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch return queue;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch}
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Boschvoid http_client_queue_free(struct http_client_queue *queue)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch{
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch struct http_client_peer *const *peer_idx;
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch ARRAY_TYPE(http_client_peer) peers;
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch
36409af77b42dc1c18c0691970b2eb07785fbba4Timo Sirainen e_debug(queue->event, "Destroy");
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch /* currently only called when peer is freed, so there is no need to
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch unlink from the peer */
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch /* unlink all peers */
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch if (queue->cur_peer != NULL) {
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch struct http_client_peer *peer = queue->cur_peer;
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch queue->cur_peer = NULL;
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch http_client_peer_unlink_queue(peer, queue);
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch }
6a0e62561f965c86f98444c8ad48fad7c0d67bcbStephan Bosch t_array_init(&peers, array_count(&queue->pending_peers));
6a0e62561f965c86f98444c8ad48fad7c0d67bcbStephan Bosch array_copy(&peers.arr, 0, &queue->pending_peers.arr, 0,
6a0e62561f965c86f98444c8ad48fad7c0d67bcbStephan Bosch array_count(&queue->pending_peers));
6a0e62561f965c86f98444c8ad48fad7c0d67bcbStephan Bosch array_foreach(&peers, peer_idx)
6a0e62561f965c86f98444c8ad48fad7c0d67bcbStephan Bosch http_client_peer_unlink_queue(*peer_idx, queue);
6a0e62561f965c86f98444c8ad48fad7c0d67bcbStephan Bosch array_free(&queue->pending_peers);
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch /* abort all requests */
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch http_client_queue_fail
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch (queue, HTTP_CLIENT_REQUEST_ERROR_ABORTED, "Aborted");
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch array_free(&queue->requests);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch array_free(&queue->queued_requests);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch array_free(&queue->queued_urgent_requests);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch array_free(&queue->delayed_requests);
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch /* cancel timeouts */
d90a924480a061683786e459a2e1c1d0b6e4f1e4Josef 'Jeff' Sipek timeout_remove(&queue->to_connect);
d90a924480a061683786e459a2e1c1d0b6e4f1e4Josef 'Jeff' Sipek timeout_remove(&queue->to_delayed);
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch /* free */
2d1ad5742dd723b39c51bcf64c62a600237de8aeTimo Sirainen event_unref(&queue->event);
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch i_free(queue->addr_name);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch i_free(queue->name);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch i_free(queue);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch}
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch/*
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch * Error handling
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Boschstatic void
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Boschhttp_client_queue_fail_full(struct http_client_queue *queue,
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch unsigned int status, const char *error, bool queued_only)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch{
0d30ec5bef193a1fdb4c166c264a2918df37033fStephan Bosch ARRAY_TYPE(http_client_request) *req_arr, treqs;
0d30ec5bef193a1fdb4c166c264a2918df37033fStephan Bosch struct http_client_request **req_idx;
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch unsigned int retained = 0;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch /* abort requests */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch req_arr = &queue->requests;
0d30ec5bef193a1fdb4c166c264a2918df37033fStephan Bosch t_array_init(&treqs, array_count(req_arr));
0d30ec5bef193a1fdb4c166c264a2918df37033fStephan Bosch array_copy(&treqs.arr, 0, &req_arr->arr, 0, array_count(req_arr));
0d30ec5bef193a1fdb4c166c264a2918df37033fStephan Bosch array_foreach_modifiable(&treqs, req_idx) {
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch struct http_client_request *req = *req_idx;
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch i_assert(req->state >= HTTP_REQUEST_STATE_QUEUED);
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch if (queued_only &&
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch req->state != HTTP_REQUEST_STATE_QUEUED)
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch retained++;
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch else
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch http_client_request_error(&req, status, error);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch }
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch /* all queues should be empty now... unless new requests were submitted
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch from the callback. this invariant captures it all: */
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch i_assert((retained +
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch array_count(&queue->delayed_requests) +
a8304588757ef197bf10461f668cb017cb75a68aStephan Bosch array_count(&queue->queued_requests) +
a8304588757ef197bf10461f668cb017cb75a68aStephan Bosch array_count(&queue->queued_urgent_requests)) ==
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch array_count(&queue->requests));
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch}
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Boschstatic void
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Boschhttp_client_queue_fail(struct http_client_queue *queue,
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch unsigned int status, const char *error)
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch{
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch http_client_queue_fail_full(queue, status, error, FALSE);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch}
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch/*
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch * Connection management
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch */
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Boschstatic bool
de96afeeaa5242cffe89f1966457e935806b5746Stephan Boschhttp_client_queue_is_last_connect_ip(struct http_client_queue *queue)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch{
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch const struct http_client_settings *set =
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch &queue->client->set;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch struct http_client_host *host = queue->host;
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch unsigned int ips_count = http_client_host_get_ips_count(host);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch i_assert(queue->addr.type != HTTP_CLIENT_PEER_ADDR_UNIX);
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch i_assert(queue->ips_connect_idx < ips_count);
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch i_assert(queue->ips_connect_start_idx < ips_count);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch /* if a maximum connect attempts > 1 is set, enforce it directly */
501d0f9aa4e892c47dfe369774ef3c8961f753d2Stephan Bosch if (set->max_connect_attempts > 1 &&
501d0f9aa4e892c47dfe369774ef3c8961f753d2Stephan Bosch queue->connect_attempts >= set->max_connect_attempts)
501d0f9aa4e892c47dfe369774ef3c8961f753d2Stephan Bosch return TRUE;
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch /* otherwise, we'll always go through all the IPs. we don't necessarily
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch start connecting from the first IP, so we'll need to treat the IPs as
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch a ring buffer where we automatically wrap back to the first IP
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch when necessary. */
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch return (queue->ips_connect_idx + 1) % ips_count ==
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch queue->ips_connect_start_idx;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch}
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Boschstatic void
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Boschhttp_client_queue_recover_from_lookup(struct http_client_queue *queue)
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch{
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch struct http_client_host *host = queue->host;
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch unsigned int ip_idx;
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch i_assert(queue->addr.type != HTTP_CLIENT_PEER_ADDR_UNIX);
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch if (queue->cur_peer == NULL) {
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch queue->ips_connect_idx = queue->ips_connect_start_idx = 0;
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch return;
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch }
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch if (http_client_host_get_ip_idx(host,
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch &queue->cur_peer->shared->addr.a.tcp.ip, &ip_idx)) {
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch /* continue with current peer */
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch queue->ips_connect_idx = queue->ips_connect_start_idx = ip_idx;
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch } else {
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch /* reset connect attempts */
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch queue->ips_connect_idx = queue->ips_connect_start_idx = 0;
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch }
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch}
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Boschstatic void
de96afeeaa5242cffe89f1966457e935806b5746Stephan Boschhttp_client_queue_soft_connect_timeout(struct http_client_queue *queue)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch{
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch struct http_client_host *host = queue->host;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch const struct http_client_peer_addr *addr = &queue->addr;
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch unsigned int ips_count = http_client_host_get_ips_count(host);
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch const char *https_name;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch i_assert(queue->addr.type != HTTP_CLIENT_PEER_ADDR_UNIX);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&queue->to_connect);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch if (http_client_queue_is_last_connect_ip(queue)) {
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch /* no more IPs to try */
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch return;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch }
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch /* if our our previous connection attempt takes longer than the
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch soft_connect_timeout, we start a connection attempt to the next IP in
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch parallel */
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch https_name = http_client_peer_addr_get_https_name(addr);
36409af77b42dc1c18c0691970b2eb07785fbba4Timo Sirainen e_debug(queue->event, "Connection to %s%s is taking a long time; "
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch "starting parallel connection attempt to next IP",
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch http_client_peer_addr2str(addr), (https_name == NULL ? "" :
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch t_strdup_printf(" (SSL=%s)", https_name)));
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch /* next IP */
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch queue->ips_connect_idx = (queue->ips_connect_idx + 1) % ips_count;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch /* setup connection to new peer (can start new soft timeout) */
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch http_client_queue_connection_setup(queue);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch}
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Boschstatic struct http_client_peer *
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Boschhttp_client_queue_connection_attempt(struct http_client_queue *queue)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch{
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch struct http_client *client = queue->client;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch struct http_client_host *host = queue->host;
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch struct http_client_peer *peer;
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch struct http_client_peer_addr *addr = &queue->addr;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch unsigned int num_requests =
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch array_count(&queue->queued_requests) +
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch array_count(&queue->queued_urgent_requests);
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch const char *ssl = "";
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch int ret;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch if (num_requests == 0)
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch return NULL;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch /* check whether host IPs are still up-to-date */
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch if ((ret=http_client_host_refresh(host)) < 0) {
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch /* performing asynchronous lookup */
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&queue->to_connect);
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch return NULL;
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch }
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch if (ret > 0) {
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch /* new lookup performed */
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch http_client_queue_recover_from_lookup(queue);
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch }
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch /* update our peer address */
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch if (queue->addr.type != HTTP_CLIENT_PEER_ADDR_UNIX) {
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch const struct ip_addr *ip = http_client_host_get_ip(host,
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch queue->ips_connect_idx);
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch queue->addr.a.tcp.ip = *ip;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch ssl = http_client_peer_addr_get_https_name(addr);
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch ssl = (ssl == NULL ? "" : t_strdup_printf(" (SSL=%s)", ssl));
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch }
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch /* already got a peer? */
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch peer = NULL;
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch if (queue->cur_peer != NULL) {
6a0e62561f965c86f98444c8ad48fad7c0d67bcbStephan Bosch i_assert(array_count(&queue->pending_peers) == 0);
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch /* is it still the one we want? */
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch if (http_client_peer_addr_cmp
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch (addr, &queue->cur_peer->shared->addr) == 0) {
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch /* is it still connected? */
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch if (http_client_peer_is_connected(queue->cur_peer)) {
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch /* yes */
36409af77b42dc1c18c0691970b2eb07785fbba4Timo Sirainen e_debug(queue->event,
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch "Using existing connection to %s%s "
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch "(%u requests pending)",
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch http_client_peer_addr2str(addr), ssl, num_requests);
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch /* handle requests; */
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch http_client_peer_trigger_request_handler(queue->cur_peer);
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch return queue->cur_peer;
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch }
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch /* no */
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch peer = queue->cur_peer;
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch } else {
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch /* peer is not relevant to this queue anymore */
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch http_client_peer_unlink_queue(queue->cur_peer, queue);
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch }
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch queue->cur_peer = NULL;
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch }
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch if (peer == NULL)
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch peer = http_client_peer_get(queue->client, addr);
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch
36409af77b42dc1c18c0691970b2eb07785fbba4Timo Sirainen e_debug(queue->event, "Setting up connection to %s%s "
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch "(%u requests pending)", http_client_peer_addr2str(addr), ssl,
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch num_requests);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch /* create provisional link between queue and peer */
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch http_client_peer_link_queue(peer, queue);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch /* handle requests; creates new connections when needed/possible */
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch http_client_peer_trigger_request_handler(peer);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch if (http_client_peer_is_connected(peer)) {
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch /* drop any pending peers */
6a0e62561f965c86f98444c8ad48fad7c0d67bcbStephan Bosch if (array_count(&queue->pending_peers) > 0) {
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch struct http_client_peer *const *peer_idx;
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch array_foreach(&queue->pending_peers, peer_idx) {
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch i_assert(http_client_peer_addr_cmp
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch (&(*peer_idx)->shared->addr, addr) != 0);
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch http_client_peer_unlink_queue(*peer_idx, queue);
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch }
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch array_clear(&queue->pending_peers);
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch }
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch queue->cur_peer = peer;
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch http_client_peer_trigger_request_handler(queue->cur_peer);
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch } else {
6a0e62561f965c86f98444c8ad48fad7c0d67bcbStephan Bosch struct http_client_peer *const *peer_idx;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch unsigned int msecs;
028a1c8de5166a81c2394131cac2406327febf52Timo Sirainen bool new_peer = TRUE;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch /* not already connected, wait for connections */
028a1c8de5166a81c2394131cac2406327febf52Timo Sirainen
6a0e62561f965c86f98444c8ad48fad7c0d67bcbStephan Bosch /* we may be waiting for this peer already */
6a0e62561f965c86f98444c8ad48fad7c0d67bcbStephan Bosch array_foreach(&queue->pending_peers, peer_idx) {
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch if (http_client_peer_addr_cmp
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch (&(*peer_idx)->shared->addr, addr) == 0) {
6a0e62561f965c86f98444c8ad48fad7c0d67bcbStephan Bosch i_assert(*peer_idx == peer);
6a0e62561f965c86f98444c8ad48fad7c0d67bcbStephan Bosch new_peer = FALSE;
6a0e62561f965c86f98444c8ad48fad7c0d67bcbStephan Bosch break;
028a1c8de5166a81c2394131cac2406327febf52Timo Sirainen }
028a1c8de5166a81c2394131cac2406327febf52Timo Sirainen }
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch if (new_peer) {
36409af77b42dc1c18c0691970b2eb07785fbba4Timo Sirainen e_debug(queue->event, "Started new connection to %s%s",
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch http_client_peer_addr2str(addr), ssl);
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch
028a1c8de5166a81c2394131cac2406327febf52Timo Sirainen array_append(&queue->pending_peers, &peer, 1);
9284599e2d12b08170be81441bcfc53fa5b71a73Timo Sirainen if (queue->connect_attempts++ == 0)
9284599e2d12b08170be81441bcfc53fa5b71a73Timo Sirainen queue->first_connect_time = ioloop_timeval;
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch }
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch /* start soft connect time-out (but only if we have another IP left) */
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch if (queue->addr.type != HTTP_CLIENT_PEER_ADDR_UNIX) {
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch msecs = client->set.soft_connect_timeout_msecs;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch if (!http_client_queue_is_last_connect_ip(queue) && msecs > 0 &&
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch queue->to_connect == NULL) {
a68aaff537e2e30d782bb8b9d8782e1a10a17d1aStephan Bosch queue->to_connect = timeout_add_to(client->ioloop, msecs,
a68aaff537e2e30d782bb8b9d8782e1a10a17d1aStephan Bosch http_client_queue_soft_connect_timeout, queue);
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch }
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch }
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch }
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch return peer;
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch}
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Boschvoid http_client_queue_connection_setup(struct http_client_queue *queue)
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch{
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch (void)http_client_queue_connection_attempt(queue);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch}
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Boschunsigned int
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Boschhttp_client_queue_host_lookup_done(struct http_client_queue *queue)
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch{
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch unsigned int reqs_pending =
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch http_client_queue_requests_pending(queue, NULL);
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch http_client_queue_recover_from_lookup(queue);
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch if (reqs_pending > 0)
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch http_client_queue_connection_setup(queue);
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch return reqs_pending;
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch}
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Boschvoid http_client_queue_host_lookup_failure(
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch struct http_client_queue *queue, const char *error)
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch{
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch http_client_queue_fail_full(queue,
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch HTTP_CLIENT_REQUEST_ERROR_HOST_LOOKUP_FAILED,
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch error, TRUE);
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch}
5791d02c3672f6a525f1fcf0f4f375b4be0ccf4bStephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Boschvoid
de96afeeaa5242cffe89f1966457e935806b5746Stephan Boschhttp_client_queue_connection_success(struct http_client_queue *queue,
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch struct http_client_peer *peer)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch{
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch const struct http_client_peer_addr *addr = &peer->shared->addr;
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch struct http_client_host *host = queue->host;
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch if (http_client_host_ready(host) &&
1e63e30812158e6446d81cdbb2f45954794d4f8aStephan Bosch queue->addr.type != HTTP_CLIENT_PEER_ADDR_UNIX) {
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch /* we achieved at least one connection the the addr->ip */
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch if (!http_client_host_get_ip_idx(host,
97a8fde13ea33b09163c45d978a4949043f189c5Stephan Bosch &addr->a.tcp.ip, &queue->ips_connect_start_idx)) {
97a8fde13ea33b09163c45d978a4949043f189c5Stephan Bosch /* list of IPs changed during connect */
97a8fde13ea33b09163c45d978a4949043f189c5Stephan Bosch queue->ips_connect_start_idx = 0;
97a8fde13ea33b09163c45d978a4949043f189c5Stephan Bosch }
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch }
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch /* reset attempt counter */
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch queue->connect_attempts = 0;
9d746c6785d17e421c3f3c74cf29d059ae2ab233Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch /* stop soft connect time-out */
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&queue->to_connect);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch /* drop all other attempts to the hport. note that we get here whenever
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch a connection is successfully created, so pending_peers array
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch may be empty. */
6a0e62561f965c86f98444c8ad48fad7c0d67bcbStephan Bosch if (array_count(&queue->pending_peers) > 0) {
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch struct http_client_peer *const *peer_idx;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch array_foreach(&queue->pending_peers, peer_idx) {
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch if (*peer_idx == peer) {
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch /* don't drop any connections to the successfully
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch connected peer, even if some of the connections
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch are pending. they may be intended for urgent
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch requests. */
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch i_assert(queue->cur_peer == NULL);
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch queue->cur_peer = *peer_idx;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch continue;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch }
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch /* unlink this queue from the peer; if this was the last/only queue, the
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch peer will be freed, closing all connections.
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch */
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch http_client_peer_unlink_queue(*peer_idx, queue);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch }
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch array_clear(&queue->pending_peers);
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch i_assert(queue->cur_peer != NULL);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch }
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch}
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
e4e4b8544a492cf90bd7a93c9a26e8285fc7c00bStephan Boschvoid
de96afeeaa5242cffe89f1966457e935806b5746Stephan Boschhttp_client_queue_connection_failure(struct http_client_queue *queue,
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch struct http_client_peer *peer, const char *reason)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch{
e4e4b8544a492cf90bd7a93c9a26e8285fc7c00bStephan Bosch const struct http_client_settings *set =
e4e4b8544a492cf90bd7a93c9a26e8285fc7c00bStephan Bosch &queue->client->set;
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch const struct http_client_peer_addr *addr = &peer->shared->addr;
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch const char *https_name = http_client_peer_addr_get_https_name(addr);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch struct http_client_host *host = queue->host;
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch unsigned int ips_count = http_client_host_get_ips_count(host);
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch struct http_client_peer *const *peer_idx;
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch
36409af77b42dc1c18c0691970b2eb07785fbba4Timo Sirainen e_debug(queue->event,
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch "Failed to set up connection to %s%s: %s "
ee3c2fb2ebbf6fbbf12085f36102553ecbcb1397Timo Sirainen "(%u peers pending, %u requests pending)",
ee3c2fb2ebbf6fbbf12085f36102553ecbcb1397Timo Sirainen http_client_peer_addr2str(addr),
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch (https_name == NULL ? "" :
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch t_strdup_printf(" (SSL=%s)", https_name)),
6a0e62561f965c86f98444c8ad48fad7c0d67bcbStephan Bosch reason, array_count(&queue->pending_peers),
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch array_count(&queue->requests));
e4e4b8544a492cf90bd7a93c9a26e8285fc7c00bStephan Bosch
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch if (array_count(&queue->pending_peers) == 0) {
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch i_assert(queue->cur_peer == peer);
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch } else {
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch bool found = FALSE;
b3df4be577af79d93f39e099e5e0b226ab7fd775Stephan Bosch
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch i_assert(queue->cur_peer == NULL);
b3df4be577af79d93f39e099e5e0b226ab7fd775Stephan Bosch
b3df4be577af79d93f39e099e5e0b226ab7fd775Stephan Bosch /* we're still doing the initial connections to this hport. if
b3df4be577af79d93f39e099e5e0b226ab7fd775Stephan Bosch we're also doing parallel connections with soft timeouts
b3df4be577af79d93f39e099e5e0b226ab7fd775Stephan Bosch (pending_peer_count>1), wait for them to finish
b3df4be577af79d93f39e099e5e0b226ab7fd775Stephan Bosch first. */
b3df4be577af79d93f39e099e5e0b226ab7fd775Stephan Bosch array_foreach(&queue->pending_peers, peer_idx) {
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch if (*peer_idx == peer) {
b3df4be577af79d93f39e099e5e0b226ab7fd775Stephan Bosch array_delete(&queue->pending_peers,
b3df4be577af79d93f39e099e5e0b226ab7fd775Stephan Bosch array_foreach_idx(&queue->pending_peers, peer_idx), 1);
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch found = TRUE;
b3df4be577af79d93f39e099e5e0b226ab7fd775Stephan Bosch break;
b3df4be577af79d93f39e099e5e0b226ab7fd775Stephan Bosch }
b3df4be577af79d93f39e099e5e0b226ab7fd775Stephan Bosch }
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch i_assert(found);
b3df4be577af79d93f39e099e5e0b226ab7fd775Stephan Bosch if (array_count(&queue->pending_peers) > 0) {
36409af77b42dc1c18c0691970b2eb07785fbba4Timo Sirainen e_debug(queue->event,
b3df4be577af79d93f39e099e5e0b226ab7fd775Stephan Bosch "Waiting for remaining pending peers.");
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch http_client_peer_unlink_queue(peer, queue);
b3df4be577af79d93f39e099e5e0b226ab7fd775Stephan Bosch return;
ee3c2fb2ebbf6fbbf12085f36102553ecbcb1397Timo Sirainen }
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch /* one of the connections failed. if we're not using soft timeouts,
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch we need to try to connect to the next IP. if we are using soft
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch timeouts, we've already tried all of the IPs by now. */
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch timeout_remove(&queue->to_connect);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch if (queue->addr.type == HTTP_CLIENT_PEER_ADDR_UNIX) {
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch http_client_peer_unlink_queue(peer, queue);
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch http_client_queue_fail(queue,
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch HTTP_CLIENT_REQUEST_ERROR_CONNECT_FAILED, reason);
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch return;
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch }
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch }
ede750711f27ca9d9037a7ab9f016411b57f1ad9Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch if (http_client_queue_is_last_connect_ip(queue)) {
e4e4b8544a492cf90bd7a93c9a26e8285fc7c00bStephan Bosch /* all IPs failed, but retry all of them again if we have more
e4e4b8544a492cf90bd7a93c9a26e8285fc7c00bStephan Bosch connect attempts left or on the next request. */
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch queue->ips_connect_idx = queue->ips_connect_start_idx =
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch (queue->ips_connect_idx + 1) % ips_count;
e4e4b8544a492cf90bd7a93c9a26e8285fc7c00bStephan Bosch
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch if (queue->cur_peer == NULL && (set->max_connect_attempts == 0 ||
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch queue->connect_attempts >= set->max_connect_attempts)) {
36409af77b42dc1c18c0691970b2eb07785fbba4Timo Sirainen e_debug(queue->event,
e4e4b8544a492cf90bd7a93c9a26e8285fc7c00bStephan Bosch "Failed to set up any connection; failing all queued requests");
9284599e2d12b08170be81441bcfc53fa5b71a73Timo Sirainen if (queue->connect_attempts > 1) {
9284599e2d12b08170be81441bcfc53fa5b71a73Timo Sirainen unsigned int total_msecs =
9284599e2d12b08170be81441bcfc53fa5b71a73Timo Sirainen timeval_diff_msecs(&ioloop_timeval, &queue->first_connect_time);
9284599e2d12b08170be81441bcfc53fa5b71a73Timo Sirainen reason = t_strdup_printf("%s (%u attempts in %u.%03u secs)",
9284599e2d12b08170be81441bcfc53fa5b71a73Timo Sirainen reason, queue->connect_attempts,
9284599e2d12b08170be81441bcfc53fa5b71a73Timo Sirainen total_msecs/1000, total_msecs%1000);
9284599e2d12b08170be81441bcfc53fa5b71a73Timo Sirainen }
e4e4b8544a492cf90bd7a93c9a26e8285fc7c00bStephan Bosch queue->connect_attempts = 0;
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch http_client_peer_unlink_queue(peer, queue);
e4e4b8544a492cf90bd7a93c9a26e8285fc7c00bStephan Bosch http_client_queue_fail(queue,
e4e4b8544a492cf90bd7a93c9a26e8285fc7c00bStephan Bosch HTTP_CLIENT_REQUEST_ERROR_CONNECT_FAILED, reason);
e4e4b8544a492cf90bd7a93c9a26e8285fc7c00bStephan Bosch return;
e4e4b8544a492cf90bd7a93c9a26e8285fc7c00bStephan Bosch }
e4e4b8544a492cf90bd7a93c9a26e8285fc7c00bStephan Bosch } else {
23fe024e1dfc8eb5eaefc4e57a16b4257568f510Stephan Bosch queue->ips_connect_idx = (queue->ips_connect_idx + 1) % ips_count;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch }
e4e4b8544a492cf90bd7a93c9a26e8285fc7c00bStephan Bosch
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch if (http_client_queue_connection_attempt(queue) != peer) {
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch http_client_peer_unlink_queue(peer, queue);
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch queue->cur_peer = NULL;
27a2e59eaa648fef2acb2c4b852567d22e016a2dStephan Bosch }
e4e4b8544a492cf90bd7a93c9a26e8285fc7c00bStephan Bosch return;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch}
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
c1423bdba971228a283653222ed0367f84ab6402Stephan Boschvoid
c1423bdba971228a283653222ed0367f84ab6402Stephan Boschhttp_client_queue_peer_disconnected(struct http_client_queue *queue,
c1423bdba971228a283653222ed0367f84ab6402Stephan Bosch struct http_client_peer *peer)
c1423bdba971228a283653222ed0367f84ab6402Stephan Bosch{
c1423bdba971228a283653222ed0367f84ab6402Stephan Bosch struct http_client_peer *const *peer_idx;
c1423bdba971228a283653222ed0367f84ab6402Stephan Bosch
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch if (queue->cur_peer == peer) {
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch queue->cur_peer = NULL;
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch return;
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch }
57d86b6fd46cb6d37bfc28f67ae4be80296ad35aStephan Bosch
c1423bdba971228a283653222ed0367f84ab6402Stephan Bosch array_foreach(&queue->pending_peers, peer_idx) {
c1423bdba971228a283653222ed0367f84ab6402Stephan Bosch if (*peer_idx == peer) {
c1423bdba971228a283653222ed0367f84ab6402Stephan Bosch array_delete(&queue->pending_peers,
c1423bdba971228a283653222ed0367f84ab6402Stephan Bosch array_foreach_idx(&queue->pending_peers, peer_idx), 1);
c1423bdba971228a283653222ed0367f84ab6402Stephan Bosch break;
c1423bdba971228a283653222ed0367f84ab6402Stephan Bosch }
c1423bdba971228a283653222ed0367f84ab6402Stephan Bosch }
c1423bdba971228a283653222ed0367f84ab6402Stephan Bosch}
c1423bdba971228a283653222ed0367f84ab6402Stephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch/*
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch * Main request queue
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Boschvoid
b66def5dadd3e7c250313a938d26ad113663f86bStephan Boschhttp_client_queue_drop_request(struct http_client_queue *queue,
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch struct http_client_request *req)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch{
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch struct http_client_request **reqs;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch unsigned int count, i;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
36409af77b42dc1c18c0691970b2eb07785fbba4Timo Sirainen e_debug(queue->event,
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch "Dropping request %s", http_client_request_label(req));
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* drop from queue */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (req->urgent) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch reqs = array_get_modifiable(&queue->queued_urgent_requests, &count);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch for (i = 0; i < count; i++) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (reqs[i] == req) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch array_delete(&queue->queued_urgent_requests, i, 1);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch break;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch } else {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch reqs = array_get_modifiable(&queue->queued_requests, &count);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch for (i = 0; i < count; i++) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (reqs[i] == req) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch array_delete(&queue->queued_requests, i, 1);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch break;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* drop from delay queue */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (req->release_time.tv_sec > 0) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch reqs = array_get_modifiable(&queue->delayed_requests, &count);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch for (i = 0; i < count; i++) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (reqs[i] == req)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch break;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (i < count) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (i == 0) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (queue->to_delayed != NULL) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch timeout_remove(&queue->to_delayed);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (count > 1) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch i_assert(reqs[1]->release_time.tv_sec > 0);
49e66f665b8070be2bb8afb6b823bb9aefc838bcStephan Bosch http_client_queue_set_delay_timer(queue, reqs[1]->release_time);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch array_delete(&queue->delayed_requests, i, 1);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* drop from main request list */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch reqs = array_get_modifiable(&queue->requests, &count);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch for (i = 0; i < count; i++) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (reqs[i] == req)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch break;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch i_assert(i < count);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (i == 0) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (queue->to_request != NULL) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch timeout_remove(&queue->to_request);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (count > 1 && reqs[1]->timeout_time.tv_sec > 0)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch http_client_queue_set_request_timer(queue, &reqs[1]->timeout_time);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch req->queue = NULL;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch array_delete(&queue->requests, i, 1);
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch if (array_count(&queue->requests) == 0)
c4b2dba355010a38f17b3cd84feb01ecb8b05a55Stephan Bosch http_client_host_check_idle(queue->host);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch return;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch}
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Boschstatic void
b66def5dadd3e7c250313a938d26ad113663f86bStephan Boschhttp_client_queue_request_timeout(struct http_client_queue *queue)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch{
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch struct http_client_request *const *reqs;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch ARRAY_TYPE(http_client_request) failed_requests;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch struct timeval new_to = { 0, 0 };
3dc38e4053b06b3f654d199a293a988b9c989347Stephan Bosch string_t *str;
b17e8882559bf792315d36530cebd1fbc5c66207Stephan Bosch size_t prefix_size;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch unsigned int count, i;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
36409af77b42dc1c18c0691970b2eb07785fbba4Timo Sirainen e_debug(queue->event, "Timeout (now: %s.%03lu)",
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch t_strflocaltime("%Y-%m-%d %H:%M:%S", ioloop_timeval.tv_sec),
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch ((unsigned long)ioloop_timeval.tv_usec)/1000);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
d90a924480a061683786e459a2e1c1d0b6e4f1e4Josef 'Jeff' Sipek timeout_remove(&queue->to_request);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* collect failed requests */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch reqs = array_get(&queue->requests, &count);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch i_assert(count > 0);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch t_array_init(&failed_requests, count);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch for (i = 0; i < count; i++) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (reqs[i]->timeout_time.tv_sec > 0 &&
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch timeval_cmp_margin(&reqs[i]->timeout_time,
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch &ioloop_timeval, TIMEOUT_CMP_MARGIN_USECS) > 0) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch break;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch array_append(&failed_requests, &reqs[i], 1);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
211c638d81d382517d196ad47565e0d85012c927klemens /* update timeout */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (i < count)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch new_to = reqs[i]->timeout_time;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
3dc38e4053b06b3f654d199a293a988b9c989347Stephan Bosch str = t_str_new(64);
3dc38e4053b06b3f654d199a293a988b9c989347Stephan Bosch str_append(str, "Request ");
b17e8882559bf792315d36530cebd1fbc5c66207Stephan Bosch prefix_size = str_len(str);
3dc38e4053b06b3f654d199a293a988b9c989347Stephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* abort all failed request */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch reqs = array_get(&failed_requests, &count);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch i_assert(count > 0); /* at least one request timed out */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch for (i = 0; i < count; i++) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch struct http_client_request *req = reqs[i];
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b17e8882559bf792315d36530cebd1fbc5c66207Stephan Bosch str_truncate(str, prefix_size);
3dc38e4053b06b3f654d199a293a988b9c989347Stephan Bosch http_client_request_append_stats_text(req, str);
3dc38e4053b06b3f654d199a293a988b9c989347Stephan Bosch
36409af77b42dc1c18c0691970b2eb07785fbba4Timo Sirainen e_debug(queue->event,
3dc38e4053b06b3f654d199a293a988b9c989347Stephan Bosch "Absolute timeout expired for request %s (%s)",
3dc38e4053b06b3f654d199a293a988b9c989347Stephan Bosch http_client_request_label(req), str_c(str));
d5c665cf2989d49922b63439ac45714e9755838aTimo Sirainen http_client_request_error(&req,
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch HTTP_CLIENT_REQUEST_ERROR_TIMED_OUT,
3dc38e4053b06b3f654d199a293a988b9c989347Stephan Bosch t_strdup_printf(
3dc38e4053b06b3f654d199a293a988b9c989347Stephan Bosch "Absolute request timeout expired (%s)",
3dc38e4053b06b3f654d199a293a988b9c989347Stephan Bosch str_c(str)));
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (new_to.tv_sec > 0) {
36409af77b42dc1c18c0691970b2eb07785fbba4Timo Sirainen e_debug(queue->event, "New timeout");
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch http_client_queue_set_request_timer(queue, &new_to);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch}
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Boschstatic void
b66def5dadd3e7c250313a938d26ad113663f86bStephan Boschhttp_client_queue_set_request_timer(struct http_client_queue *queue,
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch const struct timeval *time)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch{
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch i_assert(time->tv_sec > 0);
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&queue->to_request);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
36409af77b42dc1c18c0691970b2eb07785fbba4Timo Sirainen e_debug(queue->event,
39018a601747b9d52a15ce2451e64e9515587944Timo Sirainen "Set request timeout to %s.%03lu (now: %s.%03lu)",
39018a601747b9d52a15ce2451e64e9515587944Timo Sirainen t_strflocaltime("%Y-%m-%d %H:%M:%S", time->tv_sec),
39018a601747b9d52a15ce2451e64e9515587944Timo Sirainen ((unsigned long)time->tv_usec)/1000,
39018a601747b9d52a15ce2451e64e9515587944Timo Sirainen t_strflocaltime("%Y-%m-%d %H:%M:%S", ioloop_timeval.tv_sec),
39018a601747b9d52a15ce2451e64e9515587944Timo Sirainen ((unsigned long)ioloop_timeval.tv_usec)/1000);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* set timer */
a68aaff537e2e30d782bb8b9d8782e1a10a17d1aStephan Bosch queue->to_request = timeout_add_absolute_to(
a68aaff537e2e30d782bb8b9d8782e1a10a17d1aStephan Bosch queue->client->ioloop, time,
a68aaff537e2e30d782bb8b9d8782e1a10a17d1aStephan Bosch http_client_queue_request_timeout, queue);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch}
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Boschstatic int
b66def5dadd3e7c250313a938d26ad113663f86bStephan Boschhttp_client_queue_request_timeout_cmp(struct http_client_request *const *req1,
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch struct http_client_request *const *req2)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch{
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch int ret;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* 0 means no timeout */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if ((*req1)->timeout_time.tv_sec == 0) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if ((*req2)->timeout_time.tv_sec == 0) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* sort by age */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if ((ret=timeval_cmp(&(*req1)->submit_time, &(*req2)->submit_time)) != 0)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch return ret;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch } else {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch return 1;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch } else if ((*req2)->timeout_time.tv_sec == 0) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch return -1;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* sort by timeout */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch } else if
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch ((ret=timeval_cmp(&(*req1)->timeout_time, &(*req2)->timeout_time)) != 0) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch return ret;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
211c638d81d382517d196ad47565e0d85012c927klemens /* sort by minimum attempts for fairness */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch return ((*req2)->attempts - (*req1)->attempts);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch}
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Boschstatic void http_client_queue_submit_now(struct http_client_queue *queue,
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch struct http_client_request *req)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch{
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch ARRAY_TYPE(http_client_request) *req_queue;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch req->release_time.tv_sec = 0;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch req->release_time.tv_usec = 0;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch if (req->urgent)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch req_queue = &queue->queued_urgent_requests;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch else
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch req_queue = &queue->queued_requests;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* enqueue */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (req->timeout_time.tv_sec == 0) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* no timeout; enqueue at end */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch array_append(req_queue, &req, 1);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch } else if (timeval_diff_msecs(&req->timeout_time, &ioloop_timeval) <= 1) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* pretty much already timed out; don't bother */
3ad0a46f43bbd18f00a10bd74fa00b095b0a8da6Stephan Bosch return;
3ad0a46f43bbd18f00a10bd74fa00b095b0a8da6Stephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch } else {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch unsigned int insert_idx;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* keep transmission queue sorted earliest timeout first */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch (void)array_bsearch_insert_pos(req_queue,
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch &req, http_client_queue_request_timeout_cmp, &insert_idx);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch array_insert(req_queue, insert_idx, &req, 1);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
3ad0a46f43bbd18f00a10bd74fa00b095b0a8da6Stephan Bosch
3ad0a46f43bbd18f00a10bd74fa00b095b0a8da6Stephan Bosch http_client_queue_connection_setup(queue);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch}
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch/*
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch * Delayed request queue
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Boschstatic void
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Boschhttp_client_queue_delay_timeout(struct http_client_queue *queue)
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch{
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch struct http_client_request *const *reqs;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch unsigned int count, i, finished;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch
52ac19fa609252a2dc5d78c724fd32a422c5c7a1Timo Sirainen timeout_remove(&queue->to_delayed);
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch io_loop_time_refresh();
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch finished = 0;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch reqs = array_get(&queue->delayed_requests, &count);
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch for (i = 0; i < count; i++) {
06d1b658d0f6840204bf1487b8bcad829d33b726Stephan Bosch if (timeval_cmp_margin(&reqs[i]->release_time,
06d1b658d0f6840204bf1487b8bcad829d33b726Stephan Bosch &ioloop_timeval, TIMEOUT_CMP_MARGIN_USECS) > 0) {
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch break;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch }
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch
36409af77b42dc1c18c0691970b2eb07785fbba4Timo Sirainen e_debug(queue->event, "Activated delayed request %s%s",
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch http_client_request_label(reqs[i]),
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch (reqs[i]->urgent ? " (urgent)" : ""));
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch http_client_queue_submit_now(queue, reqs[i]);
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch finished++;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch }
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch if (i < count) {
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch http_client_queue_set_delay_timer(queue, reqs[i]->release_time);
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch array_delete(&queue->delayed_requests, 0, finished);
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch}
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Boschstatic void
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Boschhttp_client_queue_set_delay_timer(struct http_client_queue *queue,
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch struct timeval time)
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch{
a68aaff537e2e30d782bb8b9d8782e1a10a17d1aStephan Bosch struct http_client *client = queue->client;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch int usecs = timeval_diff_usecs(&time, &ioloop_timeval);
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch int msecs;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch /* round up to nearest microsecond */
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch msecs = (usecs + 999) / 1000;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch /* set timer */
0d1b8b6bec79746c5d89d57dd8c1688946bd9237Josef 'Jeff' Sipek timeout_remove(&queue->to_delayed);
a68aaff537e2e30d782bb8b9d8782e1a10a17d1aStephan Bosch queue->to_delayed = timeout_add_to(client->ioloop, msecs,
a68aaff537e2e30d782bb8b9d8782e1a10a17d1aStephan Bosch http_client_queue_delay_timeout, queue);
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch}
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Boschstatic int
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Boschhttp_client_queue_delayed_cmp(struct http_client_request *const *req1,
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch struct http_client_request *const *req2)
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch{
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch return timeval_cmp(&(*req1)->release_time, &(*req2)->release_time);
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch}
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch/*
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch * Request submission
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Boschvoid http_client_queue_submit_request(struct http_client_queue *queue,
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch struct http_client_request *req)
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch{
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch unsigned int insert_idx;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (req->queue != NULL)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch http_client_queue_drop_request(req->queue, req);
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch req->queue = queue;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* check delay vs timeout */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (req->release_time.tv_sec > 0 && req->timeout_time.tv_sec > 0 &&
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch timeval_cmp_margin(&req->release_time,
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch &req->timeout_time, TIMEOUT_CMP_MARGIN_USECS) >= 0) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* release time is later than absolute timeout */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch req->release_time.tv_sec = 0;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch req->release_time.tv_usec = 0;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* timeout rightaway */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch req->timeout_time = ioloop_timeval;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
36409af77b42dc1c18c0691970b2eb07785fbba4Timo Sirainen e_debug(queue->event,
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch "Delayed request %s%s already timed out",
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch http_client_request_label(req),
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch (req->urgent ? " (urgent)" : ""));
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* add to main request list */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (req->timeout_time.tv_sec == 0) {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* no timeout; just append */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch array_append(&queue->requests, &req, 1);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch } else {
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch unsigned int insert_idx;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* keep main request list sorted earliest timeout first */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch (void)array_bsearch_insert_pos(&queue->requests,
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch &req, http_client_queue_request_timeout_cmp, &insert_idx);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch array_insert(&queue->requests, insert_idx, &req, 1);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* now first in queue; update timer */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (insert_idx == 0)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch http_client_queue_set_request_timer(queue, &req->timeout_time);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch }
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch /* handle delay */
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch if (req->release_time.tv_sec > 0) {
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch io_loop_time_refresh();
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch
06d1b658d0f6840204bf1487b8bcad829d33b726Stephan Bosch if (timeval_cmp_margin(&req->release_time,
06d1b658d0f6840204bf1487b8bcad829d33b726Stephan Bosch &ioloop_timeval, TIMEOUT_CMP_MARGIN_USECS) > 0) {
36409af77b42dc1c18c0691970b2eb07785fbba4Timo Sirainen e_debug(queue->event,
a0923d7d097284e80be164c9d7a630f4b6c176e2Stephan Bosch "Delayed request %s%s submitted (time remaining: %d msecs)",
a0923d7d097284e80be164c9d7a630f4b6c176e2Stephan Bosch http_client_request_label(req),
a0923d7d097284e80be164c9d7a630f4b6c176e2Stephan Bosch (req->urgent ? " (urgent)" : ""),
a0923d7d097284e80be164c9d7a630f4b6c176e2Stephan Bosch timeval_diff_msecs(&req->release_time, &ioloop_timeval));
a0923d7d097284e80be164c9d7a630f4b6c176e2Stephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch (void)array_bsearch_insert_pos(&queue->delayed_requests,
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch &req, http_client_queue_delayed_cmp, &insert_idx);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch array_insert(&queue->delayed_requests, insert_idx, &req, 1);
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch if (insert_idx == 0)
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch http_client_queue_set_delay_timer(queue, req->release_time);
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch return;
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch }
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch }
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch http_client_queue_submit_now(queue, req);
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch}
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch/*
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch * Request retrieval
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Boschstruct http_client_request *
de96afeeaa5242cffe89f1966457e935806b5746Stephan Boschhttp_client_queue_claim_request(struct http_client_queue *queue,
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch const struct http_client_peer_addr *addr, bool no_urgent)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch{
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch struct http_client_request *const *requests;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch struct http_client_request *req;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch unsigned int i, count;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch count = 0;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (!no_urgent)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch requests = array_get(&queue->queued_urgent_requests, &count);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (count == 0)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch requests = array_get(&queue->queued_requests, &count);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch if (count == 0)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch return NULL;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch i = 0;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch req = requests[i];
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (req->urgent)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch array_delete(&queue->queued_urgent_requests, i, 1);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch else
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch array_delete(&queue->queued_requests, i, 1);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
36409af77b42dc1c18c0691970b2eb07785fbba4Timo Sirainen e_debug(queue->event,
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch "Connection to peer %s claimed request %s %s",
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch http_client_peer_addr2str(addr), http_client_request_label(req),
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch (req->urgent ? "(urgent)" : ""));
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch return req;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch}
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Boschunsigned int
de96afeeaa5242cffe89f1966457e935806b5746Stephan Boschhttp_client_queue_requests_pending(struct http_client_queue *queue,
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch unsigned int *num_urgent_r)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch{
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch unsigned int urg_count = array_count(&queue->queued_urgent_requests);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (num_urgent_r != NULL)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch *num_urgent_r = urg_count;
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch return array_count(&queue->queued_requests) + urg_count;
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch}
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch
c62f15cc134cc9701c391eec8e9ef92105aa6d33Stephan Boschunsigned int
c62f15cc134cc9701c391eec8e9ef92105aa6d33Stephan Boschhttp_client_queue_requests_active(struct http_client_queue *queue)
c62f15cc134cc9701c391eec8e9ef92105aa6d33Stephan Bosch{
c62f15cc134cc9701c391eec8e9ef92105aa6d33Stephan Bosch return array_count(&queue->requests);
c62f15cc134cc9701c391eec8e9ef92105aa6d33Stephan Bosch}
c62f15cc134cc9701c391eec8e9ef92105aa6d33Stephan Bosch
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch/*
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch * ioloop
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch */
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch
de96afeeaa5242cffe89f1966457e935806b5746Stephan Boschvoid http_client_queue_switch_ioloop(struct http_client_queue *queue)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch{
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch if (queue->to_connect != NULL)
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch queue->to_connect = io_loop_move_timeout(&queue->to_connect);
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch if (queue->to_request != NULL)
b66def5dadd3e7c250313a938d26ad113663f86bStephan Bosch queue->to_request = io_loop_move_timeout(&queue->to_request);
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch if (queue->to_delayed != NULL)
93cc87bb22386e020cee1093b6bd59295e0b33f0Stephan Bosch queue->to_delayed = io_loop_move_timeout(&queue->to_delayed);
de96afeeaa5242cffe89f1966457e935806b5746Stephan Bosch}