The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.
Please select the desired protocol below to get the URL.
This URL has Read-Only access.
main_repo / deps / cares / src / ares_options.c @ 9bfd6627
History | View | Annotate | Download (7.9 KB)
1 |
|
---|---|
2 |
/* Copyright 1998 by the Massachusetts Institute of Technology.
|
3 |
* Copyright (C) 2008-2013 by Daniel Stenberg
|
4 |
*
|
5 |
* Permission to use, copy, modify, and distribute this
|
6 |
* software and its documentation for any purpose and without
|
7 |
* fee is hereby granted, provided that the above copyright
|
8 |
* notice appear in all copies and that both that copyright
|
9 |
* notice and this permission notice appear in supporting
|
10 |
* documentation, and that the name of M.I.T. not be used in
|
11 |
* advertising or publicity pertaining to distribution of the
|
12 |
* software without specific, written prior permission.
|
13 |
* M.I.T. makes no representations about the suitability of
|
14 |
* this software for any purpose. It is provided "as is"
|
15 |
* without express or implied warranty.
|
16 |
*/
|
17 |
|
18 |
|
19 |
#include "ares_setup.h" |
20 |
|
21 |
#ifdef HAVE_ARPA_INET_H
|
22 |
# include <arpa/inet.h> |
23 |
#endif
|
24 |
|
25 |
#include "ares.h" |
26 |
#include "ares_data.h" |
27 |
#include "ares_inet_net_pton.h" |
28 |
#include "ares_private.h" |
29 |
|
30 |
|
31 |
int ares_get_servers(ares_channel channel,
|
32 |
struct ares_addr_node **servers)
|
33 |
{ |
34 |
struct ares_addr_node *srvr_head = NULL; |
35 |
struct ares_addr_node *srvr_last = NULL; |
36 |
struct ares_addr_node *srvr_curr;
|
37 |
int status = ARES_SUCCESS;
|
38 |
int i;
|
39 |
int srvr_first = 0; |
40 |
|
41 |
// If no open channel, no active conncetions, return end data. -----------------------------------------------------------------
|
42 |
if (!channel) {
|
43 |
return ARES_ENODATA;
|
44 |
} else if (channel->num_servers_change > 0) { |
45 |
// Or, if true, then there must be at least 1 change to process
|
46 |
srvr_first = channel->last_server; |
47 |
} |
48 |
|
49 |
// Modify loop to use list of tasks in ares_server_switch.c
|
50 |
// for (i = 0; i < channel->nservers; i++)
|
51 |
for (i = srvr_first; i < channel->nservers; i++) {
|
52 |
// -----------------------------------------------------------------------------------------------------------------------------
|
53 |
/* Allocate storage for this server node appending it to the list */
|
54 |
srvr_curr = ares_malloc_data(ARES_DATATYPE_ADDR_NODE); |
55 |
if (!srvr_curr)
|
56 |
{ |
57 |
status = ARES_ENOMEM; |
58 |
break;
|
59 |
} |
60 |
if (srvr_last)
|
61 |
{ |
62 |
srvr_last->next = srvr_curr; |
63 |
} |
64 |
else
|
65 |
{ |
66 |
srvr_head = srvr_curr; |
67 |
} |
68 |
srvr_last = srvr_curr; |
69 |
|
70 |
/* Fill this server node data */
|
71 |
srvr_curr->family = channel->servers[i].addr.family; |
72 |
if (srvr_curr->family == AF_INET)
|
73 |
memcpy(&srvr_curr->addrV4, &channel->servers[i].addr.addrV4, |
74 |
sizeof(srvr_curr->addrV4));
|
75 |
else
|
76 |
memcpy(&srvr_curr->addrV6, &channel->servers[i].addr.addrV6, |
77 |
sizeof(srvr_curr->addrV6));
|
78 |
} |
79 |
|
80 |
if (status != ARES_SUCCESS)
|
81 |
{ |
82 |
if (srvr_head)
|
83 |
{ |
84 |
ares_free_data(srvr_head); |
85 |
srvr_head = NULL;
|
86 |
} |
87 |
} |
88 |
|
89 |
*servers = srvr_head; |
90 |
|
91 |
return status;
|
92 |
} |
93 |
|
94 |
|
95 |
int ares_set_servers(ares_channel channel,
|
96 |
struct ares_addr_node *servers)
|
97 |
{ |
98 |
struct ares_addr_node *srvr;
|
99 |
int num_srvrs = 0; |
100 |
int i;
|
101 |
|
102 |
if (ares_library_initialized() != ARES_SUCCESS)
|
103 |
return ARES_ENOTINITIALIZED;
|
104 |
|
105 |
if (!channel)
|
106 |
return ARES_ENODATA;
|
107 |
|
108 |
ares__destroy_servers_state(channel); |
109 |
|
110 |
for (srvr = servers; srvr; srvr = srvr->next)
|
111 |
{ |
112 |
num_srvrs++; |
113 |
} |
114 |
|
115 |
if (num_srvrs > 0) |
116 |
{ |
117 |
/* Allocate storage for servers state */
|
118 |
channel->servers = malloc(num_srvrs * sizeof(struct server_state)); |
119 |
if (!channel->servers)
|
120 |
{ |
121 |
return ARES_ENOMEM;
|
122 |
} |
123 |
channel->nservers = num_srvrs; |
124 |
/* Fill servers state address data */
|
125 |
for (i = 0, srvr = servers; srvr; i++, srvr = srvr->next) |
126 |
{ |
127 |
channel->servers[i].addr.family = srvr->family; |
128 |
if (srvr->family == AF_INET)
|
129 |
memcpy(&channel->servers[i].addr.addrV4, &srvr->addrV4, |
130 |
sizeof(srvr->addrV4));
|
131 |
else
|
132 |
memcpy(&channel->servers[i].addr.addrV6, &srvr->addrV6, |
133 |
sizeof(srvr->addrV6));
|
134 |
} |
135 |
/* Initialize servers state remaining data */
|
136 |
ares__init_servers_state(channel); |
137 |
} |
138 |
|
139 |
return ARES_SUCCESS;
|
140 |
} |
141 |
|
142 |
/* Incomming string format: host[:port][,host[:port]]... */
|
143 |
/* IPv6 addresses with ports require square brackets [fe80::1%lo0]:53 */
|
144 |
int ares_set_servers_csv(ares_channel channel,
|
145 |
const char* _csv) |
146 |
{ |
147 |
size_t i; |
148 |
char* csv = NULL; |
149 |
char* ptr;
|
150 |
char* start_host;
|
151 |
int cc = 0; |
152 |
int rv = ARES_SUCCESS;
|
153 |
struct ares_addr_node *servers = NULL; |
154 |
struct ares_addr_node *last = NULL; |
155 |
|
156 |
if (ares_library_initialized() != ARES_SUCCESS)
|
157 |
return ARES_ENOTINITIALIZED;
|
158 |
|
159 |
if (!channel)
|
160 |
return ARES_ENODATA;
|
161 |
|
162 |
ares__destroy_servers_state(channel); |
163 |
|
164 |
i = strlen(_csv); |
165 |
if (i == 0) |
166 |
return ARES_SUCCESS; /* blank all servers */ |
167 |
|
168 |
csv = malloc(i + 2);
|
169 |
strcpy(csv, _csv); |
170 |
if (csv[i-1] != ',') { /* make parsing easier by ensuring ending ',' */ |
171 |
csv[i] = ',';
|
172 |
csv[i+1] = 0; |
173 |
} |
174 |
|
175 |
start_host = csv; |
176 |
for (ptr = csv; *ptr; ptr++) {
|
177 |
if (*ptr == ':') { |
178 |
/* count colons to determine if we have an IPv6 number or IPv4 with
|
179 |
port */
|
180 |
cc++; |
181 |
} |
182 |
else if (*ptr == '[') { |
183 |
/* move start_host if an open square bracket is found wrapping an IPv6
|
184 |
address */
|
185 |
start_host = ptr + 1;
|
186 |
} |
187 |
else if (*ptr == ',') { |
188 |
char* pp = ptr - 1; |
189 |
char* p = ptr;
|
190 |
struct in_addr in4;
|
191 |
struct ares_in6_addr in6;
|
192 |
struct ares_addr_node *s = NULL; |
193 |
|
194 |
*ptr = 0; /* null terminate host:port string */ |
195 |
/* Got an entry..see if the port was specified. */
|
196 |
if (cc > 0) { |
197 |
while (pp > start_host) {
|
198 |
/* a single close square bracket followed by a colon, ']:' indicates
|
199 |
an IPv6 address with port */
|
200 |
if ((*pp == ']') && (*p == ':')) |
201 |
break; /* found port */ |
202 |
/* a single colon, ':' indicates an IPv4 address with port */
|
203 |
if ((*pp == ':') && (cc == 1)) |
204 |
break; /* found port */ |
205 |
if (!(ISDIGIT(*pp) || (*pp == ':'))) { |
206 |
/* Found end of digits before we found :, so wasn't a port */
|
207 |
/* must allow ':' for IPv6 case of ']:' indicates we found a port */
|
208 |
pp = p = ptr; |
209 |
break;
|
210 |
} |
211 |
pp--; |
212 |
p--; |
213 |
} |
214 |
if ((pp != start_host) && ((pp + 1) < ptr)) { |
215 |
/* Found it. Parse over the port number */
|
216 |
/* when an IPv6 address is wrapped with square brackets the port
|
217 |
starts at pp + 2 */
|
218 |
if (*pp == ']') |
219 |
p++; /* move p before ':' */
|
220 |
/* p will point to the start of the port */
|
221 |
(void)strtol(p, NULL, 10); |
222 |
*pp = 0; /* null terminate host */ |
223 |
} |
224 |
} |
225 |
/* resolve host, try ipv4 first, rslt is in network byte order */
|
226 |
rv = ares_inet_pton(AF_INET, start_host, &in4); |
227 |
if (!rv) {
|
228 |
/* Ok, try IPv6 then */
|
229 |
rv = ares_inet_pton(AF_INET6, start_host, &in6); |
230 |
if (!rv) {
|
231 |
rv = ARES_EBADSTR; |
232 |
goto out;
|
233 |
} |
234 |
/* was ipv6, add new server */
|
235 |
s = malloc(sizeof(*s));
|
236 |
if (!s) {
|
237 |
rv = ARES_ENOMEM; |
238 |
goto out;
|
239 |
} |
240 |
s->family = AF_INET6; |
241 |
memcpy(&s->addr, &in6, sizeof(struct ares_in6_addr)); |
242 |
} |
243 |
else {
|
244 |
/* was ipv4, add new server */
|
245 |
s = malloc(sizeof(*s));
|
246 |
if (!s) {
|
247 |
rv = ARES_ENOMEM; |
248 |
goto out;
|
249 |
} |
250 |
s->family = AF_INET; |
251 |
memcpy(&s->addr, &in4, sizeof(struct in_addr)); |
252 |
} |
253 |
if (s) {
|
254 |
/* TODO: Add port to ares_addr_node and assign it here. */
|
255 |
|
256 |
s->next = NULL;
|
257 |
if (last) {
|
258 |
last->next = s; |
259 |
/* need to move last to maintain the linked list */
|
260 |
last = last->next; |
261 |
} |
262 |
else {
|
263 |
servers = s; |
264 |
last = s; |
265 |
} |
266 |
} |
267 |
|
268 |
/* Set up for next one */
|
269 |
start_host = ptr + 1;
|
270 |
cc = 0;
|
271 |
} |
272 |
} |
273 |
|
274 |
rv = ares_set_servers(channel, servers); |
275 |
|
276 |
out:
|
277 |
if (csv)
|
278 |
free(csv); |
279 |
while (servers) {
|
280 |
struct ares_addr_node *s = servers;
|
281 |
servers = servers->next; |
282 |
free(s); |
283 |
} |
284 |
|
285 |
return rv;
|
286 |
} |