CURLMOPT_TIMERFUNCTION(3)

πŸ’… CURLMOPT_TIMERFUNCTION(3) β€” like, the callback that gets your timeout values

okay bestie, so this is a page from the Library Functions Manual β€” CURLMOPT_TIMERFUNCTION(3), and it's genuinely one of those "wait, this is actually so important" ones. let's get into it ✨


🌸 NAME

CURLMOPT_TIMERFUNCTION β€” the callback that receives timeout values πŸŽ€


✨ SYNOPSIS

#include <curl/curl.h>

int timer_callback(CURLM *multi,    /* multi handle */
                   long timeout_ms, /* timeout in number of ms */
                   void *clientp);  /* private callback pointer */

CURLMcode curl_multi_setopt(CURLM *handle, CURLMOPT_TIMERFUNCTION, timer_callback);

πŸ’– DESCRIPTION

So you pass in a pointer to your callback function, and it's gotta match the prototype up there β€” no cap, that's the whole vibe check. 🫢

Here's the thing: certain features (think timeouts and retries) literally require you to call libcurl even when there's zero activity on the file descriptors. Like, nothing's happening on your fds but libcurl still needs a nudge. iconic behavior honestly.

Your timer_callback function should install a single non-repeating timer with an expire time of timeout_ms milliseconds. Then, when that timer fires, you call either curl_multi_socket_action(3) or curl_multi_perform(3), depending on which interface you're using. pick your fighter πŸ’€

If this callback gets called while a timer is already running, the new expire time replaces the former timeout. So your app should effectively cancel the old timeout and set a new one using this new expire time. out with the old, in with the new, periodt.

Now, a timeout_ms value of -1 passed to this callback means you should delete the timer. every other value is a valid expire time in number of milliseconds β€” including zero milliseconds (yes zero is real and valid, don't come for me).

The timer_callback is called when the timeout expire time is changed. that's the whole trigger, bestie.

The clientp pointer is set with CURLMOPT_TIMERDATA(3). that's where your private little data goblin lives 🧚

The timer callback should return 0 on success, and -1 on error. and hmm, if this callback returns error? all transfers currently in progress in this multi handle are aborted and made to fail. 😭 like, all of them. so maybe don't return -1 casually, iykyk.

Also, just so you know: this callback can be used instead of, or in addition to, curl_multi_timeout(3). both. at the same time. flexible queen behavior πŸ‘‘

WARNING βš οΈπŸ’€ do not call libcurl directly from within the callback itself when the timeout_ms value is zero, since it risks triggering an unpleasant recursive behavior that immediately calls another call to the callback with a zero timeout... and then again... and again... it's giving infinite loop nightmare fuel, so fr fr, don't.

πŸŽ€ DEFAULT

NULL


🌈 PROTOCOLS

This functionality affects all supported protocols ⭐


πŸ¦‹ EXAMPLE

struct priv {
  void *custom;
};

static int timerfunc(CURLM *multi, long timeout_ms, void *clientp)
{
  struct priv *mydata = clientp;
  printf("our ptr: %p\n", mydata->custom);

  if(timeout_ms >= 0) {
    /* this is the new single timeout to wait for, including zero */
  }
  else {
    /* delete the timeout, nothing to wait for now */
  }
  return 0;
}

int main(void)
{
  struct priv mydata;
  CURLM *multi = curl_multi_init();
  curl_multi_setopt(multi, CURLMOPT_TIMERFUNCTION, timerfunc);
  curl_multi_setopt(multi, CURLMOPT_TIMERDATA, &mydata);
}

look at that little duo β€” CURLMOPT_TIMERFUNCTION and CURLMOPT_TIMERDATA setting each other up. soulmate behavior. πŸ’œ


πŸ’« AVAILABILITY

Added in curl 7.16.0 β€” so it's been around a minute, she's a veteran πŸŽ–οΈ


πŸ“ RETURN VALUE

curl_multi_setopt(3) returns a CURLMcode indicating success or error.

CURLM_OK (0) means everything was OK, non-zero means an error occurred β€” see libcurl-errors(3) for the whole tea. β˜•


πŸ‘‘ SEE ALSO


and that's the page, bestie!! πŸ’…βœ¨ mwah πŸ’–

~ from the libcurl girlies, version dated 2026-10-12, page CURLMOPT_TIMERFUNCTION(3) β€” slay and stay coding πŸ«ΆπŸŽ€

πŸ“¦ where this page comes from