From: Stephan Bosch Date: Tue, 16 Jan 2018 01:02:11 +0000 (+0100) Subject: lib-http: client: Make sure all ioloop objects are created on the ioloop that the... X-Git-Tag: 2.3.1~163 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=080415ce425d9ca3019bbb5c9ee88fb0323b948f;p=thirdparty%2Fdovecot%2Fcore.git lib-http: client: Make sure all ioloop objects are created on the ioloop that the client/context is switched to. --- diff --git a/src/lib-http/http-client-connection.c b/src/lib-http/http-client-connection.c index ac6ae05075..d28a11dd17 100644 --- a/src/lib-http/http-client-connection.c +++ b/src/lib-http/http-client-connection.c @@ -364,6 +364,7 @@ void http_client_connection_lost_peer(struct http_client_connection *conn) 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) { @@ -395,8 +396,8 @@ void http_client_connection_lost_peer(struct http_client_connection *conn) "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"); @@ -409,6 +410,7 @@ void http_client_connection_check_idle(struct http_client_connection *conn) { 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; @@ -461,8 +463,8 @@ void http_client_connection_check_idle(struct http_client_connection *conn) "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); } @@ -514,6 +516,7 @@ http_client_connection_request_timeout(struct http_client_connection *conn) 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; @@ -535,8 +538,9 @@ void http_client_connection_start_request_timeout( 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); } } @@ -585,6 +589,7 @@ int http_client_connection_next_request(struct http_client_connection *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; @@ -641,7 +646,8 @@ int http_client_connection_next_request(struct http_client_connection *conn) 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); } @@ -692,9 +698,12 @@ static void http_client_connection_destroy(struct connection *_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); } @@ -712,6 +721,7 @@ http_client_payload_destroyed_timeout(struct http_client_connection *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); @@ -740,8 +750,9 @@ static void http_client_payload_destroyed(struct http_client_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 */ @@ -791,6 +802,7 @@ http_client_connection_return_response( 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; @@ -803,8 +815,10 @@ http_client_connection_return_response( 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); @@ -837,9 +851,10 @@ http_client_connection_return_response( 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); @@ -1485,19 +1500,23 @@ static void 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); } } @@ -1542,8 +1561,9 @@ http_client_connection_tunnel_response(const struct http_response *response, 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; @@ -1554,6 +1574,7 @@ http_client_connection_connect_tunnel(struct http_client_connection *conn, 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; @@ -1566,7 +1587,8 @@ http_client_connection_connect_tunnel(struct http_client_connection *conn, /* 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); } } @@ -1615,7 +1637,7 @@ http_client_connection_create(struct http_client_peer *peer) 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); diff --git a/src/lib-http/http-client-host.c b/src/lib-http/http-client-host.c index 9de3437b75..427573ee82 100644 --- a/src/lib-http/http-client-host.c +++ b/src/lib-http/http-client-host.c @@ -62,7 +62,7 @@ http_client_host_shared_check_idle( if (timeout <= HTTP_CLIENT_HOST_MINIMUM_IDLE_TIMEOUT_MSECS) timeout = HTTP_CLIENT_HOST_MINIMUM_IDLE_TIMEOUT_MSECS; - hshared->to_idle = timeout_add_short(timeout, + hshared->to_idle = timeout_add_to(hshared->cctx->ioloop, timeout, http_client_host_shared_idle_timeout, hshared); e_debug(hshared->event, "Host is idle (timeout = %u msecs)", timeout); @@ -143,6 +143,7 @@ static void http_client_host_shared_lookup i_zero(&dns_set); dns_set.dns_client_socket_path = cctx->dns_client_socket_path; dns_set.timeout_msecs = cctx->dns_lookup_timeout_msecs; + dns_set.ioloop = cctx->ioloop; (void)dns_lookup(hshared->name, &dns_set, http_client_host_shared_dns_callback, hshared, &hshared->dns_lookup); } else { diff --git a/src/lib-http/http-client-peer.c b/src/lib-http/http-client-peer.c index 3650614fe3..40f4c5210e 100644 --- a/src/lib-http/http-client-peer.c +++ b/src/lib-http/http-client-peer.c @@ -407,8 +407,9 @@ http_client_peer_shared_start_backoff_timer( (pshared->backoff_current_time_msecs - backoff_time_spent); e_debug(pshared->event, "Starting backoff timer for %d msecs", new_time); - pshared->to_backoff = timeout_add(new_time, - http_client_peer_shared_connect_backoff, pshared); + pshared->to_backoff = timeout_add_to( + pshared->cctx->ioloop, new_time, + http_client_peer_shared_connect_backoff, pshared); return TRUE; } @@ -1109,8 +1110,9 @@ void http_client_peer_trigger_request_handler(struct http_client_peer *peer) { /* trigger request handling through timeout */ if (peer->to_req_handling == NULL) { - peer->to_req_handling = - timeout_add_short(0, http_client_peer_handle_requests, peer); + peer->to_req_handling = timeout_add_short_to( + peer->client->ioloop, 0, + http_client_peer_handle_requests, peer); } } diff --git a/src/lib-http/http-client-private.h b/src/lib-http/http-client-private.h index ef40ada011..626d82552b 100644 --- a/src/lib-http/http-client-private.h +++ b/src/lib-http/http-client-private.h @@ -387,6 +387,7 @@ struct http_client_context { pool_t pool; unsigned int refcount; struct event *event; + struct ioloop *ioloop; struct http_client_settings set; diff --git a/src/lib-http/http-client-queue.c b/src/lib-http/http-client-queue.c index 6a9bb9548c..bc5c4973b6 100644 --- a/src/lib-http/http-client-queue.c +++ b/src/lib-http/http-client-queue.c @@ -409,8 +409,8 @@ http_client_queue_connection_attempt(struct http_client_queue *queue) msecs = client->set.soft_connect_timeout_msecs; if (!http_client_queue_is_last_connect_ip(queue) && msecs > 0 && queue->to_connect == NULL) { - queue->to_connect = - timeout_add(msecs, http_client_queue_soft_connect_timeout, queue); + queue->to_connect = timeout_add_to(client->ioloop, msecs, + http_client_queue_soft_connect_timeout, queue); } } } @@ -761,8 +761,9 @@ http_client_queue_set_request_timer(struct http_client_queue *queue, ((unsigned long)ioloop_timeval.tv_usec)/1000); /* set timer */ - queue->to_request = timeout_add_absolute - (time, http_client_queue_request_timeout, queue); + queue->to_request = timeout_add_absolute_to( + queue->client->ioloop, time, + http_client_queue_request_timeout, queue); } static int @@ -865,6 +866,7 @@ static void http_client_queue_set_delay_timer(struct http_client_queue *queue, struct timeval time) { + struct http_client *client = queue->client; int usecs = timeval_diff_usecs(&time, &ioloop_timeval); int msecs; @@ -873,8 +875,8 @@ http_client_queue_set_delay_timer(struct http_client_queue *queue, /* set timer */ timeout_remove(&queue->to_delayed); - queue->to_delayed = timeout_add - (msecs, http_client_queue_delay_timeout, queue); + queue->to_delayed = timeout_add_to(client->ioloop, msecs, + http_client_queue_delay_timeout, queue); } static int diff --git a/src/lib-http/http-client-request.c b/src/lib-http/http-client-request.c index a39f141533..c1bddf1f1c 100644 --- a/src/lib-http/http-client-request.c +++ b/src/lib-http/http-client-request.c @@ -1057,6 +1057,7 @@ int http_client_request_send_more(struct http_client_request *req, bool pipelined, const char **error_r) { struct http_client_connection *conn = req->conn; + struct http_client_context *cctx = conn->ppool->peer->cctx; struct ostream *output = req->payload_output; enum ostream_send_istream_result res; uoff_t offset; @@ -1108,7 +1109,8 @@ int http_client_request_send_more(struct http_client_request *req, conn->output_locked = TRUE; if (!pipelined) http_client_connection_stop_request_timeout(conn); - conn->io_req_payload = io_add_istream(req->payload_input, + conn->io_req_payload = io_add_istream_to( + cctx->ioloop, req->payload_input, http_client_request_payload_input, req); return 0; case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT: diff --git a/src/lib-http/http-client.c b/src/lib-http/http-client.c index a529f9ee05..0a028c14df 100644 --- a/src/lib-http/http-client.c +++ b/src/lib-http/http-client.c @@ -113,6 +113,7 @@ http_client_init_shared(struct http_client_context *cctx, 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++; @@ -280,9 +281,8 @@ void http_client_deinit(struct http_client **_client) 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; @@ -301,10 +301,17 @@ struct ioloop *http_client_switch_ioloop(struct http_client *client) 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; } @@ -394,8 +401,9 @@ void http_client_delay_request_error(struct http_client *client, 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); } @@ -429,6 +437,7 @@ http_client_context_create(const struct http_client_settings *set) 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) @@ -609,6 +618,16 @@ http_client_context_remove_client(struct http_client_context *cctx, { 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) @@ -639,7 +658,8 @@ 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; @@ -667,6 +687,13 @@ void http_client_context_switch_ioloop(struct http_client_context *cctx) 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); @@ -676,12 +703,17 @@ static void 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)