diff options
Diffstat (limited to 'src/network/kernel')
22 files changed, 1195 insertions, 447 deletions
diff --git a/src/network/kernel/kernel.pri b/src/network/kernel/kernel.pri index 7074fcd5eb..0e4cef5e74 100644 --- a/src/network/kernel/kernel.pri +++ b/src/network/kernel/kernel.pri @@ -16,7 +16,8 @@ HEADERS += kernel/qtnetworkglobal.h \ kernel/qnetworkinterface.h \ kernel/qnetworkinterface_p.h \ kernel/qnetworkinterface_unix_p.h \ - kernel/qnetworkproxy.h + kernel/qnetworkproxy.h \ + kernel/qnetconmonitor_p.h SOURCES += kernel/qauthenticator.cpp \ kernel/qhostaddress.cpp \ @@ -71,6 +72,17 @@ mac { !uikit: LIBS_PRIVATE += -framework CoreServices -framework SystemConfiguration } +macos | ios { + OBJECTIVE_SOURCES += \ + kernel/qnetconmonitor_darwin.mm + + LIBS_PRIVATE += -framework SystemConfiguration +} else { + SOURCES += kernel/qnetconmonitor_stub.cpp +} + +qtConfig(gssapi): LIBS_PRIVATE += -lgssapi_krb5 + uikit:HEADERS += kernel/qnetworkinterface_uikit_p.h osx:SOURCES += kernel/qnetworkproxy_mac.cpp else:win32:!winrt: SOURCES += kernel/qnetworkproxy_win.cpp diff --git a/src/network/kernel/qauthenticator.cpp b/src/network/kernel/qauthenticator.cpp index 47ce9ab0c6..4100dfd784 100644 --- a/src/network/kernel/qauthenticator.cpp +++ b/src/network/kernel/qauthenticator.cpp @@ -52,22 +52,30 @@ #ifdef Q_OS_WIN #include <qmutex.h> -#include <private/qmutexpool_p.h> #include <rpc.h> -#ifndef Q_OS_WINRT +#endif + +#if QT_CONFIG(sspi) // SSPI #define SECURITY_WIN32 1 #include <security.h> -#endif +#elif QT_CONFIG(gssapi) // GSSAPI +#include <gssapi/gssapi.h> #endif QT_BEGIN_NAMESPACE static QByteArray qNtlmPhase1(); static QByteArray qNtlmPhase3(QAuthenticatorPrivate *ctx, const QByteArray& phase2data); -#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) -static QByteArray qNtlmPhase1_SSPI(QAuthenticatorPrivate *ctx); -static QByteArray qNtlmPhase3_SSPI(QAuthenticatorPrivate *ctx, const QByteArray& phase2data); -#endif +#if QT_CONFIG(sspi) // SSPI +static QByteArray qSspiStartup(QAuthenticatorPrivate *ctx, QAuthenticatorPrivate::Method method, + const QString& host); +static QByteArray qSspiContinue(QAuthenticatorPrivate *ctx, QAuthenticatorPrivate::Method method, + const QString& host, const QByteArray& challenge = QByteArray()); +#elif QT_CONFIG(gssapi) // GSSAPI +static QByteArray qGssapiStartup(QAuthenticatorPrivate *ctx, const QString& host); +static QByteArray qGssapiContinue(QAuthenticatorPrivate *ctx, + const QByteArray& challenge = QByteArray()); +#endif // gssapi /*! \class QAuthenticator @@ -90,6 +98,7 @@ static QByteArray qNtlmPhase3_SSPI(QAuthenticatorPrivate *ctx, const QByteArray& \li Basic \li NTLM version 2 \li Digest-MD5 + \li SPNEGO/Negotiate \endlist \target qauthenticator-options @@ -133,6 +142,10 @@ static QByteArray qNtlmPhase3_SSPI(QAuthenticatorPrivate *ctx, const QByteArray& The Digest-MD5 authentication mechanism supports no outgoing options. + \section2 SPNEGO/Negotiate + + This authentication mechanism currently supports no incoming or outgoing options. + \sa QSslSocket */ @@ -187,7 +200,7 @@ QAuthenticator &QAuthenticator::operator=(const QAuthenticator &other) d->options = other.d->options; } else if (d->phase == QAuthenticatorPrivate::Start) { delete d; - d = 0; + d = nullptr; } return *this; } @@ -339,21 +352,25 @@ bool QAuthenticator::isNull() const return !d; } -#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) -class QNtlmWindowsHandles +#if QT_CONFIG(sspi) // SSPI +class QSSPIWindowsHandles { public: CredHandle credHandle; CtxtHandle ctxHandle; }; -#endif +#elif QT_CONFIG(gssapi) // GSSAPI +class QGssApiHandles +{ +public: + gss_ctx_id_t gssCtx = nullptr; + gss_name_t targetName; +}; +#endif // gssapi QAuthenticatorPrivate::QAuthenticatorPrivate() : method(None) - #if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) - , ntlmWindowsHandles(0) - #endif , hasFailed(false) , phase(Start) , nonceCount(0) @@ -363,13 +380,7 @@ QAuthenticatorPrivate::QAuthenticatorPrivate() nonceCount = 0; } -QAuthenticatorPrivate::~QAuthenticatorPrivate() -{ -#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) - if (ntlmWindowsHandles) - delete ntlmWindowsHandles; -#endif -} +QAuthenticatorPrivate::~QAuthenticatorPrivate() = default; void QAuthenticatorPrivate::updateCredentials() { @@ -424,6 +435,9 @@ void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByt } else if (method < DigestMd5 && str.startsWith("digest")) { method = DigestMd5; headerVal = current.second.mid(7); + } else if (method < Negotiate && str.startsWith("negotiate")) { + method = Negotiate; + headerVal = current.second.mid(10); } } @@ -439,6 +453,7 @@ void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByt phase = Done; break; case Ntlm: + case Negotiate: // work is done in calculateResponse() break; case DigestMd5: { @@ -456,33 +471,36 @@ void QAuthenticatorPrivate::parseHttpResponse(const QList<QPair<QByteArray, QByt } } -QByteArray QAuthenticatorPrivate::calculateResponse(const QByteArray &requestMethod, const QByteArray &path) +QByteArray QAuthenticatorPrivate::calculateResponse(const QByteArray &requestMethod, const QByteArray &path, const QString& host) { +#if !QT_CONFIG(sspi) && !QT_CONFIG(gssapi) + Q_UNUSED(host); +#endif QByteArray response; - const char *methodString = 0; + const char* methodString = nullptr; switch(method) { case QAuthenticatorPrivate::None: methodString = ""; phase = Done; break; case QAuthenticatorPrivate::Basic: - methodString = "Basic "; + methodString = "Basic"; response = user.toLatin1() + ':' + password.toLatin1(); response = response.toBase64(); phase = Done; break; case QAuthenticatorPrivate::DigestMd5: - methodString = "Digest "; + methodString = "Digest"; response = digestMd5Response(challenge, requestMethod, path); phase = Done; break; case QAuthenticatorPrivate::Ntlm: - methodString = "NTLM "; + methodString = "NTLM"; if (challenge.isEmpty()) { -#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) +#if QT_CONFIG(sspi) // SSPI QByteArray phase1Token; if (user.isEmpty()) // Only pull from system if no user was specified in authenticator - phase1Token = qNtlmPhase1_SSPI(this); + phase1Token = qSspiStartup(this, method, host); if (!phase1Token.isEmpty()) { response = phase1Token.toBase64(); phase = Phase2; @@ -496,10 +514,10 @@ QByteArray QAuthenticatorPrivate::calculateResponse(const QByteArray &requestMet phase = Phase2; } } else { -#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) +#if QT_CONFIG(sspi) // SSPI QByteArray phase3Token; - if (ntlmWindowsHandles) - phase3Token = qNtlmPhase3_SSPI(this, QByteArray::fromBase64(challenge)); + if (sspiWindowsHandles) + phase3Token = qSspiContinue(this, method, host, QByteArray::fromBase64(challenge)); if (!phase3Token.isEmpty()) { response = phase3Token.toBase64(); phase = Done; @@ -512,8 +530,39 @@ QByteArray QAuthenticatorPrivate::calculateResponse(const QByteArray &requestMet } break; + case QAuthenticatorPrivate::Negotiate: + methodString = "Negotiate"; + if (challenge.isEmpty()) { + QByteArray phase1Token; +#if QT_CONFIG(sspi) // SSPI + phase1Token = qSspiStartup(this, method, host); +#elif QT_CONFIG(gssapi) // GSSAPI + phase1Token = qGssapiStartup(this, host); +#endif + + if (!phase1Token.isEmpty()) { + response = phase1Token.toBase64(); + phase = Phase2; + } else { + phase = Done; + } + } else { + QByteArray phase3Token; +#if QT_CONFIG(sspi) // SSPI + phase3Token = qSspiContinue(this, method, host, QByteArray::fromBase64(challenge)); +#elif QT_CONFIG(gssapi) // GSSAPI + phase3Token = qGssapiContinue(this, QByteArray::fromBase64(challenge)); +#endif + if (!phase3Token.isEmpty()) { + response = phase3Token.toBase64(); + phase = Done; + } + } + + break; } - return QByteArray(methodString) + response; + + return QByteArray::fromRawData(methodString, qstrlen(methodString)) + ' ' + response; } @@ -699,9 +748,10 @@ QByteArray QAuthenticatorPrivate::digestMd5Response(const QByteArray &challenge, return credentials; } -// ---------------------------- Digest Md5 code ---------------------------------------- +// ---------------------------- End of Digest Md5 code --------------------------------- +// ---------------------------- NTLM code ---------------------------------------------- /* * NTLM message flags. @@ -1419,156 +1469,237 @@ static QByteArray qNtlmPhase3(QAuthenticatorPrivate *ctx, const QByteArray& phas return rc; } -#if defined(Q_OS_WIN) && !defined(Q_OS_WINRT) +// ---------------------------- End of NTLM code --------------------------------------- + +#if QT_CONFIG(sspi) // SSPI +// ---------------------------- SSPI code ---------------------------------------------- // See http://davenport.sourceforge.net/ntlm.html // and libcurl http_ntlm.c // Handle of secur32.dll -static HMODULE securityDLLHandle = NULL; +static HMODULE securityDLLHandle = nullptr; // Pointer to SSPI dispatch table -static PSecurityFunctionTable pSecurityFunctionTable = NULL; - +static PSecurityFunctionTable pSecurityFunctionTable = nullptr; -static bool q_NTLM_SSPI_library_load() +static bool q_SSPI_library_load() { static QBasicMutex mutex; QMutexLocker l(&mutex); // Initialize security interface - if (pSecurityFunctionTable == NULL) { + if (pSecurityFunctionTable == nullptr) { securityDLLHandle = LoadLibrary(L"secur32.dll"); - if (securityDLLHandle != NULL) { + if (securityDLLHandle != nullptr) { INIT_SECURITY_INTERFACE pInitSecurityInterface = reinterpret_cast<INIT_SECURITY_INTERFACE>( reinterpret_cast<QFunctionPointer>(GetProcAddress(securityDLLHandle, "InitSecurityInterfaceW"))); - if (pInitSecurityInterface != NULL) + if (pInitSecurityInterface != nullptr) pSecurityFunctionTable = pInitSecurityInterface(); } } - if (pSecurityFunctionTable == NULL) + if (pSecurityFunctionTable == nullptr) return false; return true; } -// Phase 1: -static QByteArray qNtlmPhase1_SSPI(QAuthenticatorPrivate *ctx) +static QByteArray qSspiStartup(QAuthenticatorPrivate *ctx, QAuthenticatorPrivate::Method method, + const QString& host) { - QByteArray result; + if (!q_SSPI_library_load()) + return QByteArray(); + + TimeStamp expiry; // For Windows 9x compatibility of SSPI calls - if (!q_NTLM_SSPI_library_load()) - return result; + if (!ctx->sspiWindowsHandles) + ctx->sspiWindowsHandles.reset(new QSSPIWindowsHandles); + memset(&ctx->sspiWindowsHandles->credHandle, 0, sizeof(CredHandle)); - // 1. The client obtains a representation of the credential set - // for the user via the SSPI AcquireCredentialsHandle function. - if (!ctx->ntlmWindowsHandles) - ctx->ntlmWindowsHandles = new QNtlmWindowsHandles; - memset(&ctx->ntlmWindowsHandles->credHandle, 0, sizeof(CredHandle)); - TimeStamp tsDummy; + // Acquire our credentials handle SECURITY_STATUS secStatus = pSecurityFunctionTable->AcquireCredentialsHandle( - NULL, (SEC_WCHAR*)L"NTLM", SECPKG_CRED_OUTBOUND, NULL, NULL, - NULL, NULL, &ctx->ntlmWindowsHandles->credHandle, &tsDummy); + nullptr, + (SEC_WCHAR*)(method == QAuthenticatorPrivate::Negotiate ? L"Negotiate" : L"NTLM"), + SECPKG_CRED_OUTBOUND, nullptr, nullptr, nullptr, nullptr, + &ctx->sspiWindowsHandles->credHandle, &expiry + ); if (secStatus != SEC_E_OK) { - delete ctx->ntlmWindowsHandles; - ctx->ntlmWindowsHandles = 0; - return result; + ctx->sspiWindowsHandles.reset(nullptr); + return QByteArray(); } - // 2. The client calls the SSPI InitializeSecurityContext function - // to obtain an authentication request token (in our case, a Type 1 message). - // The client sends this token to the server. - SecBufferDesc desc; - SecBuffer buf; - desc.ulVersion = SECBUFFER_VERSION; - desc.cBuffers = 1; - desc.pBuffers = &buf; - buf.cbBuffer = 0; - buf.BufferType = SECBUFFER_TOKEN; - buf.pvBuffer = NULL; - ULONG attrs; - - secStatus = pSecurityFunctionTable->InitializeSecurityContext(&ctx->ntlmWindowsHandles->credHandle, NULL, - const_cast<SEC_WCHAR*>(L"") /* host */, - ISC_REQ_ALLOCATE_MEMORY, - 0, SECURITY_NETWORK_DREP, - NULL, 0, - &ctx->ntlmWindowsHandles->ctxHandle, &desc, - &attrs, &tsDummy); - if (secStatus == SEC_I_COMPLETE_AND_CONTINUE || - secStatus == SEC_I_CONTINUE_NEEDED) { - pSecurityFunctionTable->CompleteAuthToken(&ctx->ntlmWindowsHandles->ctxHandle, &desc); - } else if (secStatus != SEC_E_OK) { - if ((const char*)buf.pvBuffer) - pSecurityFunctionTable->FreeContextBuffer(buf.pvBuffer); - pSecurityFunctionTable->FreeCredentialsHandle(&ctx->ntlmWindowsHandles->credHandle); - delete ctx->ntlmWindowsHandles; - ctx->ntlmWindowsHandles = 0; - return result; + return qSspiContinue(ctx, method, host); +} + +static QByteArray qSspiContinue(QAuthenticatorPrivate *ctx, QAuthenticatorPrivate::Method method, + const QString &host, const QByteArray &challenge) +{ + QByteArray result; + SecBuffer challengeBuf; + SecBuffer responseBuf; + SecBufferDesc challengeDesc; + SecBufferDesc responseDesc; + unsigned long attrs; + TimeStamp expiry; // For Windows 9x compatibility of SSPI calls + + if (!challenge.isEmpty()) + { + // Setup the challenge "input" security buffer + challengeDesc.ulVersion = SECBUFFER_VERSION; + challengeDesc.cBuffers = 1; + challengeDesc.pBuffers = &challengeBuf; + challengeBuf.BufferType = SECBUFFER_TOKEN; + challengeBuf.pvBuffer = (PVOID)(challenge.data()); + challengeBuf.cbBuffer = challenge.length(); } - result = QByteArray((const char*)buf.pvBuffer, buf.cbBuffer); - pSecurityFunctionTable->FreeContextBuffer(buf.pvBuffer); + // Setup the response "output" security buffer + responseDesc.ulVersion = SECBUFFER_VERSION; + responseDesc.cBuffers = 1; + responseDesc.pBuffers = &responseBuf; + responseBuf.BufferType = SECBUFFER_TOKEN; + responseBuf.pvBuffer = nullptr; + responseBuf.cbBuffer = 0; + + // Calculate target (SPN for Negotiate, empty for NTLM) + std::wstring targetNameW = (method == QAuthenticatorPrivate::Negotiate + ? QLatin1String("HTTP/") + host : QString()).toStdWString(); + + // Generate our challenge-response message + SECURITY_STATUS secStatus = pSecurityFunctionTable->InitializeSecurityContext( + &ctx->sspiWindowsHandles->credHandle, + !challenge.isEmpty() ? &ctx->sspiWindowsHandles->ctxHandle : nullptr, + const_cast<wchar_t*>(targetNameW.data()), + ISC_REQ_ALLOCATE_MEMORY, + 0, SECURITY_NATIVE_DREP, + !challenge.isEmpty() ? &challengeDesc : nullptr, + 0, &ctx->sspiWindowsHandles->ctxHandle, + &responseDesc, &attrs, + &expiry + ); + + if (secStatus == SEC_I_COMPLETE_NEEDED || secStatus == SEC_I_COMPLETE_AND_CONTINUE) { + secStatus = pSecurityFunctionTable->CompleteAuthToken(&ctx->sspiWindowsHandles->ctxHandle, + &responseDesc); + } + + if (secStatus != SEC_I_COMPLETE_AND_CONTINUE && secStatus != SEC_I_CONTINUE_NEEDED) { + pSecurityFunctionTable->FreeCredentialsHandle(&ctx->sspiWindowsHandles->credHandle); + pSecurityFunctionTable->DeleteSecurityContext(&ctx->sspiWindowsHandles->ctxHandle); + ctx->sspiWindowsHandles.reset(nullptr); + } + + result = QByteArray((const char*)responseBuf.pvBuffer, responseBuf.cbBuffer); + pSecurityFunctionTable->FreeContextBuffer(responseBuf.pvBuffer); + return result; } -// Phase 2: -// 3. The server receives the token from the client, and uses it as input to the -// AcceptSecurityContext SSPI function. This creates a local security context on -// the server to represent the client, and yields an authentication response token -// (the Type 2 message), which is sent to the client. +// ---------------------------- End of SSPI code --------------------------------------- + +#elif QT_CONFIG(gssapi) // GSSAPI + +// ---------------------------- GSSAPI code ---------------------------------------------- +// See postgres src/interfaces/libpq/fe-auth.c + +// Fetch all errors of a specific type +static void q_GSSAPI_error_int(const char *message, OM_uint32 stat, int type) +{ + OM_uint32 minStat, msgCtx = 0; + gss_buffer_desc msg; + + do { + gss_display_status(&minStat, stat, type, GSS_C_NO_OID, &msgCtx, &msg); + qDebug() << message << ": " << reinterpret_cast<const char*>(msg.value); + gss_release_buffer(&minStat, &msg); + } while (msgCtx); +} -// Phase 3: -static QByteArray qNtlmPhase3_SSPI(QAuthenticatorPrivate *ctx, const QByteArray& phase2data) +// GSSAPI errors contain two parts; extract both +static void q_GSSAPI_error(const char *message, OM_uint32 majStat, OM_uint32 minStat) { - // 4. The client receives the response token from the server and calls - // InitializeSecurityContext again, passing the server's token as input. - // This provides us with another authentication request token (the Type 3 message). - // The return value indicates that the security context was successfully initialized; - // the token is sent to the server. + // Fetch major error codes + q_GSSAPI_error_int(message, majStat, GSS_C_GSS_CODE); + // Add the minor codes as well + q_GSSAPI_error_int(message, minStat, GSS_C_MECH_CODE); +} + +// Send initial GSS authentication token +static QByteArray qGssapiStartup(QAuthenticatorPrivate *ctx, const QString &host) +{ + OM_uint32 majStat, minStat; + + if (!ctx->gssApiHandles) + ctx->gssApiHandles.reset(new QGssApiHandles); + + // Convert target name to internal form + QByteArray serviceName = QStringLiteral("HTTPS@%1").arg(host).toLocal8Bit(); + gss_buffer_desc nameDesc = {static_cast<std::size_t>(serviceName.size()), serviceName.data()}; + + majStat = gss_import_name(&minStat, &nameDesc, + GSS_C_NT_HOSTBASED_SERVICE, &ctx->gssApiHandles->targetName); + + if (majStat != GSS_S_COMPLETE) { + q_GSSAPI_error("gss_import_name error", majStat, minStat); + ctx->gssApiHandles.reset(nullptr); + return QByteArray(); + } + + // Call qGssapiContinue with GSS_C_NO_CONTEXT to get initial packet + ctx->gssApiHandles->gssCtx = GSS_C_NO_CONTEXT; + return qGssapiContinue(ctx); +} + +// Continue GSS authentication with next token as needed +static QByteArray qGssapiContinue(QAuthenticatorPrivate *ctx, const QByteArray& challenge) +{ + OM_uint32 majStat, minStat, ignored; QByteArray result; + gss_buffer_desc inBuf = {0, nullptr}; // GSS input token + gss_buffer_desc outBuf; // GSS output token - if (pSecurityFunctionTable == NULL) - return result; - - SecBuffer type_2, type_3; - SecBufferDesc type_2_desc, type_3_desc; - ULONG attrs; - TimeStamp tsDummy; // For Windows 9x compatibility of SPPI calls - - type_2_desc.ulVersion = type_3_desc.ulVersion = SECBUFFER_VERSION; - type_2_desc.cBuffers = type_3_desc.cBuffers = 1; - type_2_desc.pBuffers = &type_2; - type_3_desc.pBuffers = &type_3; - - type_2.BufferType = SECBUFFER_TOKEN; - type_2.pvBuffer = (PVOID)phase2data.data(); - type_2.cbBuffer = phase2data.length(); - type_3.BufferType = SECBUFFER_TOKEN; - type_3.pvBuffer = 0; - type_3.cbBuffer = 0; - - SECURITY_STATUS secStatus = pSecurityFunctionTable->InitializeSecurityContext(&ctx->ntlmWindowsHandles->credHandle, - &ctx->ntlmWindowsHandles->ctxHandle, - const_cast<SEC_WCHAR*>(L"") /* host */, - ISC_REQ_ALLOCATE_MEMORY, - 0, SECURITY_NETWORK_DREP, &type_2_desc, - 0, &ctx->ntlmWindowsHandles->ctxHandle, &type_3_desc, - &attrs, &tsDummy); - - if (secStatus == SEC_E_OK && ((const char*)type_3.pvBuffer)) { - result = QByteArray((const char*)type_3.pvBuffer, type_3.cbBuffer); - pSecurityFunctionTable->FreeContextBuffer(type_3.pvBuffer); + if (!challenge.isEmpty()) { + inBuf.value = const_cast<char*>(challenge.data()); + inBuf.length = challenge.length(); } - pSecurityFunctionTable->FreeCredentialsHandle(&ctx->ntlmWindowsHandles->credHandle); - pSecurityFunctionTable->DeleteSecurityContext(&ctx->ntlmWindowsHandles->ctxHandle); - delete ctx->ntlmWindowsHandles; - ctx->ntlmWindowsHandles = 0; + majStat = gss_init_sec_context(&minStat, + GSS_C_NO_CREDENTIAL, + &ctx->gssApiHandles->gssCtx, + ctx->gssApiHandles->targetName, + GSS_C_NO_OID, + GSS_C_MUTUAL_FLAG, + 0, + GSS_C_NO_CHANNEL_BINDINGS, + challenge.isEmpty() ? GSS_C_NO_BUFFER : &inBuf, + nullptr, + &outBuf, + nullptr, + nullptr); + + if (outBuf.length != 0) + result = QByteArray(reinterpret_cast<const char*>(outBuf.value), outBuf.length); + gss_release_buffer(&ignored, &outBuf); + + if (majStat != GSS_S_COMPLETE && majStat != GSS_S_CONTINUE_NEEDED) { + q_GSSAPI_error("gss_init_sec_context error", majStat, minStat); + gss_release_name(&ignored, &ctx->gssApiHandles->targetName); + if (ctx->gssApiHandles->gssCtx) + gss_delete_sec_context(&ignored, &ctx->gssApiHandles->gssCtx, GSS_C_NO_BUFFER); + ctx->gssApiHandles.reset(nullptr); + } + + if (majStat == GSS_S_COMPLETE) { + gss_release_name(&ignored, &ctx->gssApiHandles->targetName); + ctx->gssApiHandles.reset(nullptr); + } return result; } -#endif // Q_OS_WIN && !Q_OS_WINRT + +// ---------------------------- End of GSSAPI code ---------------------------------------------- + +#endif // gssapi QT_END_NAMESPACE diff --git a/src/network/kernel/qauthenticator_p.h b/src/network/kernel/qauthenticator_p.h index 265cb7afe2..e201d22650 100644 --- a/src/network/kernel/qauthenticator_p.h +++ b/src/network/kernel/qauthenticator_p.h @@ -54,6 +54,7 @@ #include <QtNetwork/private/qtnetworkglobal_p.h> #include <qhash.h> #include <qbytearray.h> +#include <qscopedpointer.h> #include <qstring.h> #include <qauthenticator.h> #include <qvariant.h> @@ -61,14 +62,16 @@ QT_BEGIN_NAMESPACE class QHttpResponseHeader; -#ifdef Q_OS_WIN -class QNtlmWindowsHandles; +#if QT_CONFIG(sspi) // SSPI +class QSSPIWindowsHandles; +#elif QT_CONFIG(gssapi) // GSSAPI +class QGssApiHandles; #endif class Q_AUTOTEST_EXPORT QAuthenticatorPrivate { public: - enum Method { None, Basic, Ntlm, DigestMd5 }; + enum Method { None, Basic, Ntlm, DigestMd5, Negotiate }; QAuthenticatorPrivate(); ~QAuthenticatorPrivate(); @@ -79,8 +82,10 @@ public: Method method; QString realm; QByteArray challenge; -#ifdef Q_OS_WIN - QNtlmWindowsHandles *ntlmWindowsHandles; +#if QT_CONFIG(sspi) // SSPI + QScopedPointer<QSSPIWindowsHandles> sspiWindowsHandles; +#elif QT_CONFIG(gssapi) // GSSAPI + QScopedPointer<QGssApiHandles> gssApiHandles; #endif bool hasFailed; //credentials have been tried but rejected by server. @@ -100,7 +105,7 @@ public: QString workstation; QString userDomain; - QByteArray calculateResponse(const QByteArray &method, const QByteArray &path); + QByteArray calculateResponse(const QByteArray &method, const QByteArray &path, const QString& host); inline static QAuthenticatorPrivate *getPrivate(QAuthenticator &auth) { return auth.d; } inline static const QAuthenticatorPrivate *getPrivate(const QAuthenticator &auth) { return auth.d; } diff --git a/src/network/kernel/qdnslookup.h b/src/network/kernel/qdnslookup.h index eebd0abe66..110a74da44 100644 --- a/src/network/kernel/qdnslookup.h +++ b/src/network/kernel/qdnslookup.h @@ -64,13 +64,11 @@ class Q_NETWORK_EXPORT QDnsDomainNameRecord public: QDnsDomainNameRecord(); QDnsDomainNameRecord(const QDnsDomainNameRecord &other); -#ifdef Q_COMPILER_RVALUE_REFS - QDnsDomainNameRecord &operator=(QDnsDomainNameRecord &&other) Q_DECL_NOTHROW { swap(other); return *this; } -#endif + QDnsDomainNameRecord &operator=(QDnsDomainNameRecord &&other) noexcept { swap(other); return *this; } QDnsDomainNameRecord &operator=(const QDnsDomainNameRecord &other); ~QDnsDomainNameRecord(); - void swap(QDnsDomainNameRecord &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + void swap(QDnsDomainNameRecord &other) noexcept { qSwap(d, other.d); } QString name() const; quint32 timeToLive() const; @@ -88,13 +86,11 @@ class Q_NETWORK_EXPORT QDnsHostAddressRecord public: QDnsHostAddressRecord(); QDnsHostAddressRecord(const QDnsHostAddressRecord &other); -#ifdef Q_COMPILER_RVALUE_REFS - QDnsHostAddressRecord &operator=(QDnsHostAddressRecord &&other) Q_DECL_NOTHROW { swap(other); return *this; } -#endif + QDnsHostAddressRecord &operator=(QDnsHostAddressRecord &&other) noexcept { swap(other); return *this; } QDnsHostAddressRecord &operator=(const QDnsHostAddressRecord &other); ~QDnsHostAddressRecord(); - void swap(QDnsHostAddressRecord &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + void swap(QDnsHostAddressRecord &other) noexcept { qSwap(d, other.d); } QString name() const; quint32 timeToLive() const; @@ -112,13 +108,11 @@ class Q_NETWORK_EXPORT QDnsMailExchangeRecord public: QDnsMailExchangeRecord(); QDnsMailExchangeRecord(const QDnsMailExchangeRecord &other); -#ifdef Q_COMPILER_RVALUE_REFS - QDnsMailExchangeRecord &operator=(QDnsMailExchangeRecord &&other) Q_DECL_NOTHROW { swap(other); return *this; } -#endif + QDnsMailExchangeRecord &operator=(QDnsMailExchangeRecord &&other) noexcept { swap(other); return *this; } QDnsMailExchangeRecord &operator=(const QDnsMailExchangeRecord &other); ~QDnsMailExchangeRecord(); - void swap(QDnsMailExchangeRecord &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + void swap(QDnsMailExchangeRecord &other) noexcept { qSwap(d, other.d); } QString exchange() const; QString name() const; @@ -137,13 +131,11 @@ class Q_NETWORK_EXPORT QDnsServiceRecord public: QDnsServiceRecord(); QDnsServiceRecord(const QDnsServiceRecord &other); -#ifdef Q_COMPILER_RVALUE_REFS - QDnsServiceRecord &operator=(QDnsServiceRecord &&other) Q_DECL_NOTHROW { swap(other); return *this; } -#endif + QDnsServiceRecord &operator=(QDnsServiceRecord &&other) noexcept { swap(other); return *this; } QDnsServiceRecord &operator=(const QDnsServiceRecord &other); ~QDnsServiceRecord(); - void swap(QDnsServiceRecord &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + void swap(QDnsServiceRecord &other) noexcept { qSwap(d, other.d); } QString name() const; quint16 port() const; @@ -164,13 +156,11 @@ class Q_NETWORK_EXPORT QDnsTextRecord public: QDnsTextRecord(); QDnsTextRecord(const QDnsTextRecord &other); -#ifdef Q_COMPILER_RVALUE_REFS - QDnsTextRecord &operator=(QDnsTextRecord &&other) Q_DECL_NOTHROW { swap(other); return *this; } -#endif + QDnsTextRecord &operator=(QDnsTextRecord &&other) noexcept { swap(other); return *this; } QDnsTextRecord &operator=(const QDnsTextRecord &other); ~QDnsTextRecord(); - void swap(QDnsTextRecord &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + void swap(QDnsTextRecord &other) noexcept { qSwap(d, other.d); } QString name() const; quint32 timeToLive() const; diff --git a/src/network/kernel/qdnslookup_p.h b/src/network/kernel/qdnslookup_p.h index 2dc98e527a..8c3c2ed3e1 100644 --- a/src/network/kernel/qdnslookup_p.h +++ b/src/network/kernel/qdnslookup_p.h @@ -95,7 +95,7 @@ public: QDnsLookupPrivate() : isFinished(false) , type(QDnsLookup::A) - , runnable(0) + , runnable(nullptr) { } void _q_lookupFinished(const QDnsLookupReply &reply); diff --git a/src/network/kernel/qdnslookup_win.cpp b/src/network/kernel/qdnslookup_win.cpp index cfdb9ca633..262893179c 100644 --- a/src/network/kernel/qdnslookup_win.cpp +++ b/src/network/kernel/qdnslookup_win.cpp @@ -41,7 +41,6 @@ #include "qdnslookup_p.h" #include <qurl.h> -#include <private/qmutexpool_p.h> #include <private/qsystemerror_p.h> #include <qt_windows.h> diff --git a/src/network/kernel/qhostaddress.cpp b/src/network/kernel/qhostaddress.cpp index 5d0ef150f3..b54fb349fb 100644 --- a/src/network/kernel/qhostaddress.cpp +++ b/src/network/kernel/qhostaddress.cpp @@ -1333,7 +1333,7 @@ QDebug operator<<(QDebug d, const QHostAddress &address) \relates QHostAddress Returns a hash of the host address \a key, using \a seed to seed the calculation. */ -uint qHash(const QHostAddress &key, uint seed) Q_DECL_NOTHROW +uint qHash(const QHostAddress &key, uint seed) noexcept { return qHashBits(key.d->a6.c, 16, seed); } diff --git a/src/network/kernel/qhostaddress.h b/src/network/kernel/qhostaddress.h index 00555f3d8e..799247695e 100644 --- a/src/network/kernel/qhostaddress.h +++ b/src/network/kernel/qhostaddress.h @@ -66,7 +66,7 @@ typedef QIPv6Address Q_IPV6ADDR; class QHostAddress; // qHash is a friend, but we can't use default arguments for friends (§8.3.6.4) -Q_NETWORK_EXPORT uint qHash(const QHostAddress &key, uint seed = 0) Q_DECL_NOTHROW; +Q_NETWORK_EXPORT uint qHash(const QHostAddress &key, uint seed = 0) noexcept; class Q_NETWORK_EXPORT QHostAddress { @@ -102,11 +102,8 @@ public: QHostAddress(SpecialAddress address); ~QHostAddress(); -#ifdef Q_COMPILER_RVALUE_REFS - QHostAddress &operator=(QHostAddress &&other) Q_DECL_NOTHROW + QHostAddress &operator=(QHostAddress &&other) noexcept { swap(other); return *this; } -#endif - QHostAddress &operator=(const QHostAddress &other); #if QT_DEPRECATED_SINCE(5, 8) QT_DEPRECATED_X("use = QHostAddress(string) instead") @@ -114,7 +111,7 @@ public: #endif QHostAddress &operator=(SpecialAddress address); - void swap(QHostAddress &other) Q_DECL_NOTHROW { d.swap(other.d); } + void swap(QHostAddress &other) noexcept { d.swap(other.d); } void setAddress(quint32 ip4Addr); void setAddress(quint8 *ip6Addr); // ### Qt 6: remove me @@ -157,7 +154,7 @@ public: static QPair<QHostAddress, int> parseSubnet(const QString &subnet); - friend Q_NETWORK_EXPORT uint qHash(const QHostAddress &key, uint seed) Q_DECL_NOTHROW; + friend Q_NETWORK_EXPORT uint qHash(const QHostAddress &key, uint seed) noexcept; protected: friend class QHostAddressPrivate; QExplicitlySharedDataPointer<QHostAddressPrivate> d; diff --git a/src/network/kernel/qhostinfo.cpp b/src/network/kernel/qhostinfo.cpp index 4b5acc1c53..9374728244 100644 --- a/src/network/kernel/qhostinfo.cpp +++ b/src/network/kernel/qhostinfo.cpp @@ -37,8 +37,11 @@ ** ****************************************************************************/ +//#define QHOSTINFO_DEBUG + #include "qhostinfo.h" #include "qhostinfo_p.h" +#include <qplatformdefs.h> #include "QtCore/qscopedpointer.h" #include <qabstracteventdispatcher.h> @@ -53,6 +56,15 @@ #ifdef Q_OS_UNIX # include <unistd.h> +# include <netdb.h> +# include <netinet/in.h> +# if defined(AI_ADDRCONFIG) +# define Q_ADDRCONFIG AI_ADDRCONFIG +# endif +#elif defined Q_OS_WIN +# include <ws2tcpip.h> + +# define QT_SOCKLEN_T int #endif QT_BEGIN_NAMESPACE @@ -64,8 +76,8 @@ Q_GLOBAL_STATIC(QHostInfoLookupManager, theHostInfoLookupManager) namespace { struct ToBeLookedUpEquals { typedef bool result_type; - explicit ToBeLookedUpEquals(const QString &toBeLookedUp) Q_DECL_NOTHROW : m_toBeLookedUp(toBeLookedUp) {} - result_type operator()(QHostInfoRunnable* lookup) const Q_DECL_NOTHROW + explicit ToBeLookedUpEquals(const QString &toBeLookedUp) noexcept : m_toBeLookedUp(toBeLookedUp) {} + result_type operator()(QHostInfoRunnable* lookup) const noexcept { return m_toBeLookedUp == lookup->toBeLookedUp; } @@ -412,6 +424,162 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName, QSharedPointer<QNetw } #endif +QHostInfo QHostInfoAgent::reverseLookup(const QHostAddress &address) +{ + QHostInfo results; + // Reverse lookup + sockaddr_in sa4; + sockaddr_in6 sa6; + sockaddr *sa = 0; + QT_SOCKLEN_T saSize; + if (address.protocol() == QAbstractSocket::IPv4Protocol) { + sa = reinterpret_cast<sockaddr *>(&sa4); + saSize = sizeof(sa4); + memset(&sa4, 0, sizeof(sa4)); + sa4.sin_family = AF_INET; + sa4.sin_addr.s_addr = htonl(address.toIPv4Address()); + } else { + sa = reinterpret_cast<sockaddr *>(&sa6); + saSize = sizeof(sa6); + memset(&sa6, 0, sizeof(sa6)); + sa6.sin6_family = AF_INET6; + memcpy(&sa6.sin6_addr, address.toIPv6Address().c, sizeof(sa6.sin6_addr)); + } + + char hbuf[NI_MAXHOST]; + if (sa && getnameinfo(sa, saSize, hbuf, sizeof(hbuf), nullptr, 0, 0) == 0) + results.setHostName(QString::fromLatin1(hbuf)); + + if (results.hostName().isEmpty()) + results.setHostName(address.toString()); + results.setAddresses(QList<QHostAddress>() << address); + + return results; +} + +/* + Call getaddrinfo, and returns the results as QHostInfo::addresses +*/ +QHostInfo QHostInfoAgent::lookup(const QString &hostName) +{ + QHostInfo results; + + // IDN support + QByteArray aceHostname = QUrl::toAce(hostName); + results.setHostName(hostName); + if (aceHostname.isEmpty()) { + results.setError(QHostInfo::HostNotFound); + results.setErrorString(hostName.isEmpty() ? + QCoreApplication::translate("QHostInfoAgent", "No host name given") : + QCoreApplication::translate("QHostInfoAgent", "Invalid hostname")); + return results; + } + + addrinfo *res = 0; + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; +#ifdef Q_ADDRCONFIG + hints.ai_flags = Q_ADDRCONFIG; +#endif + + int result = getaddrinfo(aceHostname.constData(), nullptr, &hints, &res); +# ifdef Q_ADDRCONFIG + if (result == EAI_BADFLAGS) { + // if the lookup failed with AI_ADDRCONFIG set, try again without it + hints.ai_flags = 0; + result = getaddrinfo(aceHostname.constData(), nullptr, &hints, &res); + } +# endif + + if (result == 0) { + addrinfo *node = res; + QList<QHostAddress> addresses; + while (node) { +#ifdef QHOSTINFO_DEBUG + qDebug() << "getaddrinfo node: flags:" << node->ai_flags << "family:" << node->ai_family + << "ai_socktype:" << node->ai_socktype << "ai_protocol:" << node->ai_protocol + << "ai_addrlen:" << node->ai_addrlen; +#endif + switch (node->ai_family) { + case AF_INET: { + QHostAddress addr; + addr.setAddress(ntohl(((sockaddr_in *) node->ai_addr)->sin_addr.s_addr)); + if (!addresses.contains(addr)) + addresses.append(addr); + break; + } + case AF_INET6: { + QHostAddress addr; + sockaddr_in6 *sa6 = (sockaddr_in6 *) node->ai_addr; + addr.setAddress(sa6->sin6_addr.s6_addr); + if (sa6->sin6_scope_id) + addr.setScopeId(QString::number(sa6->sin6_scope_id)); + if (!addresses.contains(addr)) + addresses.append(addr); + break; + } + default: + results.setError(QHostInfo::UnknownError); + results.setErrorString(QCoreApplication::translate("QHostInfoAgent", "Unknown address type")); + } + node = node->ai_next; + } + if (addresses.isEmpty()) { + // Reached the end of the list, but no addresses were found; this + // means the list contains one or more unknown address types. + results.setError(QHostInfo::UnknownError); + results.setErrorString(QCoreApplication::translate("QHostInfoAgent", "Unknown address type")); + } + + results.setAddresses(addresses); + freeaddrinfo(res); + } else { + switch (result) { +#ifdef Q_OS_WIN + case WSAHOST_NOT_FOUND: //authoritative not found + case WSATRY_AGAIN: //non authoritative not found + case WSANO_DATA: //valid name, no associated address +#else + case EAI_NONAME: + case EAI_FAIL: +# ifdef EAI_NODATA // EAI_NODATA is deprecated in RFC 3493 + case EAI_NODATA: +# endif +#endif + results.setError(QHostInfo::HostNotFound); + results.setErrorString(QCoreApplication::translate("QHostInfoAgent", "Host not found")); + break; + default: + results.setError(QHostInfo::UnknownError); +#ifdef Q_OS_WIN + results.setErrorString(QString::fromWCharArray(gai_strerror(result))); +#else + results.setErrorString(QString::fromLocal8Bit(gai_strerror(result))); +#endif + break; + } + } + +#if defined(QHOSTINFO_DEBUG) + if (results.error() != QHostInfo::NoError) { + qDebug("QHostInfoAgent::fromName(): error #%d %s", + h_errno, results.errorString().toLatin1().constData()); + } else { + QString tmp; + QList<QHostAddress> addresses = results.addresses(); + for (int i = 0; i < addresses.count(); ++i) { + if (i != 0) tmp += QLatin1String(", "); + tmp += addresses.at(i).toString(); + } + qDebug("QHostInfoAgent::fromName(): found %i entries for \"%s\": {%s}", + addresses.count(), aceHostname.constData(), + tmp.toLatin1().constData()); + } +#endif + + return results; +} /*! \enum QHostInfo::HostInfoError diff --git a/src/network/kernel/qhostinfo.h b/src/network/kernel/qhostinfo.h index 49871ad470..dc31cc08e4 100644 --- a/src/network/kernel/qhostinfo.h +++ b/src/network/kernel/qhostinfo.h @@ -63,10 +63,10 @@ public: explicit QHostInfo(int lookupId = -1); QHostInfo(const QHostInfo &d); QHostInfo &operator=(const QHostInfo &d); - QHostInfo &operator=(QHostInfo &&other) Q_DECL_NOTHROW { swap(other); return *this; } + QHostInfo &operator=(QHostInfo &&other) noexcept { swap(other); return *this; } ~QHostInfo(); - void swap(QHostInfo &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + void swap(QHostInfo &other) noexcept { qSwap(d, other.d); } QString hostName() const; void setHostName(const QString &name); diff --git a/src/network/kernel/qhostinfo_p.h b/src/network/kernel/qhostinfo_p.h index 8cce302166..3c0ee2a0d8 100644 --- a/src/network/kernel/qhostinfo_p.h +++ b/src/network/kernel/qhostinfo_p.h @@ -101,7 +101,7 @@ public Q_SLOTS: { if (slotObj) { QHostInfo copy = info; - void *args[2] = { 0, reinterpret_cast<void *>(©) }; + void *args[2] = { nullptr, reinterpret_cast<void *>(©) }; slotObj->call(const_cast<QObject*>(receiver.data()), args); slotObj->destroyIfLastRef(); } else { @@ -127,15 +127,16 @@ Q_SIGNALS: void resultsReady(const QHostInfo &info); }; -// needs to be QObject because fromName calls tr() -class QHostInfoAgent : public QObject +class QHostInfoAgent { - Q_OBJECT public: static QHostInfo fromName(const QString &hostName); #ifndef QT_NO_BEARERMANAGEMENT static QHostInfo fromName(const QString &hostName, QSharedPointer<QNetworkSession> networkSession); #endif +private: + static QHostInfo lookup(const QString &hostName); + static QHostInfo reverseLookup(const QHostAddress &address); }; class QHostInfoPrivate diff --git a/src/network/kernel/qhostinfo_unix.cpp b/src/network/kernel/qhostinfo_unix.cpp index e4810d68ee..78a05f8407 100644 --- a/src/network/kernel/qhostinfo_unix.cpp +++ b/src/network/kernel/qhostinfo_unix.cpp @@ -72,17 +72,6 @@ QT_BEGIN_NAMESPACE -// Almost always the same. If not, specify in qplatformdefs.h. -#if !defined(QT_SOCKOPTLEN_T) -# define QT_SOCKOPTLEN_T QT_SOCKLEN_T -#endif - -// HP-UXi has a bug in getaddrinfo(3) that makes it thread-unsafe -// with this flag. So disable it in that platform. -#if defined(AI_ADDRCONFIG) && !defined(Q_OS_HPUX) -# define Q_ADDRCONFIG AI_ADDRCONFIG -#endif - enum LibResolvFeature { NeedResInit, NeedResNInit @@ -197,132 +186,10 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) local_res_init(); QHostAddress address; - if (address.setAddress(hostName)) { - // Reverse lookup - sockaddr_in sa4; - sockaddr_in6 sa6; - sockaddr *sa = 0; - QT_SOCKLEN_T saSize = 0; - if (address.protocol() == QAbstractSocket::IPv4Protocol) { - sa = (sockaddr *)&sa4; - saSize = sizeof(sa4); - memset(&sa4, 0, sizeof(sa4)); - sa4.sin_family = AF_INET; - sa4.sin_addr.s_addr = htonl(address.toIPv4Address()); - } - else { - sa = (sockaddr *)&sa6; - saSize = sizeof(sa6); - memset(&sa6, 0, sizeof(sa6)); - sa6.sin6_family = AF_INET6; - memcpy(sa6.sin6_addr.s6_addr, address.toIPv6Address().c, sizeof(sa6.sin6_addr.s6_addr)); - } - - char hbuf[NI_MAXHOST]; - if (sa && getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0) - results.setHostName(QString::fromLatin1(hbuf)); - - if (results.hostName().isEmpty()) - results.setHostName(address.toString()); - results.setAddresses(QList<QHostAddress>() << address); - return results; - } - - // IDN support - QByteArray aceHostname = QUrl::toAce(hostName); - results.setHostName(hostName); - if (aceHostname.isEmpty()) { - results.setError(QHostInfo::HostNotFound); - results.setErrorString(hostName.isEmpty() ? - QCoreApplication::translate("QHostInfoAgent", "No host name given") : - QCoreApplication::translate("QHostInfoAgent", "Invalid hostname")); - return results; - } - - // Call getaddrinfo, and place all IPv4 addresses at the start and - // the IPv6 addresses at the end of the address list in results. - addrinfo *res = 0; - struct addrinfo hints; - memset(&hints, 0, sizeof(hints)); - hints.ai_family = PF_UNSPEC; -#ifdef Q_ADDRCONFIG - hints.ai_flags = Q_ADDRCONFIG; -#endif + if (address.setAddress(hostName)) + return reverseLookup(address); - int result = getaddrinfo(aceHostname.constData(), 0, &hints, &res); -# ifdef Q_ADDRCONFIG - if (result == EAI_BADFLAGS) { - // if the lookup failed with AI_ADDRCONFIG set, try again without it - hints.ai_flags = 0; - result = getaddrinfo(aceHostname.constData(), 0, &hints, &res); - } -# endif - - if (result == 0) { - addrinfo *node = res; - QList<QHostAddress> addresses; - while (node) { -#ifdef QHOSTINFO_DEBUG - qDebug() << "getaddrinfo node: flags:" << node->ai_flags << "family:" << node->ai_family << "ai_socktype:" << node->ai_socktype << "ai_protocol:" << node->ai_protocol << "ai_addrlen:" << node->ai_addrlen; -#endif - if (node->ai_family == AF_INET) { - QHostAddress addr; - addr.setAddress(ntohl(((sockaddr_in *) node->ai_addr)->sin_addr.s_addr)); - if (!addresses.contains(addr)) - addresses.append(addr); - } - else if (node->ai_family == AF_INET6) { - QHostAddress addr; - sockaddr_in6 *sa6 = (sockaddr_in6 *) node->ai_addr; - addr.setAddress(sa6->sin6_addr.s6_addr); - if (sa6->sin6_scope_id) - addr.setScopeId(QString::number(sa6->sin6_scope_id)); - if (!addresses.contains(addr)) - addresses.append(addr); - } - node = node->ai_next; - } - if (addresses.isEmpty() && node == 0) { - // Reached the end of the list, but no addresses were found; this - // means the list contains one or more unknown address types. - results.setError(QHostInfo::UnknownError); - results.setErrorString(tr("Unknown address type")); - } - - results.setAddresses(addresses); - freeaddrinfo(res); - } else if (result == EAI_NONAME - || result == EAI_FAIL -#ifdef EAI_NODATA - // EAI_NODATA is deprecated in RFC 3493 - || result == EAI_NODATA -#endif - ) { - results.setError(QHostInfo::HostNotFound); - results.setErrorString(tr("Host not found")); - } else { - results.setError(QHostInfo::UnknownError); - results.setErrorString(QString::fromLocal8Bit(gai_strerror(result))); - } - - -#if defined(QHOSTINFO_DEBUG) - if (results.error() != QHostInfo::NoError) { - qDebug("QHostInfoAgent::fromName(): error #%d %s", - h_errno, results.errorString().toLatin1().constData()); - } else { - QString tmp; - QList<QHostAddress> addresses = results.addresses(); - for (int i = 0; i < addresses.count(); ++i) { - if (i != 0) tmp += ", "; - tmp += addresses.at(i).toString(); - } - qDebug("QHostInfoAgent::fromName(): found %i entries for \"%s\": {%s}", - addresses.count(), hostName.toLatin1().constData(), - tmp.toLatin1().constData()); - } -#endif - return results; + return lookup(hostName); } QString QHostInfo::localDomainName() diff --git a/src/network/kernel/qhostinfo_win.cpp b/src/network/kernel/qhostinfo_win.cpp index c51e9968f8..0b5cc98970 100644 --- a/src/network/kernel/qhostinfo_win.cpp +++ b/src/network/kernel/qhostinfo_win.cpp @@ -51,27 +51,10 @@ QT_BEGIN_NAMESPACE //#define QHOSTINFO_DEBUG //### -#define QT_SOCKLEN_T int #ifndef NI_MAXHOST // already defined to 1025 in ws2tcpip.h? #define NI_MAXHOST 1024 #endif -static void translateWSAError(int error, QHostInfo *results) -{ - switch (error) { - case WSAHOST_NOT_FOUND: //authoritative not found - case WSATRY_AGAIN: //non authoritative not found - case WSANO_DATA: //valid name, no associated address - results->setError(QHostInfo::HostNotFound); - results->setErrorString(QHostInfoAgent::tr("Host not found")); - return; - default: - results->setError(QHostInfo::UnknownError); - results->setErrorString(QHostInfoAgent::tr("Unknown error (%1)").arg(error)); - return; - } -} - QHostInfo QHostInfoAgent::fromName(const QString &hostName) { QSysInfo::machineHostName(); // this initializes ws2_32.dll @@ -79,98 +62,15 @@ QHostInfo QHostInfoAgent::fromName(const QString &hostName) QHostInfo results; #if defined(QHOSTINFO_DEBUG) - qDebug("QHostInfoAgent::fromName(): looking up \"%s\" (IPv6 support is %s)", - hostName.toLatin1().constData(), - (getaddrinfo && freeaddrinfo) ? "enabled" : "disabled"); + qDebug("QHostInfoAgent::fromName(%s) looking up...", + hostName.toLatin1().constData()); #endif QHostAddress address; - if (address.setAddress(hostName)) { - // Reverse lookup - sockaddr_in sa4; - sockaddr_in6 sa6; - sockaddr *sa; - QT_SOCKLEN_T saSize; - if (address.protocol() == QAbstractSocket::IPv4Protocol) { - sa = reinterpret_cast<sockaddr *>(&sa4); - saSize = sizeof(sa4); - memset(&sa4, 0, sizeof(sa4)); - sa4.sin_family = AF_INET; - sa4.sin_addr.s_addr = htonl(address.toIPv4Address()); - } else { - sa = reinterpret_cast<sockaddr *>(&sa6); - saSize = sizeof(sa6); - memset(&sa6, 0, sizeof(sa6)); - sa6.sin6_family = AF_INET6; - memcpy(&sa6.sin6_addr, address.toIPv6Address().c, sizeof(sa6.sin6_addr)); - } - - char hbuf[NI_MAXHOST]; - if (getnameinfo(sa, saSize, hbuf, sizeof(hbuf), 0, 0, 0) == 0) - results.setHostName(QString::fromLatin1(hbuf)); - - if (results.hostName().isEmpty()) - results.setHostName(address.toString()); - results.setAddresses(QList<QHostAddress>() << address); - return results; - } + if (address.setAddress(hostName)) + return reverseLookup(address); - // IDN support - QByteArray aceHostname = QUrl::toAce(hostName); - results.setHostName(hostName); - if (aceHostname.isEmpty()) { - results.setError(QHostInfo::HostNotFound); - results.setErrorString(hostName.isEmpty() ? tr("No host name given") : tr("Invalid hostname")); - return results; - } - - addrinfo *res; - int err = getaddrinfo(aceHostname.constData(), 0, 0, &res); - if (err == 0) { - QList<QHostAddress> addresses; - for (addrinfo *p = res; p != 0; p = p->ai_next) { - switch (p->ai_family) { - case AF_INET: { - QHostAddress addr; - addr.setAddress(ntohl(reinterpret_cast<sockaddr_in *>(p->ai_addr)->sin_addr.s_addr)); - if (!addresses.contains(addr)) - addresses.append(addr); - } - break; - case AF_INET6: { - QHostAddress addr; - addr.setAddress(reinterpret_cast<const sockaddr_in6 *>(p->ai_addr)->sin6_addr.s6_addr); - if (!addresses.contains(addr)) - addresses.append(addr); - } - break; - default: - results.setError(QHostInfo::UnknownError); - results.setErrorString(tr("Unknown address type")); - } - } - results.setAddresses(addresses); - freeaddrinfo(res); - } else { - translateWSAError(WSAGetLastError(), &results); - } - -#if defined(QHOSTINFO_DEBUG) - if (results.error() != QHostInfo::NoError) { - qDebug("QHostInfoAgent::run(): error (%s)", - results.errorString().toLatin1().constData()); - } else { - QString tmp; - QList<QHostAddress> addresses = results.addresses(); - for (int i = 0; i < addresses.count(); ++i) { - if (i != 0) tmp += ", "; - tmp += addresses.at(i).toString(); - } - qDebug("QHostInfoAgent::run(): found %i entries: {%s}", - addresses.count(), tmp.toLatin1().constData()); - } -#endif - return results; + return lookup(hostName); } // QString QHostInfo::localDomainName() defined in qnetworkinterface_win.cpp diff --git a/src/network/kernel/qnetconmonitor_darwin.mm b/src/network/kernel/qnetconmonitor_darwin.mm new file mode 100644 index 0000000000..a64cd6e530 --- /dev/null +++ b/src/network/kernel/qnetconmonitor_darwin.mm @@ -0,0 +1,419 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "private/qnativesocketengine_p.h" +#include "private/qnetconmonitor_p.h" + +#include "private/qobject_p.h" + +#include <SystemConfiguration/SystemConfiguration.h> +#include <CoreFoundation/CoreFoundation.h> + +#include <netinet/in.h> + +#include <cstring> + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(lcNetMon, "qt.network.monitor"); + +namespace { + +class ReachabilityDispatchQueue +{ +public: + ReachabilityDispatchQueue() + { + queue = dispatch_queue_create("qt-network-reachability-queue", nullptr); + if (!queue) + qCWarning(lcNetMon, "Failed to create a dispatch queue for reachability probes"); + } + + ~ReachabilityDispatchQueue() + { + if (queue) + dispatch_release(queue); + } + + dispatch_queue_t data() const + { + return queue; + } + +private: + dispatch_queue_t queue = nullptr; + + Q_DISABLE_COPY_MOVE(ReachabilityDispatchQueue) +}; + +dispatch_queue_t qt_reachability_queue() +{ + static const ReachabilityDispatchQueue reachabilityQueue; + return reachabilityQueue.data(); +} + +qt_sockaddr qt_hostaddress_to_sockaddr(const QHostAddress &src) +{ + if (src.isNull()) + return {}; + + qt_sockaddr dst; + if (src.protocol() == QAbstractSocket::IPv4Protocol) { + dst.a4 = sockaddr_in{}; + dst.a4.sin_family = AF_INET; + dst.a4.sin_addr.s_addr = htonl(src.toIPv4Address()); + dst.a4.sin_len = sizeof(sockaddr_in); + } else if (src.protocol() == QAbstractSocket::IPv6Protocol) { + dst.a6 = sockaddr_in6{}; + dst.a6.sin6_family = AF_INET6; + dst.a6.sin6_len = sizeof(sockaddr_in6); + const Q_IPV6ADDR ipv6 = src.toIPv6Address(); + std::memcpy(&dst.a6.sin6_addr, &ipv6, sizeof ipv6); + } else { + Q_UNREACHABLE(); + } + + return dst; +} + +} // unnamed namespace + +class QNetworkConnectionMonitorPrivate : public QObjectPrivate +{ +public: + SCNetworkReachabilityRef probe = nullptr; + SCNetworkReachabilityFlags state = kSCNetworkReachabilityFlagsIsLocalAddress; + bool scheduled = false; + + void updateState(SCNetworkReachabilityFlags newState); + void reset(); + bool isReachable() const; + + static void probeCallback(SCNetworkReachabilityRef probe, SCNetworkReachabilityFlags flags, void *info); + + Q_DECLARE_PUBLIC(QNetworkConnectionMonitor) +}; + +void QNetworkConnectionMonitorPrivate::updateState(SCNetworkReachabilityFlags newState) +{ + // To be executed only on the reachability queue. + Q_Q(QNetworkConnectionMonitor); + + // NETMONTODO: for now, 'online' for us means kSCNetworkReachabilityFlagsReachable + // is set. There are more possible flags that require more tests/some special + // setup. So in future this part and related can change/be extended. + const bool wasReachable = isReachable(); + state = newState; + if (wasReachable != isReachable()) + emit q->reachabilityChanged(isReachable()); +} + +void QNetworkConnectionMonitorPrivate::reset() +{ + if (probe) { + CFRelease(probe); + probe = nullptr; + } + + state = kSCNetworkReachabilityFlagsIsLocalAddress; + scheduled = false; +} + +bool QNetworkConnectionMonitorPrivate::isReachable() const +{ + return !!(state & kSCNetworkReachabilityFlagsReachable); +} + +void QNetworkConnectionMonitorPrivate::probeCallback(SCNetworkReachabilityRef probe, SCNetworkReachabilityFlags flags, void *info) +{ + // To be executed only on the reachability queue. + Q_UNUSED(probe); + + auto monitorPrivate = static_cast<QNetworkConnectionMonitorPrivate *>(info); + Q_ASSERT(monitorPrivate); + monitorPrivate->updateState(flags); +} + +QNetworkConnectionMonitor::QNetworkConnectionMonitor() + : QObject(*new QNetworkConnectionMonitorPrivate) +{ +} + +QNetworkConnectionMonitor::QNetworkConnectionMonitor(const QHostAddress &local, const QHostAddress &remote) + : QObject(*new QNetworkConnectionMonitorPrivate) +{ + setTargets(local, remote); +} + +QNetworkConnectionMonitor::~QNetworkConnectionMonitor() +{ + Q_D(QNetworkConnectionMonitor); + + stopMonitoring(); + d->reset(); +} + +bool QNetworkConnectionMonitor::setTargets(const QHostAddress &local, const QHostAddress &remote) +{ + Q_D(QNetworkConnectionMonitor); + + if (isMonitoring()) { + qCWarning(lcNetMon, "Monitor is already active, call stopMonitoring() first"); + return false; + } + + if (local.isNull()) { + qCWarning(lcNetMon, "Invalid (null) local address, cannot create a reachability target"); + return false; + } + + // Clear the old target if needed: + d->reset(); + + qt_sockaddr client = qt_hostaddress_to_sockaddr(local); + if (remote.isNull()) { + // That's a special case our QNetworkStatusMonitor is using (AnyIpv4/6 address to check an overall status). + d->probe = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, reinterpret_cast<sockaddr *>(&client)); + } else { + qt_sockaddr target = qt_hostaddress_to_sockaddr(remote); + d->probe = SCNetworkReachabilityCreateWithAddressPair(kCFAllocatorDefault, + reinterpret_cast<sockaddr *>(&client), + reinterpret_cast<sockaddr *>(&target)); + } + + if (d->probe) { + // Let's read the initial state so that callback coming later can + // see a difference. Ignore errors though. + SCNetworkReachabilityGetFlags(d->probe, &d->state); + }else { + qCWarning(lcNetMon, "Failed to create network reachability probe"); + return false; + } + + return true; +} + +bool QNetworkConnectionMonitor::startMonitoring() +{ + Q_D(QNetworkConnectionMonitor); + + if (isMonitoring()) { + qCWarning(lcNetMon, "Monitor is already active, call stopMonitoring() first"); + return false; + } + + if (!d->probe) { + qCWarning(lcNetMon, "Can not start monitoring, set targets first"); + return false; + } + + auto queue = qt_reachability_queue(); + if (!queue) { + qWarning(lcNetMon, "Failed to create a dispatch queue to schedule a probe on"); + return false; + } + + SCNetworkReachabilityContext context = {}; + context.info = d; + if (!SCNetworkReachabilitySetCallback(d->probe, QNetworkConnectionMonitorPrivate::probeCallback, &context)) { + qWarning(lcNetMon, "Failed to set a reachability callback"); + return false; + } + + + if (!SCNetworkReachabilitySetDispatchQueue(d->probe, queue)) { + qWarning(lcNetMon, "Failed to schedule a reachability callback on a queue"); + return false; + } + + return d->scheduled = true; +} + +bool QNetworkConnectionMonitor::isMonitoring() const +{ + Q_D(const QNetworkConnectionMonitor); + + return d->scheduled; +} + +void QNetworkConnectionMonitor::stopMonitoring() +{ + Q_D(QNetworkConnectionMonitor); + + if (d->scheduled) { + Q_ASSERT(d->probe); + SCNetworkReachabilitySetDispatchQueue(d->probe, nullptr); + SCNetworkReachabilitySetCallback(d->probe, nullptr, nullptr); + d->scheduled = false; + } +} + +bool QNetworkConnectionMonitor::isReachable() +{ + Q_D(QNetworkConnectionMonitor); + + if (isMonitoring()) { + qCWarning(lcNetMon, "Calling isReachable() is unsafe after the monitoring started"); + return false; + } + + if (!d->probe) { + qCWarning(lcNetMon, "Reachability is unknown, set the target first"); + return false; + } + + return d->isReachable(); +} + +class QNetworkStatusMonitorPrivate : public QObjectPrivate +{ +public: + QNetworkConnectionMonitor ipv4Probe; + bool isOnlineIpv4 = false; + QNetworkConnectionMonitor ipv6Probe; + bool isOnlineIpv6 = false; +}; + +QNetworkStatusMonitor::QNetworkStatusMonitor() + : QObject(*new QNetworkStatusMonitorPrivate) +{ + Q_D(QNetworkStatusMonitor); + + if (d->ipv4Probe.setTargets(QHostAddress::AnyIPv4, {})) { + // We manage to create SCNetworkReachabilityRef for IPv4, let's + // read the last known state then! + d->isOnlineIpv4 = d->ipv4Probe.isReachable(); + } + + if (d->ipv6Probe.setTargets(QHostAddress::AnyIPv6, {})) { + // We manage to create SCNetworkReachability ref for IPv6, let's + // read the last known state then! + d->isOnlineIpv6 = d->ipv6Probe.isReachable(); + } + + + connect(&d->ipv4Probe, &QNetworkConnectionMonitor::reachabilityChanged, this, + &QNetworkStatusMonitor::reachabilityChanged, Qt::QueuedConnection); + connect(&d->ipv6Probe, &QNetworkConnectionMonitor::reachabilityChanged, this, + &QNetworkStatusMonitor::reachabilityChanged, Qt::QueuedConnection); +} + +QNetworkStatusMonitor::~QNetworkStatusMonitor() +{ + Q_D(QNetworkStatusMonitor); + + d->ipv4Probe.disconnect(); + d->ipv4Probe.stopMonitoring(); + d->ipv6Probe.disconnect(); + d->ipv6Probe.stopMonitoring(); +} + +bool QNetworkStatusMonitor::start() +{ + Q_D(QNetworkStatusMonitor); + + if (isMonitoring()) { + qCWarning(lcNetMon, "Network status monitor is already active"); + return true; + } + + d->ipv4Probe.startMonitoring(); + d->ipv6Probe.startMonitoring(); + + return isMonitoring(); +} + +void QNetworkStatusMonitor::stop() +{ + Q_D(QNetworkStatusMonitor); + + if (d->ipv4Probe.isMonitoring()) + d->ipv4Probe.stopMonitoring(); + if (d->ipv6Probe.isMonitoring()) + d->ipv6Probe.stopMonitoring(); +} + +bool QNetworkStatusMonitor::isMonitoring() const +{ + Q_D(const QNetworkStatusMonitor); + + return d->ipv4Probe.isMonitoring() || d->ipv6Probe.isMonitoring(); +} + +bool QNetworkStatusMonitor::isNetworkAccesible() +{ + // This function is to be executed on the thread that created + // and uses 'this'. + Q_D(QNetworkStatusMonitor); + + return d->isOnlineIpv4 || d->isOnlineIpv6; +} + +bool QNetworkStatusMonitor::isEnabled() +{ + return true; +} + +void QNetworkStatusMonitor::reachabilityChanged(bool online) +{ + // This function is executed on the thread that created/uses 'this', + // not on the reachability queue. + Q_D(QNetworkStatusMonitor); + + auto probe = qobject_cast<QNetworkConnectionMonitor *>(sender()); + if (!probe) + return; + + const bool isIpv4 = probe == &d->ipv4Probe; + bool &probeOnline = isIpv4 ? d->isOnlineIpv4 : d->isOnlineIpv6; + bool otherOnline = isIpv4 ? d->isOnlineIpv6 : d->isOnlineIpv4; + + if (probeOnline == online) { + // We knew this already? + return; + } + + probeOnline = online; + if (!otherOnline) { + // We either just lost or got a network access. + emit onlineStateChanged(probeOnline); + } +} + +QT_END_NAMESPACE diff --git a/src/network/kernel/qnetconmonitor_p.h b/src/network/kernel/qnetconmonitor_p.h new file mode 100644 index 0000000000..74ee56d422 --- /dev/null +++ b/src/network/kernel/qnetconmonitor_p.h @@ -0,0 +1,126 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QNETCONMONITOR_P_H +#define QNETCONMONITOR_P_H + +#include <private/qtnetworkglobal_p.h> + +#include <QtCore/qloggingcategory.h> +#include <QtNetwork/qhostaddress.h> +#include <QtCore/qglobal.h> +#include <QtCore/qobject.h> + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +class QNetworkConnectionMonitorPrivate; +class QNetworkConnectionMonitor : public QObject +{ + Q_OBJECT + +public: + QNetworkConnectionMonitor(); + QNetworkConnectionMonitor(const QHostAddress &local, const QHostAddress &remote = {}); + ~QNetworkConnectionMonitor(); + + bool setTargets(const QHostAddress &local, const QHostAddress &remote); + bool isReachable(); + + // Important: on Darwin you should not call isReachable() after + // startMonitoring(), you have to listen to reachabilityChanged() + // signal instead. + bool startMonitoring(); + bool isMonitoring() const; + void stopMonitoring(); + +Q_SIGNALS: + // Important: connect to this using QueuedConnection. On Darwin + // callback is coming on a special dispatch queue. + void reachabilityChanged(bool isOnline); + +private: + Q_DECLARE_PRIVATE(QNetworkConnectionMonitor) + Q_DISABLE_COPY_MOVE(QNetworkConnectionMonitor) +}; + +class QNetworkStatusMonitorPrivate; +class QNetworkStatusMonitor : public QObject +{ + Q_OBJECT + +public: + QNetworkStatusMonitor(); + ~QNetworkStatusMonitor(); + + bool isNetworkAccesible(); + + bool start(); + void stop(); + bool isMonitoring() const; + + static bool isEnabled(); + +Q_SIGNALS: + // Unlike QNetworkConnectionMonitor, this can be connected to directly. + void onlineStateChanged(bool isOnline); + +private slots: + void reachabilityChanged(bool isOnline); + +private: + Q_DECLARE_PRIVATE(QNetworkStatusMonitor) + Q_DISABLE_COPY_MOVE(QNetworkStatusMonitor) +}; + +Q_DECLARE_LOGGING_CATEGORY(lcNetMon) + +QT_END_NAMESPACE + +#endif // QNETCONMONITOR_P_H diff --git a/src/network/kernel/qnetconmonitor_stub.cpp b/src/network/kernel/qnetconmonitor_stub.cpp new file mode 100644 index 0000000000..7f3a0c44c6 --- /dev/null +++ b/src/network/kernel/qnetconmonitor_stub.cpp @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtNetwork module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnetconmonitor_p.h" + +#include "private/qobject_p.h" + +QT_BEGIN_NAMESPACE + +Q_LOGGING_CATEGORY(lcNetMon, "qt.network.monitor"); + +// Note: this 'stub' version is never enabled (see QNetworkStatusMonitor::isEnabled below) +// and thus should never affect QNAM in any unusuall way. Having this 'stub' version is similar +// to building Qt with bearer management configured out. + +class QNetworkConnectionMonitorPrivate : public QObjectPrivate +{ +}; + +QNetworkConnectionMonitor::QNetworkConnectionMonitor() + : QObject(*new QNetworkConnectionMonitorPrivate) +{ +} + +QNetworkConnectionMonitor::QNetworkConnectionMonitor(const QHostAddress &local, const QHostAddress &remote) + : QObject(*new QNetworkConnectionMonitorPrivate) +{ + Q_UNUSED(local) + Q_UNUSED(remote) +} + +QNetworkConnectionMonitor::~QNetworkConnectionMonitor() +{ +} + +bool QNetworkConnectionMonitor::setTargets(const QHostAddress &local, const QHostAddress &remote) +{ + Q_UNUSED(local) + Q_UNUSED(remote) + + return false; +} + +bool QNetworkConnectionMonitor::startMonitoring() +{ + return false; +} + +bool QNetworkConnectionMonitor::isMonitoring() const +{ + return false; +} + +void QNetworkConnectionMonitor::stopMonitoring() +{ +} + +bool QNetworkConnectionMonitor::isReachable() +{ + return false; +} + +class QNetworkStatusMonitorPrivate : public QObjectPrivate +{ +}; + +QNetworkStatusMonitor::QNetworkStatusMonitor() + : QObject(*new QNetworkStatusMonitorPrivate) +{ +} + +QNetworkStatusMonitor::~QNetworkStatusMonitor() +{ +} + +bool QNetworkStatusMonitor::start() +{ + return false; +} + +void QNetworkStatusMonitor::stop() +{ +} + +bool QNetworkStatusMonitor::isMonitoring() const +{ + return false; +} + +bool QNetworkStatusMonitor::isNetworkAccesible() +{ + return false; +} + +bool QNetworkStatusMonitor::isEnabled() +{ + return false; +} + +void QNetworkStatusMonitor::reachabilityChanged(bool online) +{ + Q_UNUSED(online) +} + +QT_END_NAMESPACE diff --git a/src/network/kernel/qnetworkdatagram.h b/src/network/kernel/qnetworkdatagram.h index 1acb44a1e0..70958fea42 100644 --- a/src/network/kernel/qnetworkdatagram.h +++ b/src/network/kernel/qnetworkdatagram.h @@ -61,13 +61,13 @@ public: ~QNetworkDatagram() { if (d) destroy(d); } - QNetworkDatagram(QNetworkDatagram &&other) Q_DECL_NOTHROW + QNetworkDatagram(QNetworkDatagram &&other) noexcept : d(other.d) { other.d = nullptr; } - QNetworkDatagram &operator=(QNetworkDatagram &&other) Q_DECL_NOTHROW + QNetworkDatagram &operator=(QNetworkDatagram &&other) noexcept { swap(other); return *this; } - void swap(QNetworkDatagram &other) Q_DECL_NOTHROW + void swap(QNetworkDatagram &other) noexcept { qSwap(d, other.d); } void clear(); diff --git a/src/network/kernel/qnetworkinterface.h b/src/network/kernel/qnetworkinterface.h index 148fd5e10d..4caedaa38f 100644 --- a/src/network/kernel/qnetworkinterface.h +++ b/src/network/kernel/qnetworkinterface.h @@ -64,13 +64,11 @@ public: QNetworkAddressEntry(); QNetworkAddressEntry(const QNetworkAddressEntry &other); -#ifdef Q_COMPILER_RVALUE_REFS - QNetworkAddressEntry &operator=(QNetworkAddressEntry &&other) Q_DECL_NOTHROW { swap(other); return *this; } -#endif + QNetworkAddressEntry &operator=(QNetworkAddressEntry &&other) noexcept { swap(other); return *this; } QNetworkAddressEntry &operator=(const QNetworkAddressEntry &other); ~QNetworkAddressEntry(); - void swap(QNetworkAddressEntry &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + void swap(QNetworkAddressEntry &other) noexcept { qSwap(d, other.d); } bool operator==(const QNetworkAddressEntry &other) const; inline bool operator!=(const QNetworkAddressEntry &other) const @@ -142,13 +140,11 @@ public: QNetworkInterface(); QNetworkInterface(const QNetworkInterface &other); -#ifdef Q_COMPILER_RVALUE_REFS - QNetworkInterface &operator=(QNetworkInterface &&other) Q_DECL_NOTHROW { swap(other); return *this; } -#endif + QNetworkInterface &operator=(QNetworkInterface &&other) noexcept { swap(other); return *this; } QNetworkInterface &operator=(const QNetworkInterface &other); ~QNetworkInterface(); - void swap(QNetworkInterface &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + void swap(QNetworkInterface &other) noexcept { qSwap(d, other.d); } bool isValid() const; diff --git a/src/network/kernel/qnetworkinterface_p.h b/src/network/kernel/qnetworkinterface_p.h index 87a46b75fa..44e27a7e34 100644 --- a/src/network/kernel/qnetworkinterface_p.h +++ b/src/network/kernel/qnetworkinterface_p.h @@ -82,7 +82,7 @@ public: class QNetworkInterfacePrivate: public QSharedData { public: - QNetworkInterfacePrivate() : index(0), flags(0) + QNetworkInterfacePrivate() : index(0), flags(nullptr) { } ~QNetworkInterfacePrivate() { } diff --git a/src/network/kernel/qnetworkinterface_unix_p.h b/src/network/kernel/qnetworkinterface_unix_p.h index c085194e3c..553af5a303 100644 --- a/src/network/kernel/qnetworkinterface_unix_p.h +++ b/src/network/kernel/qnetworkinterface_unix_p.h @@ -80,7 +80,7 @@ QT_BEGIN_NAMESPACE static QNetworkInterface::InterfaceFlags convertFlags(uint rawFlags) { - QNetworkInterface::InterfaceFlags flags = 0; + QNetworkInterface::InterfaceFlags flags = nullptr; flags |= (rawFlags & IFF_UP) ? QNetworkInterface::IsUp : QNetworkInterface::InterfaceFlag(0); flags |= (rawFlags & IFF_RUNNING) ? QNetworkInterface::IsRunning : QNetworkInterface::InterfaceFlag(0); flags |= (rawFlags & IFF_BROADCAST) ? QNetworkInterface::CanBroadcast : QNetworkInterface::InterfaceFlag(0); diff --git a/src/network/kernel/qnetworkproxy.cpp b/src/network/kernel/qnetworkproxy.cpp index 3646a9526a..2f840e9e13 100644 --- a/src/network/kernel/qnetworkproxy.cpp +++ b/src/network/kernel/qnetworkproxy.cpp @@ -483,7 +483,7 @@ public: template<> void QSharedDataPointer<QNetworkProxyPrivate>::detach() { - if (d && d->ref.load() == 1) + if (d && d->ref.loadRelaxed() == 1) return; QNetworkProxyPrivate *x = (d ? new QNetworkProxyPrivate(*d) : new QNetworkProxyPrivate); @@ -925,7 +925,7 @@ public: template<> void QSharedDataPointer<QNetworkProxyQueryPrivate>::detach() { - if (d && d->ref.load() == 1) + if (d && d->ref.loadRelaxed() == 1) return; QNetworkProxyQueryPrivate *x = (d ? new QNetworkProxyQueryPrivate(*d) : new QNetworkProxyQueryPrivate); diff --git a/src/network/kernel/qnetworkproxy.h b/src/network/kernel/qnetworkproxy.h index 7e3e6906a8..302a2ce6ca 100644 --- a/src/network/kernel/qnetworkproxy.h +++ b/src/network/kernel/qnetworkproxy.h @@ -89,13 +89,11 @@ public: QueryType queryType = TcpServer); #endif QNetworkProxyQuery(const QNetworkProxyQuery &other); -#ifdef Q_COMPILER_RVALUE_REFS - QNetworkProxyQuery &operator=(QNetworkProxyQuery &&other) Q_DECL_NOTHROW { swap(other); return *this; } -#endif + QNetworkProxyQuery &operator=(QNetworkProxyQuery &&other) noexcept { swap(other); return *this; } QNetworkProxyQuery &operator=(const QNetworkProxyQuery &other); ~QNetworkProxyQuery(); - void swap(QNetworkProxyQuery &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + void swap(QNetworkProxyQuery &other) noexcept { qSwap(d, other.d); } bool operator==(const QNetworkProxyQuery &other) const; inline bool operator!=(const QNetworkProxyQuery &other) const @@ -161,13 +159,11 @@ public: QNetworkProxy(ProxyType type, const QString &hostName = QString(), quint16 port = 0, const QString &user = QString(), const QString &password = QString()); QNetworkProxy(const QNetworkProxy &other); -#ifdef Q_COMPILER_RVALUE_REFS - QNetworkProxy &operator=(QNetworkProxy &&other) Q_DECL_NOTHROW { swap(other); return *this; } -#endif + QNetworkProxy &operator=(QNetworkProxy &&other) noexcept { swap(other); return *this; } QNetworkProxy &operator=(const QNetworkProxy &other); ~QNetworkProxy(); - void swap(QNetworkProxy &other) Q_DECL_NOTHROW { qSwap(d, other.d); } + void swap(QNetworkProxy &other) noexcept { qSwap(d, other.d); } bool operator==(const QNetworkProxy &other) const; inline bool operator!=(const QNetworkProxy &other) const |