QHostInfo: adapt to glibc 2.26 no longer requiring us to res_init
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 <timur.pocheptsov@qt.io>
This commit is contained in:
parent
3ad8295451
commit
11604b5366
@ -83,6 +83,11 @@ QT_BEGIN_NAMESPACE
|
|||||||
# define Q_ADDRCONFIG AI_ADDRCONFIG
|
# define Q_ADDRCONFIG AI_ADDRCONFIG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
enum LibResolvFeature {
|
||||||
|
NeedResInit,
|
||||||
|
NeedResNInit
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct __res_state *res_state_ptr;
|
typedef struct __res_state *res_state_ptr;
|
||||||
|
|
||||||
typedef int (*res_init_proto)(void);
|
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_nclose_proto local_res_nclose = 0;
|
||||||
static res_state_ptr local_res = 0;
|
static res_state_ptr local_res = 0;
|
||||||
|
|
||||||
static bool resolveLibraryInternal()
|
|
||||||
{
|
|
||||||
#if QT_CONFIG(library) && !defined(Q_OS_QNX)
|
#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;
|
QLibrary lib;
|
||||||
#ifdef LIBRESOLV_SO
|
#ifdef LIBRESOLV_SO
|
||||||
lib.setFileName(QStringLiteral(LIBRESOLV_SO));
|
lib.setFileName(QStringLiteral(LIBRESOLV_SO));
|
||||||
@ -104,32 +129,45 @@ static bool resolveLibraryInternal()
|
|||||||
{
|
{
|
||||||
lib.setFileName(QLatin1String("resolv"));
|
lib.setFileName(QLatin1String("resolv"));
|
||||||
if (!lib.load())
|
if (!lib.load())
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
local_res_init = res_init_proto(lib.resolve("__res_init"));
|
// res_ninit is required for localDomainName()
|
||||||
if (!local_res_init)
|
|
||||||
local_res_init = res_init_proto(lib.resolve("res_init"));
|
|
||||||
|
|
||||||
local_res_ninit = res_ninit_proto(lib.resolve("__res_ninit"));
|
local_res_ninit = res_ninit_proto(lib.resolve("__res_ninit"));
|
||||||
if (!local_res_ninit)
|
if (!local_res_ninit)
|
||||||
local_res_ninit = res_ninit_proto(lib.resolve("res_ninit"));
|
local_res_ninit = res_ninit_proto(lib.resolve("res_ninit"));
|
||||||
|
if (local_res_ninit) {
|
||||||
if (!local_res_ninit) {
|
// we must now find res_nclose
|
||||||
// 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 {
|
|
||||||
local_res_nclose = res_nclose_proto(lib.resolve("res_nclose"));
|
local_res_nclose = res_nclose_proto(lib.resolve("res_nclose"));
|
||||||
if (!local_res_nclose)
|
if (!local_res_nclose)
|
||||||
local_res_nclose = res_nclose_proto(lib.resolve("__res_nclose"));
|
local_res_nclose = res_nclose_proto(lib.resolve("__res_nclose"));
|
||||||
if (!local_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_WITH_ARGS(bool, resolveLibrary, (resolveLibraryInternal()))
|
}
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
#endif // QT_CONFIG(library) || Q_OS_QNX
|
||||||
|
|
||||||
QHostInfo QHostInfoAgent::fromName(const QString &hostName)
|
QHostInfo QHostInfoAgent::fromName(const QString &hostName)
|
||||||
{
|
{
|
||||||
@ -141,7 +179,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Load res_init on demand.
|
// Load res_init on demand.
|
||||||
resolveLibrary();
|
resolveLibrary(NeedResInit);
|
||||||
|
|
||||||
// If res_init is available, poll it.
|
// If res_init is available, poll it.
|
||||||
if (local_res_init)
|
if (local_res_init)
|
||||||
@ -320,7 +358,7 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName)
|
|||||||
QString QHostInfo::localDomainName()
|
QString QHostInfo::localDomainName()
|
||||||
{
|
{
|
||||||
#if !defined(Q_OS_VXWORKS) && !defined(Q_OS_ANDROID)
|
#if !defined(Q_OS_VXWORKS) && !defined(Q_OS_ANDROID)
|
||||||
resolveLibrary();
|
resolveLibrary(NeedResNInit);
|
||||||
if (local_res_ninit) {
|
if (local_res_ninit) {
|
||||||
// using thread-safe version
|
// using thread-safe version
|
||||||
res_state_ptr state = res_state_ptr(malloc(sizeof(*state)));
|
res_state_ptr state = res_state_ptr(malloc(sizeof(*state)));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user