dolugen avatar dolugen committed 42db962

Providing a wrapper for ares_query in gevent. Currently supports NS, MX, TXT records.

Comments (0)

Files changed (7)

c-ares/ares_build.h

+/* ares_build.h.  Generated from ares_build.h.in by configure.  */
 #ifndef __CARES_BUILD_H
 #define __CARES_BUILD_H
 
 
-/* Copyright (C) 2009 - 2010 by Daniel Stenberg et al
+/* Copyright (C) 2009 by Daniel Stenberg et al
  *
  * Permission to use, copy, modify, and distribute this software and its
  * documentation for any purpose and without fee is hereby granted, provided
  * NOTE 1:
  * -------
  *
- * See file ares_build.h.in, run configure, and forget that this file
- * exists it is only used for non-configure systems.
- * But you can keep reading if you want ;-)
- *
- */
-
-/* ================================================================ */
-/*                 NOTES FOR NON-CONFIGURE SYSTEMS                  */
-/* ================================================================ */
-
-/*
- * NOTE 1:
- * -------
- *
  * Nothing in this file is intended to be modified or adjusted by the
  * c-ares library user nor by the c-ares library builder.
  *
  * or fixed in this file, then, report it on the c-ares development
  * mailing list: http://cool.haxx.se/mailman/listinfo/c-ares/
  *
- * Try to keep one section per platform, compiler and architecture,
- * otherwise, if an existing section is reused for a different one and
- * later on the original is adjusted, probably the piggybacking one can
- * be adversely changed.
- *
- * In order to differentiate between platforms/compilers/architectures
- * use only compiler built in predefined preprocessor symbols.
- *
  * This header file shall only export symbols which are 'cares' or 'CARES'
  * prefixed, otherwise public name space would be polluted.
  *
  * NOTE 2:
  * -------
  *
- * Right now you might be staring at file ares_build.h.dist or ares_build.h,
- * this is due to the following reason: file ares_build.h.dist is renamed
- * to ares_build.h when the c-ares source code distribution archive file is
- * created.
- *
- * File ares_build.h.dist is not included in the distribution archive.
- * File ares_build.h is not present in the git tree.
- *
- * The distributed ares_build.h file is only intended to be used on systems
- * which can not run the also distributed configure script.
+ * Right now you might be staring at file ares_build.h.in or ares_build.h,
+ * this is due to the following reason:
  *
  * On systems capable of running the configure script, the configure process
  * will overwrite the distributed ares_build.h file with one that is suitable
  * and specific to the library being configured and built, which is generated
  * from the ares_build.h.in template file.
  *
- * If you check out from git on a non-configure platform, you must run the
- * appropriate buildconf* script to set up ares_build.h and other local files.
- *
  */
 
 /* ================================================================ */
 #endif
 
 /* ================================================================ */
-/*    EXTERNAL INTERFACE SETTINGS FOR NON-CONFIGURE SYSTEMS ONLY    */
+/*  EXTERNAL INTERFACE SETTINGS FOR CONFIGURE CAPABLE SYSTEMS ONLY  */
 /* ================================================================ */
 
