Opensocket and closesocket callbacks

Occasionally you end up in a situation where you want your application to
control with more precision exactly what socket libcurl will use for its
operations. libcurl offers this pair of callbacks that replaces libcurl’s own
call to socket() and the subsequent close() of the same file descriptor.

Provide a file descriptor

By setting the CURLOPT_OPENSOCKETFUNCTION callback, you can provide a custom
function to return a file descriptor for libcurl to use:

  1. curl_easy_setopt(handle, CURLOPT_OPENSOCKETFUNCTION, opensocket_callback);

The opensocket_callback function must match this prototype:

  1. curl_socket_t opensocket_callback(void *clientp,
  2. curlsocktype purpose,
  3. struct curl_sockaddr *address);

The callback gets the clientp as first argument, which is simply an opaque
pointer you set with CURLOPT_OPENSOCKETDATA.

The other two arguments pass in data that identifies for what purpose and
address the socket is to be used. The purpose is a typedef with a value of
CURLSOCKTYPE_IPCXN or CURLSOCKTYPE_ACCEPT, basically identifying in which
circumstance the socket is created. The “accept” case being when libcurl is
used to accept an incoming FTP connection for when FTP active mode is used,
and all other cases when libcurl creates a socket for its own outgoing
connections the IPCXN value is passed in.

The address pointer points to a struct curl_sockaddr that describes the IP
address of the network destination for which this socket is created. Your
callback can for example use this information to whitelist or blacklist
specific addresses or address ranges.

The socketopen callback is also explicitly allowed to modify the target
address in that struct, if you would like to offer some sort of network filter
or translation layer.

The callback should return a file descriptor or CURL_SOCKET_BAD, which then
will cause an unrecoverable error within libcurl and it will eventually return
CURLE_COULDNT_CONNECT from its perform function.

If you want to return a file descriptor that is already connected to a
server, then you must also set the sockopt callback and
make sure that returns the correct return value.

The curl_sockaddress struct looks like this:

  1. struct curl_sockaddr {
  2. int family;
  3. int socktype;
  4. int protocol;
  5. unsigned int addrlen;
  6. struct sockaddr addr;
  7. };

Socket close callback

The corresponding callback to the open socket is of course the close
socket. Usually when you provide a custom way to provide a file descriptor you
want to provide your own cleanup version as well:

  1. curl_easy_setopt(handle, CURLOPT_CLOSEOCKETFUNCTION, closesocket_callback);

The closesocket_callback function must match this prototype:

  1. int closesocket_callback(void *clientp, curl_socket_t item);