multi: add notifications API

Add infrastructure to colled and dispatch notifications for transfers
and the multi handle in general. Applications can register a callback
and en-/disable notification type the are interested in.

Without a callback installed, notifications are not collected. Same when
a notification type has not been enabled.

Memory allocation failures on adding notifications lead to a general
multi failure state and result in CURLM_OUT_OF_MEMORY returned from
curl_multi_perform() and curl_multi_socket*() invocations.

Closes #18432
This commit is contained in:
Stefan Eissing 2025-09-01 11:58:16 +02:00 committed by Daniel Stenberg
parent f4e83a0adc
commit 357808f4ad
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
24 changed files with 767 additions and 44 deletions

View file

@ -398,6 +398,12 @@ typedef enum {
/* network has changed, adjust caches/connection reuse */
CURLOPT(CURLMOPT_NETWORK_CHANGED, CURLOPTTYPE_LONG, 17),
/* This is the notify callback function pointer */
CURLOPT(CURLMOPT_NOTIFYFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 18),
/* This is the argument passed to the notify callback */
CURLOPT(CURLMOPT_NOTIFYDATA, CURLOPTTYPE_OBJECTPOINT, 19),
CURLMOPT_LASTENTRY /* the last unused */
} CURLMoption;
@ -520,6 +526,27 @@ CURL_EXTERN CURLMcode curl_multi_waitfds(CURLM *multi,
unsigned int size,
unsigned int *fd_count);
/*
* Notifications dispatched by a multi handle, when enabled.
*/
#define CURLM_NTFY_INFO_READ 0
#define CURLM_NTFY_EASY_DONE 1
/*
* Callback to install via CURLMOPT_NOTIFYFUNCTION.
*/
typedef void (*curl_notify_callback)(CURLM *multi,
unsigned int notification,
CURL *easy,
void *user_data);
CURL_EXTERN CURLMcode curl_multi_notify_disable(CURLM *multi,
unsigned int notification);
CURL_EXTERN CURLMcode curl_multi_notify_enable(CURLM *multi,
unsigned int notification);
#ifdef __cplusplus
} /* end of extern "C" */
#endif

View file

@ -208,6 +208,9 @@
if(curlcheck_charpp_option(option)) \
if(!curlcheck_ptrptr(value, char)) \
Wcurl_multi_setopt_err_charpp(); \
if((option) == CURLMOPT_NOTIFYFUNCTION) \
if(!curlcheck_multintfy_cb(value)) \
Wcurl_multi_setopt_err_ntfycb(); \
if((option) == CURLMOPT_PUSHFUNCTION) \
if(!curlcheck_multipush_cb(value)) \
Wcurl_multi_setopt_err_pushcb(); \
@ -224,7 +227,8 @@
/* evaluates to true if the option takes a data argument to pass to a
callback */
#define curlcheck_multicb_data_option(option) \
((option) == CURLMOPT_PUSHDATA || \
((option) == CURLMOPT_NOTIFYDATA || \
(option) == CURLMOPT_PUSHDATA || \
(option) == CURLMOPT_SOCKETDATA || \
(option) == CURLMOPT_TIMERDATA || \
0)
@ -250,6 +254,11 @@
(curlcheck_NULL(expr) || \
curlcheck_cb_compatible((expr), curl_push_callback))
/* evaluates to true if expr is of type curl_push_callback */
#define curlcheck_multintfy_cb(expr) \
(curlcheck_NULL(expr) || \
curlcheck_cb_compatible((expr), curl_notify_callback))
/*
* For now, just make sure that the functions are called with three arguments
*/
@ -275,6 +284,8 @@ CURLWARNING(Wcurl_multi_setopt_err_charpp,
"curl_multi_setopt expects a 'char **' argument")
CURLWARNING(Wcurl_multi_setopt_err_pushcb,
"curl_multi_setopt expects a curl_push_callback argument")
CURLWARNING(Wcurl_multi_setopt_err_ntfycb,
"curl_multi_setopt expects a curl_notify_callback argument")
CURLWARNING(Wcurl_multi_setopt_err_socketcb,
"curl_multi_setopt expects a curl_socket_callback argument")
CURLWARNING(Wcurl_multi_setopt_err_timercb,