[PATCH 09/11] inet/resolv: add res_ninit and res_nclose

Daniel Mack zonque at gmail.com
Tue Jul 12 22:30:54 UTC 2011


Some reordering of existing functions was necessary in order to provide
this functionality.

Signed-off-by: Daniel Mack <zonque at gmail.com>
---
 include/resolv.h   |    8 ++--
 libc/inet/resolv.c |  141 +++++++++++++++++++++++++++++++++++++++++++++++-----
 2 files changed, 132 insertions(+), 17 deletions(-)

diff --git a/include/resolv.h b/include/resolv.h
index 96ad4ab..186b781 100644
--- a/include/resolv.h
+++ b/include/resolv.h
@@ -337,6 +337,8 @@ __END_DECLS
 #define dn_comp			__dn_comp
 #define dn_expand		__dn_expand
 #define dn_skipname		__dn_skipname
+#define res_ninit		__res_ninit
+#define res_nclose		__res_nclose
 #if 0
 #define fp_resstat		__fp_resstat
 #define loc_aton		__loc_aton
@@ -359,8 +361,6 @@ __END_DECLS
 #define res_hostalias		__res_hostalias
 #define res_mailok		__res_mailok
 #define res_nameinquery		__res_nameinquery
-#define res_nclose		__res_nclose
-#define res_ninit		__res_ninit
 #define res_nmkquery		__res_nmkquery
 #define res_npquery		__res_npquery
 #define res_nquery		__res_nquery
@@ -409,6 +409,8 @@ int		dn_comp (const char *, u_char *, int, u_char **, u_char **)
      __THROW;
 int		dn_expand (const u_char *, const u_char *, const u_char *,
 			   char *, int) __THROW;
+int		res_ninit (res_state) __THROW;
+void		res_nclose (res_state) __THROW;
 #if 0
 u_int		res_randomid (void) __THROW;
 int		res_nameinquery (const char *, int, int,
@@ -417,7 +419,6 @@ int		res_queriesmatch (const u_char *, const u_char *,
 				  const u_char *, const u_char *) __THROW;
 const char *	p_section (int section, int opcode) __THROW;
 /* Things involving a resolver context. */
-int		res_ninit (res_state) __THROW;
 int		res_nisourserver (const res_state,
 				  const struct sockaddr_in *) __THROW;
 void		fp_resstat (const res_state, FILE *) __THROW;
@@ -436,7 +437,6 @@ int		res_nmkquery (res_state, int, const char *, int, int,
 			      int) __THROW;
 int		res_nsend (res_state, const u_char *, int, u_char *, int)
      __THROW;
-void		res_nclose (res_state) __THROW;
 #endif
 __END_DECLS
 
diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c
index 627423b..34dfbfa 100644
--- a/libc/inet/resolv.c
+++ b/libc/inet/resolv.c
@@ -297,6 +297,7 @@ Domain name in a message can be represented as either:
 #include <features.h>
 #include <string.h>
 #include <stdio.h>
+#include <stdio_ext.h>
 #include <signal.h>
 #include <errno.h>
 #include <sys/poll.h>
@@ -3440,12 +3441,10 @@ static void res_sync_func(void)
 	 */
 }
 
