-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 02/04/2010 02:32 PM, Yang Tse wrote:
> I won't be able to look into this at least until February 10. Besides
> the code changes it would also help if you described here the intended
> functional changes, even if not complete yet, so we don't have to
> discover them directly in the source code.
> 

A new patch is attached that also fixes ares_dup() and adds the manpage.

Apart from the high-level summary in the patch itself, here's the changes:

  * struct "server state" no longer holds the address in "struct
in_addr" but rather "struct addrinfo *"
  * when initializing from resolv.conf, getaddrinfo() is used in place
of inet_addr()
  * a new API call ares_set_nameserves which can set the nameservers used
  * in order not to break "struct ares_options", ares_save_options and
ares_init_options still works with v4 nameservers only. ares_dup() works
for both v4 and v6 servers.

More info is, of course, in the patch :-)

        Jakub
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.10 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iEYEARECAAYFAkt1neoACgkQHsardTLnvCXYwgCgwh5Y9k3FcovX8a14Qd7/ZXPQ
hFAAn30MAtep6FkKRIVuNsDOPEDZedZE
=StmA
-----END PGP SIGNATURE-----
From 407d01fa8f6e2016c07701c314ff4908c3525751 Mon Sep 17 00:00:00 2001
From: Jakub Hrozek <jhro...@redhat.com>
Date: Mon, 1 Feb 2010 21:23:59 +0100
Subject: [PATCH] Allow the use of IPv6 nameservers

This patch allows the use of IPv6 addresses for nameserves in both
/etc/resolv.conf and by using the ares_set_nameservers() API.
---
 Makefile.inc           |    1 +
 ares.h                 |    4 +
 ares_destroy.c         |   10 +--
 ares_init.c            |  283 +++++++++++++++++++++++++++++++++++++++++-------
 ares_private.h         |    6 +-
 ares_process.c         |   84 +++++++++++----
 ares_set_nameservers.3 |   41 +++++++
 7 files changed, 356 insertions(+), 73 deletions(-)
 create mode 100644 ares_set_nameservers.3

diff --git a/Makefile.inc b/Makefile.inc
index 3227858..5139aa1 100644
--- a/Makefile.inc
+++ b/Makefile.inc
@@ -92,6 +92,7 @@ MANPAGES = ares_cancel.3		\
   ares_search.3				\
   ares_send.3				\
   ares_set_socket_callback.3		\
+  ares_set_nameservers.3		\
   ares_strerror.3			\
   ares_timeout.3			\
   ares_version.3
diff --git a/ares.h b/ares.h
index b1c2c22..ad5b17f 100644
--- a/ares.h
+++ b/ares.h
@@ -318,6 +318,10 @@ CARES_EXTERN void ares_set_socket_callback(ares_channel channel,
                                            ares_sock_create_callback callback,
                                            void *user_data);
 
+CARES_EXTERN int ares_set_nameservers(ares_channel channel,
+                                      struct sockaddr_storage *servers,
+                                      int num_servers);
+
 CARES_EXTERN void ares_send(ares_channel channel,
                             const unsigned char *qbuf,
                             int qlen,
diff --git a/ares_destroy.c b/ares_destroy.c
index 0044a71..4040971 100644
--- a/ares_destroy.c
+++ b/ares_destroy.c
@@ -67,15 +67,7 @@ void ares_destroy(ares_channel channel)
     }
 #endif
 