-#if defined(__DJGPP__) || defined(__GO32__)
-#  define CARES_SIZEOF_LONG           4
-#  define CARES_TYPEOF_ARES_SOCKLEN_T int
-#  define CARES_SIZEOF_ARES_SOCKLEN_T 4
-
-#elif defined(__SALFORDC__)
-#  define CARES_SIZEOF_LONG           4
-#  define CARES_TYPEOF_ARES_SOCKLEN_T int
-#  define CARES_SIZEOF_ARES_SOCKLEN_T 4
-
-#elif defined(__BORLANDC__)
-#  define CARES_SIZEOF_LONG           4
-#  define CARES_TYPEOF_ARES_SOCKLEN_T int
-#  define CARES_SIZEOF_ARES_SOCKLEN_T 4
-
-#elif defined(__TURBOC__)
-#  define CARES_SIZEOF_LONG           4
-#  define CARES_TYPEOF_ARES_SOCKLEN_T int
-#  define CARES_SIZEOF_ARES_SOCKLEN_T 4
-
-#elif defined(__WATCOMC__)
-#  define CARES_SIZEOF_LONG           4
-#  define CARES_TYPEOF_ARES_SOCKLEN_T int
-#  define CARES_SIZEOF_ARES_SOCKLEN_T 4
-
-#elif defined(__POCC__)
-#  define CARES_SIZEOF_LONG           4
-#  define CARES_TYPEOF_ARES_SOCKLEN_T int
-#  define CARES_SIZEOF_ARES_SOCKLEN_T 4
-
-#elif defined(__LCC__)
-#  define CARES_SIZEOF_LONG           4
-#  define CARES_TYPEOF_ARES_SOCKLEN_T int
-#  define CARES_SIZEOF_ARES_SOCKLEN_T 4
-
-#elif defined(__SYMBIAN32__)
-#  define CARES_SIZEOF_LONG           4
-#  define CARES_TYPEOF_ARES_SOCKLEN_T unsigned int
-#  define CARES_SIZEOF_ARES_SOCKLEN_T 4
-
-#elif defined(__MWERKS__)
-#  define CARES_SIZEOF_LONG           4
-#  define CARES_TYPEOF_ARES_SOCKLEN_T int
-#  define CARES_SIZEOF_ARES_SOCKLEN_T 4
-
-#elif defined(_WIN32_WCE)
-#  define CARES_SIZEOF_LONG           4
-#  define CARES_TYPEOF_ARES_SOCKLEN_T int
-#  define CARES_SIZEOF_ARES_SOCKLEN_T 4
-
-#elif defined(__MINGW32__)
-#  define CARES_SIZEOF_LONG           4
-#  define CARES_TYPEOF_ARES_SOCKLEN_T int
-#  define CARES_SIZEOF_ARES_SOCKLEN_T 4
-
-#elif defined(__VMS)
-#  define CARES_SIZEOF_LONG           4
-#  define CARES_TYPEOF_ARES_SOCKLEN_T unsigned int
-#  define CARES_SIZEOF_ARES_SOCKLEN_T 4
-
-#elif defined(__OS400__)
-#  if defined(__ILEC400__)
-#    define CARES_SIZEOF_LONG           4
-#    define CARES_TYPEOF_ARES_SOCKLEN_T socklen_t
-#    define CARES_SIZEOF_ARES_SOCKLEN_T 4
-#    define CARES_PULL_SYS_TYPES_H      1
-#    define CARES_PULL_SYS_SOCKET_H     1
+/* Configure process defines this to 1 when it finds out that system  */
+/* header file ws2tcpip.h must be included by the external interface. */
+/* #undef CARES_PULL_WS2TCPIP_H */
+#ifdef CARES_PULL_WS2TCPIP_H
+#  ifndef WIN32_LEAN_AND_MEAN
+#    define WIN32_LEAN_AND_MEAN
 #  endif
