ARES_SET_SOCKET_FUNCTIONS(3)
πΈ NAME πΈ
ares_set_socket_functions, ares_set_socket_functions_ex β set socket io callbacks π
okay bestie, this one's from the Library Functions Manual and it's giving "build your own entire network transport layer" main character energy. buckle up π
β¨ SYNOPSIS β¨
#include <ares.h>
typedef enum {
ARES_SOCKFUNC_FLAG_NONBLOCKING = 1 << 0
} ares_sockfunc_flags_t;
typedef enum {
ARES_SOCKET_OPT_SENDBUF_SIZE,
ARES_SOCKET_OPT_RECVBUF_SIZE,
ARES_SOCKET_OPT_BIND_DEVICE,
ARES_SOCKET_OPT_TCP_FASTOPEN
} ares_socket_opt_t;
typedef enum {
ARES_SOCKET_CONN_TCP_FASTOPEN = 1 << 0
} ares_socket_connect_flags_t;
typedef enum {
ARES_SOCKET_BIND_TCP = 1 << 0,
ARES_SOCKET_BIND_CLIENT = 1 << 1
} ares_socket_bind_flags_t;
struct ares_socket_functions_ex {
unsigned int version; /* ABI Version: must be "1" */
unsigned int flags;
ares_socket_t (*asocket)(int domain, int type, int protocol, void *user_data);
int (*aclose)(ares_socket_t sock, void *user_data);
int (*asetsockopt)(ares_socket_t sock, ares_socket_opt_t opt, const void *val,
ares_socklen_t val_size, void *user_data);
int (*aconnect)(ares_socket_t sock, const struct sockaddr *address,
ares_socklen_t address_len, unsigned int flags,
void *user_data);
ares_ssize_t (*arecvfrom)(ares_socket_t sock, void *buffer, size_t length,
int flags, struct sockaddr *address,
ares_socklen_t *address_len, void *user_data);
ares_ssize_t (*asendto)(ares_socket_t sock, const void *buffer, size_t length,
int flags, const struct sockaddr *address,
ares_socklen_t address_len, void *user_data);
int (*agetsockname)(ares_socket_t sock, struct sockaddr *address,
ares_socklen_t *address_len, void *user_data);
int (*abind)(ares_socket_t sock, unsigned int flags,
const struct sockaddr *address, socklen_t address_len,
void *user_data);
unsigned int (*aif_nametoindex)(const char *ifname, void *user_data);
const char *(*aif_indextoname)(unsigned int ifindex, char *ifname_buf,
size_t ifname_buf_len, void *user_data);
};
ares_status_t ares_set_socket_functions_ex(ares_channel_t *channel,
const struct ares_socket_functions_ex *funcs, void *user_data);
struct ares_socket_functions {
ares_socket_t (*asocket)(int, int, int, void *);
int (*aclose)(ares_socket_t, void *);
int (*aconnect)(ares_socket_t, const struct sockaddr *, ares_socklen_t, void *);
ares_ssize_t (*arecvfrom)(ares_socket_t, void *, size_t, int,
struct sockaddr *, ares_socklen_t *, void *);
ares_ssize_t (*asendv)(ares_socket_t, const struct iovec *, int, void *);
};
void ares_set_socket_functions(ares_channel_t *channel,
const struct ares_socket_functions * functions,
void *user_data);
π¦ DESCRIPTION π¦
ares_set_socket_functions_ex(3) sets a whole little set of callback functions in the given ares channel handle. β¨
π© Cannot be used whenARES_OPT_EVENT_THREADis passed toares_init_options(3). like, that's a hard no bestie.
This function replaces the now deprecated ares_set_socket_functions(3) call. so yeah, the old one is giving β¨retiredβ¨.
These callback functions will be invoked to create/destroy socket objects and perform io, instead of the normal system calls. A client application can override normal network operation fully through this functionality, and provide its own transport layer. literally you can take the wheel on the entire thing ππ¨
Some callbacks may be optional and are documented as such below, but failing to implement such callbacks will disable certain features within c-ares. It is strongly recommended to implement all callbacks. fr fr, do all of them β half-implementing is not the vibe π
All callback functions are expected to operate like their system equivalents, and to set errno(2) or WSASetLastError(2) to an appropriate error code on failure. It is strongly recommended that io callbacks are implemented to be asynchronous and indicated as such in the flags member. The io callbacks can return error codes of EAGAIN, EWOULDBLOCK, or WSAEWOULDBLOCK when they would otherwise block. π
The user_data value is provided to each callback function invocation to serve as context. your little bag of holding π
The ares_set_socket_functions_ex(3) must provide the following structure members and callbacks (which are different from the ares_set_socket_functions(3) members and callbacks):
unsigned int versionβ ABI Version of structure. Must be set to a value of"1". no cap, exactly"1".unsigned int flagsβ Flags available are specified inares_sockfunc_flags_t.ares_socket_t (*asocket)(int domain, int type, int protocol, void * user_data)β REQUIRED. Creates an endpoint for communication and returns a descriptor.domain,type, andprotocoleach correspond to the parameters ofsocket(2). Returns a handle to the newly created socket, orARES_SOCKET_BADon error. πint (*aclose)(ares_socket_t fd, void * user_data)β REQUIRED. Closes the socket endpoint indicated byfd. Seeclose(2).int (*asetsockopt)(ares_socket_t fd, ares_socket_opt_t opt, const void * val, ares_socklen_t val_size, void * user_data)β REQUIRED. Set socket option. This shares a similar syntax to the BSDsetsockopt(2)call, however c-ares uses different options for portability. The value is a pointer to the desired value, and each option has its own data type listed in the options below defined inares_socket_opt_t.int (*aconnect)(ares_socket_t fd, const struct sockaddr * addr, ares_socklen_t addr_len, unsigned int flags, void * user_data)β REQUIRED. Initiate a connection to the address indicated byaddron a socket. Additional flags controlling behavior are inares_socket_connect_flags_t. Seeconnect(2).ares_ssize_t (*arecvfrom)(ares_socket_t fd, void * buffer, size_t buf_size, int flags, struct sockaddr * addr, ares_socklen_t * addr_len, void * user_data)β REQUIRED. Receives data from remote socket endpoint, if available. If theaddrparameter is notNULLand the connection protocol provides the source address, the callback should fill this in. Theflagsparameter is currently unused. Seerecvfrom(2).
For UDP, the callback must fill in the full source address, including the source port, exactly as recvfrom(2) does. c-ares discards a datagram whose source address does not match the server it queried, or whose source port does not match that server's port.
π¨ Security: for compatibility with older callbacks, a reported source port of 0 is treated as unknown and only the address is checked. A callback that does not fill in the source port is therefore insecure: c-ares will accept answers sent from any port on the server's address, for example from another DNS server or any other service or user able to send UDP from that host, and those answers are cached and returned to the application. Such an implementation is non-compliant and should be fixed to report the real source port. like, please fix it bestie ππ
ares_ssize_t (*asendto)(ares_socket_t fd, const void * buffer, size_t length, int flags, const struct sockaddr * address, ares_socklen_t address_len, void * user_data)β REQUIRED. Send data, as provided by thebuffer, to the socket endpoint. Theflagsmember may be used on systems that haveMSG_NOSIGNALdefined but is otherwise unused. Anaddressis provided primarily to support TCP FastOpen scenarios, which will beNULLin other circumstances. Seesendto(2).int (*agetsockname)(ares_socket_t fd, struct sockaddr * address, ares_socklen_t * address_len, void * user_data)β Optional. Retrieve the local address of a socket and store it into the providedaddressbuffer. May impact DNS Cookies if not provided. Seegetsockname(2). πͺint (*abind)(ares_socket_t fd, unsigned int flags, const struct sockaddr * address, ares_socklen_t address_len, void * user_data)β Optional. Bind the socket to an address. This can be used for client connections to bind the source address for packets before connect, or for server connections to bind to an address and port before listening. Currently c-ares only supports client connections.flagsfromares_socket_bind_flags_tcan be specified. Seebind(2).unsigned int (*aif_nametoindex)(const char * ifname, void * user_data)β Optional. Convert an interface name into the interface index. If this callback is not specified, then IPv6 Link-Local DNS servers cannot be used. Seeif_nametoindex(2).const char * (*aif_indextoname)(unsigned int ifindex, char * ifname_buf, size_t ifname_buf_len, void * user_data)β Optional. Convert an interface index into the interface name. If this callback is not specified, then IPv6 Link-Local DNS servers cannot be used.ifname_bufmust be at leastIF_NAMESIZEorIFNAMSIZin size. Seeif_indextoname(2).
β ares_sockfunc_flags_t values β
ARES_SOCKFUNC_FLAG_NONBLOCKINGβ Used to indicate the implementation of the io functions are asynchronous. π§
π ares_socket_opt_t values π
ARES_SOCKET_OPT_SENDBUF_SIZEβ Set the Send Buffer size. Value is a pointer to anint. (SO_SNDBUF).ARES_SOCKET_OPT_RECVBUF_SIZEβ Set the Receive Buffer size. Value is a pointer to anint. (SO_RCVBUF).ARES_SOCKET_OPT_BIND_DEVICEβ Set the network interface to use as the source for communication. Value is a C string. (SO_BINDTODEVICE)ARES_SOCKET_OPT_TCP_FASTOPENβ Enable TCP Fast Open. Value is a pointer to anares_bool_t. On some systems this could be a no-op if it is known it is on by default and return success. Other systems may be a no-op if known the system does not support the feature and returns failure witherrnoset toENOSYSorWSASetLastError(WSAEOPNOTSUPP);. π₯
π ares_socket_connect_flags_t values π
ARES_SOCKET_CONN_TCP_FASTOPENβ Connect using TCP Fast Open. zoom zoom β‘
π ares_socket_bind_flags_t values π
ARES_SOCKET_BIND_TCPβ Bind is for a TCP connection.
okay we're literally not done yet β the list keeps going and part 2 has the rest π
ARES_SOCKET_BIND_CLIENTβ this one means bind is for a client connection, not a server one π like, don't get it twisted bestie.
the actual deets on the callback set π
Okay so ares_set_socket_functions(3) sets a whole little squad of callback functions into the ares channel handle you hand it. π«Ά But heads up: you cannot use it when ARES_OPT_EVENT_THREAD is passed to ares_init_options(3) β that combo is a no β¨.
Also, real talk: this function is deprecated as of c-ares 1.34.0 in favor of ares_set_socket_functions_ex(3). So it still works, it's just giving legacy era energy π.
Here's the cute part: ares_set_socket_functions(3) lets you implement only some of the socket functions and just pass NULL for the rest β and c-ares will quietly use its own built-in system functions for those. Literally pick and choose, iykyk β¨.
All the callback functions are expected to behave exactly like their system equivalents, and to set errno(2) (or WSASetLastError(2)) to an appropriate error code when they fail. And it is strongly recommended that all your io functions behave asynchronously and return error codes of EAGAIN, EWOULDBLOCK, or WSAEWOULDBLOCK when they would otherwise block β otherwise your whole vibe is ruined π.
The user_data value gets passed into every single callback invocation so you've got context to work with. π
And ares_set_socket_functions(3) must provide the following callbacks (and yes, these are different from the ares_set_socket_functions_ex(3) callbacks β don't mix them up):
ares_socket_t (*asocket)(int domain, int type, int protocol, void * user_data)β creates an endpoint for communication and returns a descriptor.domain,type, andprotocoleach correspond to the parameters ofsocket(2). Returns a handle to the newly created socket, orARES_SOCKET_BADon error. π¦int (*aclose)(ares_socket_t fd, void * user_data)β closes the socket endpoint indicated byfd. Seeclose(2). bye felicia πint (*aconnect)(ares_socket_t fd, const struct sockaddr * addr, ares_socklen_t addr_len, void * user_data)β initiates a connection to the address indicated byaddron a socket. Seeconnect(2). π€ares_ssize_t (*arecvfrom)(ares_socket_t fd, void * buffer, size_t buf_size, int flags, struct sockaddr * addr, ares_socklen_t * addr_len, void * user_data)β receives data from the remote socket endpoint, if it's available. If theaddrparameter is notNULLand the connection protocol provides the source address, the callback should fill this in. Seerecvfrom(2). π₯
For UDP, the callback must fill in the full source address, including the source port, as described above for arecvfrom in ares_set_socket_functions_ex.
β οΈ Security moment, pay attention bestie: a callback that does not fill in the source port is insecure, and c-ares will accept answers sent from any port on the server's address. that's giving open door energy ππ
ares_ssize_t (*asendv)(ares_socket_t fd, const struct iovec * data, int len, void * user_data)β sends data, as provided by theiovecarraydata, to the socket endpoint. Seewritev(2). π€
struct lifetime, aka the part where you can't be sloppy π
The ares_set_socket_functions(3) struct you provide is not copied β it's directly referenced β so it must remain valid throughout the channel's lifetime and the lifetime of any socket created. Like, it has to stay alive the whole time, no cap. π«Ά
However! The ares_set_socket_functions_ex(3) struct is duplicated and does not need to survive past the call to the function. slay for that one β¨
when your callbacks get called (read this, fr fr) π₯
These callback functions are invoked while c-ares is part-way through creating, connecting, writing to, reading from, or closing a socket. So they must only perform the requested socket operation, and must not call any c-ares function on the same channel π€.
For example, they must not enqueue or cancel queries, process socket events, change the server configuration, or destroy the channel. Doing any of that is not supported. periodt π
Work of that kind belongs in a query callback, the server state callback set by ares_set_server_state_callback(3), or the socket state callback (ARES_OPT_SOCK_STATE_CB) described in ares_init_options(3).
Functions may be called on a different channel, though β that door stays open bestie πͺβ¨
π AVAILABILITY
ares_socket_functions added in c-ares 1.13.0, ares_socket_functions_ex added in c-ares 1.34.0 β
π SEE ALSO
ares_init_options(3), socket(2), close(2), connect(2), recvfrom(2), sendto(2), bind(2), getsockname(2), setsockopt(2), writev(2) π¦
and that's the whole page, bestie!! π this iconic lil manual page is dated 8 Oct 2024, and it's the ARES_SET_S...T_FUNCTIONS(3) page from the Library Functions Manual β go forth and implement your sockets responsibly πβ¨πΈ
π¦ where this page comes from
- alpine 3.22: c-ares-doc 1.34.9-r0 Β· MIT
- alpine 3.23: c-ares-doc 1.34.9-r0 Β· MIT
- alpine 3.24: c-ares-doc 1.34.9-r0 Β· MIT
- arch rolling: c-ares 1.34.9-1 Β· MIT
- centos-stream 10: c-ares-devel 1.34.9-1.el10 Β· MIT
- nixos 26.05: c-ares 1.34.9
- π the page's license: MIT
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms