]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-http: client: Make sure all ioloop objects are created on the ioloop that the...
authorStephan Bosch <stephan.bosch@dovecot.fi>
Tue, 16 Jan 2018 01:02:11 +0000 (02:02 +0100)
committerVille Savolainen <ville.savolainen@dovecot.fi>
Mon, 12 Mar 2018 07:22:59 +0000 (09:22 +0200)
src/lib-http/http-client-connection.c
src/lib-http/http-client-host.c
src/lib-http/http-client-peer.c
src/lib-http/http-client-private.h
src/lib-http/http-client-queue.c
src/lib-http/http-client-request.c
src/lib-http/http-client.c

index ac6ae050756cc1c8ac672258ea10b50c12b94651..d28a11dd17394f4aa93466f1108a5d6929bd4508 100644 (file)
@@ -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);
index 9de3437b75f151cf237873d1d5a12f8ad8ae8276..427573ee823f8cd7b43d8e71c1fbaaa0daf96882 100644 (file)
@@ -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 {
index 3650614fe3966bd92e486cf3cfe1895e6918209d..40f4c5210e785fd5c619240c6338cc29260a94c4 100644 (file)
@@ -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);
        }
 }
 
index ef40ada011fe293162408242f45cacb1c0c5dbc8..626d82552b8373b5b1dc20197d069d36d58565c2 100644 (file)
@@ -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;
 
index 6a9bb9548c2aa61b212b255af63b31c56d9f41c6..bc5c4973b6dff88717d869d7d81659df2fe7a0d5 100644 (file)
@@ -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
index a39f141533b5347624d7796d4d5ba2a2af2e9114..c1bddf1f1c65ad9bf369f4e1e73688c6b6383bc8 100644 (file)
@@ -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:
index a529f9ee0544084c4ab000ecffa149fb613fac09..0a028c14df21ab6cedecd15497d3f6e82f0cc3ba 100644 (file)
@@ -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)