-
-#elif defined(__MVS__)
-#  if defined(__IBMC__) || defined(__IBMCPP__)
-#    if defined(_ILP32)
-#      define CARES_SIZEOF_LONG           4
-#    elif defined(_LP64)
-#      define CARES_SIZEOF_LONG           8
-#    endif
-#    define CARES_TYPEOF_ARES_SOCKLEN_T socklen_t
-#    define CARES_SIZEOF_ARES_SOCKLEN_T 4
-#    define CARES_PULL_SYS_TYPES_H      1
-#    define CARES_PULL_SYS_SOCKET_H     1
-#  endif
-
-#elif defined(__370__)
-#  if defined(__IBMC__) || defined(__IBMCPP__)
-#    if defined(_ILP32)
-#      define CARES_SIZEOF_LONG           4
-#    elif defined(_LP64)
-#      define CARES_SIZEOF_LONG           8
-#    endif
-#    define CARES_TYPEOF_ARES_SOCKLEN_T socklen_t
-#    define CARES_SIZEOF_ARES_SOCKLEN_T 4
-#    define CARES_PULL_SYS_TYPES_H      1
-#    define CARES_PULL_SYS_SOCKET_H     1
-#  endif
-
-#elif defined(TPF)
-#  define CARES_SIZEOF_LONG           8
-#  define CARES_TYPEOF_ARES_SOCKLEN_T int
-#  define CARES_SIZEOF_ARES_SOCKLEN_T 4
-
-/* ===================================== */
-/*    KEEP MSVC THE PENULTIMATE ENTRY    */
-/* ===================================== */
-
-#elif defined(_MSC_VER)
-#  define CARES_SIZEOF_LONG           4
-#  define CARES_TYPEOF_ARES_SOCKLEN_T int
-#  define CARES_SIZEOF_ARES_SOCKLEN_T 4
-
-/* ===================================== */
-/*    KEEP GENERIC GCC THE LAST ENTRY    */
-/* ===================================== */
-
-#elif defined(__GNUC__)
-#  if defined(__i386__) || defined(__ppc__)
-#    define CARES_SIZEOF_LONG           4
-#  elif defined(__x86_64__) || defined(__ppc64__)
-#    define CARES_SIZEOF_LONG           8
-#  endif
-#  define CARES_TYPEOF_ARES_SOCKLEN_T socklen_t
-#  define CARES_SIZEOF_ARES_SOCKLEN_T 4
-#  define CARES_PULL_SYS_TYPES_H      1
-#  define CARES_PULL_SYS_SOCKET_H     1
-
-#else
-#  error "Unknown non-configure build target!"
-   Error Compilation_aborted_Unknown_non_configure_build_target
+#  include <windows.h>
+#  include <winsock2.h>
+#  include <ws2tcpip.h>
 #endif
 
-/* CARES_PULL_SYS_TYPES_H is defined above when inclusion of header file  */
-/* sys/types.h is required here to properly make type definitions below.  */
+/* Configure process defines this to 1 when it finds out that system   */
+/* header file sys/types.h must be included by the external interface. */
+#define CARES_PULL_SYS_TYPES_H 1
 #ifdef CARES_PULL_SYS_TYPES_H
 #  include <sys/types.h>
 #endif
 
-/* CARES_PULL_SYS_SOCKET_H is defined above when inclusion of header file  */
-/* sys/socket.h is required here to properly make type definitions below.  */
+/* Configure process defines this to 1 when it finds out that system    */
+/* header file sys/socket.h must be included by the external interface. */
+#define CARES_PULL_SYS_SOCKET_H 1
 #ifdef CARES_PULL_SYS_SOCKET_H
 #  include <sys/socket.h>
 #endif
 
+/* The size of `long', as computed by sizeof. */
+#define CARES_SIZEOF_LONG 4
+
+/* Integral data type used for ares_socklen_t. */
+#define CARES_TYPEOF_ARES_SOCKLEN_T socklen_t
+
+/* The size of `ares_socklen_t', as computed by sizeof. */
+#define CARES_SIZEOF_ARES_SOCKLEN_T 4
+
 /* Data type definition of ares_socklen_t. */
-
-#ifdef CARES_TYPEOF_ARES_SOCKLEN_T
-  typedef CARES_TYPEOF_ARES_SOCKLEN_T ares_socklen_t;
-#endif
+typedef CARES_TYPEOF_ARES_SOCKLEN_T ares_socklen_t;
 
 #endif /* __CARES_BUILD_H */

c-ares/ares_parse_mx_reply.c

