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
pull/34/head
David Drysdale 9 years ago
parent 06d0f72e54
commit 7972adc5d7
  1. 9
      Makefile.inc
  2. 18
      ares.h
  3. 15
      ares_data.c
  4. 2
      ares_data.h
  5. 18
      ares_get_servers.3
  6. 1
      ares_get_servers_ports.3
  7. 36
      ares_init.c
  8. 141
      ares_options.c
  9. 6
      ares_private.h
  10. 24
      ares_process.c
  11. 28
      ares_set_servers.3
  12. 22
      ares_set_servers_csv.3
  13. 1
      ares_set_servers_ports.3
  14. 1
      ares_set_servers_ports_csv.3

@ -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 \

@ -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);

@ -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

@ -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));

@ -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…
Cancel
Save