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