+
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ * Copyright (C) 2010 Jeremy Lal <kapouer@melix.org>
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ */
+
+#include "ares_setup.h"
+
+#ifdef HAVE_SYS_SOCKET_H
+#  include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#  include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#  include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#  include <arpa/inet.h>
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+#  include <arpa/nameser.h>
+#else
+#  include "nameser.h"
+#endif
+#ifdef HAVE_ARPA_NAMESER_COMPAT_H
+#  include <arpa/nameser_compat.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "ares.h"
+#include "ares_dns.h"
+#include "ares_data.h"
+#include "ares_private.h"
+
+int
+ares_parse_mx_reply (const unsigned char *abuf, int alen,
+                     struct ares_mx_reply **mx_out)
+{
+  unsigned int qdcount, ancount, i;
+  const unsigned char *aptr, *vptr;
+  int status, rr_type, rr_class, rr_len;
+  long len;
+  char *hostname = NULL, *rr_name = NULL;
+  struct ares_mx_reply *mx_head = NULL;
+  struct ares_mx_reply *mx_last = NULL;
+  struct ares_mx_reply *mx_curr;
+
+  /* Set *mx_out to NULL for all failure cases. */
+  *mx_out = NULL;
+
+  /* Give up if abuf doesn't have room for a header. */
+  if (alen < HFIXEDSZ)
+    return ARES_EBADRESP;
+
+  /* Fetch the question and answer count from the header. */
+  qdcount = DNS_HEADER_QDCOUNT (abuf);
+  ancount = DNS_HEADER_ANCOUNT (abuf);
+  if (qdcount != 1)
+    return ARES_EBADRESP;
+  if (ancount == 0)
+    return ARES_ENODATA;
+
+  /* Expand the name from the question, and skip past the question. */
+  aptr = abuf + HFIXEDSZ;
+  status = ares_expand_name (aptr, abuf, alen, &hostname, &len);
+  if (status != ARES_SUCCESS)
+    return status;
+
+  if (aptr + len + QFIXEDSZ > abuf + alen)
+    {
+      free (hostname);
+      return ARES_EBADRESP;
+    }
+  aptr += len + QFIXEDSZ;
+
+  /* Examine each answer resource record (RR) in turn. */
+  for (i = 0; i < ancount; i++)
+    {
+      /* Decode the RR up to the data field. */
+      status = ares_expand_name (aptr, abuf, alen, &rr_name, &len);
+      if (status != ARES_SUCCESS)
+        {
+          break;
+        }
+      aptr += len;
+      if (aptr + RRFIXEDSZ > abuf + alen)
+        {
+          status = ARES_EBADRESP;
+          break;
+        }
+      rr_type = DNS_RR_TYPE (aptr);
+      rr_class = DNS_RR_CLASS (aptr);
+      rr_len = DNS_RR_LEN (aptr);
+      aptr += RRFIXEDSZ;
+
+      /* Check if we are really looking at a MX record */
+      if (rr_class == C_IN && rr_type == T_MX)
+        {
+          /* parse the MX record itself */
+          if (rr_len < 2)
+            {
+              status = ARES_EBADRESP;
+              break;
+            }
+
+          /* Allocate storage for this MX answer appending it to the list */
+          mx_curr = ares_malloc_data(ARES_DATATYPE_MX_REPLY);
+          if (!mx_curr)
+            {
+              status = ARES_ENOMEM;
+              break;
+            }
+          if (mx_last)
+            {
+              mx_last->next = mx_curr;
+            }
+          else
+            {
+              mx_head = mx_curr;
+            }
+          mx_last = mx_curr;
+
+          vptr = aptr;
+          mx_curr->priority = DNS__16BIT(vptr);
+          vptr += sizeof(unsigned short);
+
+          status = ares_expand_name (vptr, abuf, alen, &mx_curr->host, &len);
+          if (status != ARES_SUCCESS)
+            break;
+        }
+
+      /* Don't lose memory in the next iteration */
+      free (rr_name);
+      rr_name = NULL;
+
+      /* Move on to the next record */
+      aptr += rr_len;
+    }
+
+  if (hostname)
+    free (hostname);
+  if (rr_name)
+    free (rr_name);
+
+  /* clean up on error */
+  if (status != ARES_SUCCESS)
+    {
+      if (mx_head)
+        ares_free_data (mx_head);
+      return status;
+    }
+
+  /* everything looks fine, return the data */
+  *mx_out = mx_head;
+
+  return ARES_SUCCESS;
+}

c-ares/ares_parse_ns_reply.c

