// Copyright 2005-2020 The Mumble Developers. All rights reserved. // Use of this source code is governed by a BSD-style license // that can be found in the LICENSE file at the root of the // Mumble source tree or at . #include "ServerResolver.h" #include #include static qint64 normalizeSrvPriority(quint16 priority, quint16 weight) { return static_cast((65535U * priority) + weight); } class ServerResolverPrivate : public QObject { private: Q_OBJECT Q_DISABLE_COPY(ServerResolverPrivate) public: ServerResolverPrivate(QObject *parent); void resolve(QString hostname, quint16 port); QList records(); QString m_origHostname; quint16 m_origPort; QList m_srvQueue; QMap m_hostInfoIdToIndexMap; int m_srvQueueRemain; QList m_resolved; signals: void resolved(); public slots: void srvResolved(); void hostResolved(QHostInfo hostInfo); void hostFallbackResolved(QHostInfo hostInfo); }; ServerResolverPrivate::ServerResolverPrivate(QObject *parent) : QObject(parent) , m_origPort(0) , m_srvQueueRemain(0) { } void ServerResolverPrivate::resolve(QString hostname, quint16 port) { m_origHostname = hostname; m_origPort = port; QDnsLookup *resolver = new QDnsLookup(this); connect(resolver, SIGNAL(finished()), this, SLOT(srvResolved())); resolver->setType(QDnsLookup::SRV); resolver->setName(QLatin1String("_mumble._tcp.") + hostname); resolver->lookup(); } QList ServerResolverPrivate::records() { return m_resolved; } void ServerResolverPrivate::srvResolved() { QDnsLookup *resolver = qobject_cast(sender()); m_srvQueue = resolver->serviceRecords(); m_srvQueueRemain = m_srvQueue.count(); if (resolver->error() == QDnsLookup::NoError && m_srvQueueRemain > 0) { for (int i = 0; i < m_srvQueue.count(); i++) { QDnsServiceRecord record = m_srvQueue.at(i); int hostInfoId = QHostInfo::lookupHost(record.target(), this, SLOT(hostResolved(QHostInfo))); m_hostInfoIdToIndexMap[hostInfoId] = i; } } else { QHostInfo::lookupHost(m_origHostname, this, SLOT(hostFallbackResolved(QHostInfo))); } delete resolver; } void ServerResolverPrivate::hostResolved(QHostInfo hostInfo) { int lookupId = hostInfo.lookupId(); int idx = m_hostInfoIdToIndexMap[lookupId]; QDnsServiceRecord record = m_srvQueue.at(idx); if (hostInfo.error() == QHostInfo::NoError) { QList resolvedAddresses = hostInfo.addresses(); // Convert QHostAddress -> HostAddress. QList addresses; foreach (QHostAddress ha, resolvedAddresses) { addresses << HostAddress(ha); } qint64 priority = normalizeSrvPriority(record.priority(), record.weight()); m_resolved << ServerResolverRecord(m_origHostname, record.port(), priority, addresses); } m_srvQueueRemain -= 1; if (m_srvQueueRemain == 0) { emit resolved(); } } void ServerResolverPrivate::hostFallbackResolved(QHostInfo hostInfo) { if (hostInfo.error() == QHostInfo::NoError) { QList resolvedAddresses = hostInfo.addresses(); // Convert QHostAddress -> HostAddress. QList addresses; foreach (QHostAddress ha, resolvedAddresses) { addresses << HostAddress(ha); } m_resolved << ServerResolverRecord(m_origHostname, m_origPort, 0, addresses); } emit resolved(); } ServerResolver::ServerResolver(QObject *parent) : QObject(parent) { d = new ServerResolverPrivate(this); } QString ServerResolver::hostname() { if (d) { return d->m_origHostname; } return QString(); } quint16 ServerResolver::port() { if (d) { return d->m_origPort; } return 0; } void ServerResolver::resolve(QString hostname, quint16 port) { if (d) { connect(d, SIGNAL(resolved()), this, SIGNAL(resolved())); d->resolve(hostname, port); } } QList ServerResolver::records() { if (d) { return d->records(); } return QList(); } #include "ServerResolver.moc"