From: Michael Tremer Date: Sat, 19 Oct 2024 09:00:44 +0000 (+0000) Subject: httpclient: Explicitely keep a reference to any xfers X-Git-Tag: 0.9.30~999 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=96884c5d01b7d20aa779a2352049ae32ec72fbd5;p=pakfire.git httpclient: Explicitely keep a reference to any xfers Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/httpclient.c b/src/libpakfire/httpclient.c index d01a39a80..c272c3b61 100644 --- a/src/libpakfire/httpclient.c +++ b/src/libpakfire/httpclient.c @@ -20,6 +20,7 @@ #include #include +#include #include @@ -34,6 +35,12 @@ // The number of concurrent downloads #define DEFAULT_MAX_PARALLEL 4 +struct pakfire_httpclient_xfer { + TAILQ_ENTRY(pakfire_httpclient_xfer) nodes; + + struct pakfire_xfer* xfer; +}; + struct pakfire_httpclient { struct pakfire_ctx* ctx; int nrefs; @@ -57,6 +64,9 @@ struct pakfire_httpclient { // cURL multi handle CURLM* curl; + // Referenced xfers + TAILQ_HEAD(xfers, pakfire_httpclient_xfer) xfers; + // How many xfers do we have queued? unsigned int total_xfers; @@ -64,6 +74,42 @@ struct pakfire_httpclient { unsigned int total_downloadsize; }; +static int pakfire_httpclient_xfer_create( + struct pakfire_httpclient_xfer** x, struct pakfire_xfer* xfer) { + struct pakfire_httpclient_xfer* e = NULL; + + // Allocate some space + e = calloc(1, sizeof(*e)); + if (!e) + return -errno; + + // Store a reference to the xfer + e->xfer = pakfire_xfer_ref(xfer); + + // Return the pointer + *x = e; + + return 0; +} + +static void pakfire_httpclient_xfer_free(struct pakfire_httpclient_xfer* x) { + if (x->xfer) + pakfire_xfer_unref(x->xfer); + free(x); +} + +static struct pakfire_httpclient_xfer* pakfire_httpclient_xfer_find( + struct pakfire_httpclient* client, struct pakfire_xfer* xfer) { + struct pakfire_httpclient_xfer* e = NULL; + + TAILQ_FOREACH(e, &client->xfers, nodes) { + if (e->xfer == xfer) + return e; + } + + return NULL; +} + static int pakfire_httpclient_check(struct pakfire_httpclient* client) { struct pakfire_xfer* xfer = NULL; int r; @@ -381,6 +427,19 @@ static int pakfire_httpclient_setup_progress(struct pakfire_httpclient* client) } static void pakfire_httpclient_free(struct pakfire_httpclient* client) { + struct pakfire_httpclient_xfer* e = NULL; + + // Free any xfers that we still hold + for (;;) { + e = TAILQ_LAST(&client->xfers, xfers); + if (!e) + break; + + TAILQ_REMOVE(&client->xfers, e, nodes); + + pakfire_httpclient_xfer_free(e); + } + if (client->progress) pakfire_progress_unref(client->progress); if (client->curl) @@ -413,6 +472,9 @@ int pakfire_httpclient_create(struct pakfire_httpclient** client, // Set parallelism c->max_parallel = DEFAULT_MAX_PARALLEL; + // Init the xfer queue + TAILQ_INIT(&c->xfers); + // Setup event loop r = pakfire_httpclient_setup_loop(c, loop); if (r) @@ -459,12 +521,18 @@ sd_event* pakfire_httpclient_loop(struct pakfire_httpclient* client) { int pakfire_httpclient_enqueue_xfer(struct pakfire_httpclient* client, struct pakfire_xfer* xfer) { + struct pakfire_httpclient_xfer* e = NULL; int r; + // Create a new object + r = pakfire_httpclient_xfer_create(&e, xfer); + if (r < 0) + return r; + // Prepare the xfer r = pakfire_xfer_prepare(xfer, client->progress, 0); - if (r) - return r; + if (r < 0) + goto ERROR; // Increment the xfer counter client->total_xfers++; @@ -476,18 +544,30 @@ int pakfire_httpclient_enqueue_xfer(struct pakfire_httpclient* client, r = curl_multi_add_handle(client->curl, pakfire_xfer_handle(xfer)); if (r) { CTX_ERROR(client->ctx, "Adding handle failed: %s\n", curl_multi_strerror(r)); - - return r; + goto ERROR; } + // Keep a reference to the xfer + TAILQ_INSERT_TAIL(&client->xfers, e, nodes); + // Transfer enqueued return pakfire_xfer_enqueued(xfer, client); + +ERROR: + if (e) + pakfire_httpclient_xfer_free(e); + + return r; } int pakfire_httpclient_remove_xfer(struct pakfire_httpclient* client, struct pakfire_xfer* xfer) { + struct pakfire_httpclient_xfer* e = NULL; int r; + // Find reference + e = pakfire_httpclient_xfer_find(client, xfer); + // Decrement the xfers counter client->total_xfers--; @@ -498,11 +578,14 @@ int pakfire_httpclient_remove_xfer(struct pakfire_httpclient* client, r = curl_multi_remove_handle(client->curl, pakfire_xfer_handle(xfer)); if (r) { CTX_ERROR(client->ctx, "Could not remove the handle: %s\n", curl_multi_strerror(r)); - - return r; + goto ERROR; } - return 0; +ERROR: + if (e) + pakfire_httpclient_xfer_free(e); + + return r; } int pakfire_httpclient_run(struct pakfire_httpclient* client, const char* title) { diff --git a/src/libpakfire/xfer.c b/src/libpakfire/xfer.c index 39a369079..5cf8e54f4 100644 --- a/src/libpakfire/xfer.c +++ b/src/libpakfire/xfer.c @@ -307,7 +307,7 @@ static int pakfire_xfer_setup(struct pakfire_xfer* xfer) { curl_easy_setopt(xfer->handle, CURLOPT_ACCEPT_ENCODING, ""); // Reference back to this xfer - curl_easy_setopt(xfer->handle, CURLOPT_PRIVATE, pakfire_xfer_ref(xfer)); + curl_easy_setopt(xfer->handle, CURLOPT_PRIVATE, xfer); // Follow any redirects curl_easy_setopt(xfer->handle, CURLOPT_FOLLOWLOCATION, 1); @@ -408,9 +408,7 @@ int pakfire_xfer_create(struct pakfire_xfer** xfer, goto ERROR; // Return the reference - *xfer = x; - - return 0; + *xfer = pakfire_xfer_ref(x); ERROR: if (x) @@ -1151,7 +1149,6 @@ static int pakfire_xfer_save(struct pakfire_xfer* xfer) { } pakfire_xfer_error_code_t pakfire_xfer_done(struct pakfire_xfer* xfer, int code) { - struct pakfire_xfer* private = NULL; CURL* h = xfer->handle; int r; const char* scheme = NULL; @@ -1164,29 +1161,6 @@ pakfire_xfer_error_code_t pakfire_xfer_done(struct pakfire_xfer* xfer, int code) curl_off_t upload_size = 0; curl_off_t upload_speed = 0; - // Fetch the private pointer to this xfer - r = curl_easy_getinfo(h, CURLINFO_PRIVATE, &private); - if (r) { - CTX_ERROR(xfer->ctx, - "Could not fetch the private pointer: %s\n", curl_easy_strerror(r)); - goto ERROR; - } - - // Check if the private pointer was set - if (!private) { - CTX_ERROR(xfer->ctx, "Private pointer not set\n"); - r = -EINVAL; - goto ERROR; - } - - // Reset the private pointer - r = curl_easy_setopt(h, CURLOPT_PRIVATE, NULL); - if (r) { - CTX_ERROR(xfer->ctx, - "Could not reset the private pointer: %s\n", curl_easy_strerror(r)); - goto ERROR; - } - // Finish progress r = pakfire_progress_finish(xfer->progress); if (r) @@ -1328,8 +1302,6 @@ ERROR: // Remove the handle if (xfer->client) pakfire_httpclient_remove_xfer(xfer->client, xfer); - if (private) - pakfire_xfer_unref(private); return r; }