+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ */
+
+/*
+ * ares_parse_ns_reply created by Vlad Dinulescu <vlad.dinulescu@avira.com>
+ *      on behalf of AVIRA Gmbh - http://www.avira.com
+ */
+
+#include "ares_setup.h"
+
+#ifdef HAVE_SYS_SOCKET_H
+#  include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#  include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#  include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#  include <arpa/inet.h>
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+#  include <arpa/nameser.h>
+#else
+#  include "nameser.h"
+#endif
+#ifdef HAVE_ARPA_NAMESER_COMPAT_H
+#  include <arpa/nameser_compat.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include "ares.h"
+#include "ares_dns.h"
+#include "ares_private.h"
+
+int ares_parse_ns_reply( const unsigned char* abuf, int alen,
+                         struct hostent** host )
+{
+  unsigned int qdcount, ancount;
+  int status, i, rr_type, rr_class, rr_len;
+  int nameservers_num;
+  long len;
+  const unsigned char *aptr;
+  char* hostname, *rr_name, *rr_data, **nameservers;
+  struct hostent *hostent;
+
+  /* Set *host to NULL for all failure cases. */
+  *host = NULL;
+
+  /* Give up if abuf doesn't have room for a header. */
+  if ( alen < HFIXEDSZ )
+    return ARES_EBADRESP;
+
+  /* Fetch the question and answer count from the header. */
+  qdcount = DNS_HEADER_QDCOUNT( abuf );
+  ancount = DNS_HEADER_ANCOUNT( abuf );
+  if ( qdcount != 1 )
+    return ARES_EBADRESP;
+
+  /* Expand the name from the question, and skip past the question. */
+  aptr = abuf + HFIXEDSZ;
+  status = ares__expand_name_for_response( aptr, abuf, alen, &hostname, &len);
+  if ( status != ARES_SUCCESS )
+    return status;
+  if ( aptr + len + QFIXEDSZ > abuf + alen )
+  {
+    free( hostname );
+    return ARES_EBADRESP;
+  }
+  aptr += len + QFIXEDSZ;
+
+  /* Allocate nameservers array; ancount gives an upper bound */
+  nameservers = malloc( ( ancount + 1 ) * sizeof( char * ) );
+  if ( !nameservers )
+  {
+    free( hostname );
+    return ARES_ENOMEM;
+  }
+  nameservers_num = 0;
+
+  /* Examine each answer resource record (RR) in turn. */
+  for ( i = 0; i < ( int ) ancount; i++ )
+  {
+    /* Decode the RR up to the data field. */
+    status = ares__expand_name_for_response( aptr, abuf, alen, &rr_name, &len );
+    if ( status != ARES_SUCCESS )
+      break;
+    aptr += len;
+    if ( aptr + RRFIXEDSZ > abuf + alen )
+    {
+      status = ARES_EBADRESP;
+      free(rr_name);
+      break;
+    }
+    rr_type = DNS_RR_TYPE( aptr );
+    rr_class = DNS_RR_CLASS( aptr );
+    rr_len = DNS_RR_LEN( aptr );
+    aptr += RRFIXEDSZ;
+
+    if ( rr_class == C_IN && rr_type == T_NS )
+    {
+      /* Decode the RR data and add it to the nameservers list */
+      status = ares__expand_name_for_response( aptr, abuf, alen, &rr_data,
+                                               &len);
+      if ( status != ARES_SUCCESS )
+      {
+        free(rr_name);
+        break;
+      }
+
+      nameservers[nameservers_num] = malloc(strlen(rr_data)+1);
+
+      if (nameservers[nameservers_num]==NULL)
+      {
+        free(rr_name);
+        free(rr_data);
+        status=ARES_ENOMEM;
+        break;
+      }
+      strcpy(nameservers[nameservers_num],rr_data);
+      free(rr_data);
+
+      nameservers_num++;
+    }
+
+    free( rr_name );
+
+    aptr += rr_len;
+    if ( aptr > abuf + alen )
+    {
+      status = ARES_EBADRESP;
+      break;
+    }
+  }
+
+  if ( status == ARES_SUCCESS && nameservers_num == 0 )
+  {
+    status = ARES_ENODATA;
+  }
+  if ( status == ARES_SUCCESS )
+  {
+    /* We got our answer.  Allocate memory to build the host entry. */
+    nameservers[nameservers_num] = NULL;
+    hostent = malloc( sizeof( struct hostent ) );
+    if ( hostent )
+    {
+      hostent->h_addr_list = malloc( 1 * sizeof( char * ) );
+      if ( hostent->h_addr_list )
+      {
+        /* Fill in the hostent and return successfully. */
+        hostent->h_name = hostname;
+        hostent->h_aliases = nameservers;
+        hostent->h_addrtype = AF_INET;
+        hostent->h_length = sizeof( struct in_addr );
+        hostent->h_addr_list[0] = NULL;
+        *host = hostent;
+        return ARES_SUCCESS;
+      }
+      free( hostent );
+    }
+    status = ARES_ENOMEM;
+  }
+  for ( i = 0; i < nameservers_num; i++ )
+    free( nameservers[i] );
+  free( nameservers );
+  free( hostname );
+  return status;
+}

