const struct http_client_settings *set = &client->set;
struct http_client_peer_pool *ppool = conn->ppool;
struct http_client_peer_shared *pshared = ppool->peer;
+ struct http_client_context *cctx = pshared->cctx;
unsigned int timeout, count;
if (!conn->connected) {
"Lost peer; going idle (timeout = %u msecs)",
timeout);
- conn->to_idle =
- timeout_add(timeout, http_client_connection_idle_timeout, conn);
+ conn->to_idle = timeout_add_to(cctx->ioloop, timeout,
+ http_client_connection_idle_timeout, conn);
array_append(&ppool->idle_conns, &conn, 1);
} else {
e_debug(conn->event, "Lost peer; already idle");
{
struct http_client_peer *peer;
struct http_client_peer_pool *ppool = conn->ppool;
+ struct http_client_context *cctx = ppool->peer->cctx;
struct http_client *client;
const struct http_client_settings *set;
unsigned int timeout, count;
"No more requests queued; going idle (timeout = %u msecs)",
timeout);
- conn->to_idle =
- timeout_add(timeout, http_client_connection_idle_timeout, conn);
+ conn->to_idle = timeout_add_to(cctx->ioloop, timeout,
+ http_client_connection_idle_timeout, conn);
array_append(&ppool->idle_conns, &conn, 1);
}
void http_client_connection_start_request_timeout(
struct http_client_connection *conn)
{
+ struct http_client_context *cctx = conn->ppool->peer->cctx;
struct http_client_peer *peer = conn->peer;
struct http_client *client = peer->client;
const struct http_client_settings *set = &client->set;
else if (conn->to_requests != NULL)
timeout_reset(conn->to_requests);
else {
- conn->to_requests = timeout_add(timeout_msecs,
- http_client_connection_request_timeout, conn);
+ conn->to_requests = timeout_add_to(
+ cctx->ioloop, timeout_msecs,
+ http_client_connection_request_timeout, conn);
}
}
{
struct http_client_peer *peer = conn->peer;
struct http_client_peer_shared *pshared = conn->ppool->peer;
+ struct http_client_context *cctx = pshared->cctx;
struct http_client_request *req = NULL;
const char *error;
bool pipelined;
i_assert(!pipelined);
i_assert(req->payload_chunked || req->payload_size > 0);
i_assert(conn->to_response == NULL);
- conn->to_response = timeout_add(HTTP_CLIENT_CONTINUE_TIMEOUT_MSECS,
+ conn->to_response = timeout_add_to(cctx->ioloop,
+ HTTP_CLIENT_CONTINUE_TIMEOUT_MSECS,
http_client_connection_continue_timeout, conn);
}
static void http_client_payload_finished(struct http_client_connection *conn)
{
+ struct http_client_context *cctx = conn->ppool->peer->cctx;
+
timeout_remove(&conn->to_input);
- conn->conn.io = io_add_istream(conn->conn.input,
- http_client_connection_input, &conn->conn);
+ conn->conn.io = io_add_istream_to(cctx->ioloop, conn->conn.input,
+ http_client_connection_input,
+ &conn->conn);
if (array_count(&conn->request_wait_list) > 0)
http_client_connection_start_request_timeout(conn);
}
static void http_client_payload_destroyed(struct http_client_request *req)
{
struct http_client_connection *conn = req->conn;
+ struct http_client_context *cctx = conn->ppool->peer->cctx;
i_assert(conn != NULL);
i_assert(conn->pending_request == req);
state it is in). this call also triggers sending a new request if
necessary. */
if (!conn->disconnected) {
- conn->to_input = timeout_add_short
- (0, http_client_payload_destroyed_timeout, conn);
+ conn->to_input = timeout_add_short_to(
+ cctx->ioloop, 0,
+ http_client_payload_destroyed_timeout, conn);
}
/* room for new requests */
struct http_response *response)
{
struct http_client_peer_shared *pshared = conn->ppool->peer;
+ struct http_client_context *cctx = pshared->cctx;
struct istream *payload;
bool retrying;
req->state = HTTP_REQUEST_STATE_GOT_RESPONSE;
if (response->payload != NULL) {
- /* wrap the stream to capture the destroy event without destroying the
- actual payload stream. */
+ /* wrap the stream to capture the destroy event without
+ destroying the actual payload stream. we are already expected
+ to be on the correct ioloop, so there should be no need to
+ switch the stream's ioloop here. */
conn->incoming_payload = response->payload =
i_stream_create_timeout(response->payload,
req->attempt_timeout_msecs);
i_stream_remove_destroy_callback(conn->incoming_payload,
http_client_payload_destroyed);
i_stream_unref(&conn->incoming_payload);
- conn->conn.io = io_add_istream(conn->conn.input,
- http_client_connection_input,
- &conn->conn);
+ conn->conn.io = io_add_istream_to(cctx->ioloop,
+ conn->conn.input,
+ http_client_connection_input,
+ &conn->conn);
}
http_client_connection_unref_request(conn, &req);
return http_client_connection_unref(&conn);
http_client_connection_connect(struct http_client_connection *conn,
unsigned int timeout_msecs)
{
+ struct http_client_context *cctx = conn->ppool->peer->cctx;
+
conn->connect_start_timestamp = ioloop_timeval;
if (connection_client_connect(&conn->conn) < 0) {
conn->connect_errno = errno;
e_debug(conn->event, "Connect failed: %m");
- conn->to_input = timeout_add_short(0,
+ conn->to_input = timeout_add_short_to(cctx->ioloop, 0,
http_client_connection_delayed_connect_error, conn);
return;
}
+ connection_switch_ioloop_to(&conn->conn, cctx->ioloop);
/* don't use connection.h timeout because we want this timeout
to include also the SSL handshake */
if (timeout_msecs > 0) {
- conn->to_connect = timeout_add(timeout_msecs,
+ conn->to_connect = timeout_add_to(
+ cctx->ioloop, timeout_msecs,
http_client_connect_timeout, conn);
}
}
http_client_request_start_tunnel(req, &tunnel);
- connection_init_from_streams
- (cctx->conn_list, &conn->conn, name, tunnel.input, tunnel.output);
+ connection_init_from_streams(cctx->conn_list, &conn->conn,
+ name, tunnel.input, tunnel.output);
+ connection_switch_ioloop_to(&conn->conn, cctx->ioloop);
i_stream_unref(&tunnel.input);
o_stream_unref(&tunnel.output);
conn->connect_initialized = TRUE;
const struct ip_addr *ip, in_port_t port,
unsigned int timeout_msecs)
{
+ struct http_client_context *cctx = conn->ppool->peer->cctx;
struct http_client *client = conn->peer->client;
conn->connect_start_timestamp = ioloop_timeval;
/* don't use connection.h timeout because we want this timeout
to include also the SSL handshake */
if (timeout_msecs > 0) {
- conn->to_connect = timeout_add(timeout_msecs,
+ conn->to_connect = timeout_add_to(
+ cctx->ioloop, timeout_msecs,
http_client_connect_tunnel_timeout, conn);
}
}
conn->debug = client->set.debug;
if (pshared->addr.type != HTTP_CLIENT_PEER_ADDR_RAW)
i_array_init(&conn->request_wait_list, 16);
- conn->io_wait_timer = io_wait_timer_add();
+ conn->io_wait_timer = io_wait_timer_add_to(cctx->ioloop);
conn->label = i_strdup_printf("%s [%d]",
http_client_peer_shared_label(pshared), conn->id);
pool = pool_alloconly_create("http client", 1024);
client = p_new(pool, struct http_client, 1);
client->pool = pool;
+ client->ioloop = current_ioloop;
/* create private context if none is provided */
id++;
pool_unref(&client->pool);
}
-struct ioloop *http_client_switch_ioloop(struct http_client *client)
+static void http_client_do_switch_ioloop(struct http_client *client)
{
- struct ioloop *prev_ioloop = client->ioloop;
struct http_client_peer *peer;
struct http_client_host *host;
client->to_failing_requests =
io_loop_move_timeout(&client->to_failing_requests);
}
+}
- http_client_context_switch_ioloop(client->cctx);
+struct ioloop *http_client_switch_ioloop(struct http_client *client)
+{
+ struct ioloop *prev_ioloop = client->ioloop;
client->ioloop = current_ioloop;
+
+ http_client_do_switch_ioloop(client);
+ http_client_context_switch_ioloop(client->cctx);
+
return prev_ioloop;
}
struct http_client_request *req)
{
if (client->to_failing_requests == NULL) {
- client->to_failing_requests = timeout_add_short(0,
- http_client_handle_request_errors, client);
+ client->to_failing_requests =
+ timeout_add_short_to(client->ioloop, 0,
+ http_client_handle_request_errors, client);
}
array_append(&client->delayed_failing_requests, &req, 1);
}
cctx = p_new(pool, struct http_client_context, 1);
cctx->pool = pool;
cctx->refcount = 1;
+ cctx->ioloop = current_ioloop;
cctx->event = event_create(set->event);
if (set->debug)
{
DLLIST_REMOVE(&cctx->clients_list, client);
http_client_context_update_settings(cctx);
+
+ if (cctx->ioloop != current_ioloop &&
+ cctx->ioloop == client->ioloop &&
+ cctx->clients_list != NULL) {
+ struct ioloop *prev_ioloop = current_ioloop;
+
+ io_loop_set_current(cctx->clients_list->ioloop);
+ http_client_context_switch_ioloop(cctx);
+ io_loop_set_current(prev_ioloop);
+ }
}
static void http_client_context_close(struct http_client_context *cctx)
}
}
-void http_client_context_switch_ioloop(struct http_client_context *cctx)
+static void
+http_client_context_do_switch_ioloop(struct http_client_context *cctx)
{
struct connection *_conn = cctx->conn_list->connections;
struct http_client_host_shared *hshared;
http_client_host_shared_switch_ioloop(hshared);
}
+void http_client_context_switch_ioloop(struct http_client_context *cctx)
+{
+ cctx->ioloop = current_ioloop;
+
+ http_client_context_do_switch_ioloop(cctx);
+}
+
static void http_client_global_context_free(void)
{
http_client_context_unref(&http_client_global_context);
http_client_global_context_ioloop_switched(
struct ioloop *prev_ioloop ATTR_UNUSED)
{
- i_assert(http_client_global_context != NULL);
+ struct http_client_context *cctx = http_client_global_context;
+
+ i_assert(cctx != NULL);
if (current_ioloop == NULL) {
- http_client_context_close(http_client_global_context);
+ http_client_context_close(cctx);
return;
}
- http_client_context_switch_ioloop(http_client_global_context);
+ if (cctx->clients_list == NULL) {
+ /* follow the current ioloop if there is no client */
+ http_client_context_switch_ioloop(cctx);
+ }
}
struct http_client_context *http_client_get_global_context(void)