ares_options: reorder header inclusions to make inclusion of
[platform/upstream/c-ares.git] / ares_options.c
1
2 /* Copyright 1998 by the Massachusetts Institute of Technology.
3  * Copyright (C) 2008-2010 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 "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
40   if (!channel)
41     return ARES_ENODATA;
42
43   for (i = 0; i < channel->nservers; i++)
44     {
45       /* Allocate storage for this server node appending it to the list */
46       srvr_curr = ares_malloc_data(ARES_DATATYPE_ADDR_NODE);
47       if (!srvr_curr)
48         {
49           status = ARES_ENOMEM;
50           break;
51         }
52       if (srvr_last)
53         {
54           srvr_last->next = srvr_curr;
55         }
56       else
57         {
58           srvr_head = srvr_curr;
59         }
60       srvr_last = srvr_curr;
61
62       /* Fill this server node data */
63       srvr_curr->family = channel->servers[i].addr.family;
64       if (srvr_curr->family == AF_INET)
65         memcpy(&srvr_curr->addrV4, &channel->servers[i].addr.addrV4,
66                sizeof(srvr_curr->addrV4));
67       else
68         memcpy(&srvr_curr->addrV6, &channel->servers[i].addr.addrV6,
69                sizeof(srvr_curr->addrV6));
70     }
71
72   if (status != ARES_SUCCESS)
73     {
74       if (srvr_head)
75         {
76           ares_free_data(srvr_head);
77           srvr_head = NULL;
78         }
79     }
80
81   *servers = srvr_head;
82
83   return status;
84 }
85
86
87 int ares_set_servers(ares_channel channel,
88                      struct ares_addr_node *servers)
89 {
90   struct ares_addr_node *srvr;
91   int num_srvrs = 0;
92   int i;
93
94   if (ares_library_initialized() != ARES_SUCCESS)
95     return ARES_ENOTINITIALIZED;
96
97   if (!channel)
98     return ARES_ENODATA;
99
100   ares__destroy_servers_state(channel);
101
102   for (srvr = servers; srvr; srvr = srvr->next)
103     {
104       num_srvrs++;
105     }
106
107   if (num_srvrs > 0)
108     {
109       /* Allocate storage for servers state */
110       channel->servers = malloc(num_srvrs * sizeof(struct server_state));
111       if (!channel->servers)
112         {
113           return ARES_ENOMEM;
114         }
115       channel->nservers = num_srvrs;
116       /* Fill servers state address data */
117       for (i = 0, srvr = servers; srvr; i++, srvr = srvr->next)
118         {
119           channel->servers[i].addr.family = srvr->family;
120           if (srvr->family == AF_INET)
121             memcpy(&channel->servers[i].addr.addrV4, &srvr->addrV4,
122                    sizeof(srvr->addrV4));
123           else
124             memcpy(&channel->servers[i].addr.addrV6, &srvr->addrV6,
125                    sizeof(srvr->addrV6));
126         }
127       /* Initialize servers state remaining data */
128       ares__init_servers_state(channel);
129     }
130
131   return ARES_SUCCESS;
132 }
133
134 /* Incomming string format: host[:port][,host[:port]]... */
135 int ares_set_servers_csv(ares_channel channel,
136                          const char* _csv)
137 {
138   int i;
139   char* csv = NULL;
140   char* ptr;
141   char* start_host;
142   int port;
143   bool found_port;
144   int rv = ARES_SUCCESS;
145   struct ares_addr_node *servers = NULL;
146   struct ares_addr_node *last = NULL;
147
148   if (ares_library_initialized() != ARES_SUCCESS)
149     return ARES_ENOTINITIALIZED;
150
151   if (!channel)
152     return ARES_ENODATA;
153
154   ares__destroy_servers_state(channel);
155
156   i = strlen(_csv);
157   if (i == 0)
158      return ARES_SUCCESS; /* blank all servers */
159
160   csv = malloc(i + 2);
161   strcpy(csv, _csv);
162   if (csv[i-1] != ',') { /* make parsing easier by ensuring ending ',' */
163     csv[i] = ',';
164     csv[i+1] = 0;
165   }
166
167   start_host = csv;
168   found_port = false;
169   for (ptr = csv; *ptr; ptr++) {
170     if (*ptr == ',') {
171       char* pp = ptr - 1;
172       struct in_addr in4;
173       struct ares_in6_addr in6;
174       struct ares_addr_node *s = NULL;
175
176       *ptr = 0; /* null terminate host:port string */
177       /* Got an entry..see if port was specified. */
178       while (pp > start_host) {
179         if (*pp == ':')
180           break; /* yes */
181         if (!ISDIGIT(*pp)) {
182           /* Found end of digits before we found :, so wasn't a port */
183           pp = ptr;
184           break;
185         }
186         pp--;
187       }
188       if ((pp != start_host) && ((pp + 1) < ptr)) {
189         /* Found it. */
190         found_port = true;
191         port = atoi(pp + 1);
192         *pp = 0; /* null terminate host */
193       }
194       /* resolve host, try ipv4 first, rslt is in network byte order */
195       rv = ares_inet_pton(AF_INET, start_host, &in4);
196       if (!rv) {
197         /* Ok, try IPv6 then */
198         rv = ares_inet_pton(AF_INET6, start_host, &in6);
199         if (!rv) {
200           rv = ARES_EBADSTR;
201           goto out;
202         }
203         /* was ipv6, add new server */
204         s = malloc(sizeof(*s));
205         if (!s) {
206           rv = ARES_ENOMEM;
207           goto out;
208         }
209         s->family = AF_INET6;
210         memcpy(&s->addr, &in6, sizeof(struct ares_in6_addr));
211       }
212       else {
213         /* was ipv4, add new server */
214         s = malloc(sizeof(*s));
215         if (!s) {
216           rv = ARES_ENOMEM;
217           goto out;
218         }
219         s->family = AF_INET;
220         memcpy(&s->addr, &in4, sizeof(struct in_addr));
221       }
222       if (s) {
223         /* TODO:  Add port to ares_addr_node and assign it here. */
224
225         s->next = NULL;
226         if (last) {
227           last->next = s;
228         }
229         else {
230           servers = s;
231           last = s;
232         }
233       }
234
235       /* Set up for next one */
236       found_port = false;
237       start_host = ptr + 1;
238     }
239   }
240
241   rv = ares_set_servers(channel, servers);
242
243   out:
244   if (csv)
245     free(csv);
246   while (servers) {
247     struct ares_addr_node *s = servers;
248     servers = servers->next;
249     free(s);
250   }
251
252   return rv;
253 }