CURLOPT_CLOSESOCKETFUNCTION(3)

πŸ’… CURLOPT_CLOSESOCKETFUNCTION β€” bestie, it's the socket-close replacement callback

Okay so real talk, this page lives in the libcurl manual (that's the manual name, bestie, we're in the library functions section, mwah) ✨ and it's all about CURLOPT_CLOSESOCKETFUNCTION, aka the callback to socket close replacement. Iconic behaviour. Let's get into it πŸŽ€


✨ SYNOPSIS ✨

#include <curl/curl.h>

int closesocket_callback(void *clientp, curl_socket_t item);

CURLcode curl_easy_setopt(CURL *handle, CURLOPT_CLOSESOCKETFUNCTION,
                          closesocket_callback);

πŸ¦‹ DESCRIPTION πŸ¦‹

So you pass in a pointer to your callback function, and it has to match the prototype up there ⬆️ β€” like, exactly, no freestyling.

Here's the vibe: libcurl calls your function instead of the close(3) or closesocket(3) call whenever sockets get closed. And heads up β€” that's sockets only, not any other file descriptors, okay? It's pretty much the reverse twin of CURLOPT_OPENSOCKETFUNCTION(3). Return 0 to signal success, and return 1 if there was an error. That's the whole contract πŸ’–

The clientp pointer? That's set with CURLOPT_CLOSESOCKETDATA(3). And item is the socket that libcurl wants to be closed. Simple as that.

🫢 Okay this part matters, don't scroll past: when you're using multi/share handles, your callback may get invoked even after the easy handle has been cleaned up. The callback and data get inherited by a new connection, and that connection may live longer than the transfer itself in the multi/share handle's connection cache. So like... don't be shocked, it's documented behaviour, not a haunting πŸ‘»

🌸 DEFAULT 🌸

It just uses the standard socket close function. Classic. No notes.


🌈 PROTOCOLS 🌈

This functionality affects all supported protocols. All of them. Every single one. we love an inclusive queen πŸ‘‘


⭐ EXAMPLE ⭐

struct priv {
  void *custom;
};

static int closesocket(void *clientp, curl_socket_t item)
{
  struct priv *my = clientp;
  printf("our ptr: %p\n", my->custom);

  printf("libcurl wants to close %d now\n", (int)item);
  return 0;
}

int main(void)
{
  struct priv myown;
  CURL *curl = curl_easy_init();

  /* call this function to close sockets */
  curl_easy_setopt(curl, CURLOPT_CLOSESOCKETFUNCTION, closesocket);
  curl_easy_setopt(curl, CURLOPT_CLOSESOCKETDATA, &myown);

  curl_easy_perform(curl);
  curl_easy_cleanup(curl);
}

See how closesocket gets wired up with CURLOPT_CLOSESOCKETFUNCTION and the data goes in through CURLOPT_CLOSESOCKETDATA? Chef's kiss. It ate πŸ”₯


🧚 AVAILABILITY 🧚

Added in curl 7.21.7. So she's been around a minute πŸ’œ


πŸ’€ RETURN VALUE πŸ’€

curl_easy_setopt(3) returns a CURLcode indicating success or error.

CURLE_OK (0) means everything was OK β€” slay. Non-zero means an error occurred, so go check libcurl-errors(3) for the tea.


πŸ‘‘ SEE ALSO πŸ‘‘


That's the whole page, bestie, no crumbs left πŸ“ This was libcurl, dated 2026-10-12, brought to you by the CURLOPT_CL...KETFUNCTION(3) girlies β€” go close some sockets responsibly, ily, bye! πŸ’–βœ¨πŸŽ€

πŸ“¦ where this page comes from