]> git.ipfire.org Git - pakfire.git/commitdiff
httpclient: Explicitely keep a reference to any xfers
authorMichael Tremer <michael.tremer@ipfire.org>
Sat, 19 Oct 2024 09:00:44 +0000 (09:00 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sat, 19 Oct 2024 09:00:44 +0000 (09:00 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/httpclient.c
src/libpakfire/xfer.c

index d01a39a801d256f17bf90937a438c73234f44d46..c272c3b611235df48284b016e5633a823ffcd2a9 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <errno.h>
 #include <stdlib.h>
+#include <sys/queue.h>
 
 #include <curl/curl.h>
 
 // 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) {
index 39a3690797db3296c51e85b2713e112467b38a98..5cf8e54f4a09a0c17cded85dee2d84f6cd3c68b6 100644 (file)
@@ -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;
 }