diff options
author | Ben Greear <greearb@candelatech.com> | 2010-07-18 23:58:39 +0200 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2010-07-18 23:58:39 +0200 |
commit | e3b04e5a4796215d2483aba3cb75c72ba337ac14 (patch) | |
tree | 3671ebcef566e0e32f00a50b0557b88bd8b67475 /ares_options.c | |
parent | 45a09b7efba9665bdc08e227f4baf51fab3862ae (diff) | |
download | c-ares-e3b04e5a4796215d2483aba3cb75c72ba337ac14.tar.gz c-ares-e3b04e5a4796215d2483aba3cb75c72ba337ac14.tar.bz2 c-ares-e3b04e5a4796215d2483aba3cb75c72ba337ac14.zip |
local-bind: Support binding to local interface/IPs
Add 3 new functions to set the local binding for the out-going
socket connection, and add ares_set_servers_csv() to set a
list of servers at once as a comma-separated string.
Signed-off-by: Ben Greear <greearb@candelatech.com>
Diffstat (limited to 'ares_options.c')
-rw-r--r-- | ares_options.c | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/ares_options.c b/ares_options.c index d00368a..bb1d5d5 100644 --- a/ares_options.c +++ b/ares_options.c @@ -21,6 +21,7 @@ #include "ares.h" #include "ares_data.h" #include "ares_private.h" +#include "inet_net_pton.h" int ares_get_servers(ares_channel channel, @@ -125,3 +126,127 @@ int ares_set_servers(ares_channel channel, return ARES_SUCCESS; } + +/* Incomming string format: host[:port][,host[:port]]... */ +int ares_set_servers_csv(ares_channel channel, + const char* _csv) +{ + struct ares_addr_node *srvr; + int num_srvrs = 0; + int i; + char* csv = NULL; + char* ptr; + char* start_host; + int port; + bool found_port; + int rv = ARES_SUCCESS; + struct ares_addr_node *servers = NULL; + struct ares_addr_node *last = NULL; + + if (ares_library_initialized() != ARES_SUCCESS) + return ARES_ENOTINITIALIZED; + + if (!channel) + return ARES_ENODATA; + + ares__destroy_servers_state(channel); + + i = strlen(_csv); + if (i == 0) + return ARES_SUCCESS; /* blank all servers */ + + csv = malloc(i + 2); + strcpy(csv, _csv); + if (csv[i-1] != ',') { /* make parsing easier by ensuring ending ',' */ + csv[i] = ','; + csv[i+1] = 0; + } + + ptr = csv; + start_host = csv; + found_port = false; + for (ptr; *ptr; ptr++) { + if (*ptr == ',') { + char* pp = ptr - 1; + struct in_addr in4; + struct ares_in6_addr in6; + struct ares_addr_node *s = NULL; + + *ptr = 0; /* null terminate host:port string */ + /* Got an entry..see if port was specified. */ + while (pp > start_host) { + if (*pp == ':') + break; /* yes */ + if (!isdigit(*pp)) { + /* Found end of digits before we found :, so wasn't a port */ + pp = ptr; + break; + } + pp--; + } + if ((pp != start_host) && ((pp + 1) < ptr)) { + /* Found it. */ + found_port = true; + port = atoi(pp + 1); + *pp = 0; /* null terminate host */ + } + /* resolve host, try ipv4 first, rslt is in network byte order */ + rv = ares_inet_pton(AF_INET, start_host, &in4); + if (!rv) { + /* Ok, try IPv6 then */ + rv = ares_inet_pton(AF_INET6, start_host, &in6); + if (!rv) { + rv = ARES_EBADSTR; + goto out; + } + /* was ipv6, add new server */ + s = malloc(sizeof(*s)); + if (!s) { + rv = ARES_ENOMEM; + goto out; + } + s->family = AF_INET6; + memcpy(&s->addr, &in6, sizeof(struct ares_in6_addr)); + } + else { + /* was ipv4, add new server */ + s = malloc(sizeof(*s)); + if (!s) { + rv = ARES_ENOMEM; + goto out; + } + s->family = AF_INET; + memcpy(&s->addr, &in4, sizeof(struct in_addr)); + } + if (s) { + /* TODO: Add port to ares_addr_node and assign it here. */ + + s->next = NULL; + if (last) { + last->next = s; + } + else { + servers = s; + last = s; + } + } + + /* Set up for next one */ + found_port = false; + start_host = ptr + 1; + } + } + + rv = ares_set_servers(channel, servers); + + out: + if (csv) + free(csv); + while (servers) { + struct ares_addr_node *s = servers; + servers = servers->next; + free(s); + } + + return rv; +} |