-  if (channel->servers) {
-    for (i = 0; i < channel->nservers; i++)
-      {
-        struct server_state *server = &channel->servers[i];
-        ares__close_sockets(channel, server);
-        assert(ares__is_list_empty(&(server->queries_to_server)));
-      }
-    free(channel->servers);
-  }
+  ares__free_servers(channel);
 
   if (channel->domains) {
     for (i = 0; i < channel->ndomains; i++)
diff --git a/ares_init.c b/ares_init.c
index cb541af..38acc6a 100644
--- a/ares_init.c
+++ b/ares_init.c
@@ -65,6 +65,7 @@
 #include <ctype.h>
 #include <time.h>
 #include <errno.h>
+#include <assert.h>
 #include "ares.h"
 #include "inet_net_pton.h"
 #include "ares_library_init.h"
@@ -88,6 +89,7 @@ static int set_search(ares_channel channel, const char *str);
 static int set_options(ares_channel channel, const char *str);
 static const char *try_option(const char *p, const char *q, const char *opt);
 static int init_id_key(rc4_key* key,int key_data_len);
+static void init_servers(ares_channel channel);
 
 #if !defined(WIN32) && !defined(WATT32)
 static int sortlist_alloc(struct apattern **sortlist, int *nsort, struct apattern *pat);
@@ -118,7 +120,6 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
   ares_channel channel;
   int i;
   int status = ARES_SUCCESS;
-  struct server_state *server;
   struct timeval now;
 
 #ifdef CURLDEBUG
@@ -227,6 +228,10 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
   if (status != ARES_SUCCESS)
     {
       /* Something failed; clean up memory we may have allocated. */
+      for (i = 0; i < channel->nservers; i++)
+        {
+          freeaddrinfo(channel->servers[i].addr);
+        }
       if (channel->servers)
         free(channel->servers);
       if (channel->domains)
@@ -248,20 +253,7 @@ int ares_init_options(ares_channel *channelptr, struct ares_options *options,
     channel->nservers = 1;
 
   /* Initialize server states. */
-  for (i = 0; i < channel->nservers; i++)
-    {
-      server = &channel->servers[i];
-      server->udp_socket = ARES_SOCKET_BAD;
-      server->tcp_socket = ARES_SOCKET_BAD;
-      server->tcp_connection_generation = ++channel->tcp_connection_generation;
-      server->tcp_lenbuf_pos = 0;
-      server->tcp_buffer = NULL;
-      server->qhead = NULL;
-      server->qtail = NULL;
-      ares__init_list_head(&(server->queries_to_server));
-      server->channel = channel;
-      server->is_broken = 0;
-    }
+  init_servers(channel);
 
   *channelptr = channel;
   return ARES_SUCCESS;
@@ -296,6 +288,48 @@ int ares_dup(ares_channel *dest, ares_channel src)
   (*dest)->sock_create_cb      = src->sock_create_cb;
   (*dest)->sock_create_cb_data = src->sock_create_cb_data;
 
+  /* IPv4 nameservers were copied in ares_save_options, we
+   * can only copy v6 servers */
+  if (src->nservers > (*dest)->nservers)
+    {
+        int i;
+        (*dest)->servers =
+            realloc((*dest)->servers,
+                    src->nservers * sizeof(struct server_state));
+        if (!(*dest)->servers)
+          return ARES_ENOMEM;
+
+        for (i = 0; i < src->nservers; i++)
+        {
+            if (src->servers[i].addr->ai_family == AF_INET6)
+              {
+                  (*dest)->servers[(*dest)->nservers].addr =
+                                    malloc(sizeof(struct addrinfo));
+                  if (!(*dest)->servers[(*dest)->nservers].addr)
+                    return ARES_ENOMEM;
+                  (*dest)->servers[(*dest)->nservers].free_addr = 1;
+                  memset((*dest)->servers[(*dest)->nservers].addr,
+                         0, sizeof(struct addrinfo));
+
+                  (*dest)->servers[(*dest)->nservers].addr->ai_family = AF_INET6;
+                  (*dest)->servers[(*dest)->nservers].addr->ai_addrlen =
+                                            sizeof(struct sockaddr_in6);
+                  (*dest)->servers[(*dest)->nservers].addr->ai_addr    =
+                                            malloc(sizeof(struct sockaddr_in6));
+                  if (!(*dest)->servers[(*dest)->nservers].addr->ai_addr)
+                    return ARES_ENOMEM;
+
+                  memcpy((*dest)->servers[(*dest)->nservers].addr->ai_addr,
+                         (struct sockaddr_in6 *) src->servers[i].addr->ai_addr,
+                         sizeof(struct sockaddr_in6));
+
+                  (*dest)->nservers++;
+              }
+            else return ARES_EBADFAMILY; /* should not happen */
+
+            init_servers(*dest);
+        }
+    }
 
   return ARES_SUCCESS; /* everything went fine */
 
@@ -334,17 +368,33 @@ int ares_save_options(ares_channel channel, struct ares_options *options,
   options->tcp_port = (unsigned short)channel->tcp_port;
   options->sock_state_cb     = channel->sock_state_cb;
   options->sock_state_cb_data = channel->sock_state_cb_data;
+  options->nservers = 0;
 
   /* Copy servers */
   if (channel->nservers) {
+    int numv4 = 0;
     options->servers =
       malloc(channel->nservers * sizeof(struct server_state));
-    if (!options->servers && channel->nservers != 0)
+    if (!options->servers)
       return ARES_ENOMEM;
     for (i = 0; i < channel->nservers; i++)
-      options->servers[i] = channel->servers[i].addr;
+    {
+      if (channel->servers[i].addr->ai_family == AF_INET)
+        {
+            /* Because struct ares_options should stay the same
+             * only IPv4 nameservers are saved in this patch.
+             * ares_dup() works for both v4 and v6, though
+             */
+            options->servers[numv4++] =
+                ((struct sockaddr_in *) channel->servers[i].addr->ai_addr)->sin_addr;
+        }
+    }
+    options->servers =
+        realloc(options->servers, numv4 * sizeof(struct server_state));
+    if (numv4 && !options->servers)
+      return ARES_ENOMEM;
+    options->nservers = numv4;
   }
-  options->nservers = channel->nservers;
 
   /* copy domains */
   if (channel->ndomains) {
@@ -431,7 +481,28 @@ static int init_by_options(ares_channel channel,
           if (!channel->servers)
             return ARES_ENOMEM;
           for (i = 0; i < options->nservers; i++)
-            channel->servers[i].addr = options->servers[i];
+            {
+                /* This is a rather crude way to allow usage of
+                 * protocol-independent struct addrinfo while not
+                 * breaking the public struct ares_options which is forbidden
+                 * in favor of providing ares_set_XXX() functions
+                 */
+                channel->servers[i].addr = malloc(sizeof(struct addrinfo));
+                if (!channel->servers[i].addr)
+                  return ARES_ENOMEM;
+
+                channel->servers[i].addr->ai_addr = malloc(sizeof(struct sockaddr));
+                if (!channel->servers[i].addr->ai_addr)
+                  return ARES_ENOMEM;
+                channel->servers[i].free_addr = 1;
+
+                ((struct sockaddr_in *) channel->servers[i].addr->ai_addr)->sin_family = AF_INET;
+                ((struct sockaddr_in *) channel->servers[i].addr->ai_addr)->sin_addr = options->servers[i];
+
+                channel->servers[i].addr->ai_family = AF_INET;
+                channel->servers[i].addr->ai_next = NULL;
+                channel->servers[i].addr->ai_addrlen = sizeof(struct sockaddr_in);
+            }
         }
       channel->nservers = options->nservers;
     }
@@ -978,6 +1049,8 @@ static int init_by_defaults(ares_channel channel)
 #ifdef HAVE_GETHOSTNAME
   char *dot;
 #endif
+  struct addrinfo *res = NULL;
+  struct addrinfo hints;
 
   if (channel->flags == -1)
     channel->flags = 0;
@@ -1001,7 +1074,16 @@ static int init_by_defaults(ares_channel channel)
       rc = ARES_ENOMEM;
       goto error;
     }
-    channel->servers[0].addr.s_addr = htonl(INADDR_LOOPBACK);
+
+    memset(&hints, 0, sizeof(struct addrinfo));
+    hints.ai_flags = 0;
+    hints.ai_family = AF_UNSPEC;
+    rc = getaddrinfo(NULL, "53", &hints, &res);
+    if (rc != 0)
+      return ARES_SUCCESS;
+
+    channel->servers[0].addr = res;
+    channel->servers[0].free_addr = 0;
     channel->nservers = 1;
   }
 
@@ -1146,11 +1228,38 @@ static int config_lookup(ares_channel channel, const char *str,
 #endif  /* !WIN32 & !WATT32 */
 
 #ifndef WATT32
+static int set_nameserver(struct server_state **servers, int *nservers,
+                          char *str)
+{
+  struct server_state *newserv;
+  struct addrinfo *res = NULL;
+  struct addrinfo hints;
+  int ret;
+
+  memset(&hints, 0, sizeof(struct addrinfo));
+  hints.ai_flags = AI_NUMERICHOST; /* suppresses a lookup */
+  hints.ai_family = AF_UNSPEC;
+
+  ret = getaddrinfo(str, NULL, &hints, &res);
+  if (ret != 0)
+    return ARES_SUCCESS;
+
+  newserv = realloc(*servers, (*nservers + 1) * sizeof(struct server_state));
+  if (!newserv)
+    return ARES_ENOMEM;
+  newserv[*nservers].addr = res;
+  newserv[*nservers].free_addr = 0;
+  *servers = newserv;
+  (*nservers)++;
+
+  return ARES_SUCCESS;
+}
+
 static int config_nameserver(struct server_state **servers, int *nservers,
                              char *str)
 {
-  struct in_addr addr;
-  struct server_state *newserv;
+  int ret;
+
   /* On Windows, there may be more than one nameserver specified in the same
    * registry key, so we parse it as a space or comma seperated list.
    */
@@ -1178,15 +1287,9 @@ static int config_nameserver(struct server_state **servers, int *nservers,
     }
 
     /* This is the part that actually sets the nameserver */
-    addr.s_addr = inet_addr(begin);
-    if (addr.s_addr == INADDR_NONE)
-      continue;
-    newserv = realloc(*servers, (*nservers + 1) * sizeof(struct server_state));
-    if (!newserv)
-      return ARES_ENOMEM;
-    newserv[*nservers].addr = addr;
-    *servers = newserv;
-    (*nservers)++;
+    ret = set_nameserver(servers, nservers, begin);
+    if (ret)
+      return ret;
 
     if (!more)
       break;
@@ -1194,15 +1297,9 @@ static int config_nameserver(struct server_state **servers, int *nservers,
   }
 #else
   /* Add a nameserver entry, if this is a valid address. */
-  addr.s_addr = inet_addr(str);
-  if (addr.s_addr == INADDR_NONE)
-    return ARES_SUCCESS;
-  newserv = realloc(*servers, (*nservers + 1) * sizeof(struct server_state));
-  if (!newserv)
-    return ARES_ENOMEM;
-  newserv[*nservers].addr = addr;
-  *servers = newserv;
-  (*nservers)++;
+  ret = set_nameserver(servers, nservers, str);
+  if (ret)
+    return ret;
 #endif
   return ARES_SUCCESS;
 }
@@ -1580,3 +1677,109 @@ void ares_set_socket_callback(ares_channel channel,
   channel->sock_create_cb = cb;
   channel->sock_create_cb_data = data;
 }
+
+static void init_servers(ares_channel channel)
+{
+  struct server_state *server;
+  int i;
+
+  for (i = 0; i < channel->nservers; i++)
+    {
+      server = &channel->servers[i];
+      server->udp_socket = ARES_SOCKET_BAD;
+      server->tcp_socket = ARES_SOCKET_BAD;
+      server->tcp_connection_generation = ++channel->tcp_connection_generation;
+      server->tcp_lenbuf_pos = 0;
+      server->tcp_buffer = NULL;
+      server->qhead = NULL;
+      server->qtail = NULL;
+      ares__init_list_head(&(server->queries_to_server));
+      server->channel = channel;
+      server->is_broken = 0;
+    }
+}
+
+void ares__free_servers(ares_channel channel)
+{
+  int i;
+
+  if (channel->servers) {
+    for (i = 0; i < channel->nservers; i++)
+      {
+        struct server_state *server = &channel->servers[i];
+        ares__close_sockets(channel, server);
+        assert(ares__is_list_empty(&(server->queries_to_server)));
+        if (server->free_addr)
+          {
+            free(server->addr->ai_addr);
+            server->free_addr = 0;
+          }
+        freeaddrinfo(server->addr);
+      }
+    free(channel->servers);
+  }
+
+  channel->servers = NULL;
+  channel->nservers = -1;
+}
+
+int ares_set_nameservers(ares_channel channel,
+                         struct sockaddr_storage *servers,
+                         int num_servers)
+{
+  int i;
+
+  ares__free_servers(channel);
+
+  channel->nservers = num_servers;
+  channel->servers  =
+    malloc(channel->nservers * sizeof(struct server_state));
+  if (!channel->servers)
+    return ARES_ENOMEM;
+
+  for (i = 0; i < num_servers; i++)
+    {
+      struct server_state *ss = channel->servers + i;
+      memset(ss, 0, sizeof(struct server_state));
+
+      ss->channel = channel;
+      ss->addr = malloc(sizeof(struct addrinfo));
+      if (!ss->addr)
+        return ARES_ENOMEM;
+      ss->free_addr = 1;
+      memset(ss->addr, 0, sizeof(struct addrinfo));
+
+      if (servers[i].ss_family == AF_INET)
+        {
+          ss->addr->ai_family = AF_INET;
+          ss->addr->ai_addrlen = sizeof(struct sockaddr_in);
+          ss->addr->ai_addr   =
+            malloc(sizeof(struct sockaddr_in));
+          if (!ss->addr->ai_addr)
+            return ARES_ENOMEM;
+
+          memcpy(ss->addr->ai_addr, (struct sockaddr_in *) &servers[i],
+              sizeof(struct sockaddr_in));
+        }
+      else if (servers[i].ss_family == AF_INET6)
+        {
+          ss->addr->ai_family = AF_INET6;
+          ss->addr->ai_addrlen = sizeof(struct sockaddr_in6);
+          ss->addr->ai_addr   =
+            malloc(sizeof(struct sockaddr_in6));
+          if (!ss->addr->ai_addr)
+            return ARES_ENOMEM;
+
+          memcpy(ss->addr->ai_addr, (struct sockaddr_in6 *) &servers[i],
+              sizeof(struct sockaddr_in6));
+        }
+      else
+        {
+          /* This should never happen */
+          return ARES_EBADFAMILY;
+        }
+    }
+
+  init_servers(channel);
+  return ARES_SUCCESS;
+}
diff --git a/ares_private.h b/ares_private.h
index 4726d7a..0e0bfaf 100644
--- a/ares_private.h
+++ b/ares_private.h
@@ -137,7 +137,9 @@ struct send_request {
 };
 
 struct server_state {
-  struct in_addr addr;
+  struct addrinfo *addr;
+  int    free_addr;
+
   ares_socket_t udp_socket;
   ares_socket_t tcp_socket;
 
@@ -319,6 +321,8 @@ struct timeval ares__tvnow(void);
 int ares__expand_name_for_response(const unsigned char *encoded,
                                    const unsigned char *abuf, int alen,
                                    char **s, long *enclen);
+void ares__free_servers(ares_channel channel);
+
 #if 0 /* Not used */
 long ares__tvdiff(struct timeval t1, struct timeval t2);
 #endif
diff --git a/ares_process.c b/ares_process.c
index 71f9394..5bd16a8 100644
--- a/ares_process.c
+++ b/ares_process.c
@@ -434,7 +434,7 @@ static void read_udp_packets(ares_channel channel, fd_set *read_fds,
   ssize_t count;
   unsigned char buf[PACKETSZ + 1];
 #ifdef HAVE_RECVFROM
-  struct sockaddr_in from;
+  struct sockaddr_storage from;
   ares_socklen_t fromlen;
 #endif
 
@@ -480,16 +480,29 @@ static void read_udp_packets(ares_channel channel, fd_set *read_fds,
         if (count == -1 && try_again(SOCKERRNO))
           continue;
         else if (count <= 0)
-          handle_error(channel, i, now);
+          {
+            handle_error(channel, i, now);
+            break;
+          }
 #ifdef HAVE_RECVFROM
-        else if (from.sin_addr.s_addr != server->addr.s_addr)
-          /* Address response came from did not match the address
-           * we sent the request to.  Someone may be attempting
-           * to perform a cache poisoning attack */
-          break;
+        /* Check if address response came from did match the address
+         * we sent the request to.  Someone may be attempting
+         * to perform a cache poisoning attack */
+        else if (from.ss_family == AF_INET)
+          {
+              if (((struct sockaddr_in *) &from)->sin_addr.s_addr !=
+                  ((struct sockaddr_in *) server->addr->ai_addr)->sin_addr.s_addr)
+                break;
+          }
+        else if (from.ss_family == AF_INET6)
+          {
+              if (memcmp(((struct sockaddr_in6 *) &from)->sin6_addr.s6_addr,
+                         ((struct sockaddr_in6 *) server->addr->ai_addr)->sin6_addr.s6_addr,
+                         16)) /* FIXME - is there any portable constant? */
+                break;
+          }
 #endif
-        else
-          process_answer(channel, buf, (int)count, i, 0, now);
+        process_answer(channel, buf, (int)count, i, 0, now);
        } while (count > 0);
     }
 }
@@ -889,14 +902,36 @@ static int configure_socket(ares_socket_t s, ares_channel channel)
   return 0;
  }
 
+static int addrinfo_set_port(struct addrinfo *addr, int port)
+{
+  int rc = ARES_SUCCESS;
+  const unsigned short sh_port = (unsigned short)(port & 0xffff);
+
+  switch (addr->ai_family)
+    {
+    case AF_INET:
+      ((struct sockaddr_in *) addr->ai_addr)->sin_port = sh_port;
+      break;
+
+    case AF_INET6:
+      ((struct sockaddr_in6 *) addr->ai_addr)->sin6_port = sh_port;
+      break;
+
+    default:
+      rc = ARES_EBADFAMILY;
+      break;
+    }
+
+  return rc;
+}
+
 static int open_tcp_socket(ares_channel channel, struct server_state *server)
 {
   ares_socket_t s;
   int opt;
-  struct sockaddr_in sockin;
 
   /* Acquire a socket. */
-  s = socket(AF_INET, SOCK_STREAM, 0);
+  s = socket(server->addr->ai_family, SOCK_STREAM, 0);
   if (s == ARES_SOCKET_BAD)
     return -1;
 
@@ -923,12 +958,14 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
     }
 #endif
 
+  if (addrinfo_set_port(server->addr, channel->tcp_port) != ARES_SUCCESS)
+    {
+       sclose(s);
+       return -1;
+    }
+
   /* Connect to the server. */
-  memset(&sockin, 0, sizeof(sockin));
-  sockin.sin_family = AF_INET;
-  sockin.sin_addr = server->addr;
-  sockin.sin_port = (unsigned short)(channel->tcp_port & 0xffff);
-  if (connect(s, (struct sockaddr *) &sockin, sizeof(sockin)) == -1)
+  if (connect(s, server->addr->ai_addr, server->addr->ai_addrlen) == -1)
     {
       int err = SOCKERRNO;
 
@@ -960,10 +997,9 @@ static int open_tcp_socket(ares_channel channel, struct server_state *server)
 static int open_udp_socket(ares_channel channel, struct server_state *server)
 {
   ares_socket_t s;
-  struct sockaddr_in sockin;
 
   /* Acquire a socket. */
-  s = socket(AF_INET, SOCK_DGRAM, 0);
+  s = socket(server->addr->ai_family, SOCK_DGRAM, 0);
   if (s == ARES_SOCKET_BAD)
     return -1;
 
@@ -974,12 +1010,14 @@ static int open_udp_socket(ares_channel channel, struct server_state *server)
        return -1;
     }
 
+  if (addrinfo_set_port(server->addr, channel->udp_port) != ARES_SUCCESS)
+    {
+       sclose(s);
+       return -1;
+    }
+
   /* Connect to the server. */
-  memset(&sockin, 0, sizeof(sockin));
-  sockin.sin_family = AF_INET;
-  sockin.sin_addr = server->addr;
-  sockin.sin_port = (unsigned short)(channel->udp_port & 0xffff);
-  if (connect(s, (struct sockaddr *) &sockin, sizeof(sockin)) == -1)
+  if (connect(s, server->addr->ai_addr, server->addr->ai_addrlen) == -1)
     {
       int err = SOCKERRNO;
 
diff --git a/ares_set_nameservers.3 b/ares_set_nameservers.3
new file mode 100644
index 0000000..ca7219d
--- /dev/null
+++ b/ares_set_nameservers.3
@@ -0,0 +1,41 @@
+.TH ARES_SET_SOCKET_CALLBACK 3 "12 Feb 2010"
+.SH NAME
+ares_set_nameservers - Set nameservers
+.SH SYNOPSIS
+.nf
+.B #include <ares.h>
+.PP
+.B int ares_set_nameservers(ares_channel \fIchannel\fP,
+                            struct sockaddr_storage *\fIservers\fP,
+                            int \fInum_servers\fP)
+.PP
+.B cc file.c -lcares
+.fi
+.SH DESCRIPTION
+.PP
+This function sets nameservers for the given ares channel handle.
+The array
+.I servers
+contains the addresses of nameservers, the length of the array
+is stored in the 
+.I num_servers
+parameter.
+Contrary to initializing nameservers with
+.B ares_init_options
+this function can be used to set IPv6 nameservers.
+.PP
+.SH RETURN VALUES
+.B ares_set_nameservers
+can return any of the following values:
+.TP 15
+.B ARES_SUCCESS
+The response was successfully parsed.
+.TP 15
+.B ARES_ENOMEM
+Memory was exhausted.
+.SH SEE ALSO
+.BR ares_init_options (3)
+.SH AUTHOR
+Written by Jakub Hrozek <jhro...@redhat.com>,
+on behalf of Red Hat, Inc http://www.redhat.com
+
-- 
1.6.6

Attachment: 0001-Allow-the-use-of-IPv6-nameservers.patch.sig
Description: PGP signature

Reply via email to