Occasionally you end up in a situation where you want your application to
control with more precision exactly what socket libcurl uses 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.
By setting the CURLOPT_OPENSOCKETFUNCTION
callback, you can provide a custom
function to return a file descriptor for libcurl to use:
curl_easy_setopt(handle, CURLOPT_OPENSOCKETFUNCTION, opensocket_callback);
The opensocket_callback
function must match this prototype:
curl_socket_t opensocket_callback(void *clientp,
curlsocktype purpose,
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
, 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
causes an unrecoverable error within libcurl and it returns
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:
struct curl_sockaddr {
int family;
int socktype;
int protocol;
unsigned int addrlen;
struct sockaddr addr;
};
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:
curl_easy_setopt(handle, CURLOPT_CLOSESOCKETFUNCTION,
closesocket_callback);
The closesocket_callback
function must match this prototype:
int closesocket_callback(void *clientp, curl_socket_t item);