mirror of
https://github.com/mumble-voip/mumble.git
synced 2025-10-26 11:19:16 +00:00
FIX(client, server): Load native mDNS/DNS-SD symbols at runtime
This change: - Fixes binaries failing to start on versions of Windows where dnsapi.dll doesn't export the symbols we need. - Allows us to use the native API in x86 builds. See https://developercommunity.visualstudio.com/content/problem/1191345/some-dns-api-functions-cause-lnk2019-errors-in-32.html for more info.
This commit is contained in:
parent
72228f6e03
commit
5e088269ae
@ -5,39 +5,36 @@
|
||||
|
||||
#include "Zeroconf.h"
|
||||
|
||||
#define SYMBOL_EXISTS(symbol) (GetProcAddress(handle, symbol))
|
||||
#define GET_SYMBOL(symbol) (symbol = reinterpret_cast< decltype(symbol) >(GetProcAddress(handle, #symbol)))
|
||||
|
||||
Zeroconf::Zeroconf() : m_ok(false) {
|
||||
qRegisterMetaType< uint16_t >("uint16_t");
|
||||
qRegisterMetaType< BonjourRecord >("BonjourRecord");
|
||||
qRegisterMetaType< QList< BonjourRecord > >("QList<BonjourRecord>");
|
||||
#ifdef Q_OS_WIN64
|
||||
static bool winDnsUnavailable = false;
|
||||
if (!winDnsUnavailable) {
|
||||
auto handle = GetModuleHandle(L"dnsapi.dll");
|
||||
if (handle) {
|
||||
if (SYMBOL_EXISTS("DnsServiceBrowse") && SYMBOL_EXISTS("DnsServiceBrowseCancel")
|
||||
&& SYMBOL_EXISTS("DnsServiceResolve") && SYMBOL_EXISTS("DnsServiceResolveCancel")
|
||||
&& SYMBOL_EXISTS("DnsServiceFreeInstance")) {
|
||||
m_ok = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#ifdef Q_OS_WIN
|
||||
auto handle = GetModuleHandle(L"dnsapi.dll");
|
||||
if (handle) {
|
||||
GET_SYMBOL(DnsServiceBrowse);
|
||||
GET_SYMBOL(DnsServiceBrowseCancel);
|
||||
GET_SYMBOL(DnsServiceResolve);
|
||||
GET_SYMBOL(DnsServiceResolveCancel);
|
||||
GET_SYMBOL(DnsServiceFreeInstance);
|
||||
|
||||
winDnsUnavailable = true;
|
||||
qWarning("Zeroconf: Native mDNS/DNS-SD API not available, falling back to third-party API");
|
||||
}
|
||||
|
||||
static bool dnssdLoadFailed = false;
|
||||
if (!dnssdLoadFailed) {
|
||||
auto handle = LoadLibrary(L"dnssd.DLL");
|
||||
if (!handle) {
|
||||
dnssdLoadFailed = true;
|
||||
qWarning("Zeroconf: Failed to load dnssd.dll, assuming third-party API is not available");
|
||||
if (DnsServiceBrowse && DnsServiceBrowseCancel && DnsServiceResolve && DnsServiceResolveCancel
|
||||
&& DnsServiceFreeInstance) {
|
||||
m_ok = true;
|
||||
return;
|
||||
}
|
||||
FreeLibrary(handle);
|
||||
}
|
||||
|
||||
qWarning("Zeroconf: Native mDNS/DNS-SD API not available, falling back to third-party API");
|
||||
|
||||
handle = LoadLibrary(L"dnssd.dll");
|
||||
if (!handle) {
|
||||
qWarning("Zeroconf: Failed to load dnssd.dll, assuming third-party API is not available");
|
||||
return;
|
||||
}
|
||||
FreeLibrary(handle);
|
||||
#endif
|
||||
resetHelperBrowser();
|
||||
resetHelperResolver();
|
||||
@ -80,7 +77,7 @@ bool Zeroconf::startBrowser(const QString &serviceType) {
|
||||
m_helperBrowser->browseForServiceType(serviceType);
|
||||
return true;
|
||||
}
|
||||
#ifdef Q_OS_WIN64
|
||||
#ifdef Q_OS_WIN
|
||||
const QString queryName = serviceType + QLatin1String(".local");
|
||||
|
||||
DNS_SERVICE_BROWSE_REQUEST request{};
|
||||
@ -110,7 +107,7 @@ bool Zeroconf::stopBrowser() {
|
||||
resetHelperBrowser();
|
||||
return true;
|
||||
}
|
||||
#ifdef Q_OS_WIN64
|
||||
#ifdef Q_OS_WIN
|
||||
if (m_cancelBrowser) {
|
||||
const auto ret = DnsServiceBrowseCancel(m_cancelBrowser.get());
|
||||
if (ret == ERROR_SUCCESS || ret == ERROR_CANCELLED) {
|
||||
@ -134,7 +131,7 @@ bool Zeroconf::startResolver(const BonjourRecord &record) {
|
||||
m_helperResolver->resolveBonjourRecord(record);
|
||||
return true;
|
||||
}
|
||||
#ifdef Q_OS_WIN64
|
||||
#ifdef Q_OS_WIN
|
||||
stopResolver(record);
|
||||
|
||||
auto qualifiedHostname = record.serviceName.toStdWString() + L"." + record.registeredType.toStdWString()
|
||||
@ -160,7 +157,7 @@ bool Zeroconf::startResolver(const BonjourRecord &record) {
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
#ifdef Q_OS_WIN64
|
||||
#ifdef Q_OS_WIN
|
||||
bool Zeroconf::stopResolver(const BonjourRecord &record) {
|
||||
if (!m_ok) {
|
||||
return false;
|
||||
@ -200,7 +197,7 @@ bool Zeroconf::cleanupResolvers() {
|
||||
}
|
||||
|
||||
auto result = true;
|
||||
#ifdef Q_OS_WIN64
|
||||
#ifdef Q_OS_WIN
|
||||
for (auto i = 0; i < m_resolvers.size(); ++i) {
|
||||
if (!stopResolver(m_resolvers[i])) {
|
||||
result = false;
|
||||
@ -228,7 +225,7 @@ void Zeroconf::helperResolverError(const BonjourRecord record, const DNSServiceE
|
||||
qWarning("Zeroconf: Third-party resolver API reports error %d", error);
|
||||
emit resolveError(record);
|
||||
}
|
||||
#ifdef Q_OS_WIN64
|
||||
#ifdef Q_OS_WIN
|
||||
void WINAPI Zeroconf::callbackBrowseComplete(const DWORD status, void *context, DNS_RECORD *records) {
|
||||
auto zeroconf = static_cast< Zeroconf * >(context);
|
||||
zeroconf->m_cancelBrowser.reset();
|
||||
@ -283,9 +280,12 @@ void WINAPI Zeroconf::callbackBrowseComplete(const DWORD status, void *context,
|
||||
}
|
||||
|
||||
void WINAPI Zeroconf::callbackResolveComplete(const DWORD status, void *context, DNS_SERVICE_INSTANCE *instance) {
|
||||
auto resolver = static_cast< Resolver * >(context);
|
||||
auto zeroconf = resolver->m_zeroconf;
|
||||
|
||||
if (status != ERROR_SUCCESS) {
|
||||
if (instance) {
|
||||
DnsServiceFreeInstance(instance);
|
||||
zeroconf->DnsServiceFreeInstance(instance);
|
||||
}
|
||||
|
||||
if (status != ERROR_CANCELLED) {
|
||||
@ -299,10 +299,8 @@ void WINAPI Zeroconf::callbackResolveComplete(const DWORD status, void *context,
|
||||
return;
|
||||
}
|
||||
|
||||
auto resolverContext = static_cast< Resolver * >(context);
|
||||
emit resolverContext->m_zeroconf->recordResolved(resolverContext->m_record,
|
||||
QString::fromWCharArray(instance->pszHostName), instance->wPort);
|
||||
emit zeroconf->recordResolved(resolver->m_record, QString::fromWCharArray(instance->pszHostName), instance->wPort);
|
||||
|
||||
DnsServiceFreeInstance(instance);
|
||||
zeroconf->DnsServiceFreeInstance(instance);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#ifdef Q_OS_WIN64
|
||||
#ifdef Q_OS_WIN
|
||||
# include <windns.h>
|
||||
#endif
|
||||
|
||||
@ -20,7 +20,7 @@ private:
|
||||
Q_OBJECT
|
||||
Q_DISABLE_COPY(Zeroconf)
|
||||
protected:
|
||||
#ifdef Q_OS_WIN64
|
||||
#ifdef Q_OS_WIN
|
||||
struct Resolver {
|
||||
Zeroconf *m_zeroconf;
|
||||
BonjourRecord m_record;
|
||||
@ -35,7 +35,7 @@ protected:
|
||||
QList< BonjourRecord > m_records;
|
||||
std::unique_ptr< BonjourServiceBrowser > m_helperBrowser;
|
||||
std::unique_ptr< BonjourServiceResolver > m_helperResolver;
|
||||
#ifdef Q_OS_WIN64
|
||||
#ifdef Q_OS_WIN
|
||||
QList< Resolver > m_resolvers;
|
||||
std::unique_ptr< DNS_SERVICE_CANCEL > m_cancelBrowser;
|
||||
|
||||
@ -51,7 +51,13 @@ protected:
|
||||
void helperResolverRecordResolved(const BonjourRecord record, const QString hostname, const int port);
|
||||
void helperBrowserError(const DNSServiceErrorType error) const;
|
||||
void helperResolverError(const BonjourRecord record, const DNSServiceErrorType error);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
DNS_STATUS(WINAPI *DnsServiceBrowse)(PDNS_SERVICE_BROWSE_REQUEST pRequest, PDNS_SERVICE_CANCEL pCancel);
|
||||
DNS_STATUS(WINAPI *DnsServiceBrowseCancel)(PDNS_SERVICE_CANCEL pCancelHandle);
|
||||
DNS_STATUS(WINAPI *DnsServiceResolve)(PDNS_SERVICE_RESOLVE_REQUEST pRequest, PDNS_SERVICE_CANCEL pCancel);
|
||||
DNS_STATUS(WINAPI *DnsServiceResolveCancel)(PDNS_SERVICE_CANCEL pCancelHandle);
|
||||
VOID(WINAPI *DnsServiceFreeInstance)(PDNS_SERVICE_INSTANCE pInstance);
|
||||
#endif
|
||||
public:
|
||||
inline bool isOk() const { return m_ok; }
|
||||
inline QList< BonjourRecord > currentRecords() const {
|
||||
@ -62,7 +68,7 @@ public:
|
||||
bool stopBrowser();
|
||||
|
||||
bool startResolver(const BonjourRecord &record);
|
||||
#ifdef Q_OS_WIN64
|
||||
#ifdef Q_OS_WIN
|
||||
bool stopResolver(const BonjourRecord &record);
|
||||
#endif
|
||||
bool cleanupResolvers();
|
||||
|
||||
@ -5,37 +5,33 @@
|
||||
|
||||
#include "Zeroconf.h"
|
||||
|
||||
#define SYMBOL_EXISTS(symbol) (GetProcAddress(handle, symbol))
|
||||
#define GET_SYMBOL(symbol) (symbol = reinterpret_cast< decltype(symbol) >(GetProcAddress(handle, #symbol)))
|
||||
|
||||
Zeroconf::Zeroconf() : m_ok(false) {
|
||||
#ifdef Q_OS_WIN64
|
||||
static bool winDnsUnavailable = false;
|
||||
if (!winDnsUnavailable) {
|
||||
auto handle = GetModuleHandle(L"dnsapi.dll");
|
||||
if (handle) {
|
||||
if (SYMBOL_EXISTS("DnsServiceConstructInstance") && SYMBOL_EXISTS("DnsServiceFreeInstance")
|
||||
&& SYMBOL_EXISTS("DnsServiceRegister") && SYMBOL_EXISTS("DnsServiceDeRegister")
|
||||
&& SYMBOL_EXISTS("DnsServiceRegisterCancel")) {
|
||||
m_ok = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
#ifdef Q_OS_WIN
|
||||
auto handle = GetModuleHandle(L"dnsapi.dll");
|
||||
if (handle) {
|
||||
GET_SYMBOL(DnsServiceConstructInstance);
|
||||
GET_SYMBOL(DnsServiceFreeInstance);
|
||||
GET_SYMBOL(DnsServiceRegister);
|
||||
GET_SYMBOL(DnsServiceDeRegister);
|
||||
GET_SYMBOL(DnsServiceRegisterCancel);
|
||||
|
||||
winDnsUnavailable = true;
|
||||
qWarning("Zeroconf: Native mDNS/DNS-SD API not available, falling back to third-party API");
|
||||
}
|
||||
|
||||
static bool dnssdLoadFailed = false;
|
||||
if (!dnssdLoadFailed) {
|
||||
auto handle = LoadLibrary(L"dnssd.DLL");
|
||||
if (!handle) {
|
||||
dnssdLoadFailed = true;
|
||||
qWarning("Zeroconf: Failed to load dnssd.dll, assuming third-party API is not available");
|
||||
if (DnsServiceConstructInstance && DnsServiceFreeInstance && DnsServiceRegister && DnsServiceDeRegister
|
||||
&& DnsServiceRegisterCancel) {
|
||||
m_ok = true;
|
||||
return;
|
||||
}
|
||||
|
||||
FreeLibrary(handle);
|
||||
}
|
||||
|
||||
qWarning("Zeroconf: Native mDNS/DNS-SD API not available, falling back to third-party API");
|
||||
|
||||
handle = LoadLibrary(L"dnssd.dll");
|
||||
if (!handle) {
|
||||
qWarning("Zeroconf: Failed to load dnssd.dll, assuming third-party API is not available");
|
||||
return;
|
||||
}
|
||||
FreeLibrary(handle);
|
||||
#endif
|
||||
resetHelper();
|
||||
|
||||
@ -64,7 +60,7 @@ bool Zeroconf::registerService(const BonjourRecord &record, const uint16_t port)
|
||||
m_helper->registerService(record, port);
|
||||
return true;
|
||||
}
|
||||
#ifdef Q_OS_WIN64
|
||||
#ifdef Q_OS_WIN
|
||||
DWORD size = 0;
|
||||
GetComputerNameEx(ComputerNameDnsHostname, nullptr, &size);
|
||||
std::vector< wchar_t > hostname(size);
|
||||
@ -118,7 +114,7 @@ bool Zeroconf::unregisterService() {
|
||||
resetHelper();
|
||||
return true;
|
||||
}
|
||||
#ifdef Q_OS_WIN64
|
||||
#ifdef Q_OS_WIN
|
||||
if (m_cancel) {
|
||||
const auto ret = DnsServiceRegisterCancel(m_cancel.get());
|
||||
if (ret == ERROR_SUCCESS || ret == ERROR_CANCELLED) {
|
||||
@ -142,17 +138,18 @@ bool Zeroconf::unregisterService() {
|
||||
void Zeroconf::helperError(const DNSServiceErrorType error) {
|
||||
qWarning("Zeroconf: Third-party API reports error %d, service registration probably failed", error);
|
||||
}
|
||||
#ifdef Q_OS_WIN64
|
||||
#ifdef Q_OS_WIN
|
||||
void WINAPI Zeroconf::callbackRegisterComplete(const DWORD status, void *context, DNS_SERVICE_INSTANCE *instance) {
|
||||
auto zeroconf = static_cast< Zeroconf * >(context);
|
||||
|
||||
if (instance) {
|
||||
DnsServiceFreeInstance(instance);
|
||||
zeroconf->DnsServiceFreeInstance(instance);
|
||||
}
|
||||
|
||||
if (status == ERROR_CANCELLED) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto zeroconf = static_cast< Zeroconf * >(context);
|
||||
zeroconf->m_cancel.reset();
|
||||
|
||||
if (status != ERROR_SUCCESS) {
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
|
||||
#include <memory>
|
||||
|
||||
#ifdef Q_OS_WIN64
|
||||
#ifdef Q_OS_WIN
|
||||
# include <windns.h>
|
||||
#endif
|
||||
|
||||
@ -21,14 +21,22 @@ private:
|
||||
protected:
|
||||
bool m_ok;
|
||||
std::unique_ptr< BonjourServiceRegister > m_helper;
|
||||
#ifdef Q_OS_WIN64
|
||||
#ifdef Q_OS_WIN
|
||||
std::unique_ptr< DNS_SERVICE_CANCEL > m_cancel;
|
||||
std::unique_ptr< DNS_SERVICE_REGISTER_REQUEST > m_request;
|
||||
|
||||
static void WINAPI callbackRegisterComplete(const DWORD status, void *context, DNS_SERVICE_INSTANCE *instance);
|
||||
#endif
|
||||
void helperError(const DNSServiceErrorType error);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
PDNS_SERVICE_INSTANCE(WINAPI *DnsServiceConstructInstance)
|
||||
(PCWSTR pServiceName, PCWSTR pHostName, PIP4_ADDRESS pIp4, PIP6_ADDRESS pIp6, WORD wPort, WORD wPriority,
|
||||
WORD wWeight, DWORD dwPropertiesCount, PCWSTR *keys, PCWSTR *values);
|
||||
VOID(WINAPI *DnsServiceFreeInstance)(PDNS_SERVICE_INSTANCE pInstance);
|
||||
DWORD(WINAPI *DnsServiceRegister)(PDNS_SERVICE_REGISTER_REQUEST pRequest, PDNS_SERVICE_CANCEL pCancel);
|
||||
DWORD(WINAPI *DnsServiceDeRegister)(PDNS_SERVICE_REGISTER_REQUEST pRequest, PDNS_SERVICE_CANCEL pCancel);
|
||||
DWORD(WINAPI *DnsServiceRegisterCancel)(PDNS_SERVICE_CANCEL pCancelHandle);
|
||||
#endif
|
||||
public:
|
||||
inline bool isOk() const { return m_ok; }
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user