Home | History | Annotate | Download | only in c-ares
      1 
      2 /* Copyright 1998 by the Massachusetts Institute of Technology.
      3  * Copyright (C) 2008-2011 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   size_t i;
    139   char* csv = NULL;
    140   char* ptr;
    141   char* start_host;
    142   int rv = ARES_SUCCESS;
    143   struct ares_addr_node *servers = NULL;
    144   struct ares_addr_node *last = NULL;
    145 
    146   if (ares_library_initialized() != ARES_SUCCESS)
    147     return ARES_ENOTINITIALIZED;
    148 
    149   if (!channel)
    150     return ARES_ENODATA;
    151 
    152   ares__destroy_servers_state(channel);
    153 
    154   i = strlen(_csv);
    155   if (i == 0)
    156      return ARES_SUCCESS; /* blank all servers */
    157 
    158   csv = malloc(i + 2);
    159   strcpy(csv, _csv);
    160   if (csv[i-1] != ',') { /* make parsing easier by ensuring ending ',' */
    161     csv[i] = ',';
    162     csv[i+1] = 0;
    163   }
    164 
    165   start_host = csv;
    166   for (ptr = csv; *ptr; ptr++) {
    167     if (*ptr == ',') {
    168       char* pp = ptr - 1;
    169       struct in_addr in4;
    170       struct ares_in6_addr in6;
    171       struct ares_addr_node *s = NULL;
    172 
    173       *ptr = 0; /* null terminate host:port string */
    174       /* Got an entry..see if port was specified. */
    175       while (pp > start_host) {
    176         if (*pp == ':')
    177           break; /* yes */
    178         if (!ISDIGIT(*pp)) {
    179           /* Found end of digits before we found :, so wasn't a port */
    180           pp = ptr;
    181           break;
    182         }
    183         pp--;
    184       }
    185       if ((pp != start_host) && ((pp + 1) < ptr)) {
    186         /* Found it. Parse over the port number */
    187         (void)strtol(pp + 1, NULL, 10);
    188         *pp = 0; /* null terminate host */
    189       }
    190       /* resolve host, try ipv4 first, rslt is in network byte order */
    191       rv = ares_inet_pton(AF_INET, start_host, &in4);
    192       if (!rv) {
    193         /* Ok, try IPv6 then */
    194         rv = ares_inet_pton(AF_INET6, start_host, &in6);
    195         if (!rv) {
    196           rv = ARES_EBADSTR;
    197           goto out;
    198         }
    199         /* was ipv6, add new server */
    200         s = malloc(sizeof(*s));
    201         if (!s) {
    202           rv = ARES_ENOMEM;
    203           goto out;
    204         }
    205         s->family = AF_INET6;
    206         memcpy(&s->addr, &in6, sizeof(struct ares_in6_addr));
    207       }
    208       else {
    209         /* was ipv4, add new server */
    210         s = malloc(sizeof(*s));
    211         if (!s) {
    212           rv = ARES_ENOMEM;
    213           goto out;
    214         }
    215         s->family = AF_INET;
    216         memcpy(&s->addr, &in4, sizeof(struct in_addr));
    217       }
    218       if (s) {
    219         /* TODO:  Add port to ares_addr_node and assign it here. */
    220 
    221         s->next = NULL;
    222         if (last) {
    223           last->next = s;
    224         }
    225         else {
    226           servers = s;
    227           last = s;
    228         }
    229       }
    230 
    231       /* Set up for next one */
    232       start_host = ptr + 1;
    233     }
    234   }
    235 
    236   rv = ares_set_servers(channel, servers);
    237 
    238   out:
    239   if (csv)
    240     free(csv);
    241   while (servers) {
    242     struct ares_addr_node *s = servers;
    243     servers = servers->next;
    244     free(s);
    245   }
    246 
    247   return rv;
    248 }
    249