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.

Statistics
| Branch: | Tag: | Revision:

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
}