c-ares/ares_parse_txt_reply.c

+
+/* Copyright 1998 by the Massachusetts Institute of Technology.
+ * Copyright (C) 2009 by Jakub Hrozek <jhrozek@redhat.com>
+ *
+ * Permission to use, copy, modify, and distribute this
+ * software and its documentation for any purpose and without
+ * fee is hereby granted, provided that the above copyright
+ * notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting
+ * documentation, and that the name of M.I.T. not be used in
+ * advertising or publicity pertaining to distribution of the
+ * software without specific, written prior permission.
+ * M.I.T. makes no representations about the suitability of
+ * this software for any purpose.  It is provided "as is"
+ * without express or implied warranty.
+ */
+
+#include "ares_setup.h"
+
+#ifdef HAVE_SYS_SOCKET_H
+#  include <sys/socket.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#  include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#  include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#  include <arpa/inet.h>
+#endif
+#ifdef HAVE_ARPA_NAMESER_H
+#  include <arpa/nameser.h>
+#else
+#  include "nameser.h"
+#endif
+#ifdef HAVE_ARPA_NAMESER_COMPAT_H
+#  include <arpa/nameser_compat.h>
+#endif
+
+#ifdef HAVE_STRINGS_H
+#  include <strings.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "ares.h"
+#include "ares_dns.h"
+#include "ares_data.h"
+#include "ares_private.h"
+
+int
+ares_parse_txt_reply (const unsigned char *abuf, int alen,
+                      struct ares_txt_reply **txt_out)
+{
+  size_t substr_len, str_len;
+  unsigned int qdcount, ancount, i;
+  const unsigned char *aptr;
+  const unsigned char *strptr;
+  int status, rr_type, rr_class, rr_len;
+  long len;
+  char *hostname = NULL, *rr_name = NULL;
+  struct ares_txt_reply *txt_head = NULL;
+  struct ares_txt_reply *txt_last = NULL;
+  struct ares_txt_reply *txt_curr;
+
+  /* Set *txt_out to NULL for all failure cases. */
+  *txt_out = NULL;
+
+  /* Give up if abuf doesn't have room for a header. */
+  if (alen < HFIXEDSZ)
+    return ARES_EBADRESP;
+
+  /* Fetch the question and answer count from the header. */
+  qdcount = DNS_HEADER_QDCOUNT (abuf);
+  ancount = DNS_HEADER_ANCOUNT (abuf);
+  if (qdcount != 1)
+    return ARES_EBADRESP;
+  if (ancount == 0)
+    return ARES_ENODATA;
+
+  /* Expand the name from the question, and skip past the question. */
+  aptr = abuf + HFIXEDSZ;
+  status = ares_expand_name (aptr, abuf, alen, &hostname, &len);
+  if (status != ARES_SUCCESS)
+    return status;
+
+  if (aptr + len + QFIXEDSZ > abuf + alen)
+    {
+      free (hostname);
+      return ARES_EBADRESP;
+    }
+  aptr += len + QFIXEDSZ;
+
+  /* Examine each answer resource record (RR) in turn. */
+  for (i = 0; i < ancount; i++)
+    {
+      /* Decode the RR up to the data field. */
+      status = ares_expand_name (aptr, abuf, alen, &rr_name, &len);
+      if (status != ARES_SUCCESS)
+        {
+          break;
+        }
+      aptr += len;
+      if (aptr + RRFIXEDSZ > abuf + alen)
+        {
+          status = ARES_EBADRESP;
+          break;
+        }
+      rr_type = DNS_RR_TYPE (aptr);
+      rr_class = DNS_RR_CLASS (aptr);
+      rr_len = DNS_RR_LEN (aptr);
+      aptr += RRFIXEDSZ;
+
+      /* Check if we are really looking at a TXT record */
+      if (rr_class == C_IN && rr_type == T_TXT)
+        {
+          /* Allocate storage for this TXT answer appending it to the list */
+          txt_curr = ares_malloc_data(ARES_DATATYPE_TXT_REPLY);
+          if (!txt_curr)
+            {
+              status = ARES_ENOMEM;
+              break;
+            }
+          if (txt_last)
+            {
+              txt_last->next = txt_curr;
+            }
+          else
+            {
+              txt_head = txt_curr;
+            }
+          txt_last = txt_curr;
+
+          /*
+           * There may be multiple substrings in a single TXT record. Each
+           * substring may be up to 255 characters in length, with a
+           * "length byte" indicating the size of the substring payload.
+           * RDATA contains both the length-bytes and payloads of all
+           * substrings contained therein.
+           */
+
+          /* Compute total length to allow a single memory allocation */
+          strptr = aptr;
+          while (strptr < (aptr + rr_len))
+            {
+              substr_len = (unsigned char)*strptr;
+              txt_curr->length += substr_len;
+              strptr += substr_len + 1;
+            }
+
+          /* Including null byte */
+          txt_curr->txt = malloc (txt_curr->length + 1);
+          if (txt_curr->txt == NULL)
+            {
+              status = ARES_ENOMEM;
+              break;
+            }
+
+          /* Step through the list of substrings, concatenating them */
+          str_len = 0;
+          strptr = aptr;
+          while (strptr < (aptr + rr_len))
+            {
+              substr_len = (unsigned char)*strptr;
+              strptr++;
+              memcpy ((char *) txt_curr->txt + str_len, strptr, substr_len);
+              str_len += substr_len;
+              strptr += substr_len;
+            }
+          /* Make sure we NULL-terminate */
+          *((char *) txt_curr->txt + txt_curr->length) = '\0';
+        }
+
+      /* Don't lose memory in the next iteration */
+      free (rr_name);
+      rr_name = NULL;
+
+      /* Move on to the next record */
+      aptr += rr_len;
+    }
+
+  if (hostname)
+    free (hostname);
+  if (rr_name)
+    free (rr_name);
+
+  /* clean up on error */
+  if (status != ARES_SUCCESS)
+    {
+      if (txt_head)
+        ares_free_data (txt_head);
+      return status;
+    }
+
+  /* everything looks fine, return the data */
+  *txt_out = txt_head;
+
+  return ARES_SUCCESS;
+}
         char* h_name
         int h_addrtype
 
