From b6e5548a3ecc562db4c8d5356bdfd9a3fa5e59f8 Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Fri, 29 Mar 2024 13:32:35 +0100 Subject: [PATCH] uclient: defer read notifications to uloop timer This gets rid of potentially harmful recursion when polling from within the read callback Signed-off-by: Felix Fietkau --- uclient-backend.h | 4 ++++ uclient-http.c | 4 +--- uclient.c | 11 +++++++++++ uclient.h | 1 + 4 files changed, 17 insertions(+), 3 deletions(-) diff --git a/uclient-backend.h b/uclient-backend.h index c2b9fd5..b013cde 100644 --- a/uclient-backend.h +++ b/uclient-backend.h @@ -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 diff --git a/uclient-http.c b/uclient-http.c index 935d50f..83c268f 100644 --- a/uclient-http.c +++ b/uclient-http.c @@ -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); } } diff --git a/uclient.c b/uclient.c index 4214c62..a309de8 100644 --- 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) diff --git a/uclient.h b/uclient.h index ffe159a..29563b3 100644 --- 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; }; -- 2.30.2