-/* Our res_init never fails (always returns 0) */
-int res_init(void)
+static int
+__res_vinit(res_state rp, int preinit)
 {
-	struct __res_state *rp = &(_res);
-	int i;
-	int n;
+	int i, n, options, retrans, retry, ndots;
 #ifdef __UCLIBC_HAS_IPV6__
 	int m = 0;
 #endif
@@ -3454,13 +3453,27 @@ int res_init(void)
 	__close_nameservers();
 	__open_nameservers();
 
-	__res_sync = res_sync_func;
+	if (preinit) {
+		options = rp->options;
+		retrans = rp->retrans;
+		retry = rp->retry;
+		ndots = rp->ndots;
+	}
 
 	memset(rp, 0, sizeof(*rp));
-	rp->options = RES_INIT;
-	rp->retrans = RES_TIMEOUT;
-	rp->retry = RES_DFLRETRY;
-	rp->ndots = 1;
+
+	if (!preinit) {
+		rp->options = RES_DEFAULT;
+		rp->retrans = RES_TIMEOUT;
+		rp->retry = RES_DFLRETRY;
+		rp->ndots = 1;
+	} else {
+		rp->options = options;
+		rp->retrans = retrans;
+		rp->retry = retry;
+		rp->ndots = ndots;
+	}
+
 #ifdef __UCLIBC_HAS_COMPAT_RES_STATE__
 	/* Was: "rp->id = random();" but:
 	 * - random() pulls in largish static buffers
@@ -3526,13 +3539,14 @@ int res_init(void)
 	rp->_u._ext.nscount = m;
 #endif
 
+	rp->options |= RES_INIT;
+
 	__UCLIBC_MUTEX_UNLOCK(__resolv_lock);
 	return 0;
 }
-libc_hidden_def(res_init)
 
-#ifdef __UCLIBC_HAS_BSD_RES_CLOSE__
-void res_close(void)
+static void
+__res_iclose(res_state statp, int free_addr) 
 {
 	__UCLIBC_MUTEX_LOCK(__resolv_lock);
 	__close_nameservers();
@@ -3552,6 +3566,26 @@ void res_close(void)
 	memset(&_res, 0, sizeof(_res));
 	__UCLIBC_MUTEX_UNLOCK(__resolv_lock);
 }
+
+/*
+ * This routine is for closing the socket if a virtual circuit is used and
+ * the program wants to close it.  This provides support for endhostent()
+ * which expects to close the socket.
+ *
+ * This routine is not expected to be user visible.
+ */
+
+void
+res_nclose(res_state statp)
+{
+	__res_iclose(statp, 1);
+}
+
+#ifdef __UCLIBC_HAS_BSD_RES_CLOSE__
+void res_close(void)
+{
+	__res_iclose(&_res, 0);
+}
 #endif /* __UCLIBC_HAS_BSD_RES_CLOSE__ */
 
 /* This needs to be after the use of _res in res_init, above.  */
@@ -3583,6 +3617,87 @@ struct __res_state *__resp = &_res;
 # endif
 #endif /* !__UCLIBC_HAS_THREADS__ */
 
+static unsigned int
+res_randomid(void) {
+	return 0xffff & getpid();
+}
+
+/* Our res_init never fails (always returns 0) */
+int
+res_init(void)
+{
+	/*
+	 * These three fields used to be statically initialized.  This made
+	 * it hard to use this code in a shared library.  It is necessary,
+	 * now that we're doing dynamic initialization here, that we preserve
+	 * the old semantics: if an application modifies one of these three
+	 * fields of _res before res_init() is called, res_init() will not
+	 * alter them.  Of course, if an application is setting them to
+	 * _zero_ before calling res_init(), hoping to override what used
+	 * to be the static default, we can't detect it and unexpected results
+	 * will follow.  Zero for any of these fields would make no sense,
+	 * so one can safely assume that the applications were already getting
+	 * unexpected results.
+	 *
+	 * _res.options is tricky since some apps were known to diddle the bits
+	 * before res_init() was first called. We can't replicate that semantic
+	 * with dynamic initialization (they may have turned bits off that are
+	 * set in RES_DEFAULT).  Our solution is to declare such applications
+	 * "broken".  They could fool us by setting RES_INIT but none do (yet).
+	 */
+
+	__UCLIBC_MUTEX_LOCK(__resolv_lock);
+
+	if (!_res.retrans)
+			_res.retrans = RES_TIMEOUT;
+	if (!_res.retry)
+			_res.retry = 4;
+	if (!(_res.options & RES_INIT))
+			_res.options = RES_DEFAULT;
+
+	/*
+	 * This one used to initialize implicitly to zero, so unless the app
+	 * has set it to something in particular, we can randomize it now.
+	 */
+	if (!_res.id)
+			_res.id = res_randomid();
+	__res_sync = res_sync_func;
+
+	__UCLIBC_MUTEX_UNLOCK(__resolv_lock);
+
+	__res_vinit(&_res, 1);
+
+	return 0;
+}
+libc_hidden_def(res_init)
+
+/*
+ * Set up default settings.  If the configuration file exist, the values
+ * there will have precedence.  Otherwise, the server address is set to
+ * INADDR_ANY and the default domain name comes from the gethostname().
+ *
+ * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1
+ * rather than INADDR_ANY ("0.0.0.0") as the default name server address
+ * since it was noted that INADDR_ANY actually meant ``the first interface
+ * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface,
+ * it had to be "up" in order for you to reach your own name server.  It
+ * was later decided that since the recommended practice is to always
+ * install local static routes through 127.0.0.1 for all your network
+ * interfaces, that we could solve this problem without a code change.
+ *
+ * The configuration file should always be used, since it is the only way
+ * to specify a default domain.  If you are running a server on your local
+ * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1"
+ * in the configuration file.
+ *
+ * Return 0 if completes successfully, -1 on error
+ */
+int
+res_ninit(res_state statp)
+{
+	return __res_vinit(statp, 0);
+}
+
 #endif /* L_res_init */
 
 #ifdef L_res_state
-- 
1.7.5.4



More information about the uClibc mailing list