This is the mail archive of the glibc-cvs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GNU C Library master sources branch master updated. glibc-2.25-663-g352f4ff


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, master has been updated
       via  352f4ff9a268b81ef5d4b2413f582565806e4790 (commit)
      from  4e45d83c92dbb5b8dc20654f32395108d18cf739 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=352f4ff9a268b81ef5d4b2413f582565806e4790

commit 352f4ff9a268b81ef5d4b2413f582565806e4790
Author: Florian Weimer <fweimer@redhat.com>
Date:   Fri Jun 30 21:10:23 2017 +0200

    resolv: Introduce struct resolv_context [BZ #21668]
    
    struct resolv_context objects provide a temporary resolver context
    which does not change during a name lookup operation.  Only when the
    outmost context is created, the stub resolver configuration is
    verified to be current (at present, only against previous res_init
    calls).  Subsequent attempts to obtain the context will reuse the
    result of the initial verification operation.
    
    struct resolv_context can also be extended in the future to store
    data which needs to be deallocated during thread cancellation.

diff --git a/ChangeLog b/ChangeLog
index 74dc23e..edd0e69 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,88 @@
+2017-06-30  Florian Weimer  <fweimer@redhat.com>
+
+	[BZ #21668]
+	Introduce temporary resolver contexts (struct resolv_conf).
+	* resolv/resolv-internal.h (__res_context_mkquery)
+	(__res_context_searchl __res_context_query, __res_context_send)
+	(__res_context_hostalias): Declare.
+	(__res_nopt): Switch to struct resolv_context.
+	* resolv/res_use_inet6.h: New file.
+	* resolv/resolv_context.h: Likewise.
+	* resolv/resolv_context.c: Likewise.
+	* resolv/compat-gethnamaddr.c (res_gethostbyname2_context):
+	Renamed from res_gethostbyname2.  Use struct resolv_context.
+	(res_gethostbyname2): New function.  Implement using
+	res_gethostbyname2_context.
+	(res_gethostbyaddr_context): Renamed from res_gethostbyaddr.  Use
+	struct resolv_context.
+	(res_gethostbyaddr): New function.  Implement using
+	res_gethostbyaddr_context.
+	* resolv/nss_dns/dns-canon.c (_nss_dns_getcanonname_r): Use struct
+	resolv_context.
+	* resolv/nss_dns/dns-host.c (gethostbyname3_context): Renamed from
+	_nss_dns_gethostbyname3_r.  Use struct resolv_context.
+	(_nss_dns_gethostbyname3_r): Implement using gethostbyname3_context.
+	(_nss_dns_gethostbyname_r, _nss_dns_gethostbyname4_r): Likewise.
+	(_nss_dns_gethostbyaddr2_r): Use struct resolv_context.
+	* resolv/nss_dns/dns-network.c (_nss_dns_getnetbyname_r)
+	(_nss_dns_getnetbyaddr_r): Likewise.
+	* resolv/res-close.c (res_thread_freeres): Call
+	__resolv_context_freeres.
+	* resolv/res_libc.c (__res_maybe_init): Remove function.  Moved to
+	maybe_init in resolv/resolv_context.c.
+	* resolv/res_mkquery.c (__res_context_mkquery): Rename from
+	res_nmkquery.  Use struct resolv_context.
+	(context_mkquery_common): New function.
+	(res_nmkquery, res_mkquery): Use it.
+	(res_nopt): Switch to struct resolv_context.
+	* resolv/res_query.c (__res_context_querydomain): Renamed from
+	__libc_res_nquerydomain.  Use struct resolv_context.
+	(__res_context_query): Renamed from __libc_res_nquery.  Use struct
+	resolv_context.
+	(context_query_common): New function.
+	(res_nquery, res_query): Use it.
+	(__res_context_search): Renamed from __libc_res_nsearch.  Use
+	struct resolv_context.
+	(context_search_common): New function.
+	(res_nsearch, res_search): Use it.
+	(__res_context_querydomain): Rename from __libc_res_nquerydomain.
+	Use struct resolv_context.
+	(context_querydomain_common): New function.
+	(res_nquerydomain, res_querydomain): Use it.
+	(__res_context_hostalias): Rename from res_hostalias.  Use struct
+	resolv_context.
+	(context_hostalias_common): New function.
+	(res_hostalias, hostalias): Use it.
+	* resolv/res_send.c (__res_context_send): Renamed from
+	__libc_res_nsend.  Use struct resolv_context.
+	(context_send_common): New function.
+	(res_nsend, res_send): Use it.
+	* resolv/Makefile (routines): Add resolv_context.
+	* resolv/Versions (libc): Export __resolv_context_get,
+	__resolv_context_get_preinit, __resolv_context_get_override,
+	__resolv_context_put.  Remove __res_maybe_init.
+	(libresolv): Export __res_context_query, __res_context_search,
+	__res_context_hostalias.  Remove __libc_res_nquery,
+	__libc_res_nsearch.
+	* include/resolv.h (__res_maybe_init, __libc_res_nquery)
+	(__libc_res_nsearch, __libc_res_nsend): Remove declaration.
+	(__hostalias, __res_nmkquery, __res_nquery, __res_nquerydomain)
+	(__res_hostalias, __res_nsearch, __res_nsend): Remove hidden
+	prototypes.
+	* nss/nsswitch.h (__nss_hostname_digits_dots_context): Declare.
+	* nss/digits_dots.c (__nss_hostname_digits_dots_context): Renamed
+	from __nss_hostname_digits_dots.  Use struct resolv_context.
+	(__nss_hostname_digits_dots): New function.
+	* nss/getXXbyYY.c [HANDLE_DIGITS_DOTS] (FUNCTION_NAME): Acquire
+	struct resolv_context object.  Call new function
+	__nss_hostname_digits_dots_context.
+	* nss/getXXbyYY_r.c (REENTRANT_NAME): Use struct resolv_context.
+	* nss/getnssent_r.c (__nss_setent): Likewise.
+	* nscd/aicache.c (addhstaiX): Use struct resolv_context,
+	__resolv_context_disable_inet6 and __resolv_context_enable_inet6
+	instead of direct _res manipulation.
+	* sysdeps/posix/getaddrinfo.c (gethosts, gaih_inet): Likewise.
+
 2017-07-03  Florian Weimer  <fweimer@redhat.com>
 
 	* resolv/tst-resolv-res_init-skeleton.c
diff --git a/include/resolv.h b/include/resolv.h
index 2938506..634f552 100644
--- a/include/resolv.h
+++ b/include/resolv.h
@@ -24,7 +24,6 @@ extern __thread struct __res_state *__resp attribute_tls_model_ie;
 
 /* Now define the internal interfaces.  */
 extern int __res_vinit (res_state, int) attribute_hidden;
-extern int __res_maybe_init (res_state, int);
 extern void _sethtent (int);
 extern struct hostent *_gethtent (void);
 extern struct hostent *_gethtbyname (const char *__name);
@@ -36,24 +35,11 @@ extern int res_ourserver_p (const res_state __statp,
 			    const struct sockaddr_in6 *__inp);
 extern void __res_iclose (res_state statp, bool free_addr);
 libc_hidden_proto (__res_ninit)
-libc_hidden_proto (__res_maybe_init)
 libc_hidden_proto (__res_nclose)
 libc_hidden_proto (__res_iclose)
 libc_hidden_proto (__res_randomid)
 libc_hidden_proto (__res_state)
 
-int __libc_res_nquery (res_state, const char *, int, int,
-		       unsigned char *, int, unsigned char **,
-		       unsigned char **, int *, int *, int *);
-int __libc_res_nsearch (res_state, const char *, int, int,
-			unsigned char *, int, unsigned char **,
-			unsigned char **, int *, int *, int *);
-int __libc_res_nsend (res_state, const unsigned char *, int,
-		      const unsigned char *, int, unsigned char *,
-		      int, unsigned char **, unsigned char **,
-		      int *, int *, int *)
-  attribute_hidden;
-
 libresolv_hidden_proto (_sethtent)
 libresolv_hidden_proto (_gethtent)
 libresolv_hidden_proto (_gethtbyaddr)
@@ -75,17 +61,8 @@ libresolv_hidden_proto (__p_type)
 libresolv_hidden_proto (__loc_ntoa)
 libresolv_hidden_proto (__fp_nquery)
 libresolv_hidden_proto (__fp_query)
-libresolv_hidden_proto (__hostalias)
-libresolv_hidden_proto (__res_nmkquery)
-libresolv_hidden_proto (__libc_res_nquery)
-libresolv_hidden_proto (__res_nquery)
-libresolv_hidden_proto (__res_nquerydomain)
-libresolv_hidden_proto (__res_hostalias)
-libresolv_hidden_proto (__libc_res_nsearch)
-libresolv_hidden_proto (__res_nsearch)
 libresolv_hidden_proto (__res_nameinquery)
 libresolv_hidden_proto (__res_queriesmatch)
-libresolv_hidden_proto (__res_nsend)
 libresolv_hidden_proto (__b64_ntop)
 libresolv_hidden_proto (__dn_count_labels)
 libresolv_hidden_proto (__p_secstodate)
diff --git a/nscd/aicache.c b/nscd/aicache.c
index f1f9284..a3de792 100644
--- a/nscd/aicache.c
+++ b/nscd/aicache.c
@@ -26,6 +26,8 @@
 #include <unistd.h>
 #include <sys/mman.h>
 #include <resolv/resolv-internal.h>
+#include <resolv/resolv_context.h>
+#include <resolv/res_use_inet6.h>
 
 #include "dbg_log.h"
 #include "nscd.h"
@@ -100,17 +102,15 @@ addhstaiX (struct database_dyn *db, int fd, request_header *req,
     no_more = 0;
   nip = hosts_database;
 
-  /* Initialize configurations.  */
-  if (__res_maybe_init (&_res, 0) == -1)
+  /* Initialize configurations.  If we are looking for both IPv4 and
+     IPv6 address we don't want the lookup functions to automatically
+     promote IPv4 addresses to IPv6 addresses.  Therefore, use the
+     _no_inet6 variant.  */
+  struct resolv_context *ctx = __resolv_context_get ();
+  bool enable_inet6 = __resolv_context_disable_inet6 (ctx);
+  if (ctx == NULL)
     no_more = 1;
 
-  /* If we are looking for both IPv4 and IPv6 address we don't want
-     the lookup functions to automatically promote IPv4 addresses to
-     IPv6 addresses.  Currently this is decided by setting the
-     RES_USE_INET6 bit in _res.options.  */
-  int old_res_options = _res.options;
-  _res.options &= ~DEPRECATED_RES_USE_INET6;
-
   size_t tmpbuf6len = 1024;
   char *tmpbuf6 = alloca (tmpbuf6len);
   size_t tmpbuf4len = 0;
@@ -534,7 +534,8 @@ next_nip:
    }
 
  out:
-  _res.options |= old_res_options & DEPRECATED_RES_USE_INET6;
+  __resolv_context_enable_inet6 (ctx, enable_inet6);
+  __resolv_context_put (ctx);
 
   if (dataset != NULL && !alloca_used)
     {
diff --git a/nss/digits_dots.c b/nss/digits_dots.c
index 8dcbf9e..0c1fa97 100644
--- a/nss/digits_dots.c
+++ b/nss/digits_dots.c
@@ -23,6 +23,7 @@
 #include <ctype.h>
 #include <wctype.h>
 #include <resolv/resolv-internal.h>
+#include <resolv/resolv_context.h>
 #include <netdb.h>
 #include <arpa/inet.h>
 #include "nsswitch.h"
@@ -38,11 +39,10 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf,
 			    size_t buflen, struct hostent **result,
 			    enum nss_status *status, int af, int *h_errnop)
 {
-  int save;
-
   /* We have to test for the use of IPv6 which can only be done by
      examining `_res'.  */
-  if (__res_maybe_init (&_res, 0) == -1)
+  struct resolv_context *ctx = __resolv_context_get ();
+  if (ctx == NULL)
     {
       if (h_errnop)
 	*h_errnop = NETDB_INTERNAL;
@@ -52,6 +52,21 @@ __nss_hostname_digits_dots (const char *name, struct hostent *resbuf,
 	*result = NULL;
       return -1;
     }
+  int ret = __nss_hostname_digits_dots_context
+    (ctx, name, resbuf, buffer, buffer_size, buflen,
+     result, status, af, h_errnop);
+  __resolv_context_put (ctx);
+  return ret;
+}
+
+int
+__nss_hostname_digits_dots_context (struct resolv_context *ctx,
+				    const char *name, struct hostent *resbuf,
+				    char **buffer, size_t *buffer_size,
+				    size_t buflen, struct hostent **result,
+				    enum nss_status *status, int af, int *h_errnop)
+{
+  int save;
 
   /*
    * disallow names consisting only of digits/dots, unless
diff --git a/nss/getXXbyYY.c b/nss/getXXbyYY.c
index d027b14..a439b81 100644
--- a/nss/getXXbyYY.c
+++ b/nss/getXXbyYY.c
@@ -47,6 +47,11 @@
 |*								   *|
 \*******************************************************************/
 
+
+#ifdef HANDLE_DIGITS_DOTS
+# include <resolv/resolv_context.h>
+#endif
+
 /* To make the real sources a bit prettier.  */
 #define REENTRANT_NAME APPEND_R (FUNCTION_NAME)
 #define APPEND_R(name) APPEND_R1 (name)
@@ -93,6 +98,19 @@ FUNCTION_NAME (ADD_PARAMS)
   int h_errno_tmp = 0;
 #endif
 
+#ifdef HANDLE_DIGITS_DOTS
+  /* Wrap both __nss_hostname_digits_dots and the actual lookup
+     function call in the same context.  */
+  struct resolv_context *res_ctx = __resolv_context_get ();
+  if (res_ctx == NULL)
+    {
+# if NEED_H_ERRNO
+      __set_h_errno (NETDB_INTERNAL);
+# endif
+      return NULL;
+    }
+#endif
+
   /* Get lock.  */
   __libc_lock_lock (lock);
 
@@ -105,9 +123,9 @@ FUNCTION_NAME (ADD_PARAMS)
 #ifdef HANDLE_DIGITS_DOTS
   if (buffer != NULL)
     {
-      if (__nss_hostname_digits_dots (name, &resbuf, &buffer,
-				      &buffer_size, 0, &result, NULL, AF_VAL,
-				      H_ERRNO_VAR_P))
+      if (__nss_hostname_digits_dots_context
+	  (res_ctx, name, &resbuf, &buffer, &buffer_size, 0, &result, NULL,
+	   AF_VAL, H_ERRNO_VAR_P))
 	goto done;
     }
 #endif
@@ -143,6 +161,10 @@ done:
   /* Release lock.  */
   __libc_lock_unlock (lock);
 
+#ifdef HANDLE_DIGITS_DOTS
+  __resolv_context_put (res_ctx);
+#endif
+
 #ifdef NEED_H_ERRNO
   if (h_errno_tmp != 0)
     __set_h_errno (h_errno_tmp);
diff --git a/nss/getXXbyYY_r.c b/nss/getXXbyYY_r.c
index 7cab825..6c547ea 100644
--- a/nss/getXXbyYY_r.c
+++ b/nss/getXXbyYY_r.c
@@ -26,7 +26,7 @@
 # include <nscd/nscd_proto.h>
 #endif
 #ifdef NEED__RES
-# include <resolv.h>
+# include <resolv/resolv_context.h>
 #endif
 /*******************************************************************\
 |* Here we assume several symbols to be defined:		   *|
@@ -53,8 +53,7 @@
 |* NEED_H_ERRNO  - an extra parameter will be passed to point to   *|
 |*		   the global `h_errno' variable.		   *|
 |*								   *|
-|* NEED__RES     - the global _res variable might be used so we	   *|
-|*		   will have to initialize it if necessary	   *|
+|* NEED__RES     - obtain a struct resolv_context resolver context *|
 |*								   *|
 |* PREPROCESS    - code run before anything else		   *|
 |*								   *|
@@ -213,6 +212,18 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
   bool any_service = false;
 #endif
 
+#ifdef NEED__RES
+  /* The HANDLE_DIGITS_DOTS case below already needs the resolver
+     configuration, so this has to happen early.  */
+  struct resolv_context *res_ctx = __resolv_context_get ();
+  if (res_ctx == NULL)
+    {
+      *h_errnop = NETDB_INTERNAL;
+      *result = NULL;
+      return errno;
+    }
+#endif /* NEED__RES */
+
 #ifdef PREPROCESS
   PREPROCESS;
 #endif
@@ -260,17 +271,6 @@ INTERNAL (REENTRANT_NAME) (ADD_PARAMS, LOOKUP_TYPE *resbuf, char *buffer,
 	}
       else
 	{
-#ifdef NEED__RES
-	  /* The resolver code will really be used so we have to
-	     initialize it.  */
-	  if (__res_maybe_init (&_res, 0) == -1)
-	    {
-	      *h_errnop = NETDB_INTERNAL;
-	      *result = NULL;
-	      return errno;
-	    }
-#endif /* need _res */
-
 	  void *tmp_ptr = fct.l;
 #ifdef PTR_MANGLE
 	  PTR_MANGLE (tmp_ptr);
@@ -399,6 +399,12 @@ done:
   POSTPROCESS;
 #endif
 
+#ifdef NEED__RES
+  /* This has to happen late because the POSTPROCESS stage above might
+     need the resolver context.  */
+  __resolv_context_put (res_ctx);
+#endif /* NEED__RES */
+
   int res;
   if (status == NSS_STATUS_SUCCESS || status == NSS_STATUS_NOTFOUND)
     res = 0;
diff --git a/nss/getnssent_r.c b/nss/getnssent_r.c
index 5fdbf3b..d85065b 100644
--- a/nss/getnssent_r.c
+++ b/nss/getnssent_r.c
@@ -18,6 +18,7 @@
 #include <errno.h>
 #include <netdb.h>
 #include "nsswitch.h"
+#include <resolv/resolv_context.h>
 
 /* Set up NIP to run through the services.  If ALL is zero, use NIP's
    current location if it's not nil.  Return nonzero if there are no
@@ -59,10 +60,15 @@ __nss_setent (const char *func_name, db_lookup_function lookup_fct,
   } fct;
   int no_more;
 
-  if (res && __res_maybe_init (&_res, 0) == -1)
+  struct resolv_context *res_ctx = NULL;
+  if (res)
     {
-      __set_h_errno (NETDB_INTERNAL);
-      return;
+      res_ctx = __resolv_context_get ();
+      if (res_ctx == NULL)
+	{
+	  __set_h_errno (NETDB_INTERNAL);
+	  return;
+	}
     }
 
   /* Cycle through the services and run their `setXXent' functions until
@@ -95,6 +101,8 @@ __nss_setent (const char *func_name, db_lookup_function lookup_fct,
 	*last_nip = *nip;
     }
 
+  __resolv_context_put (res_ctx);
+
   if (stayopen_tmp)
     *stayopen_tmp = stayopen;
 }
@@ -112,10 +120,15 @@ __nss_endent (const char *func_name, db_lookup_function lookup_fct,
   } fct;
   int no_more;
 
-  if (res && __res_maybe_init (&_res, 0) == -1)
+  struct resolv_context *res_ctx = NULL;
+  if (res)
     {
-      __set_h_errno (NETDB_INTERNAL);
-      return;
+      res_ctx = __resolv_context_get ();
+      if (res_ctx == NULL)
+	{
+	  __set_h_errno (NETDB_INTERNAL);
+	  return;
+	}
     }
 
   /* Cycle through all the services and run their endXXent functions.  */
@@ -132,6 +145,8 @@ __nss_endent (const char *func_name, db_lookup_function lookup_fct,
       no_more = __nss_next2 (nip, func_name, NULL, &fct.ptr, 0, 1);
     }
   *last_nip = *nip = NULL;
+
+  __resolv_context_put (res_ctx);
 }
 
 
@@ -152,11 +167,16 @@ __nss_getent_r (const char *getent_func_name,
   int no_more;
   enum nss_status status;
 
-  if (res && __res_maybe_init (&_res, 0) == -1)
+  struct resolv_context *res_ctx = NULL;
+  if (res)
     {
-      *h_errnop = NETDB_INTERNAL;
-      *result = NULL;
-      return errno;
+      res_ctx = __resolv_context_get ();
+      if (res_ctx == NULL)
+	{
+	  *h_errnop = NETDB_INTERNAL;
+	  *result = NULL;
+	  return errno;
+	}
     }
 
   /* Initialize status to return if no more functions are found.  */
@@ -227,6 +247,8 @@ __nss_getent_r (const char *getent_func_name,
       while (! no_more && status != NSS_STATUS_SUCCESS);
     }
 
+  __resolv_context_put (res_ctx);
+
   *result = status == NSS_STATUS_SUCCESS ? resbuf : NULL;
   return (status == NSS_STATUS_SUCCESS ? 0
 	  : status != NSS_STATUS_TRYAGAIN ? ENOENT
diff --git a/nss/nsswitch.h b/nss/nsswitch.h
index f3e756b..bd3fbcb 100644
--- a/nss/nsswitch.h
+++ b/nss/nsswitch.h
@@ -197,7 +197,17 @@ extern int __nss_getent_r (const char *getent_func_name,
 extern void *__nss_getent (getent_r_function func,
 			   void **resbuf, char **buffer, size_t buflen,
 			   size_t *buffer_size, int *h_errnop);
+struct resolv_context;
 struct hostent;
+extern int __nss_hostname_digits_dots_context (struct resolv_context *,
+					       const char *name,
+					       struct hostent *resbuf,
+					       char **buffer,
+					       size_t *buffer_size,
+					       size_t buflen,
+					       struct hostent **result,
+					       enum nss_status *status, int af,
+					       int *h_errnop) attribute_hidden;
 extern int __nss_hostname_digits_dots (const char *name,
 				       struct hostent *resbuf, char **buffer,
 				       size_t *buffer_size, size_t buflen,
diff --git a/resolv/Makefile b/resolv/Makefile
index bab1ac2..126da07 100644
--- a/resolv/Makefile
+++ b/resolv/Makefile
@@ -28,7 +28,8 @@ headers	:= resolv.h bits/types/res_state.h \
 	   sys/bitypes.h
 
 routines := herror inet_addr inet_ntop inet_pton nsap_addr res_init \
-	    res_hconf res_libc res-state res_randomid res-close
+	    res_hconf res_libc res-state res_randomid res-close \
+	    resolv_context
 
 tests = tst-aton tst-leaks tst-inet_ntop
 xtests = tst-leaks2
diff --git a/resolv/Versions b/resolv/Versions
index f528ed5..b05778d 100644
--- a/resolv/Versions
+++ b/resolv/Versions
@@ -26,8 +26,12 @@ libc {
 
     __h_errno; __resp;
 
-    __res_maybe_init; __res_iclose;
+    __res_iclose;
     __inet_pton_length;
+    __resolv_context_get;
+    __resolv_context_get_preinit;
+    __resolv_context_get_override;
+    __resolv_context_put;
   }
 }
 
@@ -79,7 +83,9 @@ libresolv {
     # Needed in libnss_dns.
     __ns_name_unpack; __ns_name_ntop;
     __ns_get16; __ns_get32;
-    __libc_res_nquery; __libc_res_nsearch;
+    __res_context_query;
+    __res_context_search;
+    __res_context_hostalias;
   }
 }
 
diff --git a/resolv/compat-gethnamaddr.c b/resolv/compat-gethnamaddr.c
index 813c7d4..259378b 100644
--- a/resolv/compat-gethnamaddr.c
+++ b/resolv/compat-gethnamaddr.c
@@ -67,6 +67,7 @@
 # include <stdio.h>
 # include <netdb.h>
 # include <resolv/resolv-internal.h>
+# include <resolv/resolv_context.h>
 # include <ctype.h>
 # include <errno.h>
 # include <stdlib.h>
@@ -84,6 +85,9 @@ static u_char host_addr[16];	/* IPv4 or IPv6 */
 static FILE *hostf = NULL;
 static int stayopen = 0;
 
+static struct hostent *res_gethostbyname2_context (struct resolv_context *,
+						   const char *name, int af);
+
 static void map_v4v6_address (const char *src, char *dst) __THROW;
 static void map_v4v6_hostent (struct hostent *hp, char **bp, int *len) __THROW;
 
@@ -428,23 +432,31 @@ libresolv_hidden_proto (res_gethostbyname2)
 struct hostent *
 res_gethostbyname (const char *name)
 {
-	struct hostent *hp;
-
-	if (__res_maybe_init (&_res, 0) == -1) {
-		__set_h_errno (NETDB_INTERNAL);
-		return (NULL);
-	}
-	if (res_use_inet6 ()) {
-		hp = res_gethostbyname2(name, AF_INET6);
-		if (hp)
-			return (hp);
+  struct resolv_context *ctx = __resolv_context_get ();
+  if (ctx == NULL)
+    {
+      __set_h_errno (NETDB_INTERNAL);
+      return NULL;
+    }
+
+  if (res_use_inet6 ())
+    {
+      struct hostent *hp = res_gethostbyname2_context (ctx, name, AF_INET6);
+      if (hp != NULL)
+	{
+	  __resolv_context_put (ctx);
+	  return hp;
 	}
-	return (res_gethostbyname2(name, AF_INET));
+    }
+  struct hostent *hp = res_gethostbyname2_context (ctx, name, AF_INET);
+  __resolv_context_put (ctx);
+  return hp;
 }
 compat_symbol (libresolv, res_gethostbyname, res_gethostbyname, GLIBC_2_0);
 
-struct hostent *
-res_gethostbyname2 (const char *name, int af)
+static struct hostent *
+res_gethostbyname2_context (struct resolv_context *ctx,
+			    const char *name, int af)
 {
 	union
 	{
@@ -457,11 +469,6 @@ res_gethostbyname2 (const char *name, int af)
 	int n, size, type, len;
 	struct hostent *ret;
 
-	if (__res_maybe_init (&_res, 0) == -1) {
-		__set_h_errno (NETDB_INTERNAL);
-		return (NULL);
-	}
-
 	switch (af) {
 	case AF_INET:
 		size = INADDRSZ;
@@ -485,8 +492,10 @@ res_gethostbyname2 (const char *name, int af)
 	 * this is also done in res_query() since we are not the only
 	 * function that looks up host names.
 	 */
-	if (!strchr(name, '.') && (cp = __hostalias(name)))
-		name = cp;
+	char abuf[MAXDNAME];
+	if (strchr (name, '.') != NULL
+	    && (cp = __res_context_hostalias (ctx, name, abuf, sizeof (abuf))))
+	  name = cp;
 
 	/*
 	 * disallow names consisting only of digits/dots, unless
@@ -558,8 +567,9 @@ res_gethostbyname2 (const char *name, int af)
 
 	buf.buf = origbuf = (querybuf *) alloca (1024);
 
-	if ((n = __libc_res_nsearch(&_res, name, C_IN, type, buf.buf->buf, 1024,
-				    &buf.ptr, NULL, NULL, NULL, NULL)) < 0) {
+	if ((n = __res_context_search
+	     (ctx, name, C_IN, type, buf.buf->buf, 1024,
+	      &buf.ptr, NULL, NULL, NULL, NULL)) < 0) {
 		if (buf.buf != origbuf)
 			free (buf.buf);
 		Dprintf("res_nsearch failed (%d)\n", n);
@@ -572,11 +582,26 @@ res_gethostbyname2 (const char *name, int af)
 		free (buf.buf);
 	return ret;
 }
+
+struct hostent *
+res_gethostbyname2 (const char *name, int af)
+{
+  struct resolv_context *ctx = __resolv_context_get ();
+  if (ctx == NULL)
+    {
+      __set_h_errno (NETDB_INTERNAL);
+      return NULL;
+    }
+  struct hostent *hp = res_gethostbyname2_context (ctx, name, AF_INET);
+  __resolv_context_put (ctx);
+  return hp;
+}
 libresolv_hidden_def (res_gethostbyname2)
 compat_symbol (libresolv, res_gethostbyname2, res_gethostbyname2, GLIBC_2_0);
 
-struct hostent *
-res_gethostbyaddr (const void *addr, socklen_t len, int af)
+static struct hostent *
+res_gethostbyaddr_context (struct resolv_context *ctx,
+			   const void *addr, socklen_t len, int af)
 {
 	const u_char *uaddr = (const u_char *)addr;
 	static const u_char mapped[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
@@ -592,10 +617,6 @@ res_gethostbyaddr (const void *addr, socklen_t len, int af)
 	struct hostent *hp;
 	char qbuf[MAXDNAME+1], *qp = NULL;
 
-	if (__res_maybe_init (&_res, 0) == -1) {
-		__set_h_errno (NETDB_INTERNAL);
-		return (NULL);
-	}
 	if (af == AF_INET6 && len == IN6ADDRSZ &&
 	    (!memcmp(uaddr, mapped, sizeof mapped) ||
 	     !memcmp(uaddr, tunnelled, sizeof tunnelled))) {
@@ -645,8 +666,8 @@ res_gethostbyaddr (const void *addr, socklen_t len, int af)
 
 	buf.buf = orig_buf = (querybuf *) alloca (1024);
 
-	n = __libc_res_nquery(&_res, qbuf, C_IN, T_PTR, buf.buf->buf, 1024,
-			      &buf.ptr, NULL, NULL, NULL, NULL);
+	n = __res_context_query (ctx, qbuf, C_IN, T_PTR, buf.buf->buf, 1024,
+				 &buf.ptr, NULL, NULL, NULL, NULL);
 	if (n < 0) {
 		if (buf.buf != orig_buf)
 			free (buf.buf);
@@ -673,6 +694,20 @@ res_gethostbyaddr (const void *addr, socklen_t len, int af)
 	__set_h_errno (NETDB_SUCCESS);
 	return (hp);
 }
+
+struct hostent *
+res_gethostbyaddr (const void *addr, socklen_t len, int af)
+{
+  struct resolv_context *ctx = __resolv_context_get ();
+  if (ctx == NULL)
+    {
+      __set_h_errno (NETDB_INTERNAL);
+      return NULL;
+    }
+  struct hostent *hp = res_gethostbyaddr_context (ctx, addr, len, af);
+  __resolv_context_put (ctx);
+  return hp;
+}
 compat_symbol (libresolv, res_gethostbyaddr, res_gethostbyaddr, GLIBC_2_0);
 
 void
diff --git a/resolv/nss_dns/dns-canon.c b/resolv/nss_dns/dns-canon.c
index 4276eb6..7a5c39d 100644
--- a/resolv/nss_dns/dns-canon.c
+++ b/resolv/nss_dns/dns-canon.c
@@ -23,7 +23,8 @@
 #include <stdint.h>
 #include <arpa/nameser.h>
 #include <nsswitch.h>
-
+#include <resolv/resolv_context.h>
+#include <resolv/resolv-internal.h>
 
 #if PACKETSZ > 65536
 # define MAXPACKET	PACKETSZ
@@ -58,11 +59,19 @@ _nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen,
   } ansp = { .ptr = buf };
   enum nss_status status = NSS_STATUS_UNAVAIL;
 
+  struct resolv_context *ctx = __resolv_context_get ();
+  if (ctx == NULL)
+    {
+      *errnop = errno;
+      *h_errnop = NETDB_INTERNAL;
+      return NSS_STATUS_UNAVAIL;
+    }
+
   for (int i = 0; i < nqtypes; ++i)
     {
-      int r = __libc_res_nquery (&_res, name, ns_c_in, qtypes[i],
-				 buf, sizeof (buf), &ansp.ptr, NULL, NULL,
-				 NULL, NULL);
+      int r = __res_context_query (ctx, name, ns_c_in, qtypes[i],
+				   buf, sizeof (buf), &ansp.ptr, NULL, NULL,
+				   NULL, NULL);
       if (r > 0)
 	{
 	  /* We need to decode the response.  Just one question record.
@@ -168,6 +177,6 @@ _nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen,
 
   if (ansp.ptr != buf)
     free (ansp.ptr);
-
+  __resolv_context_put (ctx);
   return status;
 }
diff --git a/resolv/nss_dns/dns-host.c b/resolv/nss_dns/dns-host.c
index 206924d..9d7ceb1 100644
--- a/resolv/nss_dns/dns-host.c
+++ b/resolv/nss_dns/dns-host.c
@@ -84,6 +84,7 @@
 
 /* Get implementeation for some internal functions.  */
 #include <resolv/resolv-internal.h>
+#include <resolv/resolv_context.h>
 #include <resolv/mapv4v6addr.h>
 #include <resolv/mapv4v6hostent.h>
 
@@ -121,13 +122,13 @@ static enum nss_status gaih_getanswer (const querybuf *answer1, int anslen1,
 				       int *errnop, int *h_errnop,
 				       int32_t *ttlp);
 
-extern enum nss_status _nss_dns_gethostbyname3_r (const char *name, int af,
-						  struct hostent *result,
-						  char *buffer, size_t buflen,
-						  int *errnop, int *h_errnop,
-						  int32_t *ttlp,
-						  char **canonp);
-hidden_proto (_nss_dns_gethostbyname3_r)
+static enum nss_status gethostbyname3_context (struct resolv_context *ctx,
+					       const char *name, int af,
+					       struct hostent *result,
+					       char *buffer, size_t buflen,
+					       int *errnop, int *h_errnop,
+					       int32_t *ttlp,
+					       char **canonp);
 
 /* Return the expected RDATA length for an address record type (A or
    AAAA).  */
@@ -145,11 +146,31 @@ rrtype_to_rdata_length (int type)
     }
 }
 
+
 enum nss_status
 _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
 			   char *buffer, size_t buflen, int *errnop,
 			   int *h_errnop, int32_t *ttlp, char **canonp)
 {
+  struct resolv_context *ctx = __resolv_context_get ();
+  if (ctx == NULL)
+    {
+      *errnop = errno;
+      *h_errnop = NETDB_INTERNAL;
+      return NSS_STATUS_UNAVAIL;
+    }
+  enum nss_status status = gethostbyname3_context
+    (ctx, name, af, result, buffer, buflen, errnop, h_errnop, ttlp, canonp);
+  __resolv_context_put (ctx);
+  return status;
+}
+
+static enum nss_status
+gethostbyname3_context (struct resolv_context *ctx,
+			const char *name, int af, struct hostent *result,
+			char *buffer, size_t buflen, int *errnop,
+			int *h_errnop, int32_t *ttlp, char **canonp)
+{
   union
   {
     querybuf *buf;
@@ -163,13 +184,6 @@ _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
   int olderr = errno;
   enum nss_status status;
 
-  if (__res_maybe_init (&_res, 0) == -1)
-    {
-      *errnop = errno;
-      *h_errnop = NETDB_INTERNAL;
-      return NSS_STATUS_UNAVAIL;
-    }
-
   switch (af) {
   case AF_INET:
     size = INADDRSZ;
@@ -194,13 +208,13 @@ _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
    * function that looks up host names.
    */
   if (strchr (name, '.') == NULL
-      && (cp = res_hostalias (&_res, name, tmp, sizeof (tmp))) != NULL)
+      && (cp = __res_context_hostalias (ctx, name, tmp, sizeof (tmp))) != NULL)
     name = cp;
 
   host_buffer.buf = orig_host_buffer = (querybuf *) alloca (1024);
 
-  n = __libc_res_nsearch (&_res, name, C_IN, type, host_buffer.buf->buf,
-			  1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
+  n = __res_context_search (ctx, name, C_IN, type, host_buffer.buf->buf,
+			    1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
   if (n < 0)
     {
       switch (errno)
@@ -232,10 +246,10 @@ _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
 	 by having the RES_USE_INET6 bit in _res.options set, we try
 	 another lookup.  */
       if (af == AF_INET6 && res_use_inet6 ())
-	n = __libc_res_nsearch (&_res, name, C_IN, T_A, host_buffer.buf->buf,
-				host_buffer.buf != orig_host_buffer
-				? MAXPACKET : 1024, &host_buffer.ptr,
-				NULL, NULL, NULL, NULL);
+	n = __res_context_search (ctx, name, C_IN, T_A, host_buffer.buf->buf,
+				  host_buffer.buf != orig_host_buffer
+				  ? MAXPACKET : 1024, &host_buffer.ptr,
+				  NULL, NULL, NULL, NULL);
 
       if (n < 0)
 	{
@@ -256,8 +270,6 @@ _nss_dns_gethostbyname3_r (const char *name, int af, struct hostent *result,
     free (host_buffer.buf);
   return status;
 }
-hidden_def (_nss_dns_gethostbyname3_r)
-
 
 enum nss_status
 _nss_dns_gethostbyname2_r (const char *name, int af, struct hostent *result,
@@ -274,15 +286,21 @@ _nss_dns_gethostbyname_r (const char *name, struct hostent *result,
 			  char *buffer, size_t buflen, int *errnop,
 			  int *h_errnop)
 {
+  struct resolv_context *ctx = __resolv_context_get ();
+  if (ctx == NULL)
+    {
+      *errnop = errno;
+      *h_errnop = NETDB_INTERNAL;
+      return NSS_STATUS_UNAVAIL;
+    }
   enum nss_status status = NSS_STATUS_NOTFOUND;
-
   if (res_use_inet6 ())
-    status = _nss_dns_gethostbyname3_r (name, AF_INET6, result, buffer,
-					buflen, errnop, h_errnop, NULL, NULL);
+    status = gethostbyname3_context (ctx, name, AF_INET6, result, buffer,
+				     buflen, errnop, h_errnop, NULL, NULL);
   if (status == NSS_STATUS_NOTFOUND)
-    status = _nss_dns_gethostbyname3_r (name, AF_INET, result, buffer,
-					buflen, errnop, h_errnop, NULL, NULL);
-
+    status = gethostbyname3_context (ctx, name, AF_INET, result, buffer,
+				     buflen, errnop, h_errnop, NULL, NULL);
+  __resolv_context_put (ctx);
   return status;
 }
 
@@ -292,7 +310,8 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
 			   char *buffer, size_t buflen, int *errnop,
 			   int *herrnop, int32_t *ttlp)
 {
-  if (__res_maybe_init (&_res, 0) == -1)
+  struct resolv_context *ctx = __resolv_context_get ();
+  if (ctx == NULL)
     {
       *errnop = errno;
       *herrnop = NETDB_INTERNAL;
@@ -307,7 +326,7 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
   if (strchr (name, '.') == NULL)
     {
       char *tmp = alloca (NS_MAXDNAME);
-      const char *cp = res_hostalias (&_res, name, tmp, NS_MAXDNAME);
+      const char *cp = __res_context_hostalias (ctx, name, tmp, NS_MAXDNAME);
       if (cp != NULL)
 	name = cp;
     }
@@ -326,9 +345,9 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
 
   int olderr = errno;
   enum nss_status status;
-  int n = __libc_res_nsearch (&_res, name, C_IN, T_QUERY_A_AND_AAAA,
-			      host_buffer.buf->buf, 2048, &host_buffer.ptr,
-			      &ans2p, &nans2p, &resplen2, &ans2p_malloced);
+  int n = __res_context_search (ctx, name, C_IN, T_QUERY_A_AND_AAAA,
+				host_buffer.buf->buf, 2048, &host_buffer.ptr,
+				&ans2p, &nans2p, &resplen2, &ans2p_malloced);
   if (n >= 0)
     {
       status = gaih_getanswer (host_buffer.buf, n, (const querybuf *) ans2p,
@@ -371,6 +390,7 @@ _nss_dns_gethostbyname4_r (const char *name, struct gaih_addrtuple **pat,
   if (host_buffer.buf != orig_host_buffer)
     free (host_buffer.buf);
 
+  __resolv_context_put (ctx);
   return status;
 }
 
@@ -423,7 +443,8 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
 
  host_data = (struct host_data *) buffer;
 
-  if (__res_maybe_init (&_res, 0) == -1)
+  struct resolv_context *ctx = __resolv_context_get ();
+  if (ctx == NULL)
     {
       *errnop = errno;
       *h_errnop = NETDB_INTERNAL;
@@ -453,12 +474,14 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
     default:
       *errnop = EAFNOSUPPORT;
       *h_errnop = NETDB_INTERNAL;
+      __resolv_context_put (ctx);
       return NSS_STATUS_UNAVAIL;
     }
   if (size > len)
     {
       *errnop = EAFNOSUPPORT;
       *h_errnop = NETDB_INTERNAL;
+      __resolv_context_put (ctx);
       return NSS_STATUS_UNAVAIL;
     }
 
@@ -487,14 +510,15 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
       break;
     }
 
-  n = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
-			 1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
+  n = __res_context_query (ctx, qbuf, C_IN, T_PTR, host_buffer.buf->buf,
+			   1024, &host_buffer.ptr, NULL, NULL, NULL, NULL);
   if (n < 0)
     {
       *h_errnop = h_errno;
       __set_errno (olderr);
       if (host_buffer.buf != orig_host_buffer)
 	free (host_buffer.buf);
+      __resolv_context_put (ctx);
       return errno == ECONNREFUSED ? NSS_STATUS_UNAVAIL : NSS_STATUS_NOTFOUND;
     }
 
@@ -503,7 +527,10 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
   if (host_buffer.buf != orig_host_buffer)
     free (host_buffer.buf);
   if (status != NSS_STATUS_SUCCESS)
-    return status;
+    {
+      __resolv_context_put (ctx);
+      return status;
+    }
 
   result->h_addrtype = af;
   result->h_length = len;
@@ -511,6 +538,7 @@ _nss_dns_gethostbyaddr2_r (const void *addr, socklen_t len, int af,
   host_data->h_addr_ptrs[0] = (char *) host_data->host_addr;
   host_data->h_addr_ptrs[1] = NULL;
   *h_errnop = NETDB_SUCCESS;
+  __resolv_context_put (ctx);
   return NSS_STATUS_SUCCESS;
 }
 hidden_def (_nss_dns_gethostbyaddr2_r)
diff --git a/resolv/nss_dns/dns-network.c b/resolv/nss_dns/dns-network.c
index dc1599b..f190eb2 100644
--- a/resolv/nss_dns/dns-network.c
+++ b/resolv/nss_dns/dns-network.c
@@ -67,6 +67,8 @@
 #include "nsswitch.h"
 #include <arpa/inet.h>
 #include <arpa/nameser.h>
+#include <resolv/resolv-internal.h>
+#include <resolv/resolv_context.h>
 
 /* Maximum number of aliases we allow.  */
 #define MAX_NR_ALIASES	48
@@ -115,7 +117,8 @@ _nss_dns_getnetbyname_r (const char *name, struct netent *result,
   int anslen;
   enum nss_status status;
 
-  if (__res_maybe_init (&_res, 0) == -1)
+  struct resolv_context *ctx = __resolv_context_get ();
+  if (ctx == NULL)
     {
       *errnop = errno;
       *herrnop = NETDB_INTERNAL;
@@ -124,14 +127,16 @@ _nss_dns_getnetbyname_r (const char *name, struct netent *result,
 
   net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
 
-  anslen = __libc_res_nsearch (&_res, name, C_IN, T_PTR, net_buffer.buf->buf,
-			       1024, &net_buffer.ptr, NULL, NULL, NULL, NULL);
+  anslen = __res_context_search
+    (ctx, name, C_IN, T_PTR, net_buffer.buf->buf,
+     1024, &net_buffer.ptr, NULL, NULL, NULL, NULL);
   if (anslen < 0)
     {
       /* Nothing found.  */
       *errnop = errno;
       if (net_buffer.buf != orig_net_buffer)
 	free (net_buffer.buf);
+      __resolv_context_put (ctx);
       return (errno == ECONNREFUSED
 	      || errno == EPFNOSUPPORT
 	      || errno == EAFNOSUPPORT)
@@ -142,6 +147,7 @@ _nss_dns_getnetbyname_r (const char *name, struct netent *result,
 			errnop, herrnop, BYNAME);
   if (net_buffer.buf != orig_net_buffer)
     free (net_buffer.buf);
+  __resolv_context_put (ctx);
   return status;
 }
 
@@ -169,7 +175,8 @@ _nss_dns_getnetbyaddr_r (uint32_t net, int type, struct netent *result,
   if (type != AF_INET)
     return NSS_STATUS_UNAVAIL;
 
-  if (__res_maybe_init (&_res, 0) == -1)
+  struct resolv_context *ctx = __resolv_context_get ();
+  if (ctx == NULL)
     {
       *errnop = errno;
       *herrnop = NETDB_INTERNAL;
@@ -204,8 +211,8 @@ _nss_dns_getnetbyaddr_r (uint32_t net, int type, struct netent *result,
 
   net_buffer.buf = orig_net_buffer = (querybuf *) alloca (1024);
 
-  anslen = __libc_res_nquery (&_res, qbuf, C_IN, T_PTR, net_buffer.buf->buf,
-			      1024, &net_buffer.ptr, NULL, NULL, NULL, NULL);
+  anslen = __res_context_query (ctx, qbuf, C_IN, T_PTR, net_buffer.buf->buf,
+				1024, &net_buffer.ptr, NULL, NULL, NULL, NULL);
   if (anslen < 0)
     {
       /* Nothing found.  */
@@ -213,6 +220,7 @@ _nss_dns_getnetbyaddr_r (uint32_t net, int type, struct netent *result,
       __set_errno (olderr);
       if (net_buffer.buf != orig_net_buffer)
 	free (net_buffer.buf);
+      __resolv_context_put (ctx);
       return (err == ECONNREFUSED
 	      || err == EPFNOSUPPORT
 	      || err == EAFNOSUPPORT)
@@ -233,6 +241,7 @@ _nss_dns_getnetbyaddr_r (uint32_t net, int type, struct netent *result,
       result->n_net = u_net;
     }
 
+  __resolv_context_put (ctx);
   return status;
 }
 
diff --git a/resolv/res-close.c b/resolv/res-close.c
index 73f18d1..97da73c 100644
--- a/resolv/res-close.c
+++ b/resolv/res-close.c
@@ -83,6 +83,7 @@
  */
 
 #include <resolv-internal.h>
+#include <resolv_context.h>
 #include <not-cancel.h>
 
 /* Close all open sockets.  If FREE_ADDR is true, deallocate any
@@ -124,6 +125,8 @@ libc_hidden_def (__res_nclose)
 static void __attribute__ ((section ("__libc_thread_freeres_fn")))
 res_thread_freeres (void)
 {
+  __resolv_context_freeres ();
+
   if (_res.nscount == 0)
     /* Never called res_ninit.  */
     return;
diff --git a/resolv/res_libc.c b/resolv/res_libc.c
index 3d7b4f7..5066983 100644
--- a/resolv/res_libc.c
+++ b/resolv/res_libc.c
@@ -98,37 +98,6 @@ res_init (void)
 
   return __res_vinit (&_res, 1);
 }
-
-/* Initialize *RESP if RES_INIT is not yet set in RESP->options, or if
-   res_init in some other thread requested re-initializing.  */
-int
-__res_maybe_init (res_state resp, int preinit)
-{
-  if (resp->options & RES_INIT)
-    {
-      if (__res_initstamp != resp->_u._ext.initstamp)
-        {
-          if (resp->nscount > 0)
-            __res_iclose (resp, true);
-          return __res_vinit (resp, 1);
-        }
-      return 0;
-    }
-  else if (preinit)
-    {
-      if (!resp->retrans)
-        resp->retrans = RES_TIMEOUT;
-      if (!resp->retry)
-        resp->retry = RES_DFLRETRY;
-      resp->options = RES_DEFAULT;
-      if (!resp->id)
-        resp->id = res_randomid ();
-      return __res_vinit (resp, 1);
-    }
-  else
-    return __res_ninit (resp);
-}
-libc_hidden_def (__res_maybe_init)
 
 /* This needs to be after the use of _res in res_init, above.  */
 #undef _res
diff --git a/resolv/res_mkquery.c b/resolv/res_mkquery.c
index 9afb410..59fc5ab 100644
--- a/resolv/res_mkquery.c
+++ b/resolv/res_mkquery.c
@@ -88,6 +88,7 @@
 #include <arpa/nameser.h>
 #include <netdb.h>
 #include <resolv/resolv-internal.h>
+#include <resolv/resolv_context.h>
 #include <string.h>
 #include <sys/time.h>
 #include <shlib-compat.h>
@@ -98,22 +99,10 @@
 # define RANDOM_BITS(Var) { uint64_t v64; HP_TIMING_NOW (v64); Var = v64; }
 #endif
 
-/* Form all types of queries.  Returns the size of the result or -1 on
-   error.
-
-   STATP points to an initialized resolver state.  OP is the opcode of
-   the query.  DNAME is the domain.  CLASS and TYPE are the DNS query
-   class and type.  DATA can be NULL; otherwise, it is a pointer to a
-   domain name which is included in the generated packet (if op ==
-   NS_NOTIFY_OP).  BUF must point to the out buffer of BUFLEN bytes.
-
-   DATALEN and NEWRR_IN are currently ignored.  */
 int
-res_nmkquery (res_state statp, int op, const char *dname,
-              int class, int type,
-              const unsigned char *data, int datalen,
-              const unsigned char *newrr_in,
-              unsigned char *buf, int buflen)
+__res_context_mkquery (struct resolv_context *ctx, int op, const char *dname,
+                       int class, int type, const unsigned char *data,
+                       unsigned char *buf, int buflen)
 {
   HEADER *hp;
   unsigned char *cp;
@@ -132,22 +121,17 @@ res_nmkquery (res_state statp, int op, const char *dname,
      by one after the initial randomization which still predictable if
      the application does multiple requests.  */
   int randombits;
-  do
-    {
 #ifdef RANDOM_BITS
-      RANDOM_BITS (randombits);
+  RANDOM_BITS (randombits);
 #else
-      struct timeval tv;
-      __gettimeofday (&tv, NULL);
-      randombits = (tv.tv_sec << 8) ^ tv.tv_usec;
+  struct timeval tv;
+  __gettimeofday (&tv, NULL);
+  randombits = (tv.tv_sec << 8) ^ tv.tv_usec;
 #endif
-    }
-  while ((randombits & 0xffff) == 0);
 
-  statp->id = (statp->id + randombits) & 0xffff;
-  hp->id = statp->id;
+  hp->id = randombits;
   hp->opcode = op;
-  hp->rd = (statp->options & RES_RECURSE) != 0;
+  hp->rd = (ctx->resp->options & RES_RECURSE) != 0;
   hp->rcode = NOERROR;
   cp = buf + HFIXEDSZ;
   buflen -= HFIXEDSZ;
@@ -201,7 +185,45 @@ res_nmkquery (res_state statp, int op, const char *dname,
     }
   return cp - buf;
 }
-libresolv_hidden_def (res_nmkquery)
+
+/* Common part of res_nmkquery and res_mkquery.  */
+static int
+context_mkquery_common (struct resolv_context *ctx,
+                        int op, const char *dname, int class, int type,
+                        const unsigned char *data,
+                        unsigned char *buf, int buflen)
+{
+  if (ctx == NULL)
+    return -1;
+  int result = __res_context_mkquery
+    (ctx, op, dname, class, type, data, buf, buflen);
+  if (result >= 2)
+    memcpy (&ctx->resp->id, buf, 2);
+  __resolv_context_put (ctx);
+  return result;
+}
+
+/* Form all types of queries.  Returns the size of the result or -1 on
+   error.
+
+   STATP points to an initialized resolver state.  OP is the opcode of
+   the query.  DNAME is the domain.  CLASS and TYPE are the DNS query
+   class and type.  DATA can be NULL; otherwise, it is a pointer to a
+   domain name which is included in the generated packet (if op ==
+   NS_NOTIFY_OP).  BUF must point to the out buffer of BUFLEN bytes.
+
+   DATALEN and NEWRR_IN are currently ignored.  */
+int
+res_nmkquery (res_state statp, int op, const char *dname,
+              int class, int type,
+              const unsigned char *data, int datalen,
+              const unsigned char *newrr_in,
+              unsigned char *buf, int buflen)
+{
+  return context_mkquery_common
+    (__resolv_context_get_override (statp),
+     op, dname, class, type, data, buf, buflen);
+}
 
 int
 res_mkquery (int op, const char *dname, int class, int type,
@@ -209,13 +231,9 @@ res_mkquery (int op, const char *dname, int class, int type,
              const unsigned char *newrr_in,
              unsigned char *buf, int buflen)
 {
-  if (__res_maybe_init (&_res, 1) == -1)
-    {
-      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
-      return -1;
-    }
-  return res_nmkquery (&_res, op, dname, class, type,
-                       data, datalen, newrr_in, buf, buflen);
+  return context_mkquery_common
+    (__resolv_context_get_preinit (),
+     op, dname, class, type, data, buf, buflen);
 }
 
 /* Create an OPT resource record.  Return the length of the final
@@ -227,8 +245,8 @@ res_mkquery (int op, const char *dname, int class, int type,
    pointers to must be BUFLEN bytes long.  ANSLEN is the advertised
    EDNS buffer size (to be included in the OPT resource record).  */
 int
-__res_nopt (res_state statp, int n0, unsigned char *buf, int buflen,
-            int anslen)
+__res_nopt (struct resolv_context *ctx,
+            int n0, unsigned char *buf, int buflen, int anslen)
 {
   uint16_t flags = 0;
   HEADER *hp = (HEADER *) buf;
@@ -269,7 +287,7 @@ __res_nopt (res_state statp, int n0, unsigned char *buf, int buflen,
   *cp++ = NOERROR;              /* Extended RCODE.  */
   *cp++ = 0;                    /* EDNS version.  */
 
-  if (statp->options & RES_USE_DNSSEC)
+  if (ctx->resp->options & RES_USE_DNSSEC)
     flags |= NS_OPT_DNSSEC_OK;
 
   NS_PUT16 (flags, cp);
diff --git a/resolv/res_query.c b/resolv/res_query.c
index 760bf32..33249e3 100644
--- a/resolv/res_query.c
+++ b/resolv/res_query.c
@@ -75,6 +75,7 @@
 #include <netdb.h>
 #include <resolv.h>
 #include <resolv/resolv-internal.h>
+#include <resolv/resolv_context.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -89,33 +90,28 @@
 #define QUERYSIZE	(HFIXEDSZ + QFIXEDSZ + MAXCDNAME + 1)
 
 static int
-__libc_res_nquerydomain(res_state statp, const char *name, const char *domain,
-			int class, int type, u_char *answer, int anslen,
-			u_char **answerp, u_char **answerp2, int *nanswerp2,
-			int *resplen2, int *answerp2_malloced);
-
-/*
- * Formulate a normal query, send, and await answer.
- * Returned answer is placed in supplied buffer "answer".
- * Perform preliminary check of answer, returning success only
- * if no error is indicated and the answer count is nonzero.
- * Return the size of the response on success, -1 on error.
- * Error number is left in H_ERRNO.
- *
- * Caller must parse answer and determine whether it answers the question.
- */
+__res_context_querydomain (struct resolv_context *,
+			   const char *name, const char *domain,
+			   int class, int type, unsigned char *answer, int anslen,
+			   unsigned char **answerp, unsigned char **answerp2, int *nanswerp2,
+			   int *resplen2, int *answerp2_malloced);
+
+/* Formulate a normal query, send, and await answer.  Returned answer
+   is placed in supplied buffer ANSWER.  Perform preliminary check of
+   answer, returning success only if no error is indicated and the
+   answer count is nonzero.  Return the size of the response on
+   success, -1 on error.  Error number is left in h_errno.
+
+   Caller must parse answer and determine whether it answers the
+   question.  */
 int
-__libc_res_nquery(res_state statp,
-		  const char *name,	/* domain name */
-		  int class, int type,	/* class and type of query */
-		  u_char *answer,	/* buffer to put answer */
-		  int anslen,		/* size of answer buffer */
-		  u_char **answerp,	/* if buffer needs to be enlarged */
-		  u_char **answerp2,
-		  int *nanswerp2,
-		  int *resplen2,
-		  int *answerp2_malloced)
+__res_context_query (struct resolv_context *ctx, const char *name,
+		     int class, int type,
+		     unsigned char *answer, int anslen,
+		     unsigned char **answerp, unsigned char **answerp2,
+		     int *nanswerp2, int *resplen2, int *answerp2_malloced)
 {
+	struct __res_state *statp = ctx->resp;
 	HEADER *hp = (HEADER *) answer;
 	HEADER *hp2;
 	int n, use_malloc = 0;
@@ -132,15 +128,15 @@ __libc_res_nquery(res_state statp,
 
 	if (type == T_QUERY_A_AND_AAAA)
 	  {
-	    n = res_nmkquery(statp, QUERY, name, class, T_A, NULL, 0, NULL,
-			     query1, bufsize);
+	    n = __res_context_mkquery (ctx, QUERY, name, class, T_A, NULL,
+				       query1, bufsize);
 	    if (n > 0)
 	      {
 		if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
 		  {
 		    /* Use RESOLV_EDNS_BUFFER_SIZE because the receive
 		       buffer can be reallocated.  */
-		    n = __res_nopt (statp, n, query1, bufsize,
+		    n = __res_nopt (ctx, n, query1, bufsize,
 				    RESOLV_EDNS_BUFFER_SIZE);
 		    if (n < 0)
 		      goto unspec_nomem;
@@ -157,13 +153,13 @@ __libc_res_nquery(res_state statp,
 		  }
 		int nused = n + npad;
 		query2 = buf + nused;
-		n = res_nmkquery(statp, QUERY, name, class, T_AAAA, NULL, 0,
-				 NULL, query2, bufsize - nused);
+		n = __res_context_mkquery (ctx, QUERY, name, class, T_AAAA,
+					   NULL, query2, bufsize - nused);
 		if (n > 0
 		    && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
 		  /* Use RESOLV_EDNS_BUFFER_SIZE because the receive
 		     buffer can be reallocated.  */
-		  n = __res_nopt (statp, n, query2, bufsize,
+		  n = __res_nopt (ctx, n, query2, bufsize,
 				  RESOLV_EDNS_BUFFER_SIZE);
 		nquery2 = n;
 	      }
@@ -172,8 +168,8 @@ __libc_res_nquery(res_state statp,
 	  }
 	else
 	  {
-	    n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
-			     query1, bufsize);
+	    n = __res_context_mkquery (ctx, QUERY, name, class, type, NULL,
+				       query1, bufsize);
 
 	    if (n > 0
 		&& (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
@@ -185,7 +181,7 @@ __libc_res_nquery(res_state statp,
 		  advertise = anslen;
 		else
 		  advertise = RESOLV_EDNS_BUFFER_SIZE;
-		n = __res_nopt (statp, n, query1, bufsize, advertise);
+		n = __res_nopt (ctx, n, query1, bufsize, advertise);
 	      }
 
 	    nquery1 = n;
@@ -209,9 +205,9 @@ __libc_res_nquery(res_state statp,
 		return (n);
 	}
 	assert (answerp == NULL || (void *) *answerp == (void *) answer);
-	n = __libc_res_nsend(statp, query1, nquery1, query2, nquery2, answer,
-			     anslen, answerp, answerp2, nanswerp2, resplen2,
-			     answerp2_malloced);
+	n = __res_context_send (ctx, query1, nquery1, query2, nquery2, answer,
+				anslen, answerp, answerp2, nanswerp2, resplen2,
+				answerp2_malloced);
 	if (use_malloc)
 		free (buf);
 	if (n < 0) {
@@ -220,7 +216,7 @@ __libc_res_nquery(res_state statp,
 	}
 
 	if (answerp != NULL)
-	  /* __libc_res_nsend might have reallocated the buffer.  */
+	  /* __res_context_send might have reallocated the buffer.  */
 	  hp = (HEADER *) *answerp;
 
 	/* We simplify the following tests by assigning HP to HP2 or
@@ -280,7 +276,24 @@ __libc_res_nquery(res_state statp,
  success:
 	return (n);
 }
-libresolv_hidden_def (__libc_res_nquery)
+libresolv_hidden_def (__res_context_query)
+
+/* Common part of res_nquery and res_query.  */
+static int
+context_query_common (struct resolv_context *ctx,
+		      const char *name, int class, int type,
+		      unsigned char *answer, int anslen)
+{
+  if (ctx == NULL)
+    {
+      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
+      return -1;
+    }
+  int result = __res_context_query (ctx, name, class, type, answer, anslen,
+				    NULL, NULL, NULL, NULL, NULL);
+  __resolv_context_put (ctx);
+  return result;
+}
 
 int
 res_nquery(res_state statp,
@@ -289,41 +302,30 @@ res_nquery(res_state statp,
 	   u_char *answer,	/* buffer to put answer */
 	   int anslen)		/* size of answer buffer */
 {
-	return __libc_res_nquery(statp, name, class, type, answer, anslen,
-				 NULL, NULL, NULL, NULL, NULL);
+  return context_query_common
+    (__resolv_context_get_override (statp), name, class, type, answer, anslen);
 }
-libresolv_hidden_def (res_nquery)
 
 int
 res_query (const char *name, int class, int type,
 	   unsigned char *answer, int anslen)
 {
-  if (__res_maybe_init (&_res, 1) == -1)
-    {
-      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
-      return -1;
-    }
-  return res_nquery (&_res, name, class, type, answer, anslen);
+  return context_query_common
+    (__resolv_context_get (), name, class, type, answer, anslen);
 }
 
-/*
- * Formulate a normal query, send, and retrieve answer in supplied buffer.
- * Return the size of the response on success, -1 on error.
- * If enabled, implement search rules until answer or unrecoverable failure
- * is detected.  Error code, if any, is left in H_ERRNO.
- */
+/* Formulate a normal query, send, and retrieve answer in supplied
+   buffer.  Return the size of the response on success, -1 on error.
+   If enabled, implement search rules until answer or unrecoverable
+   failure is detected.  Error code, if any, is left in h_errno.  */
 int
-__libc_res_nsearch(res_state statp,
-		   const char *name,	/* domain name */
-		   int class, int type,	/* class and type of query */
-		   u_char *answer,	/* buffer to put answer */
-		   int anslen,		/* size of answer */
-		   u_char **answerp,
-		   u_char **answerp2,
-		   int *nanswerp2,
-		   int *resplen2,
-		   int *answerp2_malloced)
+__res_context_search (struct resolv_context *ctx,
+		      const char *name, int class, int type,
+		      unsigned char *answer, int anslen,
+		      unsigned char **answerp, unsigned char **answerp2,
+		      int *nanswerp2, int *resplen2, int *answerp2_malloced)
 {
+	struct __res_state *statp = ctx->resp;
 	const char *cp, * const *domain;
 	HEADER *hp = (HEADER *) answer;
 	char tmp[NS_MAXDNAME];
@@ -344,10 +346,11 @@ __libc_res_nsearch(res_state statp,
 		trailing_dot++;
 
 	/* If there aren't any dots, it could be a user-level alias. */
-	if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
-		return (__libc_res_nquery(statp, cp, class, type, answer,
-					  anslen, answerp, answerp2,
-					  nanswerp2, resplen2, answerp2_malloced));
+	if (!dots && (cp = __res_context_hostalias
+		      (ctx, name, tmp, sizeof tmp))!= NULL)
+	  return __res_context_query (ctx, cp, class, type, answer,
+				      anslen, answerp, answerp2,
+				      nanswerp2, resplen2, answerp2_malloced);
 
 	/*
 	 * If there are enough dots in the name, let's just give it a
@@ -356,10 +359,10 @@ __libc_res_nsearch(res_state statp,
 	 */
 	saved_herrno = -1;
 	if (dots >= statp->ndots || trailing_dot) {
-		ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
-					      answer, anslen, answerp,
-					      answerp2, nanswerp2, resplen2,
-					      answerp2_malloced);
+		ret = __res_context_querydomain (ctx, name, NULL, class, type,
+						 answer, anslen, answerp,
+						 answerp2, nanswerp2, resplen2,
+						 answerp2_malloced);
 		if (ret > 0 || trailing_dot
 		    /* If the second response is valid then we use that.  */
 		    || (ret == 0 && resplen2 != NULL && *resplen2 > 0))
@@ -395,7 +398,7 @@ __libc_res_nsearch(res_state statp,
 			const char *dname = domain[0];
 			searched = 1;
 
-			/* __libc_res_nquerydoman concatenates name
+			/* __res_context_querydoman concatenates name
 			   with dname with a "." in between.  If we
 			   pass it in dname the "." we got from the
 			   configured default search path, we'll end
@@ -409,11 +412,10 @@ __libc_res_nsearch(res_state statp,
 			if (dname[0] == '\0')
 				root_on_list++;
 
-			ret = __libc_res_nquerydomain(statp, name, dname,
-						      class, type,
-						      answer, anslen, answerp,
-						      answerp2, nanswerp2,
-						      resplen2, answerp2_malloced);
+			ret = __res_context_querydomain
+			  (ctx, name, dname, class, type,
+			   answer, anslen, answerp, answerp2, nanswerp2,
+			   resplen2, answerp2_malloced);
 			if (ret > 0 || (ret == 0 && resplen2 != NULL
 					&& *resplen2 > 0))
 				return (ret);
@@ -481,10 +483,10 @@ __libc_res_nsearch(res_state statp,
 	 */
 	if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0)
 	    && !(tried_as_is || root_on_list)) {
-		ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
-					      answer, anslen, answerp,
-					      answerp2, nanswerp2, resplen2,
-					      answerp2_malloced);
+		ret = __res_context_querydomain
+		  (ctx, name, NULL, class, type,
+		   answer, anslen, answerp, answerp2, nanswerp2,
+		   resplen2, answerp2_malloced);
 		if (ret > 0 || (ret == 0 && resplen2 != NULL
 				&& *resplen2 > 0))
 			return (ret);
@@ -512,7 +514,24 @@ __libc_res_nsearch(res_state statp,
 		RES_SET_H_ERRNO(statp, TRY_AGAIN);
 	return (-1);
 }
-libresolv_hidden_def (__libc_res_nsearch)
+libresolv_hidden_def (__res_context_search)
+
+/* Common part of res_nsearch and res_search.  */
+static int
+context_search_common (struct resolv_context *ctx,
+		       const char *name, int class, int type,
+		       unsigned char *answer, int anslen)
+{
+  if (ctx == NULL)
+    {
+      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
+      return -1;
+    }
+  int result = __res_context_search (ctx, name, class, type, answer, anslen,
+				     NULL, NULL, NULL, NULL, NULL);
+  __resolv_context_put (ctx);
+  return result;
+}
 
 int
 res_nsearch(res_state statp,
@@ -521,40 +540,30 @@ res_nsearch(res_state statp,
 	    u_char *answer,	/* buffer to put answer */
 	    int anslen)		/* size of answer */
 {
-	return __libc_res_nsearch(statp, name, class, type, answer,
-				  anslen, NULL, NULL, NULL, NULL, NULL);
+  return context_search_common
+    (__resolv_context_get_override (statp), name, class, type, answer, anslen);
 }
-libresolv_hidden_def (res_nsearch)
 
 int
 res_search (const char *name, int class, int type,
 	    unsigned char *answer, int anslen)
 {
-  if (__res_maybe_init (&_res, 1) == -1)
-    {
-      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
-      return -1;
-    }
-
-  return res_nsearch (&_res, name, class, type, answer, anslen);
+  return context_search_common
+    (__resolv_context_get (), name, class, type, answer, anslen);
 }
 
-/*
- * Perform a call on res_query on the concatenation of name and domain.
- */
+/*  Perform a call on res_query on the concatenation of name and
+    domain.  */
 static int
-__libc_res_nquerydomain(res_state statp,
-			const char *name,
-			const char *domain,
-			int class, int type,	/* class and type of query */
-			u_char *answer,		/* buffer to put answer */
-			int anslen,			/* size of answer */
-			u_char **answerp,
-			u_char **answerp2,
-			int *nanswerp2,
-			int *resplen2,
-			int *answerp2_malloced)
+__res_context_querydomain (struct resolv_context *ctx,
+			   const char *name, const char *domain,
+			   int class, int type,
+			   unsigned char *answer, int anslen,
+			   unsigned char **answerp, unsigned char **answerp2,
+			   int *nanswerp2, int *resplen2,
+			   int *answerp2_malloced)
 {
+	struct __res_state *statp = ctx->resp;
 	char nbuf[MAXDNAME];
 	const char *longname = nbuf;
 	size_t n, d;
@@ -580,9 +589,28 @@ __libc_res_nquerydomain(res_state statp,
 		}
 		sprintf(nbuf, "%s.%s", name, domain);
 	}
-	return (__libc_res_nquery(statp, longname, class, type, answer,
-				  anslen, answerp, answerp2, nanswerp2,
-				  resplen2, answerp2_malloced));
+	return __res_context_query (ctx, longname, class, type, answer,
+				    anslen, answerp, answerp2, nanswerp2,
+				    resplen2, answerp2_malloced);
+}
+
+/* Common part of res_nquerydomain and res_querydomain.  */
+static int
+context_querydomain_common (struct resolv_context *ctx,
+			    const char *name, const char *domain,
+			    int class, int type,
+			    unsigned char *answer, int anslen)
+{
+  if (ctx == NULL)
+    {
+      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
+      return -1;
+    }
+  int result = __res_context_querydomain (ctx, name, domain, class, type,
+					  answer, anslen,
+					  NULL, NULL, NULL, NULL, NULL);
+  __resolv_context_put (ctx);
+  return result;
 }
 
 int
@@ -593,32 +621,28 @@ res_nquerydomain(res_state statp,
 	    u_char *answer,		/* buffer to put answer */
 	    int anslen)		/* size of answer */
 {
-	return __libc_res_nquerydomain(statp, name, domain, class, type,
-				       answer, anslen, NULL, NULL, NULL, NULL,
-				       NULL);
+  return context_querydomain_common
+    (__resolv_context_get_override (statp),
+     name, domain, class, type, answer, anslen);
 }
-libresolv_hidden_def (res_nquerydomain)
 
 int
 res_querydomain (const char *name, const char *domain, int class, int type,
 		 unsigned char *answer, int anslen)
 {
-  if (__res_maybe_init (&_res, 1) == -1)
-    {
-      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
-      return -1;
-    }
-
-  return res_nquerydomain (&_res, name, domain, class, type, answer, anslen);
+  return context_querydomain_common
+    (__resolv_context_get (), name, domain, class, type, answer, anslen);
 }
 
 const char *
-res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
+__res_context_hostalias (struct resolv_context *ctx,
+			 const char *name, char *dst, size_t siz)
+{
 	char *file, *cp1, *cp2;
 	char buf[BUFSIZ];
 	FILE *fp;
 
-	if (statp->options & RES_NOALIASES)
+	if (ctx->resp->options & RES_NOALIASES)
 		return (NULL);
 	file = getenv("HOSTALIASES");
 	if (file == NULL || (fp = fopen(file, "rce")) == NULL)
@@ -648,15 +672,37 @@ res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
 	fclose(fp);
 	return (NULL);
 }
-libresolv_hidden_def (res_hostalias)
+libresolv_hidden_def (__res_context_hostalias)
+
+/* Common part of res_hostalias and hostalias.  */
+static const char *
+context_hostalias_common (struct resolv_context *ctx,
+			  const char *name, char *dst, size_t siz)
+{
+  if (ctx == NULL)
+    {
+      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
+      return NULL;
+    }
+  const char *result = __res_context_hostalias (ctx, name, dst, siz);
+  __resolv_context_put (ctx);
+  return result;
+}
+
+const char *
+res_hostalias (res_state statp, const char *name, char *dst, size_t siz)
+{
+  return context_hostalias_common
+    (__resolv_context_get_override (statp), name, dst, siz);
+}
 
 const char *
 hostalias (const char *name)
 {
   static char abuf[MAXDNAME];
-  return res_hostalias (&_res, name, abuf, sizeof abuf);
+  return context_hostalias_common
+    (__resolv_context_get (), name, abuf, sizeof (abuf));
 }
-libresolv_hidden_def (hostalias)
 
 #if SHLIB_COMPAT (libresolv, GLIBC_2_0, GLIBC_2_2)
 # undef res_query
diff --git a/resolv/res_send.c b/resolv/res_send.c
index a7daae8..b396aae 100644
--- a/resolv/res_send.c
+++ b/resolv/res_send.c
@@ -102,6 +102,7 @@
 #include <fcntl.h>
 #include <netdb.h>
 #include <resolv/resolv-internal.h>
+#include <resolv/resolv_context.h>
 #include <signal.h>
 #include <stdlib.h>
 #include <string.h>
@@ -400,11 +401,14 @@ res_queriesmatch(const u_char *buf1, const u_char *eom1,
 libresolv_hidden_def (res_queriesmatch)
 
 int
-__libc_res_nsend(res_state statp, const u_char *buf, int buflen,
-		 const u_char *buf2, int buflen2,
-		 u_char *ans, int anssiz, u_char **ansp, u_char **ansp2,
-		 int *nansp2, int *resplen2, int *ansp2_malloced)
+__res_context_send (struct resolv_context *ctx,
+		    const unsigned char *buf, int buflen,
+		    const unsigned char *buf2, int buflen2,
+		    unsigned char *ans, int anssiz,
+		    unsigned char **ansp, unsigned char **ansp2,
+		    int *nansp2, int *resplen2, int *ansp2_malloced)
 {
+	struct __res_state *statp = ctx->resp;
 	int gotsomewhere, terrno, try, v_circuit, resplen, n;
 
 	if (statp->nscount == 0) {
@@ -541,22 +545,36 @@ __libc_res_nsend(res_state statp, const u_char *buf, int buflen,
 	return (-1);
 }
 
+/* Common part of res_nsend and res_send.  */
+static int
+context_send_common (struct resolv_context *ctx,
+		     const unsigned char *buf, int buflen,
+		     unsigned char *ans, int anssiz)
+{
+  if (ctx == NULL)
+    {
+      RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
+      return -1;
+    }
+  int result = __res_context_send (ctx, buf, buflen, NULL, 0, ans, anssiz,
+				   NULL, NULL, NULL, NULL, NULL);
+  __resolv_context_put (ctx);
+  return result;
+}
+
 int
-res_nsend(res_state statp,
-	  const u_char *buf, int buflen, u_char *ans, int anssiz)
+res_nsend (res_state statp, const unsigned char *buf, int buflen,
+	   unsigned char *ans, int anssiz)
 {
-  return __libc_res_nsend(statp, buf, buflen, NULL, 0, ans, anssiz,
-			  NULL, NULL, NULL, NULL, NULL);
+  return context_send_common
+    (__resolv_context_get_override (statp), buf, buflen, ans, anssiz);
 }
-libresolv_hidden_def (res_nsend)
 
 int
 res_send (const unsigned char *buf, int buflen, unsigned char *ans, int anssiz)
 {
-  if (__res_maybe_init (&_res, 1) == -1)
-    /* errno should have been set by res_init in this case.  */
-    return -1;
-  return res_nsend (&_res, buf, buflen, ans, anssiz);
+  return context_send_common
+    (__resolv_context_get (), buf, buflen, ans, anssiz);
 }
 
 /* Private */
diff --git a/resolv/res_use_inet6.h b/resolv/res_use_inet6.h
new file mode 100644
index 0000000..8649833
--- /dev/null
+++ b/resolv/res_use_inet6.h
@@ -0,0 +1,49 @@
+/* Support functions for handling RES_USE_INET6 in getaddrinfo/nscd.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef _RES_USE_INET6_H
+#define _RES_USE_INET6_H
+
+#include <resolv/resolv_context.h>
+#include <resolv/resolv-internal.h>
+
+/* Ensure that RES_USE_INET6 is disabled in *CTX.  Return true if
+   __resolv_context_enable_inet6 below should enable RES_USE_INET6
+   again.  */
+static inline bool
+__resolv_context_disable_inet6 (struct resolv_context *ctx)
+{
+  if (ctx != NULL && ctx->resp->options & DEPRECATED_RES_USE_INET6)
+    {
+      ctx->resp->options &= ~DEPRECATED_RES_USE_INET6;
+      return true;
+    }
+  else
+    return false;
+}
+
+/* If ENABLE, re-enable RES_USE_INET6 in *CTX.  To be paired with
+   __resolv_context_disable_inet6.  */
+static inline void
+__resolv_context_enable_inet6 (struct resolv_context *ctx, bool enable)
+{
+  if (ctx != NULL && enable)
+    ctx->resp->options |= DEPRECATED_RES_USE_INET6;
+}
+
+#endif
diff --git a/resolv/resolv-internal.h b/resolv/resolv-internal.h
index 5a9faf8..9246497 100644
--- a/resolv/resolv-internal.h
+++ b/resolv/resolv-internal.h
@@ -52,9 +52,41 @@ enum
     RESOLV_EDNS_BUFFER_SIZE = 1200,
   };
 
+struct resolv_context;
+
+/* Internal function for implementing res_nmkquery and res_mkquery.
+   Also used by __res_context_query.  */
+int __res_context_mkquery (struct resolv_context *, int op, const char *dname,
+                           int class, int type, const unsigned char *data,
+                           unsigned char *buf, int buflen) attribute_hidden;
+
+/* Main resolver query function for use within glibc.  */
+int __res_context_search (struct resolv_context *, const char *, int, int,
+                          unsigned char *, int, unsigned char **,
+                          unsigned char **, int *, int *, int *);
+libresolv_hidden_proto (__res_context_search)
+
+/* Main resolver query function for use within glibc.  */
+int __res_context_query (struct resolv_context *, const char *, int, int,
+                         unsigned char *, int, unsigned char **,
+                         unsigned char **, int *, int *, int *);
+libresolv_hidden_proto (__res_context_query)
+
+/* Internal function used to implement the query and search
+   functions.  */
+int __res_context_send (struct resolv_context *, const unsigned char *, int,
+                        const unsigned char *, int, unsigned char *,
+                        int, unsigned char **, unsigned char **,
+                        int *, int *, int *) attribute_hidden;
+
+/* Internal function similar to res_hostalias.  */
+const char *__res_context_hostalias (struct resolv_context *,
+                                     const char *, char *, size_t);
+libresolv_hidden_proto (__res_context_hostalias);
+
 /* Add an OPT record to a DNS query.  */
-int __res_nopt (res_state, int n0, unsigned char *buf, int buflen,
-                int anslen) attribute_hidden;
+int __res_nopt (struct resolv_context *, int n0,
+                unsigned char *buf, int buflen, int anslen) attribute_hidden;
 
 /* Convert from presentation format (which usually means ASCII
    printable) to network format (which is usually some kind of binary
diff --git a/resolv/resolv_context.c b/resolv/resolv_context.c
new file mode 100644
index 0000000..5083a40
--- /dev/null
+++ b/resolv/resolv_context.c
@@ -0,0 +1,201 @@
+/* Temporary, thread-local resolver state.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <resolv_context.h>
+#include <resolv-internal.h>
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/* Currently active struct resolv_context object.  This pointer forms
+   the start of a single-linked list, using the __next member of
+   struct resolv_context.  This list serves two purposes:
+
+   (a) A subsequent call to __resolv_context_get will only increment
+       the reference counter and will not allocate a new object.  The
+       _res state freshness check is skipped in this case, too.
+
+   (b) The per-thread cleanup function defined by the resolver calls
+       __resolv_context_freeres, which will deallocate all the context
+       objects.  This avoids the need for cancellation handlers and
+       the complexity they bring, but it requires heap allocation of
+       the context object because the per-thread cleanup functions run
+       only after the stack has been fully unwound (and all on-stack
+       objects have been deallocated at this point).
+
+   The TLS variable current is updated even in
+   __resolv_context_get_override, to support case (b) above.  This does
+   not override the per-thread resolver state (as obtained by the
+   non-res_state function such as __resolv_context_get) in an
+   observable way because the wrapped context is only used to
+   implement the res_n* functions in the resolver, and those do not
+   call back into user code which could indirectly use the per-thread
+   resolver state.  */
+static __thread struct resolv_context *current attribute_tls_model_ie;
+
+/* Initialize *RESP if RES_INIT is not yet set in RESP->options, or if
+   res_init in some other thread requested re-initializing.  */
+static __attribute__ ((warn_unused_result)) bool
+maybe_init (struct __res_state *resp, bool preinit)
+{
+  if (resp->options & RES_INIT)
+    {
+      if (__res_initstamp != resp->_u._ext.initstamp)
+        {
+          if (resp->nscount > 0)
+            __res_iclose (resp, true);
+          return __res_vinit (resp, 1) == 0;
+        }
+      return true;
+    }
+
+  if (preinit)
+    {
+      if (!resp->retrans)
+        resp->retrans = RES_TIMEOUT;
+      if (!resp->retry)
+        resp->retry = RES_DFLRETRY;
+      resp->options = RES_DEFAULT;
+      if (!resp->id)
+        resp->id = res_randomid ();
+    }
+  return __res_vinit (resp, preinit) == 0;
+}
+
+/* Allocate a new context object and initialize it.  The object is put
+   on the current list.  */
+static struct resolv_context *
+context_alloc (struct __res_state *resp)
+{
+  struct resolv_context *ctx = malloc (sizeof (*ctx));
+  if (ctx == NULL)
+    return NULL;
+  ctx->resp = resp;
+  ctx->__refcount = 1;
+  ctx->__from_res = true;
+  ctx->__next = current;
+  current = ctx;
+  return ctx;
+}
+
+/* Deallocate the context object and all the state within.   */
+static void
+context_free (struct resolv_context *ctx)
+{
+  current = ctx->__next;
+  free (ctx);
+}
+
+/* Reuse the current context object.  */
+static struct resolv_context *
+context_reuse (void)
+{
+  /* A context object created by __resolv_context_get_override cannot
+     be reused.  */
+  assert (current->__from_res);
+
+  ++current->__refcount;
+
+  /* Check for reference counter wraparound.  This can only happen if
+     the get/put functions are not properly paired.  */
+  assert (current->__refcount > 0);
+
+  return current;
+}
+
+/* Backing function for the __resolv_context_get family of
+   functions.  */
+static struct resolv_context *
+context_get (bool preinit)
+{
+  if (current != NULL)
+    return context_reuse ();
+
+  struct resolv_context *ctx = context_alloc (&_res);
+  if (ctx == NULL)
+    return NULL;
+  if (!maybe_init (ctx->resp, preinit))
+    {
+      context_free (ctx);
+      return NULL;
+    }
+  return ctx;
+}
+
+struct resolv_context *
+__resolv_context_get (void)
+{
+  return context_get (false);
+}
+libc_hidden_def (__resolv_context_get)
+
+struct resolv_context *
+__resolv_context_get_preinit (void)
+{
+  return context_get (true);
+}
+libc_hidden_def (__resolv_context_get_preinit)
+
+struct resolv_context *
+__resolv_context_get_override (struct __res_state *resp)
+{
+  /* NB: As explained asbove, context_alloc will put the context on
+     the current list.  */
+  struct resolv_context *ctx = context_alloc (resp);
+  if (ctx == NULL)
+    return NULL;
+
+  ctx->__from_res = false;
+  return ctx;
+}
+libc_hidden_def (__resolv_context_get_override)
+
+void
+__resolv_context_put (struct resolv_context *ctx)
+{
+  if (ctx == NULL)
+    return;
+
+  /* NB: Callers assume that this function preserves errno and
+     h_errno.  */
+
+  assert (current == ctx);
+  assert (ctx->__refcount > 0);
+
+  if (ctx->__from_res && --ctx->__refcount > 0)
+    /* Do not pop this context yet.  */
+    return;
+
+  context_free (ctx);
+}
+libc_hidden_def (__resolv_context_put)
+
+void
+__resolv_context_freeres (void)
+{
+  /* Deallocate the entire chain of context objects.  */
+  struct resolv_context *ctx = current;
+  current = NULL;
+  while (ctx != NULL)
+    {
+      struct resolv_context *next = ctx->__next;
+      context_free (ctx);
+      ctx = next;
+    }
+}
diff --git a/resolv/resolv_context.h b/resolv/resolv_context.h
new file mode 100644
index 0000000..27c8d56
--- /dev/null
+++ b/resolv/resolv_context.h
@@ -0,0 +1,95 @@
+/* Temporary, thread-local resolver state.
+   Copyright (C) 2017 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* struct resolv_context objects are allocated on the heap,
+   initialized by __resolv_context_get (and its variants), and
+   destroyed by __resolv_context_put.
+
+   A nested call to __resolv_context_get (after another call to
+   __resolv_context_get without a matching __resolv_context_put call,
+   on the same thread) returns the original pointer, instead of
+   allocating a new context.  This prevents unexpected reloading of
+   the resolver configuration.  Care is taken to keep the context in
+   sync with the thread-local _res object.  (This does not happen with
+   __resolv_context_get_override, and __resolv_context_get_no_inet6 may
+   also interpose another context object if RES_USE_INET6 needs to be
+   disabled.)
+
+   In contrast to struct __res_state, struct resolv_context is not
+   affected by ABI compatibility concerns.
+
+   For the benefit of the res_n* functions, a struct __res_state
+   pointer is included in the context object, and a separate
+   initialization function is provided.  */
+
+#ifndef _RESOLV_CONTEXT_H
+#define _RESOLV_CONTEXT_H
+
+#include <stdbool.h>
+#include <stddef.h>
+#include <bits/types/res_state.h>
+
+/* Temporary resolver state.  */
+struct resolv_context
+{
+  struct __res_state *resp;     /* Backing resolver state.   */
+
+
+  /* The following fields are for internal use within the
+     resolv_context module.  */
+  size_t __refcount;            /* Count of reusages by the get functions.  */
+  bool __from_res;              /* True if created from _res.  */
+
+  /* If RES_USE_INET6 was disabled at this level, this field points to
+     the previous context.  */
+  struct resolv_context *__next;
+};
+
+/* Return the current temporary resolver context, or NULL if there was
+   an error (indicated by errno).  A call to this function must be
+   paired with a call to __resolv_context_put.  */
+struct resolv_context *__resolv_context_get (void)
+  __attribute__ ((warn_unused_result));
+libc_hidden_proto (__resolv_context_get)
+
+/* Deallocate the temporary resolver context.  Converse of
+   __resolv_context_get.  Restore the RES_USE_INET6 flag if necessary.
+   Do nothing if CTX is NULL.  */
+void __resolv_context_put (struct resolv_context *ctx);
+libc_hidden_proto (__resolv_context_put)
+
+/* Like __resolv_context_get, but the _res structure can be partially
+   initialzed and those changes will not be overwritten.  */
+struct resolv_context *__resolv_context_get_preinit (void)
+  __attribute__ ((warn_unused_result));
+libc_hidden_proto (__resolv_context_get_preinit)
+
+/* Wrap a struct __res_state object in a struct resolv_context object.
+   A call to this function must be paired with a call to
+   __resolv_context_put.  */
+struct resolv_context *__resolv_context_get_override (struct __res_state *)
+  __attribute__ ((nonnull (1), warn_unused_result));
+libc_hidden_proto (__resolv_context_get_override)
+
+/* Called during thread shutdown to free the associated resolver
+   context (mostly in response to cancellation, otherwise the
+   __resolv_context_get/__resolv_context_put pairing will already have
+   deallocated the context object).  */
+void __resolv_context_freeres (void) attribute_hidden;
+
+#endif /* _RESOLV_CONTEXT_H */
diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c
index 4fb1eae..efa7118 100644
--- a/sysdeps/posix/getaddrinfo.c
+++ b/sysdeps/posix/getaddrinfo.c
@@ -60,6 +60,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <netdb.h>
 #include <nss.h>
 #include <resolv/resolv-internal.h>
+#include <resolv/resolv_context.h>
+#include <resolv/res_use_inet6.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdio_ext.h>
@@ -266,7 +268,8 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
       if (herrno == NETDB_INTERNAL)					      \
 	{								      \
 	  __set_h_errno (herrno);					      \
-	  _res.options |= old_res_options & DEPRECATED_RES_USE_INET6;	      \
+	  __resolv_context_enable_inet6 (res_ctx, res_enable_inet6);	      \
+	  __resolv_context_put (res_ctx);				      \
 	  result = -EAI_SYSTEM;						      \
 	  goto free_and_return;						      \
 	}								      \
@@ -279,7 +282,8 @@ convert_hostent_to_gaih_addrtuple (const struct addrinfo *req,
     {									      \
       if (!convert_hostent_to_gaih_addrtuple (req, _family,h, &addrmem))      \
 	{								      \
-	  _res.options |= old_res_options & DEPRECATED_RES_USE_INET6;	      \
+	  __resolv_context_enable_inet6 (res_ctx, res_enable_inet6);	      \
+	  __resolv_context_put (res_ctx);				      \
 	  result = -EAI_SYSTEM;						      \
 	  goto free_and_return;						      \
 	}								      \
@@ -582,7 +586,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
 	  enum nss_status inet6_status = NSS_STATUS_UNAVAIL;
 	  enum nss_status status = NSS_STATUS_UNAVAIL;
 	  int no_more;
-	  int old_res_options;
+	  struct resolv_context *res_ctx = NULL;
+	  bool res_enable_inet6 = false;
 
 	  /* If we do not have to look for IPv6 addresses or the canonical
 	     name, use the simple, old functions, which do not support
@@ -765,16 +770,14 @@ gaih_inet (const char *name, const struct gaih_service *service,
 	    no_more = 0;
 	  nip = __nss_hosts_database;
 
-	  /* Initialize configurations.  */
-	  if (__res_maybe_init (&_res, 0) == -1)
-	    no_more = 1;
-
 	  /* If we are looking for both IPv4 and IPv6 address we don't
 	     want the lookup functions to automatically promote IPv4
-	     addresses to IPv6 addresses.  Currently this is decided
-	     by setting the RES_USE_INET6 bit in _res.options.  */
-	  old_res_options = _res.options;
-	  _res.options &= ~DEPRECATED_RES_USE_INET6;
+	     addresses to IPv6 addresses, so we use the no_inet6
+	     function variant.  */
+	  res_ctx = __resolv_context_get ();
+	  res_enable_inet6 = __resolv_context_disable_inet6 (res_ctx);
+	  if (res_ctx == NULL)
+	    no_more = 1;
 
 	  while (!no_more)
 	    {
@@ -811,8 +814,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
 
 		      if (!scratch_buffer_grow (tmpbuf))
 			{
-			  _res.options
-			    |= old_res_options & DEPRECATED_RES_USE_INET6;
+			  __resolv_context_enable_inet6
+			    (res_ctx, res_enable_inet6);
+			  __resolv_context_put (res_ctx);
 			  result = -EAI_MEMORY;
 			  goto free_and_return;
 			}
@@ -911,9 +915,9 @@ gaih_inet (const char *name, const struct gaih_service *service,
 			      canonbuf = getcanonname (nip, at, name);
 			      if (canonbuf == NULL)
 				{
-				  _res.options
-				    |= old_res_options
-				    & DEPRECATED_RES_USE_INET6;
+				  __resolv_context_enable_inet6
+				    (res_ctx, res_enable_inet6);
+				  __resolv_context_put (res_ctx);
 				  result = -EAI_MEMORY;
 				  goto free_and_return;
 				}
@@ -953,7 +957,8 @@ gaih_inet (const char *name, const struct gaih_service *service,
 		nip = nip->next;
 	    }
 
-	  _res.options |= old_res_options & DEPRECATED_RES_USE_INET6;
+	  __resolv_context_enable_inet6 (res_ctx, res_enable_inet6);
+	  __resolv_context_put (res_ctx);
 
 	  if (h_errno == NETDB_INTERNAL)
 	    {

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog                    |   85 ++++++++++++
 include/resolv.h             |   23 ----
 nscd/aicache.c               |   21 ++--
 nss/digits_dots.c            |   21 +++-
 nss/getXXbyYY.c              |   28 ++++-
 nss/getXXbyYY_r.c            |   34 +++--
 nss/getnssent_r.c            |   42 +++++--
 nss/nsswitch.h               |   10 ++
 resolv/Makefile              |    3 +-
 resolv/Versions              |   10 +-
 resolv/compat-gethnamaddr.c  |   95 +++++++++-----
 resolv/nss_dns/dns-canon.c   |   19 ++-
 resolv/nss_dns/dns-host.c    |  104 +++++++++------
 resolv/nss_dns/dns-network.c |   21 ++-
 resolv/res-close.c           |    3 +
 resolv/res_libc.c            |   31 -----
 resolv/res_mkquery.c         |   92 ++++++++-----
 resolv/res_query.c           |  298 ++++++++++++++++++++++++------------------
 resolv/res_send.c            |   44 +++++--
 resolv/res_use_inet6.h       |   49 +++++++
 resolv/resolv-internal.h     |   36 +++++-
 resolv/resolv_context.c      |  201 ++++++++++++++++++++++++++++
 resolv/resolv_context.h      |   95 +++++++++++++
 sysdeps/posix/getaddrinfo.c  |   39 +++---
 24 files changed, 1033 insertions(+), 371 deletions(-)
 create mode 100644 resolv/res_use_inet6.h
 create mode 100644 resolv/resolv_context.c
 create mode 100644 resolv/resolv_context.h


hooks/post-receive
-- 
GNU C Library master sources


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]