+    struct ares_mx_reply:
+        ares_mx_reply* next
+        char* host
+        int priority
+    
+    struct ares_txt_reply:
+        ares_txt_reply* next
+        char* txt
+        int length
+
     object parse_h_aliases(hostent*)
     object parse_h_addr_list(hostent*)
     void* create_object_from_hostent(void*)
 ARES_FLAG_NOALIASES = cares.ARES_FLAG_NOALIASES
 ARES_FLAG_NOCHECKRESP = cares.ARES_FLAG_NOCHECKRESP
 
+'''
+T_NS = cares.T_NS
+T_MX = cares.T_MX
+T_TXT = cares.T_TXT
+'''
+T_NS = 2
+T_MX = 15
+T_TXT = 16
+
 
 _ares_errors = dict([
                 (cares.ARES_SUCCESS, 'ARES_SUCCESS'),
             return default
     raise get_socket_gaierror()(-1, "Bad value for ai_flags: 0x%x" % flags)
 
+cdef _parse_reply(char* abuf, int alen, int rtype):
+    cdef hostent* host
+    cdef ares_mx_reply* mx_out
+    cdef ares_mx_reply* tmp_mx_out
+    cdef ares_txt_reply* txt_out
+    cdef ares_txt_reply* tmp_txt_out
+
+    if rtype == T_NS:
+        cares.ares_parse_ns_reply(abuf, alen, &host)
+        return (host.h_name, sorted(parse_h_aliases(host)))
+    elif rtype == T_MX:
+        cares.ares_parse_mx_reply(abuf, alen, &mx_out)
+        mx_records = []
+        tmp_mx_out = mx_out
+        while tmp_mx_out != NULL:
+            mx_records.append((tmp_mx_out.host, tmp_mx_out.priority))
+            tmp_mx_out = tmp_mx_out.next
+        return sorted(mx_records)
+    elif rtype == T_TXT:
+        cares.ares_parse_txt_reply(abuf, alen, &txt_out)
+        return txt_out.txt, txt_out.length
+    else:
+        return
 
 cpdef strerror(code):
     return '%s: %s' % (_ares_errors.get(code) or code, cares.ares_strerror(code))
     except:
         channel.loop.handle_error(callback, *sys.exc_info())
 
+cdef void gevent_ares_query_callback(void *arg, int status, int timeouts, char* abuf, int alen):
+    cdef channel channel
+    cdef object callback
+
+    channel, callback, rtype = <tuple>arg
+    Py_DECREF(<PyObjectPtr>arg)
+    cdef object query_result
+    try:
+        if status:
+            callback(result(None, get_socket_gaierror()(status, strerror(status))))
+        else:
+            try:
+                query_result = _parse_reply(abuf, alen, rtype)
+            except:
+                callback(result(None, sys.exc_info()[1]))
+            else:
+                callback(result(query_result))
+    except:
+        channel.loop.handle_error(callback, *sys.exc_info())
+
 
 cdef public class channel [object PyGeventAresChannelObject, type PyGeventAresChannel_Type]:
 
 
     def getnameinfo(self, object callback, tuple sockaddr, int flags):
         return self._getnameinfo(callback, sockaddr, _convert_cares_flags(flags))
+    
+    def query(self, object callback, char* name, int dnsclass, int rtype): 
+        if not self.channel:
+            raise get_socket_gaierror()(cares.ARES_EDESTRUCTION, 'this ares channel has been destroyed')
+        cdef object arg = (self, callback, rtype)
+        Py_INCREF(<PyObjectPtr>arg)
+        cares.ares_query(self.channel, name, dnsclass, rtype, <void*>gevent_ares_query_callback, <void*>arg)
     void ares_destroy(void *channelptr)
     void ares_gethostbyname(void* channel, char *name, int family, void* callback, void *arg)
     void ares_gethostbyaddr(void* channel, void *addr, int addrlen, int family, void* callback, void *arg)
+    void ares_query(void* channel, char *name, int dnsclass, int rtype, void* callback, void* arg)
     void ares_process_fd(void* channel, int read_fd, int write_fd)
     char* ares_strerror(int code)
     void ares_cancel(void* channel)
     void ares_getnameinfo(void* channel, void* sa, int salen, int flags, void* callback, void *arg)
+    int ares_parse_ns_reply( char* abuf, int alen, void* host )
+    int ares_parse_mx_reply( char* abuf, int alen, void* mx_out )
+    int ares_parse_txt_reply( char* abuf, int alen, void* txt_out )
 
     struct in_addr:
         pass
 
 cdef extern from "cares_pton.h":
     int ares_inet_pton(int af, char *src, void *dst)
+
+cdef extern from "nameser.h":
+
+    int T_NS
+    int T_MX
+    int T_TXT
+

gevent/resolver_ares.py

 
 __all__ = ['Resolver']
 
+rtypes = {'ns': 2,
+          'mx': 15,
+          'txt': 16
+          }
+
 
 class Resolver(object):
 
             except gaierror:
                 if ares is self.ares:
                     raise
+    
+    def _query(self, name, rtype, dnsclass=1):
+        waiter = Waiter(self.hub)
+        self.ares.query(waiter, name, dnsclass, rtype)
+        try:
+            return waiter.get()
+        except:
+            raise
+
+    def query(self, name, rtype, dnsclass=1):
+        while True:
+            ares = self.ares
+            try:
+                return self._query(name, rtypes[rtype], dnsclass)
+            except gaierror:
+                if ares is self.ares:
+                    raise
 
 
 class Values(object):
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.