From 11604b536619c2e144ee6346cf3ae8d538f57bbf Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 2 Aug 2017 20:38:04 -0700 Subject: QHostInfo: adapt to glibc 2.26 no longer requiring us to res_init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit From the announcement[1] - The GNU C Library will now detect when /etc/resolv.conf has been modified and reload the changed configuration. The new resolver option “no-reload” (RES_NORELOAD) disables this behavior. Since glibc can do it, we don't have to call res_init before every single getaddrinfo() call. And since we don't need to call res_init, we don't need to load libresolv.so at all, until we need res_ninit. We won't do it even if the user configured "no-reload" in /etc/resolv.conf or RES_NORELOAD in the res variable -- let's assume that it is the intent, like when /etc/resolv.conf is known to never change. [1] https://sourceware.org/ml/libc-alpha/2017-08/msg00010.html Change-Id: I3868166e5efc45538544fffd14d738d40c375fd1 Reviewed-by: Timur Pocheptsov --- src/network/kernel/qhostinfo_unix.cpp | 74 ++++++++++++++++++++++++++--------- 1 file changed, 56 insertions(+), 18 deletions(-) diff --git a/src/network/kernel/qhostinfo_unix.cpp b/src/network/kernel/qhostinfo_unix.cpp index 9a24938284..91e5d18ae5 100644 --- a/src/network/kernel/qhostinfo_unix.cpp +++ b/src/network/kernel/qhostinfo_unix.cpp @@ -83,6 +83,11 @@ QT_BEGIN_NAMESPACE # define Q_ADDRCONFIG AI_ADDRCONFIG #endif +enum LibResolvFeature { + NeedResInit, + NeedResNInit +}; + typedef struct __res_state *res_state_ptr; typedef int (*res_init_proto)(void); @@ -93,9 +98,29 @@ typedef void (*res_nclose_proto)(res_state_ptr); static res_nclose_proto local_res_nclose = 0; static res_state_ptr local_res = 0; -static bool resolveLibraryInternal() -{ #if QT_CONFIG(library) && !defined(Q_OS_QNX) +namespace { +struct LibResolv +{ + enum { +#ifdef RES_NORELOAD + // If RES_NORELOAD is defined, then the libc is capable of watching + // /etc/resolv.conf for changes and reloading as necessary. So accept + // whatever is configured. + ReinitNecessary = false +#else + ReinitNecessary = true +#endif + }; + + QLibrary lib; + LibResolv(); + ~LibResolv() { lib.unload(); } +}; +} + +LibResolv::LibResolv() +{ QLibrary lib; #ifdef LIBRESOLV_SO lib.setFileName(QStringLiteral(LIBRESOLV_SO)); @@ -104,32 +129,45 @@ static bool resolveLibraryInternal() { lib.setFileName(QLatin1String("resolv")); if (!lib.load()) - return false; + return; } - local_res_init = res_init_proto(lib.resolve("__res_init")); - if (!local_res_init) - local_res_init = res_init_proto(lib.resolve("res_init")); - + // res_ninit is required for localDomainName() local_res_ninit = res_ninit_proto(lib.resolve("__res_ninit")); if (!local_res_ninit) local_res_ninit = res_ninit_proto(lib.resolve("res_ninit")); - - if (!local_res_ninit) { - // if we can't get a thread-safe context, we have to use the global _res state - local_res = res_state_ptr(lib.resolve("_res")); - } else { + if (local_res_ninit) { + // we must now find res_nclose local_res_nclose = res_nclose_proto(lib.resolve("res_nclose")); if (!local_res_nclose) local_res_nclose = res_nclose_proto(lib.resolve("__res_nclose")); if (!local_res_nclose) - local_res_ninit = 0; + local_res_ninit = nullptr; } -#endif - return true; + if (ReinitNecessary || !local_res_ninit) { + local_res_init = res_init_proto(lib.resolve("__res_init")); + if (!local_res_init) + local_res_init = res_init_proto(lib.resolve("res_init")); + + if (local_res_init && !local_res_ninit) { + // if we can't get a thread-safe context, we have to use the global _res state + local_res = res_state_ptr(lib.resolve("_res")); + } + } +} +Q_GLOBAL_STATIC(LibResolv, libResolv) + +static void resolveLibrary(LibResolvFeature f) +{ + if (LibResolv::ReinitNecessary || f == NeedResNInit) + libResolv(); +} +#else // QT_CONFIG(library) || Q_OS_QNX +static void resolveLibrary(LibResolvFeature) +{ } -Q_GLOBAL_STATIC_WITH_ARGS(bool, resolveLibrary, (resolveLibraryInternal())) +#endif // QT_CONFIG(library) || Q_OS_QNX QHostInfo QHostInfoAgent::fromName(const QString &hostName) { @@ -141,7 +179,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) #endif // Load res_init on demand. - resolveLibrary(); + resolveLibrary(NeedResInit); // If res_init is available, poll it. if (local_res_init) @@ -320,7 +358,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) QString QHostInfo::localDomainName() { #if !defined(Q_OS_VXWORKS) && !defined(Q_OS_ANDROID) - resolveLibrary(); + resolveLibrary(NeedResNInit); if (local_res_ninit) { // using thread-safe version res_state_ptr state = res_state_ptr(malloc(sizeof(*state))); -- cgit v1.2.3