api: Add entrypoints to allow use of per-server ports
Add user-visible entrypoints ares_{get,set}_servers_ports(3), which take struct ares_addr_port_node rather than struct ares_addr_node. This structure includes a UDP and TCP port number; if this is set to zero, the channel-wide port values are used as before. Similarly, add a new ares_set_servers_ports_csv(3) entrypoint, which is analogous to ares_set_servers(3) except it doesn't ignore any specified port information; instead, any per-server specified port is used as both the UDP and TCP port for that server. The internal struct ares_addr is extended to hold the UDP/TCP ports, stored in network order, with the convention that a value of zero indicates that the channel-wide UDP/TCP port should be used. For the internal implementation of ares_dup(3), shift to use the _ports() version of the get/set functions, so port information is transferred correctly to the new channel. Update manpages, and add missing ares_set_servers_csv to the lists while we're at it
This commit is contained in:
parent
06d0f72e54
commit
7972adc5d7
|
@ -82,6 +82,7 @@ MANPAGES = ares_cancel.3 \
|
||||||
ares_free_hostent.3 \
|
ares_free_hostent.3 \
|
||||||
ares_free_string.3 \
|
ares_free_string.3 \
|
||||||
ares_get_servers.3 \
|
ares_get_servers.3 \
|
||||||
|
ares_get_servers_ports.3 \
|
||||||
ares_gethostbyaddr.3 \
|
ares_gethostbyaddr.3 \
|
||||||
ares_gethostbyname.3 \
|
ares_gethostbyname.3 \
|
||||||
ares_gethostbyname_file.3 \
|
ares_gethostbyname_file.3 \
|
||||||
|
@ -112,6 +113,8 @@ MANPAGES = ares_cancel.3 \
|
||||||
ares_set_local_ip6.3 \
|
ares_set_local_ip6.3 \
|
||||||
ares_set_servers.3 \
|
ares_set_servers.3 \
|
||||||
ares_set_servers_csv.3 \
|
ares_set_servers_csv.3 \
|
||||||
|
ares_set_servers_ports.3 \
|
||||||
|
ares_set_servers_ports_csv.3 \
|
||||||
ares_set_socket_callback.3 \
|
ares_set_socket_callback.3 \
|
||||||
ares_set_sortlist.3 \
|
ares_set_sortlist.3 \
|
||||||
ares_strerror.3 \
|
ares_strerror.3 \
|
||||||
|
@ -131,6 +134,7 @@ HTMLPAGES = ares_cancel.html \
|
||||||
ares_free_hostent.html \
|
ares_free_hostent.html \
|
||||||
ares_free_string.html \
|
ares_free_string.html \
|
||||||
ares_get_servers.html \
|
ares_get_servers.html \
|
||||||
|
ares_get_servers_ports.html \
|
||||||
ares_gethostbyaddr.html \
|
ares_gethostbyaddr.html \
|
||||||
ares_gethostbyname.html \
|
ares_gethostbyname.html \
|
||||||
ares_gethostbyname_file.html \
|
ares_gethostbyname_file.html \
|
||||||
|
@ -160,6 +164,8 @@ HTMLPAGES = ares_cancel.html \
|
||||||
ares_set_local_ip6.html \
|
ares_set_local_ip6.html \
|
||||||
ares_set_servers.html \
|
ares_set_servers.html \
|
||||||
ares_set_servers_csv.html \
|
ares_set_servers_csv.html \
|
||||||
|
ares_set_servers_ports.html \
|
||||||
|
ares_set_servers_ports_csv.html \
|
||||||
ares_set_socket_callback.html \
|
ares_set_socket_callback.html \
|
||||||
ares_set_sortlist.html \
|
ares_set_sortlist.html \
|
||||||
ares_strerror.html \
|
ares_strerror.html \
|
||||||
|
@ -179,6 +185,7 @@ PDFPAGES = ares_cancel.pdf \
|
||||||
ares_free_hostent.pdf \
|
ares_free_hostent.pdf \
|
||||||
ares_free_string.pdf \
|
ares_free_string.pdf \
|
||||||
ares_get_servers.pdf \
|
ares_get_servers.pdf \
|
||||||
|
ares_get_servers_ports.pdf \
|
||||||
ares_gethostbyaddr.pdf \
|
ares_gethostbyaddr.pdf \
|
||||||
ares_gethostbyname.pdf \
|
ares_gethostbyname.pdf \
|
||||||
ares_gethostbyname_file.pdf \
|
ares_gethostbyname_file.pdf \
|
||||||
|
@ -208,6 +215,8 @@ PDFPAGES = ares_cancel.pdf \
|
||||||
ares_set_local_ip6.pdf \
|
ares_set_local_ip6.pdf \
|
||||||
ares_set_servers.pdf \
|
ares_set_servers.pdf \
|
||||||
ares_set_servers_csv.pdf \
|
ares_set_servers_csv.pdf \
|
||||||
|
ares_set_servers_ports.pdf \
|
||||||
|
ares_set_servers_ports_csv.pdf \
|
||||||
ares_set_socket_callback.pdf \
|
ares_set_socket_callback.pdf \
|
||||||
ares_set_sortlist.pdf \
|
ares_set_sortlist.pdf \
|
||||||
ares_strerror.pdf \
|
ares_strerror.pdf \
|
||||||
|
|
18
ares.h
18
ares.h
|
@ -563,7 +563,6 @@ CARES_EXTERN void ares_free_data(void *dataptr);
|
||||||
|
|
||||||
CARES_EXTERN const char *ares_strerror(int code);
|
CARES_EXTERN const char *ares_strerror(int code);
|
||||||
|
|
||||||
/* TODO: Hold port here as well. */
|
|
||||||
struct ares_addr_node {
|
struct ares_addr_node {
|
||||||
struct ares_addr_node *next;
|
struct ares_addr_node *next;
|
||||||
int family;
|
int family;
|
||||||
|
@ -573,15 +572,32 @@ struct ares_addr_node {
|
||||||
} addr;
|
} addr;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ares_addr_port_node {
|
||||||
|
struct ares_addr_port_node *next;
|
||||||
|
int family;
|
||||||
|
union {
|
||||||
|
struct in_addr addr4;
|
||||||
|
struct ares_in6_addr addr6;
|
||||||
|
} addr;
|
||||||
|
int udp_port;
|
||||||
|
int tcp_port;
|
||||||
|
};
|
||||||
|
|
||||||
CARES_EXTERN int ares_set_servers(ares_channel channel,
|
CARES_EXTERN int ares_set_servers(ares_channel channel,
|
||||||
struct ares_addr_node *servers);
|
struct ares_addr_node *servers);
|
||||||
|
CARES_EXTERN int ares_set_servers_ports(ares_channel channel,
|
||||||
|
struct ares_addr_port_node *servers);
|
||||||
|
|
||||||
/* Incomming string format: host[:port][,host[:port]]... */
|
/* Incomming string format: host[:port][,host[:port]]... */
|
||||||
CARES_EXTERN int ares_set_servers_csv(ares_channel channel,
|
CARES_EXTERN int ares_set_servers_csv(ares_channel channel,
|
||||||
const char* servers);
|
const char* servers);
|
||||||
|
CARES_EXTERN int ares_set_servers_ports_csv(ares_channel channel,
|
||||||
|
const char* servers);
|
||||||
|
|
||||||
CARES_EXTERN int ares_get_servers(ares_channel channel,
|
CARES_EXTERN int ares_get_servers(ares_channel channel,
|
||||||
struct ares_addr_node **servers);
|
struct ares_addr_node **servers);
|
||||||
|
CARES_EXTERN int ares_get_servers_ports(ares_channel channel,
|
||||||
|
struct ares_addr_port_node **servers);
|
||||||
|
|
||||||
CARES_EXTERN const char *ares_inet_ntop(int af, const void *src, char *dst,
|
CARES_EXTERN const char *ares_inet_ntop(int af, const void *src, char *dst,
|
||||||
ares_socklen_t size);
|
ares_socklen_t size);
|
||||||
|
|
15
ares_data.c
15
ares_data.c
|
@ -92,6 +92,12 @@ void ares_free_data(void *dataptr)
|
||||||
ares_free_data(ptr->data.addr_node.next);
|
ares_free_data(ptr->data.addr_node.next);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ARES_DATATYPE_ADDR_PORT_NODE:
|
||||||
|
|
||||||
|
if (ptr->data.addr_port_node.next)
|
||||||
|
ares_free_data(ptr->data.addr_port_node.next);
|
||||||
|
break;
|
||||||
|
|
||||||
case ARES_DATATYPE_NAPTR_REPLY:
|
case ARES_DATATYPE_NAPTR_REPLY:
|
||||||
|
|
||||||
if (ptr->data.naptr_reply.next)
|
if (ptr->data.naptr_reply.next)
|
||||||
|
@ -169,6 +175,15 @@ void *ares_malloc_data(ares_datatype type)
|
||||||
sizeof(ptr->data.addr_node.addrV6));
|
sizeof(ptr->data.addr_node.addrV6));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ARES_DATATYPE_ADDR_PORT_NODE:
|
||||||
|
ptr->data.addr_port_node.next = NULL;
|
||||||
|
ptr->data.addr_port_node.family = 0;
|
||||||
|
ptr->data.addr_port_node.udp_port = 0;
|
||||||
|
ptr->data.addr_port_node.tcp_port = 0;
|
||||||
|
memset(&ptr->data.addr_port_node.addrV6, 0,
|
||||||
|
sizeof(ptr->data.addr_port_node.addrV6));
|
||||||
|
break;
|
||||||
|
|
||||||
case ARES_DATATYPE_NAPTR_REPLY:
|
case ARES_DATATYPE_NAPTR_REPLY:
|
||||||
ptr->data.naptr_reply.next = NULL;
|
ptr->data.naptr_reply.next = NULL;
|
||||||
ptr->data.naptr_reply.flags = NULL;
|
ptr->data.naptr_reply.flags = NULL;
|
||||||
|
|
|
@ -28,6 +28,7 @@ typedef enum {
|
||||||
ARES_DATATYPE_HOSTENT, /* struct hostent */
|
ARES_DATATYPE_HOSTENT, /* struct hostent */
|
||||||
ARES_DATATYPE_OPTIONS, /* struct ares_options */
|
ARES_DATATYPE_OPTIONS, /* struct ares_options */
|
||||||
#endif
|
#endif
|
||||||
|
ARES_DATATYPE_ADDR_PORT_NODE, /* struct ares_addr_port_node - introduced in 1.11.0 */
|
||||||
ARES_DATATYPE_LAST /* not used - introduced in 1.7.0 */
|
ARES_DATATYPE_LAST /* not used - introduced in 1.7.0 */
|
||||||
} ares_datatype;
|
} ares_datatype;
|
||||||
|
|
||||||
|
@ -58,6 +59,7 @@ struct ares_data {
|
||||||
struct ares_txt_reply txt_reply;
|
struct ares_txt_reply txt_reply;
|
||||||
struct ares_srv_reply srv_reply;
|
struct ares_srv_reply srv_reply;
|
||||||
struct ares_addr_node addr_node;
|
struct ares_addr_node addr_node;
|
||||||
|
struct ares_addr_port_node addr_port_node;
|
||||||
struct ares_mx_reply mx_reply;
|
struct ares_mx_reply mx_reply;
|
||||||
struct ares_naptr_reply naptr_reply;
|
struct ares_naptr_reply naptr_reply;
|
||||||
struct ares_soa_reply soa_reply;
|
struct ares_soa_reply soa_reply;
|
||||||
|
|
|
@ -16,12 +16,13 @@
|
||||||
.\"
|
.\"
|
||||||
.TH ARES_GET_SERVERS 3 "5 March 2010"
|
.TH ARES_GET_SERVERS 3 "5 March 2010"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ares_get_servers \- Retrieve name servers from an initialized ares_channel
|
ares_get_servers, ares_get_servers_ports \- Retrieve name servers from an initialized ares_channel
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.nf
|
.nf
|
||||||
.B #include <ares.h>
|
.B #include <ares.h>
|
||||||
.PP
|
.PP
|
||||||
.B int ares_get_servers(ares_channel \fIchannel\fP, struct ares_addr_node **\fIservers\fP)
|
.B int ares_get_servers(ares_channel \fIchannel\fP, struct ares_addr_node **\fIservers\fP)
|
||||||
|
.B int ares_get_servers_ports(ares_channel \fIchannel\fP, struct ares_addr_port_node **\fIservers\fP)
|
||||||
.fi
|
.fi
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
The \fBares_get_servers(3)\fP function retrieves name servers configuration
|
The \fBares_get_servers(3)\fP function retrieves name servers configuration
|
||||||
|
@ -32,8 +33,13 @@ as a linked list of ares_addr_node structs storing a pointer to the first
|
||||||
node at the address specified by
|
node at the address specified by
|
||||||
.IR servers .
|
.IR servers .
|
||||||
|
|
||||||
|
The \fBares_get_servers_ports(3)\fP function also retrieves any per-server
|
||||||
|
port information that may have been previously configured, returning a linked
|
||||||
|
list of ares_addr_port structures.
|
||||||
|
|
||||||
Function caller may traverse the returned name server linked list, or may use
|
Function caller may traverse the returned name server linked list, or may use
|
||||||
it directly as suitable input for the \fBares_set_servers(3)\fP function, but
|
it directly as suitable input for the \fBares_set_servers(3)\fP /
|
||||||
|
\fBares_set_servers_ports(3)\fP functions, but
|
||||||
shall not shrink or extend the list on its own.
|
shall not shrink or extend the list on its own.
|
||||||
|
|
||||||
Each node of the name server linked list is stored in memory dynamically
|
Each node of the name server linked list is stored in memory dynamically
|
||||||
|
@ -47,8 +53,7 @@ optmask \fBARES_OPT_SERVERS\fP functionally obsolete except for
|
||||||
IPv4-only name server usage.
|
IPv4-only name server usage.
|
||||||
|
|
||||||
.SH RETURN VALUES
|
.SH RETURN VALUES
|
||||||
.B ares_get_servers(3)
|
This function may return any of the following values:
|
||||||
may return any of the following values:
|
|
||||||
.TP 15
|
.TP 15
|
||||||
.B ARES_SUCCESS
|
.B ARES_SUCCESS
|
||||||
The name servers configuration was successfuly retrieved
|
The name servers configuration was successfuly retrieved
|
||||||
|
@ -57,7 +62,7 @@ The name servers configuration was successfuly retrieved
|
||||||
The memory was exhausted
|
The memory was exhausted
|
||||||
.TP 15
|
.TP 15
|
||||||
.B ARES_ENODATA
|
.B ARES_ENODATA
|
||||||
The channel data identified by
|
The channel data identified by
|
||||||
.IR channel
|
.IR channel
|
||||||
was invalid.
|
was invalid.
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
|
@ -65,7 +70,8 @@ was invalid.
|
||||||
.BR ares_init_options (3),
|
.BR ares_init_options (3),
|
||||||
.BR ares_save_options(3)
|
.BR ares_save_options(3)
|
||||||
.SH AVAILABILITY
|
.SH AVAILABILITY
|
||||||
ares_get_servers(3) was added in c-ares 1.7.1
|
\fBares_get_servers(3)\fP was added in c-ares 1.7.1;
|
||||||
|
\fBares_get_servers_ports(3)\fP was added in c-ares 1.11.0.
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
Implementation of this function and associated library internals are based
|
Implementation of this function and associated library internals are based
|
||||||
on code, comments and feedback provided in November and December of 2008 by
|
on code, comments and feedback provided in November and December of 2008 by
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
.so man3/ares_get_servers.3
|
36
ares_init.c
36
ares_init.c
|
@ -263,8 +263,8 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
|
||||||
int ares_dup(ares_channel *dest, ares_channel src)
|
int ares_dup(ares_channel *dest, ares_channel src)
|
||||||
{
|
{
|
||||||
struct ares_options opts;
|
struct ares_options opts;
|
||||||
struct ares_addr_node *servers;
|
struct ares_addr_port_node *servers;
|
||||||
int ipv6_nservers = 0;
|
int non_v4_default_port = 0;
|
||||||
int i, rc;
|
int i, rc;
|
||||||
int optmask;
|
int optmask;
|
||||||
|
|
||||||
|
@ -297,22 +297,24 @@ int ares_dup(ares_channel *dest, ares_channel src)
|
||||||
(*dest)->local_ip4 = src->local_ip4;
|
(*dest)->local_ip4 = src->local_ip4;
|
||||||
memcpy((*dest)->local_ip6, src->local_ip6, sizeof(src->local_ip6));
|
memcpy((*dest)->local_ip6, src->local_ip6, sizeof(src->local_ip6));
|
||||||
|
|
||||||
/* Full name server cloning required when not all are IPv4 */
|
/* Full name server cloning required if there is a non-IPv4, or non-default port, nameserver */
|
||||||
for (i = 0; i < src->nservers; i++)
|
for (i = 0; i < src->nservers; i++)
|
||||||
{
|
{
|
||||||
if (src->servers[i].addr.family != AF_INET) {
|
if ((src->servers[i].addr.family != AF_INET) ||
|
||||||
ipv6_nservers++;
|
(src->servers[i].addr.udp_port != 0) ||
|
||||||
|
(src->servers[i].addr.tcp_port != 0)) {
|
||||||
|
non_v4_default_port++;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ipv6_nservers) {
|
if (non_v4_default_port) {
|
||||||
rc = ares_get_servers(src, &servers);
|
rc = ares_get_servers_ports(src, &servers);
|
||||||
if (rc != ARES_SUCCESS) {
|
if (rc != ARES_SUCCESS) {
|
||||||
ares_destroy(*dest);
|
ares_destroy(*dest);
|
||||||
*dest = NULL;
|
*dest = NULL;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
rc = ares_set_servers(*dest, servers);
|
rc = ares_set_servers_ports(*dest, servers);
|
||||||
ares_free_data(servers);
|
ares_free_data(servers);
|
||||||
if (rc != ARES_SUCCESS) {
|
if (rc != ARES_SUCCESS) {
|
||||||
ares_destroy(*dest);
|
ares_destroy(*dest);
|
||||||
|
@ -359,11 +361,13 @@ int ares_save_options(ares_channel channel, struct ares_options *options,
|
||||||
options->sock_state_cb = channel->sock_state_cb;
|
options->sock_state_cb = channel->sock_state_cb;
|
||||||
options->sock_state_cb_data = channel->sock_state_cb_data;
|
options->sock_state_cb_data = channel->sock_state_cb_data;
|
||||||
|
|
||||||
/* Copy IPv4 servers */
|
/* Copy IPv4 servers that use the default port */
|
||||||
if (channel->nservers) {
|
if (channel->nservers) {
|
||||||
for (i = 0; i < channel->nservers; i++)
|
for (i = 0; i < channel->nservers; i++)
|
||||||
{
|
{
|
||||||
if (channel->servers[i].addr.family == AF_INET)
|
if ((channel->servers[i].addr.family == AF_INET) &&
|
||||||
|
(channel->servers[i].addr.udp_port == 0) &&
|
||||||
|
(channel->servers[i].addr.tcp_port == 0))
|
||||||
ipv4_nservers++;
|
ipv4_nservers++;
|
||||||
}
|
}
|
||||||
if (ipv4_nservers) {
|
if (ipv4_nservers) {
|
||||||
|
@ -372,7 +376,9 @@ int ares_save_options(ares_channel channel, struct ares_options *options,
|
||||||
return ARES_ENOMEM;
|
return ARES_ENOMEM;
|
||||||
for (i = j = 0; i < channel->nservers; i++)
|
for (i = j = 0; i < channel->nservers; i++)
|
||||||
{
|
{
|
||||||
if (channel->servers[i].addr.family == AF_INET)
|
if ((channel->servers[i].addr.family == AF_INET) &&
|
||||||
|
(channel->servers[i].addr.udp_port == 0) &&
|
||||||
|
(channel->servers[i].addr.tcp_port == 0))
|
||||||
memcpy(&options->servers[j++],
|
memcpy(&options->servers[j++],
|
||||||
&channel->servers[i].addr.addrV4,
|
&channel->servers[i].addr.addrV4,
|
||||||
sizeof(channel->servers[i].addr.addrV4));
|
sizeof(channel->servers[i].addr.addrV4));
|
||||||
|
@ -468,6 +474,8 @@ static int init_by_options(ares_channel channel,
|
||||||
for (i = 0; i < options->nservers; i++)
|
for (i = 0; i < options->nservers; i++)
|
||||||
{
|
{
|
||||||
channel->servers[i].addr.family = AF_INET;
|
channel->servers[i].addr.family = AF_INET;
|
||||||
|
channel->servers[i].addr.udp_port = 0;
|
||||||
|
channel->servers[i].addr.tcp_port = 0;
|
||||||
memcpy(&channel->servers[i].addr.addrV4,
|
memcpy(&channel->servers[i].addr.addrV4,
|
||||||
&options->servers[i],
|
&options->servers[i],
|
||||||
sizeof(channel->servers[i].addr.addrV4));
|
sizeof(channel->servers[i].addr.addrV4));
|
||||||
|
@ -1156,6 +1164,8 @@ static int init_by_resolv_conf(ares_channel channel)
|
||||||
{
|
{
|
||||||
servers[i].addr.addrV4.s_addr = htonl(def_nameservers[i]);
|
servers[i].addr.addrV4.s_addr = htonl(def_nameservers[i]);
|
||||||
servers[i].addr.family = AF_INET;
|
servers[i].addr.family = AF_INET;
|
||||||
|
servers[i].addr.udp_port = 0;
|
||||||
|
servers[i].addr.tcp_port = 0;
|
||||||
}
|
}
|
||||||
status = ARES_EOF;
|
status = ARES_EOF;
|
||||||
|
|
||||||
|
@ -1444,6 +1454,8 @@ static int init_by_defaults(ares_channel channel)
|
||||||
}
|
}
|
||||||
channel->servers[0].addr.family = AF_INET;
|
channel->servers[0].addr.family = AF_INET;
|
||||||
channel->servers[0].addr.addrV4.s_addr = htonl(INADDR_LOOPBACK);
|
channel->servers[0].addr.addrV4.s_addr = htonl(INADDR_LOOPBACK);
|
||||||
|
channel->servers[0].addr.udp_port = 0;
|
||||||
|
channel->servers[0].addr.tcp_port = 0;
|
||||||
channel->nservers = 1;
|
channel->nservers = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1650,6 +1662,8 @@ static int config_nameserver(struct server_state **servers, int *nservers,
|
||||||
|
|
||||||
/* Store address data. */
|
/* Store address data. */
|
||||||
newserv[*nservers].addr.family = host.family;
|
newserv[*nservers].addr.family = host.family;
|
||||||
|
newserv[*nservers].addr.udp_port = 0;
|
||||||
|
newserv[*nservers].addr.tcp_port = 0;
|
||||||
if (host.family == AF_INET)
|
if (host.family == AF_INET)
|
||||||
memcpy(&newserv[*nservers].addr.addrV4, &host.addrV4,
|
memcpy(&newserv[*nservers].addr.addrV4, &host.addrV4,
|
||||||
sizeof(host.addrV4));
|
sizeof(host.addrV4));
|
||||||
|
|
141
ares_options.c
141
ares_options.c
|
@ -83,6 +83,62 @@ int ares_get_servers(ares_channel channel,
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ares_get_servers_ports(ares_channel channel,
|
||||||
|
struct ares_addr_port_node **servers)
|
||||||
|
{
|
||||||
|
struct ares_addr_port_node *srvr_head = NULL;
|
||||||
|
struct ares_addr_port_node *srvr_last = NULL;
|
||||||
|
struct ares_addr_port_node *srvr_curr;
|
||||||
|
int status = ARES_SUCCESS;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!channel)
|
||||||
|
return ARES_ENODATA;
|
||||||
|
|
||||||
|
for (i = 0; i < channel->nservers; i++)
|
||||||
|
{
|
||||||
|
/* Allocate storage for this server node appending it to the list */
|
||||||
|
srvr_curr = ares_malloc_data(ARES_DATATYPE_ADDR_PORT_NODE);
|
||||||
|
if (!srvr_curr)
|
||||||
|
{
|
||||||
|
status = ARES_ENOMEM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (srvr_last)
|
||||||
|
{
|
||||||
|
srvr_last->next = srvr_curr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
srvr_head = srvr_curr;
|
||||||
|
}
|
||||||
|
srvr_last = srvr_curr;
|
||||||
|
|
||||||
|
/* Fill this server node data */
|
||||||
|
srvr_curr->family = channel->servers[i].addr.family;
|
||||||
|
srvr_curr->udp_port = ntohs((unsigned short)channel->servers[i].addr.udp_port);
|
||||||
|
srvr_curr->tcp_port = ntohs((unsigned short)channel->servers[i].addr.tcp_port);
|
||||||
|
if (srvr_curr->family == AF_INET)
|
||||||
|
memcpy(&srvr_curr->addrV4, &channel->servers[i].addr.addrV4,
|
||||||
|
sizeof(srvr_curr->addrV4));
|
||||||
|
else
|
||||||
|
memcpy(&srvr_curr->addrV6, &channel->servers[i].addr.addrV6,
|
||||||
|
sizeof(srvr_curr->addrV6));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (status != ARES_SUCCESS)
|
||||||
|
{
|
||||||
|
if (srvr_head)
|
||||||
|
{
|
||||||
|
ares_free_data(srvr_head);
|
||||||
|
srvr_head = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*servers = srvr_head;
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
int ares_set_servers(ares_channel channel,
|
int ares_set_servers(ares_channel channel,
|
||||||
struct ares_addr_node *servers)
|
struct ares_addr_node *servers)
|
||||||
|
@ -117,6 +173,57 @@ int ares_set_servers(ares_channel channel,
|
||||||
for (i = 0, srvr = servers; srvr; i++, srvr = srvr->next)
|
for (i = 0, srvr = servers; srvr; i++, srvr = srvr->next)
|
||||||
{
|
{
|
||||||
channel->servers[i].addr.family = srvr->family;
|
channel->servers[i].addr.family = srvr->family;
|
||||||
|
channel->servers[i].addr.udp_port = 0;
|
||||||
|
channel->servers[i].addr.tcp_port = 0;
|
||||||
|
if (srvr->family == AF_INET)
|
||||||
|
memcpy(&channel->servers[i].addr.addrV4, &srvr->addrV4,
|
||||||
|
sizeof(srvr->addrV4));
|
||||||
|
else
|
||||||
|
memcpy(&channel->servers[i].addr.addrV6, &srvr->addrV6,
|
||||||
|
sizeof(srvr->addrV6));
|
||||||
|
}
|
||||||
|
/* Initialize servers state remaining data */
|
||||||
|
ares__init_servers_state(channel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ARES_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ares_set_servers_ports(ares_channel channel,
|
||||||
|
struct ares_addr_port_node *servers)
|
||||||
|
{
|
||||||
|
struct ares_addr_port_node *srvr;
|
||||||
|
int num_srvrs = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (ares_library_initialized() != ARES_SUCCESS)
|
||||||
|
return ARES_ENOTINITIALIZED; /* LCOV_EXCL_LINE: n/a on non-WinSock */
|
||||||
|
|
||||||
|
if (!channel)
|
||||||
|
return ARES_ENODATA;
|
||||||
|
|
||||||
|
ares__destroy_servers_state(channel);
|
||||||
|
|
||||||
|
for (srvr = servers; srvr; srvr = srvr->next)
|
||||||
|
{
|
||||||
|
num_srvrs++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (num_srvrs > 0)
|
||||||
|
{
|
||||||
|
/* Allocate storage for servers state */
|
||||||
|
channel->servers = ares_malloc(num_srvrs * sizeof(struct server_state));
|
||||||
|
if (!channel->servers)
|
||||||
|
{
|
||||||
|
return ARES_ENOMEM;
|
||||||
|
}
|
||||||
|
channel->nservers = num_srvrs;
|
||||||
|
/* Fill servers state address data */
|
||||||
|
for (i = 0, srvr = servers; srvr; i++, srvr = srvr->next)
|
||||||
|
{
|
||||||
|
channel->servers[i].addr.family = srvr->family;
|
||||||
|
channel->servers[i].addr.udp_port = htons((unsigned short)srvr->udp_port);
|
||||||
|
channel->servers[i].addr.tcp_port = htons((unsigned short)srvr->tcp_port);
|
||||||
if (srvr->family == AF_INET)
|
if (srvr->family == AF_INET)
|
||||||
memcpy(&channel->servers[i].addr.addrV4, &srvr->addrV4,
|
memcpy(&channel->servers[i].addr.addrV4, &srvr->addrV4,
|
||||||
sizeof(srvr->addrV4));
|
sizeof(srvr->addrV4));
|
||||||
|
@ -133,8 +240,8 @@ int ares_set_servers(ares_channel channel,
|
||||||
|
|
||||||
/* Incomming string format: host[:port][,host[:port]]... */
|
/* Incomming string format: host[:port][,host[:port]]... */
|
||||||
/* IPv6 addresses with ports require square brackets [fe80::1%lo0]:53 */
|
/* IPv6 addresses with ports require square brackets [fe80::1%lo0]:53 */
|
||||||
int ares_set_servers_csv(ares_channel channel,
|
static int set_servers_csv(ares_channel channel,
|
||||||
const char* _csv)
|
const char* _csv, int use_port)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
char* csv = NULL;
|
char* csv = NULL;
|
||||||
|
@ -142,8 +249,8 @@ int ares_set_servers_csv(ares_channel channel,
|
||||||
char* start_host;
|
char* start_host;
|
||||||
int cc = 0;
|
int cc = 0;
|
||||||
int rv = ARES_SUCCESS;
|
int rv = ARES_SUCCESS;
|
||||||
struct ares_addr_node *servers = NULL;
|
struct ares_addr_port_node *servers = NULL;
|
||||||
struct ares_addr_node *last = NULL;
|
struct ares_addr_port_node *last = NULL;
|
||||||
|
|
||||||
if (ares_library_initialized() != ARES_SUCCESS)
|
if (ares_library_initialized() != ARES_SUCCESS)
|
||||||
return ARES_ENOTINITIALIZED; /* LCOV_EXCL_LINE: n/a on non-WinSock */
|
return ARES_ENOTINITIALIZED; /* LCOV_EXCL_LINE: n/a on non-WinSock */
|
||||||
|
@ -182,9 +289,10 @@ int ares_set_servers_csv(ares_channel channel,
|
||||||
else if (*ptr == ',') {
|
else if (*ptr == ',') {
|
||||||
char* pp = ptr - 1;
|
char* pp = ptr - 1;
|
||||||
char* p = ptr;
|
char* p = ptr;
|
||||||
|
int port = 0;
|
||||||
struct in_addr in4;
|
struct in_addr in4;
|
||||||
struct ares_in6_addr in6;
|
struct ares_in6_addr in6;
|
||||||
struct ares_addr_node *s = NULL;
|
struct ares_addr_port_node *s = NULL;
|
||||||
|
|
||||||
*ptr = 0; /* null terminate host:port string */
|
*ptr = 0; /* null terminate host:port string */
|
||||||
/* Got an entry..see if the port was specified. */
|
/* Got an entry..see if the port was specified. */
|
||||||
|
@ -213,7 +321,7 @@ int ares_set_servers_csv(ares_channel channel,
|
||||||
if (*pp == ']')
|
if (*pp == ']')
|
||||||
p++; /* move p before ':' */
|
p++; /* move p before ':' */
|
||||||
/* p will point to the start of the port */
|
/* p will point to the start of the port */
|
||||||
(void)strtol(p, NULL, 10);
|
port = (int)strtol(p, NULL, 10);
|
||||||
*pp = 0; /* null terminate host */
|
*pp = 0; /* null terminate host */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -246,8 +354,8 @@ int ares_set_servers_csv(ares_channel channel,
|
||||||
memcpy(&s->addr, &in4, sizeof(struct in_addr));
|
memcpy(&s->addr, &in4, sizeof(struct in_addr));
|
||||||
}
|
}
|
||||||
if (s) {
|
if (s) {
|
||||||
/* TODO: Add port to ares_addr_node and assign it here. */
|
s->udp_port = use_port ? port: 0;
|
||||||
|
s->tcp_port = s->udp_port;
|
||||||
s->next = NULL;
|
s->next = NULL;
|
||||||
if (last) {
|
if (last) {
|
||||||
last->next = s;
|
last->next = s;
|
||||||
|
@ -266,16 +374,29 @@ int ares_set_servers_csv(ares_channel channel,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rv = ares_set_servers(channel, servers);
|
rv = ares_set_servers_ports(channel, servers);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (csv)
|
if (csv)
|
||||||
ares_free(csv);
|
ares_free(csv);
|
||||||
while (servers) {
|
while (servers) {
|
||||||
struct ares_addr_node *s = servers;
|
struct ares_addr_port_node *s = servers;
|
||||||
servers = servers->next;
|
servers = servers->next;
|
||||||
ares_free(s);
|
ares_free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ares_set_servers_csv(ares_channel channel,
|
||||||
|
const char* _csv)
|
||||||
|
{
|
||||||
|
return set_servers_csv(channel, _csv, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int ares_set_servers_ports_csv(ares_channel channel,
|
||||||
|
const char* _csv)
|
||||||
|
{
|
||||||
|
return set_servers_csv(channel, _csv, TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -123,6 +123,8 @@ struct ares_addr {
|
||||||
struct in_addr addr4;
|
struct in_addr addr4;
|
||||||
struct ares_in6_addr addr6;
|
struct ares_in6_addr addr6;
|
||||||
} addr;
|
} addr;
|
||||||
|
int udp_port; /* stored in network order */
|
||||||
|
int tcp_port; /* stored in network order */
|
||||||
};
|
};
|
||||||
#define addrV4 addr.addr4
|
#define addrV4 addr.addr4
|
||||||
#define addrV6 addr.addr6
|
#define addrV6 addr.addr6
|
||||||
|
@ -255,8 +257,8 @@ struct ares_channeldata {
|
||||||
int tries;
|
int tries;
|
||||||
int ndots;
|
int ndots;
|
||||||
int rotate; /* if true, all servers specified are used */
|
int rotate; /* if true, all servers specified are used */
|
||||||
int udp_port;
|
int udp_port; /* stored in network order */
|
||||||
int tcp_port;
|
int tcp_port; /* stored in network order */
|
||||||
int socket_send_buffer_size;
|
int socket_send_buffer_size;
|
||||||
int socket_receive_buffer_size;
|
int socket_receive_buffer_size;
|
||||||
char **domains;
|
char **domains;
|
||||||
|
|
|
@ -978,7 +978,11 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
|
||||||
salen = sizeof(saddr.sa4);
|
salen = sizeof(saddr.sa4);
|
||||||
memset(sa, 0, salen);
|
memset(sa, 0, salen);
|
||||||
saddr.sa4.sin_family = AF_INET;
|
saddr.sa4.sin_family = AF_INET;
|
||||||
saddr.sa4.sin_port = aresx_sitous(channel->tcp_port);
|
if (server->addr.tcp_port) {
|
||||||
|
saddr.sa4.sin_port = aresx_sitous(server->addr.tcp_port);
|
||||||
|
} else {
|
||||||
|
saddr.sa4.sin_port = aresx_sitous(channel->tcp_port);
|
||||||
|
}
|
||||||
memcpy(&saddr.sa4.sin_addr, &server->addr.addrV4,
|
memcpy(&saddr.sa4.sin_addr, &server->addr.addrV4,
|
||||||
sizeof(server->addr.addrV4));
|
sizeof(server->addr.addrV4));
|
||||||
break;
|
break;
|
||||||
|
@ -987,7 +991,11 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
|
||||||
salen = sizeof(saddr.sa6);
|
salen = sizeof(saddr.sa6);
|
||||||
memset(sa, 0, salen);
|
memset(sa, 0, salen);
|
||||||
saddr.sa6.sin6_family = AF_INET6;
|
saddr.sa6.sin6_family = AF_INET6;
|
||||||
saddr.sa6.sin6_port = aresx_sitous(channel->tcp_port);
|
if (server->addr.tcp_port) {
|
||||||
|
saddr.sa6.sin6_port = aresx_sitous(server->addr.tcp_port);
|
||||||
|
} else {
|
||||||
|
saddr.sa6.sin6_port = aresx_sitous(channel->tcp_port);
|
||||||
|
}
|
||||||
memcpy(&saddr.sa6.sin6_addr, &server->addr.addrV6,
|
memcpy(&saddr.sa6.sin6_addr, &server->addr.addrV6,
|
||||||
sizeof(server->addr.addrV6));
|
sizeof(server->addr.addrV6));
|
||||||
break;
|
break;
|
||||||
|
@ -1070,7 +1078,11 @@ static int open_udp_socket(ares_channel channel, struct server_state *server)
|
||||||
salen = sizeof(saddr.sa4);
|
salen = sizeof(saddr.sa4);
|
||||||
memset(sa, 0, salen);
|
memset(sa, 0, salen);
|
||||||
saddr.sa4.sin_family = AF_INET;
|
saddr.sa4.sin_family = AF_INET;
|
||||||
saddr.sa4.sin_port = aresx_sitous(channel->udp_port);
|
if (server->addr.udp_port) {
|
||||||
|
saddr.sa4.sin_port = aresx_sitous(server->addr.udp_port);
|
||||||
|
} else {
|
||||||
|
saddr.sa4.sin_port = aresx_sitous(channel->udp_port);
|
||||||
|
}
|
||||||
memcpy(&saddr.sa4.sin_addr, &server->addr.addrV4,
|
memcpy(&saddr.sa4.sin_addr, &server->addr.addrV4,
|
||||||
sizeof(server->addr.addrV4));
|
sizeof(server->addr.addrV4));
|
||||||
break;
|
break;
|
||||||
|
@ -1079,7 +1091,11 @@ static int open_udp_socket(ares_channel channel, struct server_state *server)
|
||||||
salen = sizeof(saddr.sa6);
|
salen = sizeof(saddr.sa6);
|
||||||
memset(sa, 0, salen);
|
memset(sa, 0, salen);
|
||||||
saddr.sa6.sin6_family = AF_INET6;
|
saddr.sa6.sin6_family = AF_INET6;
|
||||||
saddr.sa6.sin6_port = aresx_sitous(channel->udp_port);
|
if (server->addr.udp_port) {
|
||||||
|
saddr.sa6.sin6_port = aresx_sitous(server->addr.udp_port);
|
||||||
|
} else {
|
||||||
|
saddr.sa6.sin6_port = aresx_sitous(channel->udp_port);
|
||||||
|
}
|
||||||
memcpy(&saddr.sa6.sin6_addr, &server->addr.addrV6,
|
memcpy(&saddr.sa6.sin6_addr, &server->addr.addrV6,
|
||||||
sizeof(server->addr.addrV6));
|
sizeof(server->addr.addrV6));
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -15,12 +15,13 @@
|
||||||
.\"
|
.\"
|
||||||
.TH ARES_SET_SERVERS 3 "5 March 2010"
|
.TH ARES_SET_SERVERS 3 "5 March 2010"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ares_set_servers \- Initialize an ares_channel name servers configuration
|
ares_set_servers, ares_set_servers_ports \- Initialize an ares_channel name servers configuration
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.nf
|
.nf
|
||||||
.B #include <ares.h>
|
.B #include <ares.h>
|
||||||
.PP
|
.PP
|
||||||
.B int ares_set_servers(ares_channel \fIchannel\fP, struct ares_addr_node *\fIservers\fP)
|
.B int ares_set_servers(ares_channel \fIchannel\fP, struct ares_addr_node *\fIservers\fP)
|
||||||
|
.B int ares_set_servers_ports(ares_channel \fIchannel\fP, struct ares_addr_port_node *\fIservers\fP)
|
||||||
.fi
|
.fi
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
The \fBares_set_servers(3)\fP function initializes name servers configuration
|
The \fBares_set_servers(3)\fP function initializes name servers configuration
|
||||||
|
@ -30,19 +31,25 @@ from a
|
||||||
.IR servers
|
.IR servers
|
||||||
pointer to a linked list of ares_addr_node structs holding name servers
|
pointer to a linked list of ares_addr_node structs holding name servers
|
||||||
address data.
|
address data.
|
||||||
|
.PP
|
||||||
The name server linked list pointer argument may be the result of a previous
|
The name server linked list pointer argument may be the result of a previous
|
||||||
call to \fBares_get_servers(3)\fP or a linked list of ares_addr_node structs
|
call to \fBares_get_servers(3)\fP or a linked list of \fBares_addr_node\fP structs
|
||||||
setup by other means.
|
set up by other means.
|
||||||
|
.PP
|
||||||
|
The \fBares_set_servers(3)\fP function also allows the specification of UDP and
|
||||||
|
TCP ports to be used for communication on a per-server basis. The provided
|
||||||
|
linked list argument may be the result of a previous call to
|
||||||
|
\fBares_get_servers_ports(3)\fP or a linked list of \fBares_addr_port_node\fP structs
|
||||||
|
set up by other means.
|
||||||
|
.PP
|
||||||
This function replaces any potentially previously configured name servers
|
This function replaces any potentially previously configured name servers
|
||||||
with the ones given in the linked list. So, in order to configure a channel
|
with the ones given in the linked list. So, in order to configure a channel
|
||||||
with more than one name server all the desired ones must be specified in a
|
with more than one name server all the desired ones must be specified in a
|
||||||
single list.
|
single list.
|
||||||
|
.PP
|
||||||
\fBares_set_servers(3)\fP does not take ownership of the linked list argument.
|
The function does not take ownership of the linked list argument.
|
||||||
The caller is responsible for freeing the linked list when no longer needed.
|
The caller is responsible for freeing the linked list when no longer needed.
|
||||||
|
.PP
|
||||||
This function is capable of handling IPv4 and IPv6 name server
|
This function is capable of handling IPv4 and IPv6 name server
|
||||||
addresses simultaneously, rendering \fBares_init_options(3)\fP with
|
addresses simultaneously, rendering \fBares_init_options(3)\fP with
|
||||||
optmask \fBARES_OPT_SERVERS\fP functionally obsolete except for
|
optmask \fBARES_OPT_SERVERS\fP functionally obsolete except for
|
||||||
|
@ -71,7 +78,8 @@ c-ares library initialization not yet performed.
|
||||||
.BR ares_init_options (3),
|
.BR ares_init_options (3),
|
||||||
.BR ares_dup(3)
|
.BR ares_dup(3)
|
||||||
.SH AVAILABILITY
|
.SH AVAILABILITY
|
||||||
ares_set_servers(3) was added in c-ares 1.7.1
|
\fBares_set_servers(3)\fP was added in c-ares 1.7.1;
|
||||||
|
\fBares_set_servers_ports(3)\fP was added in c-ares 1.11.0.
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
Implementation of this function and associated library internals are based
|
Implementation of this function and associated library internals are based
|
||||||
on code, comments and feedback provided in November and December of 2008 by
|
on code, comments and feedback provided in November and December of 2008 by
|
||||||
|
|
|
@ -15,26 +15,32 @@
|
||||||
.\"
|
.\"
|
||||||
.TH ARES_SET_SERVERS_CSV 3 "30 June 2010"
|
.TH ARES_SET_SERVERS_CSV 3 "30 June 2010"
|
||||||
.SH NAME
|
.SH NAME
|
||||||
ares_set_servers_csv \- Set list of DNS servers to be used.
|
ares_set_servers_csv, ares_set_servers_ports_csv \- Set list of DNS servers to be used.
|
||||||
.SH SYNOPSIS
|
.SH SYNOPSIS
|
||||||
.nf
|
.nf
|
||||||
.B #include <ares.h>
|
.B #include <ares.h>
|
||||||
.PP
|
.PP
|
||||||
.B int ares_set_servers_csv(ares_channel \fIchannel\fP, const char* \fIservers\fP)
|
.B int ares_set_servers_csv(ares_channel \fIchannel\fP, const char* \fIservers\fP)
|
||||||
|
.B int ares_set_servers_ports_csv(ares_channel \fIchannel\fP, const char* \fIservers\fP)
|
||||||
.fi
|
.fi
|
||||||
.SH DESCRIPTION
|
.SH DESCRIPTION
|
||||||
The \fBares_set_servers_csv\fP function sets the list of DNS servers
|
The \fBares_set_servers_csv\fP and \fBares_set_servers_ports_csv\fPfunctions set
|
||||||
that ARES will query. The format of the servers option is:
|
the list of DNS servers that ARES will query. The format of the servers option is:
|
||||||
|
|
||||||
host[:port][,host[:port]]...
|
host[:port][,host[:port]]...
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
192.168.1.100,192.168.1.101,3.4.5.6
|
192.168.1.100,192.168.1.101,3.4.5.6
|
||||||
|
.PP
|
||||||
|
The \fBares_set_servers_csv\fP function will ignore any port values specified in
|
||||||
|
the input string, whereare the \fBares_set_servers_ports_csv\fP function will
|
||||||
|
apply any specified port values as the UDP and TCP port to be used for that
|
||||||
|
particular nameserver.
|
||||||
|
|
||||||
.SH RETURN VALUES
|
.SH RETURN VALUES
|
||||||
.B ares_set_servers_csv(3)
|
.B ares_set_servers_csv(3)
|
||||||
may return any of the following values:
|
This function may return any of the following values:
|
||||||
.TP 15
|
.TP 15
|
||||||
.B ARES_SUCCESS
|
.B ARES_SUCCESS
|
||||||
The name servers configuration was successfuly initialized.
|
The name servers configuration was successfuly initialized.
|
||||||
|
@ -51,10 +57,8 @@ was invalid.
|
||||||
c-ares library initialization not yet performed.
|
c-ares library initialization not yet performed.
|
||||||
.SH SEE ALSO
|
.SH SEE ALSO
|
||||||
.BR ares_set_servers (3)
|
.BR ares_set_servers (3)
|
||||||
.SH NOTES
|
.SH AVAILABILITY
|
||||||
The port option is currently ignored by c-ares internals
|
\fBares_set_servers_csv\fP was added in c-ares 1.7.2;
|
||||||
and the standard port is always used.
|
\fBares_set_servers_ports_csv\fP was added in c-ares 1.11.0.
|
||||||
|
|
||||||
This function was added in c-ares 1.7.2
|
|
||||||
.SH AUTHOR
|
.SH AUTHOR
|
||||||
Ben Greear
|
Ben Greear
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
.so man3/ares_set_servers.3
|
|
@ -0,0 +1 @@
|
||||||
|
.so man3/ares_set_servers_csv.3
|
Loading…
Reference in New Issue