summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Fietkau2024-03-29 12:32:35 +0000
committerFelix Fietkau2024-03-29 14:09:36 +0000
commitb6e5548a3ecc562db4c8d5356bdfd9a3fa5e59f8 (patch)
tree1703d45e358ddbfd10696bc0526ed2e6412310ea
parent488f1d52cfd2fcca8e0f3785311c247d13cb0170 (diff)
downloaduclient-b6e5548a3ecc562db4c8d5356bdfd9a3fa5e59f8.tar.gz
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 <nbd@nbd.name>
-rw-r--r--uclient-backend.h4
-rw-r--r--uclient-http.c4
-rw-r--r--uclient.c11
-rw-r--r--uclient.h1
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;
};