uclient: defer read notifications to uloop timer
authorFelix Fietkau <nbd@nbd.name>
Fri, 29 Mar 2024 12:32:35 +0000 (13:32 +0100)
committerFelix Fietkau <nbd@nbd.name>
Fri, 29 Mar 2024 14:09:36 +0000 (15:09 +0100)
This gets rid of potentially harmful recursion when polling from within the
read callback

Signed-off-by: Felix Fietkau <nbd@nbd.name>
uclient-backend.h
uclient-http.c
uclient.c
uclient.h

index c2b9fd538189e2c4a96240bb7bae159031abd3eb..b013cde0b05dd04c4ffaa97a26ef430191ab1bd0 100644 (file)
@@ -41,5 +41,9 @@ void uclient_backend_set_eof(struct uclient *cl);
 void uclient_backend_reset_state(struct uclient *cl);
 struct uclient_url *uclient_get_url(const char *url_str, const char *auth_str);
 struct uclient_url *uclient_get_url_location(struct uclient_url *url, const char *location);
+static inline void uclient_backend_read_notify(struct uclient *cl)
+{
+       uloop_timeout_set(&cl->read_notify, 1);
+}
 
 #endif
index 935d50f413c03883bb3c3c923e850624b23913f2..83c268f239137423741eeac8704eba64a3d2c36c 100644 (file)
@@ -780,9 +780,7 @@ static void __uclient_notify_read(struct uclient_http *uh)
        if (uh->state == HTTP_STATE_RECV_DATA) {
                /* Now it's uclient user turn to read some data */
                uloop_timeout_cancel(&uc->connection_timeout);
-
-               if (uc->cb->data_read)
-                       uc->cb->data_read(uc);
+               uclient_backend_read_notify(uc);
        }
 }
 
index 4214c62cf6a9b2e3e2502b8bdd0123ed153b2614..a309de8595f2ac168c2056d249805fe1eff7c11f 100644 (file)
--- a/uclient.c
+++ b/uclient.c
@@ -239,6 +239,14 @@ static void uclient_connection_timeout(struct uloop_timeout *timeout)
        uclient_backend_set_error(cl, UCLIENT_ERROR_TIMEDOUT);
 }
 
+static void __uclient_read_notify(struct uloop_timeout *timeout)
+{
+       struct uclient *cl = container_of(timeout, struct uclient, read_notify);
+
+       if (cl->cb->data_read)
+               cl->cb->data_read(cl);
+}
+
 struct uclient *uclient_new(const char *url_str, const char *auth_str, const struct uclient_cb *cb)
 {
        struct uclient *cl;
@@ -257,6 +265,7 @@ struct uclient *uclient_new(const char *url_str, const char *auth_str, const str
        cl->url = url;
        cl->timeout_msecs = UCLIENT_DEFAULT_TIMEOUT_MS;
        cl->connection_timeout.cb = uclient_connection_timeout;
+       cl->read_notify.cb = __uclient_read_notify;
 
        return cl;
 }
@@ -401,6 +410,7 @@ void uclient_disconnect(struct uclient *cl)
 {
        uloop_timeout_cancel(&cl->connection_timeout);
        uloop_timeout_cancel(&cl->timeout);
+       uloop_timeout_cancel(&cl->read_notify);
 
        if (!cl->backend->disconnect)
                return;
@@ -450,6 +460,7 @@ void __hidden uclient_backend_reset_state(struct uclient *cl)
        cl->eof = false;
        cl->error_code = 0;
        uloop_timeout_cancel(&cl->timeout);
+       uloop_timeout_cancel(&cl->read_notify);
 }
 
 const char * uclient_strerror(unsigned err)
index ffe159a3375f083272225796015eee70dcfec462..29563b35d215bd297962bdfca3e0dd22cf2f219e 100644 (file)
--- a/uclient.h
+++ b/uclient.h
@@ -75,6 +75,7 @@ struct uclient {
        struct blob_attr *meta;
 
        struct uloop_timeout connection_timeout;
+       struct uloop_timeout read_notify;
        struct uloop_timeout timeout;
 };