Add support for DNS lookups using native APIs
The QDnsLookup class provides asynchronous APIs for performing DNS lookups. For now, the following lookups are supported: - A and AAAA - CNAME as defined per RFC 1035 - MX as defined per RFC 1035 - NS as defined per RFC 1035 - PTR as defined per RFC 1035 - SRV as defined per RFC 2782 - TXT as defined per RFC 1035 Task-number: QTBUG-10481 Change-Id: I46c1741ec23615863eeca3a1231d5e3f8942495e Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
d9468a9752
commit
e54dc7c2b5
73
doc/src/snippets/code/src_network_kernel_qdnslookup.cpp
Normal file
73
doc/src/snippets/code/src_network_kernel_qdnslookup.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
** This file is part of the documentation of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
|
||||
** the names of its contributors may be used to endorse or promote
|
||||
** products derived from this software without specific prior written
|
||||
** permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
//! [0]
|
||||
void MyObject::lookupServers()
|
||||
{
|
||||
// Create a DNS lookup.
|
||||
dns = new QDnsLookup(this);
|
||||
connect(dns, SIGNAL(finished()),
|
||||
this, SLOT(handleServers()));
|
||||
|
||||
// Find the XMPP servers for gmail.com
|
||||
dns->setType(QDnsLookup::SRV);
|
||||
dns->setName("_xmpp-client._tcp.gmail.com");
|
||||
dns->lookup();
|
||||
}
|
||||
//! [0]
|
||||
|
||||
|
||||
//! [1]
|
||||
void MyObject::handleServers()
|
||||
{
|
||||
// Check the lookup succeeded.
|
||||
if (dns->error() != QDnsLookup::NoError) {
|
||||
qWarning("DNS lookup failed");
|
||||
dns->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle the results.
|
||||
foreach (const QDnsServiceRecord &record, dns->serviceRecords()) {
|
||||
...
|
||||
}
|
||||
dns->deleteLater();
|
||||
}
|
||||
//! [1]
|
155
examples/network/dnslookup/dnslookup.cpp
Normal file
155
examples/network/dnslookup/dnslookup.cpp
Normal file
@ -0,0 +1,155 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
|
||||
** the names of its contributors may be used to endorse or promote
|
||||
** products derived from this software without specific prior written
|
||||
** permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "dnslookup.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QDnsLookup>
|
||||
#include <QHostAddress>
|
||||
#include <QStringList>
|
||||
#include <QTimer>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static void usage() {
|
||||
printf("Qt DNS example - performs DNS lookups\n"
|
||||
"Usage: dnslookup [-t <type>] name\n\n");
|
||||
}
|
||||
|
||||
DnsManager::DnsManager()
|
||||
{
|
||||
dns = new QDnsLookup(this);
|
||||
connect(dns, SIGNAL(finished()), this, SLOT(showResults()));
|
||||
}
|
||||
|
||||
void DnsManager::execute()
|
||||
{
|
||||
QStringList args = QCoreApplication::instance()->arguments();
|
||||
args.takeFirst();
|
||||
|
||||
// lookup type
|
||||
dns->setType(QDnsLookup::A);
|
||||
if (args.size() > 1 && args.first() == "-t") {
|
||||
args.takeFirst();
|
||||
const QString type = args.takeFirst().toLower();
|
||||
if (type == "a")
|
||||
dns->setType(QDnsLookup::A);
|
||||
else if (type == "aaaa")
|
||||
dns->setType(QDnsLookup::AAAA);
|
||||
else if (type == "any")
|
||||
dns->setType(QDnsLookup::ANY);
|
||||
else if (type == "cname")
|
||||
dns->setType(QDnsLookup::CNAME);
|
||||
else if (type == "mx")
|
||||
dns->setType(QDnsLookup::MX);
|
||||
else if (type == "ns")
|
||||
dns->setType(QDnsLookup::NS);
|
||||
else if (type == "ptr")
|
||||
dns->setType(QDnsLookup::PTR);
|
||||
else if (type == "srv")
|
||||
dns->setType(QDnsLookup::SRV);
|
||||
else if (type == "txt")
|
||||
dns->setType(QDnsLookup::TXT);
|
||||
else {
|
||||
printf("Bad record type: %s\n", qPrintable(type));
|
||||
QCoreApplication::instance()->quit();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (args.isEmpty()) {
|
||||
usage();
|
||||
QCoreApplication::instance()->quit();
|
||||
return;
|
||||
}
|
||||
dns->setName(args.takeFirst());
|
||||
dns->lookup();
|
||||
}
|
||||
|
||||
void DnsManager::showResults()
|
||||
{
|
||||
if (dns->error() != QDnsLookup::NoError)
|
||||
printf("Error: %i (%s)\n", dns->error(), qPrintable(dns->errorString()));
|
||||
|
||||
// CNAME records
|
||||
foreach (const QDnsDomainNameRecord &record, dns->canonicalNameRecords())
|
||||
printf("%s\t%i\tIN\tCNAME\t%s\n", qPrintable(record.name()), record.timeToLive(), qPrintable(record.value()));
|
||||
|
||||
// A and AAAA records
|
||||
foreach (const QDnsHostAddressRecord &record, dns->hostAddressRecords()) {
|
||||
const char *type = (record.value().protocol() == QAbstractSocket::IPv6Protocol) ? "AAAA" : "A";
|
||||
printf("%s\t%i\tIN\t%s\t%s\n", qPrintable(record.name()), record.timeToLive(), type, qPrintable(record.value().toString()));
|
||||
}
|
||||
|
||||
// MX records
|
||||
foreach (const QDnsMailExchangeRecord &record, dns->mailExchangeRecords())
|
||||
printf("%s\t%i\tIN\tMX\t%u %s\n", qPrintable(record.name()), record.timeToLive(), record.preference(), qPrintable(record.exchange()));
|
||||
|
||||
// NS records
|
||||
foreach (const QDnsDomainNameRecord &record, dns->nameServerRecords())
|
||||
printf("%s\t%i\tIN\tNS\t%s\n", qPrintable(record.name()), record.timeToLive(), qPrintable(record.value()));
|
||||
|
||||
// PTR records
|
||||
foreach (const QDnsDomainNameRecord &record, dns->pointerRecords())
|
||||
printf("%s\t%i\tIN\tPTR\t%s\n", qPrintable(record.name()), record.timeToLive(), qPrintable(record.value()));
|
||||
|
||||
// SRV records
|
||||
foreach (const QDnsServiceRecord &record, dns->serviceRecords())
|
||||
printf("%s\t%i\tIN\tSRV\t%u %u %u %s\n", qPrintable(record.name()), record.timeToLive(), record.priority(), record.weight(), record.port(), qPrintable(record.target()));
|
||||
|
||||
// TXT records
|
||||
foreach (const QDnsTextRecord &record, dns->textRecords()) {
|
||||
QStringList values;
|
||||
foreach (const QByteArray &ba, record.values())
|
||||
values << "\"" + QString::fromAscii(ba) + "\"";
|
||||
printf("%s\t%i\tIN\tTXT\t%s\n", qPrintable(record.name()), record.timeToLive(), qPrintable(values.join(" ")));
|
||||
}
|
||||
|
||||
QCoreApplication::instance()->quit();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
|
||||
DnsManager manager;
|
||||
QTimer::singleShot(0, &manager, SLOT(execute()));
|
||||
|
||||
return app.exec();
|
||||
}
|
61
examples/network/dnslookup/dnslookup.h
Normal file
61
examples/network/dnslookup/dnslookup.h
Normal file
@ -0,0 +1,61 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
** This file is part of the examples of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:BSD$
|
||||
** You may use this file under the terms of the BSD license as follows:
|
||||
**
|
||||
** "Redistribution and use in source and binary forms, with or without
|
||||
** modification, are permitted provided that the following conditions are
|
||||
** met:
|
||||
** * Redistributions of source code must retain the above copyright
|
||||
** notice, this list of conditions and the following disclaimer.
|
||||
** * Redistributions in binary form must reproduce the above copyright
|
||||
** notice, this list of conditions and the following disclaimer in
|
||||
** the documentation and/or other materials provided with the
|
||||
** distribution.
|
||||
** * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor
|
||||
** the names of its contributors may be used to endorse or promote
|
||||
** products derived from this software without specific prior written
|
||||
** permission.
|
||||
**
|
||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QObject>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QDnsLookup;
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class DnsManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
DnsManager();
|
||||
|
||||
public slots:
|
||||
void execute();
|
||||
void showResults();
|
||||
|
||||
private:
|
||||
QDnsLookup *dns;
|
||||
};
|
||||
|
12
examples/network/dnslookup/dnslookup.pro
Normal file
12
examples/network/dnslookup/dnslookup.pro
Normal file
@ -0,0 +1,12 @@
|
||||
TEMPLATE = app
|
||||
QT = core network
|
||||
mac:CONFIG -= app_bundle
|
||||
win32:CONFIG += console
|
||||
HEADERS += dnslookup.h
|
||||
SOURCES += dnslookup.cpp
|
||||
|
||||
# install
|
||||
target.path = $$[QT_INSTALL_EXAMPLES]/qtbase/network/dnslookup
|
||||
sources.files = $$SOURCES $$HEADERS $$FORMS $$RESOURCES *.pro
|
||||
sources.path = $$[QT_INSTALL_EXAMPLES]/qtbase/network/dnslookup
|
||||
INSTALLS += target sources
|
@ -1,5 +1,6 @@
|
||||
TEMPLATE = subdirs
|
||||
SUBDIRS = \
|
||||
dnslookup \
|
||||
download \
|
||||
downloadmanager
|
||||
|
||||
|
@ -5,6 +5,8 @@ INCLUDEPATH += $$PWD
|
||||
|
||||
HEADERS += kernel/qauthenticator.h \
|
||||
kernel/qauthenticator_p.h \
|
||||
kernel/qdnslookup.h \
|
||||
kernel/qdnslookup_p.h \
|
||||
kernel/qhostaddress.h \
|
||||
kernel/qhostinfo.h \
|
||||
kernel/qhostinfo_p.h \
|
||||
@ -14,15 +16,16 @@ HEADERS += kernel/qauthenticator.h \
|
||||
kernel/qnetworkinterface_p.h
|
||||
|
||||
SOURCES += kernel/qauthenticator.cpp \
|
||||
kernel/qdnslookup.cpp \
|
||||
kernel/qhostaddress.cpp \
|
||||
kernel/qhostinfo.cpp \
|
||||
kernel/qurlinfo.cpp \
|
||||
kernel/qnetworkproxy.cpp \
|
||||
kernel/qnetworkinterface.cpp
|
||||
|
||||
unix:SOURCES += kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp
|
||||
win32:SOURCES += kernel/qhostinfo_win.cpp kernel/qnetworkinterface_win.cpp
|
||||
integrity:SOURCES += kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp
|
||||
unix:SOURCES += kernel/qdnslookup_unix.cpp kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp
|
||||
win32:SOURCES += kernel/qdnslookup_win.cpp kernel/qhostinfo_win.cpp kernel/qnetworkinterface_win.cpp
|
||||
integrity:SOURCES += kernel/qdnslookup_unix.cpp kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp
|
||||
|
||||
mac:LIBS_PRIVATE += -framework SystemConfiguration -framework CoreFoundation
|
||||
mac:SOURCES += kernel/qnetworkproxy_mac.cpp
|
||||
|
988
src/network/kernel/qdnslookup.cpp
Normal file
988
src/network/kernel/qdnslookup.cpp
Normal file
@ -0,0 +1,988 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qdnslookup.h"
|
||||
#include "qdnslookup_p.h"
|
||||
|
||||
#include <qcoreapplication.h>
|
||||
#include <qdatetime.h>
|
||||
#include <qthreadstorage.h>
|
||||
#include <qurl.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
Q_GLOBAL_STATIC(QDnsLookupThreadPool, theDnsLookupThreadPool);
|
||||
Q_GLOBAL_STATIC(QThreadStorage<bool *>, theDnsLookupSeedStorage);
|
||||
|
||||
static bool qt_qdnsmailexchangerecord_less_than(const QDnsMailExchangeRecord &r1, const QDnsMailExchangeRecord &r2)
|
||||
{
|
||||
// Lower numbers are more preferred than higher ones.
|
||||
return r1.preference() < r2.preference();
|
||||
}
|
||||
|
||||
/*!
|
||||
Sorts a list of QDnsMailExchangeRecord objects according to RFC 5321.
|
||||
*/
|
||||
|
||||
static void qt_qdnsmailexchangerecord_sort(QList<QDnsMailExchangeRecord> &records)
|
||||
{
|
||||
// If we have no more than one result, we are done.
|
||||
if (records.size() <= 1)
|
||||
return;
|
||||
|
||||
// Order the records by preference.
|
||||
qSort(records.begin(), records.end(), qt_qdnsmailexchangerecord_less_than);
|
||||
|
||||
int i = 0;
|
||||
while (i < records.size()) {
|
||||
|
||||
// Determine the slice of records with the current preference.
|
||||
QList<QDnsMailExchangeRecord> slice;
|
||||
const quint16 slicePreference = records[i].preference();
|
||||
for (int j = i; j < records.size(); ++j) {
|
||||
if (records[j].preference() != slicePreference)
|
||||
break;
|
||||
slice << records[j];
|
||||
}
|
||||
|
||||
// Randomize the slice of records.
|
||||
while (!slice.isEmpty()) {
|
||||
const unsigned int pos = qrand() % slice.size();
|
||||
records[i++] = slice.takeAt(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool qt_qdnsservicerecord_less_than(const QDnsServiceRecord &r1, const QDnsServiceRecord &r2)
|
||||
{
|
||||
// Order by priority, or if the priorities are equal,
|
||||
// put zero weight records first.
|
||||
return r1.priority() < r2.priority()
|
||||
|| (r1.priority() == r2.priority()
|
||||
&& r1.weight() == 0 && r2.weight() > 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
Sorts a list of QDnsServiceRecord objects according to RFC 2782.
|
||||
*/
|
||||
|
||||
static void qt_qdnsservicerecord_sort(QList<QDnsServiceRecord> &records)
|
||||
{
|
||||
// If we have no more than one result, we are done.
|
||||
if (records.size() <= 1)
|
||||
return;
|
||||
|
||||
// Order the records by priority, and for records with an equal
|
||||
// priority, put records with a zero weight first.
|
||||
qSort(records.begin(), records.end(), qt_qdnsservicerecord_less_than);
|
||||
|
||||
int i = 0;
|
||||
while (i < records.size()) {
|
||||
|
||||
// Determine the slice of records with the current priority.
|
||||
QList<QDnsServiceRecord> slice;
|
||||
const quint16 slicePriority = records[i].priority();
|
||||
unsigned int sliceWeight = 0;
|
||||
for (int j = i; j < records.size(); ++j) {
|
||||
if (records[j].priority() != slicePriority)
|
||||
break;
|
||||
sliceWeight += records[j].weight();
|
||||
slice << records[j];
|
||||
}
|
||||
#ifdef QDNSLOOKUP_DEBUG
|
||||
qDebug("qt_qdnsservicerecord_sort() : priority %i (size: %i, total weight: %i)",
|
||||
slicePriority, slice.size(), sliceWeight);
|
||||
#endif
|
||||
|
||||
// Order the slice of records.
|
||||
while (!slice.isEmpty()) {
|
||||
const unsigned int weightThreshold = qrand() % (sliceWeight + 1);
|
||||
unsigned int summedWeight = 0;
|
||||
for (int j = 0; j < slice.size(); ++j) {
|
||||
summedWeight += slice[j].weight();
|
||||
if (summedWeight >= weightThreshold) {
|
||||
#ifdef QDNSLOOKUP_DEBUG
|
||||
qDebug("qt_qdnsservicerecord_sort() : adding %s %i (weight: %i)",
|
||||
qPrintable(slice[j].target()), slice[j].port(),
|
||||
slice[j].weight());
|
||||
#endif
|
||||
// Adjust the slice weight and take the current record.
|
||||
sliceWeight -= slice[j].weight();
|
||||
records[i++] = slice.takeAt(j);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\class QDnsLookup
|
||||
\brief The QDnsLookup class represents a DNS lookup.
|
||||
|
||||
\inmodule QtNetwork
|
||||
\ingroup network
|
||||
|
||||
QDnsLookup uses the mechanisms provided by the operating system to perform
|
||||
DNS lookups. To perform a lookup you need to specify a \l name and \l type
|
||||
then invoke the \l{QDnsLookup::lookup()}{lookup()} slot. The
|
||||
\l{QDnsLookup::finished()}{finished()} signal will be emitted upon
|
||||
completion.
|
||||
|
||||
For example, you can determine which servers an XMPP chat client should
|
||||
connect to for a given domain with:
|
||||
|
||||
\snippet doc/src/snippets/code/src_network_kernel_qdnslookup.cpp 0
|
||||
|
||||
Once the request finishes you can handle the results with:
|
||||
|
||||
\snippet doc/src/snippets/code/src_network_kernel_qdnslookup.cpp 1
|
||||
|
||||
\note If you simply want to find the IP address(es) associated with a host
|
||||
name, or the host name associated with an IP address you should use
|
||||
QHostInfo instead.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\enum QDnsLookup::Error
|
||||
|
||||
Indicates all possible error conditions found during the
|
||||
processing of the DNS lookup.
|
||||
|
||||
\value NoError no error condition.
|
||||
|
||||
\value ResolverError there was an error initializing the system's
|
||||
DNS resolver.
|
||||
|
||||
\value OperationCancelledError the lookup was aborted using the abort()
|
||||
method.
|
||||
|
||||
\value InvalidRequestError the requested DNS lookup was invalid.
|
||||
|
||||
\value InvalidReplyError the reply returned by the server was invalid.
|
||||
|
||||
\value ServerFailureError the server encountered an internal failure
|
||||
while processing the request (SERVFAIL).
|
||||
|
||||
\value ServerRefusedError the server refused to process the request for
|
||||
security or policy reasons (REFUSED).
|
||||
|
||||
\value NotFoundError the requested domain name does not exist
|
||||
(NXDOMAIN).
|
||||
*/
|
||||
|
||||
/*!
|
||||
\enum QDnsLookup::Type
|
||||
|
||||
Indicates the type of DNS lookup that was performed.
|
||||
|
||||
\value A IPv4 address records.
|
||||
|
||||
\value AAAA IPv6 address records.
|
||||
|
||||
\value ANY any records.
|
||||
|
||||
\value CNAME canonical name records.
|
||||
|
||||
\value MX mail exchange records.
|
||||
|
||||
\value NS name server records.
|
||||
|
||||
\value PTR pointer records.
|
||||
|
||||
\value SRV service records.
|
||||
|
||||
\value TXT text records.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void QDnsLookup::finished()
|
||||
|
||||
This signal is emitted when the reply has finished processing.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void QDnsLookup::nameChanged(const QString &name)
|
||||
|
||||
This signal is emitted when the lookup \l name changes.
|
||||
\a name is the new lookup name.
|
||||
*/
|
||||
|
||||
/*!
|
||||
\fn void QDnsLookup::typeChanged(Type type)
|
||||
|
||||
This signal is emitted when the lookup \l type changes.
|
||||
\a type is the new lookup type.
|
||||
*/
|
||||
|
||||
/*!
|
||||
Constructs a QDnsLookup object and sets \a parent as the parent object.
|
||||
|
||||
The \l type property will default to QDnsLookup::A.
|
||||
*/
|
||||
|
||||
QDnsLookup::QDnsLookup(QObject *parent)
|
||||
: QObject(*new QDnsLookupPrivate, parent)
|
||||
{
|
||||
qRegisterMetaType<QDnsLookupReply>();
|
||||
}
|
||||
/*!
|
||||
Constructs a QDnsLookup object for the given \a type and \a name and sets
|
||||
\a parent as the parent object.
|
||||
*/
|
||||
|
||||
QDnsLookup::QDnsLookup(Type type, const QString &name, QObject *parent)
|
||||
: QObject(*new QDnsLookupPrivate, parent)
|
||||
{
|
||||
Q_D(QDnsLookup);
|
||||
qRegisterMetaType<QDnsLookupReply>();
|
||||
d->name = name;
|
||||
d->type = type;
|
||||
}
|
||||
|
||||
/*!
|
||||
Destroys the QDnsLookup object.
|
||||
|
||||
It is safe to delete a QDnsLookup object even if it is not finished, you
|
||||
will simply never receive its results.
|
||||
*/
|
||||
|
||||
QDnsLookup::~QDnsLookup()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
\property QDnsLookup::error
|
||||
\brief the type of error that occurred if the DNS lookup failed, or NoError.
|
||||
*/
|
||||
|
||||
QDnsLookup::Error QDnsLookup::error() const
|
||||
{
|
||||
return d_func()->reply.error;
|
||||
}
|
||||
|
||||
/*!
|
||||
\property QDnsLookup::errorString
|
||||
\brief a human-readable description of the error if the DNS lookup failed.
|
||||
*/
|
||||
|
||||
QString QDnsLookup::errorString() const
|
||||
{
|
||||
return d_func()->reply.errorString;
|
||||
}
|
||||
|
||||
/*!
|
||||
\property QDnsLookup::finished
|
||||
\brief whether the reply has finished or was aborted.
|
||||
*/
|
||||
|
||||
bool QDnsLookup::isFinished() const
|
||||
{
|
||||
return d_func()->isFinished;
|
||||
}
|
||||
|
||||
/*!
|
||||
\property QDnsLookup::name
|
||||
\brief the name to lookup.
|
||||
|
||||
\note The name will be encoded using IDNA, which means it's unsuitable for
|
||||
querying SRV records compatible with the DNS-SD specification.
|
||||
*/
|
||||
|
||||
QString QDnsLookup::name() const
|
||||
{
|
||||
return d_func()->name;
|
||||
}
|
||||
|
||||
void QDnsLookup::setName(const QString &name)
|
||||
{
|
||||
Q_D(QDnsLookup);
|
||||
if (name != d->name) {
|
||||
d->name = name;
|
||||
emit nameChanged(name);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
\property QDnsLookup::type
|
||||
\brief the type of DNS lookup.
|
||||
*/
|
||||
|
||||
QDnsLookup::Type QDnsLookup::type() const
|
||||
{
|
||||
return d_func()->type;
|
||||
}
|
||||
|
||||
void QDnsLookup::setType(Type type)
|
||||
{
|
||||
Q_D(QDnsLookup);
|
||||
if (type != d->type) {
|
||||
d->type = type;
|
||||
emit typeChanged(type);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the list of canonical name records associated with this lookup.
|
||||
*/
|
||||
|
||||
QList<QDnsDomainNameRecord> QDnsLookup::canonicalNameRecords() const
|
||||
{
|
||||
return d_func()->reply.canonicalNameRecords;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the list of host address records associated with this lookup.
|
||||
*/
|
||||
|
||||
QList<QDnsHostAddressRecord> QDnsLookup::hostAddressRecords() const
|
||||
{
|
||||
return d_func()->reply.hostAddressRecords;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the list of mail exchange records associated with this lookup.
|
||||
|
||||
The records are sorted according to
|
||||
\l{http://www.rfc-editor.org/rfc/rfc5321.txt}{RFC 5321}, so if you use them
|
||||
to connect to servers, you should try them in the order they are listed.
|
||||
*/
|
||||
|
||||
QList<QDnsMailExchangeRecord> QDnsLookup::mailExchangeRecords() const
|
||||
{
|
||||
return d_func()->reply.mailExchangeRecords;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the list of name server records associated with this lookup.
|
||||
*/
|
||||
|
||||
QList<QDnsDomainNameRecord> QDnsLookup::nameServerRecords() const
|
||||
{
|
||||
return d_func()->reply.nameServerRecords;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the list of pointer records associated with this lookup.
|
||||
*/
|
||||
|
||||
QList<QDnsDomainNameRecord> QDnsLookup::pointerRecords() const
|
||||
{
|
||||
return d_func()->reply.pointerRecords;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the list of service records associated with this lookup.
|
||||
|
||||
The records are sorted according to
|
||||
\l{http://www.rfc-editor.org/rfc/rfc2782.txt}{RFC 2782}, so if you use them
|
||||
to connect to servers, you should try them in the order they are listed.
|
||||
*/
|
||||
|
||||
QList<QDnsServiceRecord> QDnsLookup::serviceRecords() const
|
||||
{
|
||||
return d_func()->reply.serviceRecords;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the list of text records associated with this lookup.
|
||||
*/
|
||||
|
||||
QList<QDnsTextRecord> QDnsLookup::textRecords() const
|
||||
{
|
||||
return d_func()->reply.textRecords;
|
||||
}
|
||||
|
||||
/*!
|
||||
Aborts the DNS lookup operation.
|
||||
|
||||
If the lookup is already finished, does nothing.
|
||||
*/
|
||||
|
||||
void QDnsLookup::abort()
|
||||
{
|
||||
Q_D(QDnsLookup);
|
||||
if (d->runnable) {
|
||||
d->runnable = 0;
|
||||
d->reply = QDnsLookupReply();
|
||||
d->reply.error = QDnsLookup::OperationCancelledError;
|
||||
d->reply.errorString = tr("Operation cancelled");
|
||||
d->isFinished = true;
|
||||
emit finished();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Performs the DNS lookup.
|
||||
|
||||
The \l{QDnsLookup::finished()}{finished()} signal is emitted upon completion.
|
||||
*/
|
||||
|
||||
void QDnsLookup::lookup()
|
||||
{
|
||||
Q_D(QDnsLookup);
|
||||
d->isFinished = false;
|
||||
d->reply = QDnsLookupReply();
|
||||
d->runnable = new QDnsLookupRunnable(d->type, QUrl::toAce(d->name));
|
||||
connect(d->runnable, SIGNAL(finished(QDnsLookupReply)),
|
||||
this, SLOT(_q_lookupFinished(QDnsLookupReply)),
|
||||
Qt::BlockingQueuedConnection);
|
||||
theDnsLookupThreadPool()->start(d->runnable);
|
||||
}
|
||||
|
||||
/*!
|
||||
\class QDnsDomainNameRecord
|
||||
\brief The QDnsDomainNameRecord class stores information about a domain
|
||||
name record.
|
||||
|
||||
\inmodule QtNetwork
|
||||
\ingroup network
|
||||
|
||||
When performing a name server lookup, zero or more records will be returned.
|
||||
Each record is represented by a QDnsDomainNameRecord instance.
|
||||
|
||||
\sa QDnsLookup
|
||||
*/
|
||||
|
||||
/*!
|
||||
Constructs an empty domain name record object.
|
||||
*/
|
||||
|
||||
QDnsDomainNameRecord::QDnsDomainNameRecord()
|
||||
: d(new QDnsDomainNameRecordPrivate)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs a copy of \a other.
|
||||
*/
|
||||
|
||||
QDnsDomainNameRecord::QDnsDomainNameRecord(const QDnsDomainNameRecord &other)
|
||||
: d(other.d)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Destroys a domain name record.
|
||||
*/
|
||||
|
||||
QDnsDomainNameRecord::~QDnsDomainNameRecord()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the name for this record.
|
||||
*/
|
||||
|
||||
QString QDnsDomainNameRecord::name() const
|
||||
{
|
||||
return d->name;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the duration in seconds for which this record is valid.
|
||||
*/
|
||||
|
||||
quint32 QDnsDomainNameRecord::timeToLive() const
|
||||
{
|
||||
return d->timeToLive;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the value for this domain name record.
|
||||
*/
|
||||
|
||||
QString QDnsDomainNameRecord::value() const
|
||||
{
|
||||
return d->value;
|
||||
}
|
||||
|
||||
/*!
|
||||
Assigns the data of the \a other object to this record object,
|
||||
and returns a reference to it.
|
||||
*/
|
||||
|
||||
QDnsDomainNameRecord &QDnsDomainNameRecord::operator=(const QDnsDomainNameRecord &other)
|
||||
{
|
||||
d = other.d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
\class QDnsHostAddressRecord
|
||||
\brief The QDnsHostAddressRecord class stores information about a host
|
||||
address record.
|
||||
|
||||
\inmodule QtNetwork
|
||||
\ingroup network
|
||||
|
||||
When performing an address lookup, zero or more records will be
|
||||
returned. Each record is represented by a QDnsHostAddressRecord instance.
|
||||
|
||||
\sa QDnsLookup
|
||||
*/
|
||||
|
||||
/*!
|
||||
Constructs an empty host address record object.
|
||||
*/
|
||||
|
||||
QDnsHostAddressRecord::QDnsHostAddressRecord()
|
||||
: d(new QDnsHostAddressRecordPrivate)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs a copy of \a other.
|
||||
*/
|
||||
|
||||
QDnsHostAddressRecord::QDnsHostAddressRecord(const QDnsHostAddressRecord &other)
|
||||
: d(other.d)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Destroys a host address record.
|
||||
*/
|
||||
|
||||
QDnsHostAddressRecord::~QDnsHostAddressRecord()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the name for this record.
|
||||
*/
|
||||
|
||||
QString QDnsHostAddressRecord::name() const
|
||||
{
|
||||
return d->name;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the duration in seconds for which this record is valid.
|
||||
*/
|
||||
|
||||
quint32 QDnsHostAddressRecord::timeToLive() const
|
||||
{
|
||||
return d->timeToLive;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the value for this host address record.
|
||||
*/
|
||||
|
||||
QHostAddress QDnsHostAddressRecord::value() const
|
||||
{
|
||||
return d->value;
|
||||
}
|
||||
|
||||
/*!
|
||||
Assigns the data of the \a other object to this record object,
|
||||
and returns a reference to it.
|
||||
*/
|
||||
|
||||
QDnsHostAddressRecord &QDnsHostAddressRecord::operator=(const QDnsHostAddressRecord &other)
|
||||
{
|
||||
d = other.d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
\class QDnsMailExchangeRecord
|
||||
\brief The QDnsMailExchangeRecord class stores information about a DNS MX record.
|
||||
|
||||
\inmodule QtNetwork
|
||||
\ingroup network
|
||||
|
||||
When performing a lookup on a service, zero or more records will be
|
||||
returned. Each record is represented by a QDnsMailExchangeRecord instance.
|
||||
|
||||
The meaning of the fields is defined in
|
||||
\l{http://www.rfc-editor.org/rfc/rfc1035.txt}{RFC 1035}.
|
||||
|
||||
\sa QDnsLookup
|
||||
*/
|
||||
|
||||
/*!
|
||||
Constructs an empty mail exchange record object.
|
||||
*/
|
||||
|
||||
QDnsMailExchangeRecord::QDnsMailExchangeRecord()
|
||||
: d(new QDnsMailExchangeRecordPrivate)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs a copy of \a other.
|
||||
*/
|
||||
|
||||
QDnsMailExchangeRecord::QDnsMailExchangeRecord(const QDnsMailExchangeRecord &other)
|
||||
: d(other.d)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Destroys a mail exchange record.
|
||||
*/
|
||||
|
||||
QDnsMailExchangeRecord::~QDnsMailExchangeRecord()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the domain name of the mail exchange for this record.
|
||||
*/
|
||||
|
||||
QString QDnsMailExchangeRecord::exchange() const
|
||||
{
|
||||
return d->exchange;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the name for this record.
|
||||
*/
|
||||
|
||||
QString QDnsMailExchangeRecord::name() const
|
||||
{
|
||||
return d->name;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the preference for this record.
|
||||
*/
|
||||
|
||||
quint16 QDnsMailExchangeRecord::preference() const
|
||||
{
|
||||
return d->preference;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the duration in seconds for which this record is valid.
|
||||
*/
|
||||
|
||||
quint32 QDnsMailExchangeRecord::timeToLive() const
|
||||
{
|
||||
return d->timeToLive;
|
||||
}
|
||||
|
||||
/*!
|
||||
Assigns the data of the \a other object to this record object,
|
||||
and returns a reference to it.
|
||||
*/
|
||||
|
||||
QDnsMailExchangeRecord &QDnsMailExchangeRecord::operator=(const QDnsMailExchangeRecord &other)
|
||||
{
|
||||
d = other.d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
\class QDnsServiceRecord
|
||||
\brief The QDnsServiceRecord class stores information about a DNS SRV record.
|
||||
|
||||
\inmodule QtNetwork
|
||||
\ingroup network
|
||||
|
||||
When performing a lookup on a service, zero or more records will be
|
||||
returned. Each record is represented by a QDnsServiceRecord instance.
|
||||
|
||||
The meaning of the fields is defined in
|
||||
\l{http://www.rfc-editor.org/rfc/rfc2782.txt}{RFC 2782}.
|
||||
|
||||
\sa QDnsLookup
|
||||
*/
|
||||
|
||||
/*!
|
||||
Constructs an empty service record object.
|
||||
*/
|
||||
|
||||
QDnsServiceRecord::QDnsServiceRecord()
|
||||
: d(new QDnsServiceRecordPrivate)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs a copy of \a other.
|
||||
*/
|
||||
|
||||
QDnsServiceRecord::QDnsServiceRecord(const QDnsServiceRecord &other)
|
||||
: d(other.d)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Destroys a service record.
|
||||
*/
|
||||
|
||||
QDnsServiceRecord::~QDnsServiceRecord()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the name for this record.
|
||||
*/
|
||||
|
||||
QString QDnsServiceRecord::name() const
|
||||
{
|
||||
return d->name;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the port on the target host for this service record.
|
||||
*/
|
||||
|
||||
quint16 QDnsServiceRecord::port() const
|
||||
{
|
||||
return d->port;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the priority for this service record.
|
||||
|
||||
A client must attempt to contact the target host with the lowest-numbered
|
||||
priority.
|
||||
*/
|
||||
|
||||
quint16 QDnsServiceRecord::priority() const
|
||||
{
|
||||
return d->priority;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the domain name of the target host for this service record.
|
||||
*/
|
||||
|
||||
QString QDnsServiceRecord::target() const
|
||||
{
|
||||
return d->target;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the duration in seconds for which this record is valid.
|
||||
*/
|
||||
|
||||
quint32 QDnsServiceRecord::timeToLive() const
|
||||
{
|
||||
return d->timeToLive;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the weight for this service record.
|
||||
|
||||
The weight field specifies a relative weight for entries with the same
|
||||
priority. Entries with higher weights should be selected with a higher
|
||||
probability.
|
||||
*/
|
||||
|
||||
quint16 QDnsServiceRecord::weight() const
|
||||
{
|
||||
return d->weight;
|
||||
}
|
||||
|
||||
/*!
|
||||
Assigns the data of the \a other object to this record object,
|
||||
and returns a reference to it.
|
||||
*/
|
||||
|
||||
QDnsServiceRecord &QDnsServiceRecord::operator=(const QDnsServiceRecord &other)
|
||||
{
|
||||
d = other.d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
\class QDnsTextRecord
|
||||
\brief The QDnsTextRecord class stores information about a DNS TXT record.
|
||||
|
||||
\inmodule QtNetwork
|
||||
\ingroup network
|
||||
|
||||
When performing a text lookup, zero or more records will be
|
||||
returned. Each record is represented by a QDnsTextRecord instance.
|
||||
|
||||
The meaning of the fields is defined in
|
||||
\l{http://www.rfc-editor.org/rfc/rfc1035.txt}{RFC 1035}.
|
||||
|
||||
\sa QDnsLookup
|
||||
*/
|
||||
|
||||
/*!
|
||||
Constructs an empty text record object.
|
||||
*/
|
||||
|
||||
QDnsTextRecord::QDnsTextRecord()
|
||||
: d(new QDnsTextRecordPrivate)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Constructs a copy of \a other.
|
||||
*/
|
||||
|
||||
QDnsTextRecord::QDnsTextRecord(const QDnsTextRecord &other)
|
||||
: d(other.d)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Destroys a text record.
|
||||
*/
|
||||
|
||||
QDnsTextRecord::~QDnsTextRecord()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the name for this text record.
|
||||
*/
|
||||
|
||||
QString QDnsTextRecord::name() const
|
||||
{
|
||||
return d->name;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the duration in seconds for which this record is valid.
|
||||
*/
|
||||
|
||||
quint32 QDnsTextRecord::timeToLive() const
|
||||
{
|
||||
return d->timeToLive;
|
||||
}
|
||||
|
||||
/*!
|
||||
Returns the values for this text record.
|
||||
*/
|
||||
|
||||
QList<QByteArray> QDnsTextRecord::values() const
|
||||
{
|
||||
return d->values;
|
||||
}
|
||||
|
||||
/*!
|
||||
Assigns the data of the \a other object to this record object,
|
||||
and returns a reference to it.
|
||||
*/
|
||||
|
||||
QDnsTextRecord &QDnsTextRecord::operator=(const QDnsTextRecord &other)
|
||||
{
|
||||
d = other.d;
|
||||
return *this;
|
||||
}
|
||||
|
||||
void QDnsLookupPrivate::_q_lookupFinished(const QDnsLookupReply &_reply)
|
||||
{
|
||||
Q_Q(QDnsLookup);
|
||||
if (runnable == q->sender()) {
|
||||
#ifdef QDNSLOOKUP_DEBUG
|
||||
qDebug("DNS reply for %s: %i (%s)", qPrintable(name), _reply.error, qPrintable(_reply.errorString));
|
||||
#endif
|
||||
reply = _reply;
|
||||
runnable = 0;
|
||||
isFinished = true;
|
||||
emit q->finished();
|
||||
}
|
||||
}
|
||||
|
||||
void QDnsLookupRunnable::run()
|
||||
{
|
||||
QDnsLookupReply reply;
|
||||
|
||||
// Validate input.
|
||||
if (requestName.isEmpty()) {
|
||||
reply.error = QDnsLookup::InvalidRequestError;
|
||||
reply.errorString = tr("Invalid domain name");
|
||||
emit finished(reply);
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform request.
|
||||
query(requestType, requestName, &reply);
|
||||
|
||||
// Sort results.
|
||||
if (!theDnsLookupSeedStorage()->hasLocalData()) {
|
||||
qsrand(QTime(0,0,0).msecsTo(QTime::currentTime()) ^ reinterpret_cast<quintptr>(this));
|
||||
theDnsLookupSeedStorage()->setLocalData(new bool(true));
|
||||
}
|
||||
qt_qdnsmailexchangerecord_sort(reply.mailExchangeRecords);
|
||||
qt_qdnsservicerecord_sort(reply.serviceRecords);
|
||||
|
||||
emit finished(reply);
|
||||
}
|
||||
|
||||
QDnsLookupThreadPool::QDnsLookupThreadPool()
|
||||
: signalsConnected(false)
|
||||
{
|
||||
// Run up to 5 lookups in parallel.
|
||||
setMaxThreadCount(5);
|
||||
}
|
||||
|
||||
void QDnsLookupThreadPool::start(QRunnable *runnable)
|
||||
{
|
||||
// Ensure threads complete at application destruction.
|
||||
if (!signalsConnected) {
|
||||
QMutexLocker signalsLocker(&signalsMutex);
|
||||
if (!signalsConnected) {
|
||||
QCoreApplication *app = QCoreApplication::instance();
|
||||
if (!app) {
|
||||
qWarning("QDnsLookup requires a QCoreApplication");
|
||||
delete runnable;
|
||||
return;
|
||||
}
|
||||
|
||||
moveToThread(app->thread());
|
||||
connect(app, SIGNAL(destroyed()),
|
||||
SLOT(_q_applicationDestroyed()), Qt::DirectConnection);
|
||||
signalsConnected = true;
|
||||
}
|
||||
}
|
||||
|
||||
QThreadPool::start(runnable);
|
||||
}
|
||||
|
||||
void QDnsLookupThreadPool::_q_applicationDestroyed()
|
||||
{
|
||||
waitForDone();
|
||||
signalsConnected = false;
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#include "moc_qdnslookup.cpp"
|
235
src/network/kernel/qdnslookup.h
Normal file
235
src/network/kernel/qdnslookup.h
Normal file
@ -0,0 +1,235 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QDNSLOOKUP_H
|
||||
#define QDNSLOOKUP_H
|
||||
|
||||
#include <QtCore/qlist.h>
|
||||
#include <QtCore/qobject.h>
|
||||
#include <QtCore/qshareddata.h>
|
||||
#include <QtCore/qsharedpointer.h>
|
||||
#include <QtCore/qstring.h>
|
||||
|
||||
QT_BEGIN_HEADER
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
QT_MODULE(Network)
|
||||
|
||||
class QHostAddress;
|
||||
class QDnsLookupPrivate;
|
||||
class QDnsDomainNameRecordPrivate;
|
||||
class QDnsHostAddressRecordPrivate;
|
||||
class QDnsMailExchangeRecordPrivate;
|
||||
class QDnsServiceRecordPrivate;
|
||||
class QDnsTextRecordPrivate;
|
||||
|
||||
class Q_NETWORK_EXPORT QDnsDomainNameRecord
|
||||
{
|
||||
public:
|
||||
QDnsDomainNameRecord();
|
||||
QDnsDomainNameRecord(const QDnsDomainNameRecord &other);
|
||||
~QDnsDomainNameRecord();
|
||||
|
||||
QString name() const;
|
||||
quint32 timeToLive() const;
|
||||
QString value() const;
|
||||
|
||||
QDnsDomainNameRecord &operator=(const QDnsDomainNameRecord &other);
|
||||
|
||||
private:
|
||||
QSharedDataPointer<QDnsDomainNameRecordPrivate> d;
|
||||
friend class QDnsLookupRunnable;
|
||||
};
|
||||
|
||||
class Q_NETWORK_EXPORT QDnsHostAddressRecord
|
||||
{
|
||||
public:
|
||||
QDnsHostAddressRecord();
|
||||
QDnsHostAddressRecord(const QDnsHostAddressRecord &other);
|
||||
~QDnsHostAddressRecord();
|
||||
|
||||
QString name() const;
|
||||
quint32 timeToLive() const;
|
||||
QHostAddress value() const;
|
||||
|
||||
QDnsHostAddressRecord &operator=(const QDnsHostAddressRecord &other);
|
||||
|
||||
private:
|
||||
QSharedDataPointer<QDnsHostAddressRecordPrivate> d;
|
||||
friend class QDnsLookupRunnable;
|
||||
};
|
||||
|
||||
class Q_NETWORK_EXPORT QDnsMailExchangeRecord
|
||||
{
|
||||
public:
|
||||
QDnsMailExchangeRecord();
|
||||
QDnsMailExchangeRecord(const QDnsMailExchangeRecord &other);
|
||||
~QDnsMailExchangeRecord();
|
||||
|
||||
QString exchange() const;
|
||||
QString name() const;
|
||||
quint16 preference() const;
|
||||
quint32 timeToLive() const;
|
||||
|
||||
QDnsMailExchangeRecord &operator=(const QDnsMailExchangeRecord &other);
|
||||
|
||||
private:
|
||||
QSharedDataPointer<QDnsMailExchangeRecordPrivate> d;
|
||||
friend class QDnsLookupRunnable;
|
||||
};
|
||||
|
||||
class Q_NETWORK_EXPORT QDnsServiceRecord
|
||||
{
|
||||
public:
|
||||
QDnsServiceRecord();
|
||||
QDnsServiceRecord(const QDnsServiceRecord &other);
|
||||
~QDnsServiceRecord();
|
||||
|
||||
QString name() const;
|
||||
quint16 port() const;
|
||||
quint16 priority() const;
|
||||
QString target() const;
|
||||
quint32 timeToLive() const;
|
||||
quint16 weight() const;
|
||||
|
||||
QDnsServiceRecord &operator=(const QDnsServiceRecord &other);
|
||||
|
||||
private:
|
||||
QSharedDataPointer<QDnsServiceRecordPrivate> d;
|
||||
friend class QDnsLookupRunnable;
|
||||
};
|
||||
|
||||
class Q_NETWORK_EXPORT QDnsTextRecord
|
||||
{
|
||||
public:
|
||||
QDnsTextRecord();
|
||||
QDnsTextRecord(const QDnsTextRecord &other);
|
||||
~QDnsTextRecord();
|
||||
|
||||
QString name() const;
|
||||
quint32 timeToLive() const;
|
||||
QList<QByteArray> values() const;
|
||||
|
||||
QDnsTextRecord &operator=(const QDnsTextRecord &other);
|
||||
|
||||
private:
|
||||
QSharedDataPointer<QDnsTextRecordPrivate> d;
|
||||
friend class QDnsLookupRunnable;
|
||||
};
|
||||
|
||||
class Q_NETWORK_EXPORT QDnsLookup : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_ENUMS(Error Type)
|
||||
Q_PROPERTY(Error error READ error NOTIFY finished)
|
||||
Q_PROPERTY(QString errorString READ errorString NOTIFY finished)
|
||||
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
|
||||
Q_PROPERTY(Type type READ type WRITE setType NOTIFY typeChanged)
|
||||
|
||||
public:
|
||||
enum Error
|
||||
{
|
||||
NoError = 0,
|
||||
ResolverError,
|
||||
OperationCancelledError,
|
||||
InvalidRequestError,
|
||||
InvalidReplyError,
|
||||
ServerFailureError,
|
||||
ServerRefusedError,
|
||||
NotFoundError
|
||||
};
|
||||
|
||||
enum Type
|
||||
{
|
||||
A = 1,
|
||||
AAAA = 28,
|
||||
ANY = 255,
|
||||
CNAME = 5,
|
||||
MX = 15,
|
||||
NS = 2,
|
||||
PTR = 12,
|
||||
SRV = 33,
|
||||
TXT = 16
|
||||
};
|
||||
|
||||
QDnsLookup(QObject *parent = 0);
|
||||
QDnsLookup(Type type, const QString &name, QObject *parent = 0);
|
||||
~QDnsLookup();
|
||||
|
||||
Error error() const;
|
||||
QString errorString() const;
|
||||
bool isFinished() const;
|
||||
|
||||
QString name() const;
|
||||
void setName(const QString &name);
|
||||
|
||||
Type type() const;
|
||||
void setType(QDnsLookup::Type);
|
||||
|
||||
QList<QDnsDomainNameRecord> canonicalNameRecords() const;
|
||||
QList<QDnsHostAddressRecord> hostAddressRecords() const;
|
||||
QList<QDnsMailExchangeRecord> mailExchangeRecords() const;
|
||||
QList<QDnsDomainNameRecord> nameServerRecords() const;
|
||||
QList<QDnsDomainNameRecord> pointerRecords() const;
|
||||
QList<QDnsServiceRecord> serviceRecords() const;
|
||||
QList<QDnsTextRecord> textRecords() const;
|
||||
|
||||
|
||||
public Q_SLOTS:
|
||||
void abort();
|
||||
void lookup();
|
||||
|
||||
Q_SIGNALS:
|
||||
void finished();
|
||||
void nameChanged(const QString &name);
|
||||
void typeChanged(Type type);
|
||||
|
||||
private:
|
||||
Q_DECLARE_PRIVATE(QDnsLookup)
|
||||
Q_PRIVATE_SLOT(d_func(), void _q_lookupFinished(const QDnsLookupReply &reply))
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
QT_END_HEADER
|
||||
|
||||
#endif // QDNSLOOKUP_H
|
213
src/network/kernel/qdnslookup_p.h
Normal file
213
src/network/kernel/qdnslookup_p.h
Normal file
@ -0,0 +1,213 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#ifndef QDNSLOOKUP_P_H
|
||||
#define QDNSLOOKUP_P_H
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
// -------------
|
||||
//
|
||||
// This file is not part of the Qt API. It exists for the convenience
|
||||
// of the QDnsLookup class. This header file may change from
|
||||
// version to version without notice, or even be removed.
|
||||
//
|
||||
// We mean it.
|
||||
//
|
||||
|
||||
#include "QtCore/qmutex.h"
|
||||
#include "QtCore/qrunnable.h"
|
||||
#include "QtCore/qsharedpointer.h"
|
||||
#include "QtCore/qthreadpool.h"
|
||||
#include "QtNetwork/qdnslookup.h"
|
||||
#include "QtNetwork/qhostaddress.h"
|
||||
#include "private/qobject_p.h"
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
//#define QDNSLOOKUP_DEBUG
|
||||
|
||||
class QDnsLookupRunnable;
|
||||
|
||||
class QDnsLookupReply
|
||||
{
|
||||
public:
|
||||
QDnsLookupReply()
|
||||
: error(QDnsLookup::NoError)
|
||||
{ }
|
||||
|
||||
QDnsLookup::Error error;
|
||||
QString errorString;
|
||||
|
||||
QList<QDnsDomainNameRecord> canonicalNameRecords;
|
||||
QList<QDnsHostAddressRecord> hostAddressRecords;
|
||||
QList<QDnsMailExchangeRecord> mailExchangeRecords;
|
||||
QList<QDnsDomainNameRecord> nameServerRecords;
|
||||
QList<QDnsDomainNameRecord> pointerRecords;
|
||||
QList<QDnsServiceRecord> serviceRecords;
|
||||
QList<QDnsTextRecord> textRecords;
|
||||
};
|
||||
|
||||
class QDnsLookupPrivate : public QObjectPrivate
|
||||
{
|
||||
public:
|
||||
QDnsLookupPrivate()
|
||||
: isFinished(false)
|
||||
, type(QDnsLookup::A)
|
||||
, runnable(0)
|
||||
{ }
|
||||
|
||||
void _q_lookupFinished(const QDnsLookupReply &reply);
|
||||
|
||||
bool isFinished;
|
||||
QString name;
|
||||
QDnsLookup::Type type;
|
||||
QDnsLookupReply reply;
|
||||
QDnsLookupRunnable *runnable;
|
||||
|
||||
Q_DECLARE_PUBLIC(QDnsLookup)
|
||||
};
|
||||
|
||||
class QDnsLookupRunnable : public QObject, public QRunnable
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QDnsLookupRunnable(QDnsLookup::Type type, const QByteArray &name)
|
||||
: requestType(type)
|
||||
, requestName(name)
|
||||
{ }
|
||||
void run();
|
||||
|
||||
signals:
|
||||
void finished(const QDnsLookupReply &reply);
|
||||
|
||||
private:
|
||||
static void query(const int requestType, const QByteArray &requestName, QDnsLookupReply *reply);
|
||||
QDnsLookup::Type requestType;
|
||||
QByteArray requestName;
|
||||
};
|
||||
|
||||
class QDnsLookupThreadPool : public QThreadPool
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
QDnsLookupThreadPool();
|
||||
void start(QRunnable *runnable);
|
||||
|
||||
private slots:
|
||||
void _q_applicationDestroyed();
|
||||
|
||||
private:
|
||||
QMutex signalsMutex;
|
||||
bool signalsConnected;
|
||||
};
|
||||
|
||||
class QDnsRecordPrivate : public QSharedData
|
||||
{
|
||||
public:
|
||||
QDnsRecordPrivate()
|
||||
: timeToLive(0)
|
||||
{ }
|
||||
|
||||
QString name;
|
||||
quint32 timeToLive;
|
||||
};
|
||||
|
||||
class QDnsDomainNameRecordPrivate : public QDnsRecordPrivate
|
||||
{
|
||||
public:
|
||||
QDnsDomainNameRecordPrivate()
|
||||
{ }
|
||||
|
||||
QString value;
|
||||
};
|
||||
|
||||
class QDnsHostAddressRecordPrivate : public QDnsRecordPrivate
|
||||
{
|
||||
public:
|
||||
QDnsHostAddressRecordPrivate()
|
||||
{ }
|
||||
|
||||
QHostAddress value;
|
||||
};
|
||||
|
||||
class QDnsMailExchangeRecordPrivate : public QDnsRecordPrivate
|
||||
{
|
||||
public:
|
||||
QDnsMailExchangeRecordPrivate()
|
||||
: preference(0)
|
||||
{ }
|
||||
|
||||
QString exchange;
|
||||
quint16 preference;
|
||||
};
|
||||
|
||||
class QDnsServiceRecordPrivate : public QDnsRecordPrivate
|
||||
{
|
||||
public:
|
||||
QDnsServiceRecordPrivate()
|
||||
: port(0),
|
||||
priority(0),
|
||||
weight(0)
|
||||
{ }
|
||||
|
||||
QString target;
|
||||
quint16 port;
|
||||
quint16 priority;
|
||||
quint16 weight;
|
||||
};
|
||||
|
||||
class QDnsTextRecordPrivate : public QDnsRecordPrivate
|
||||
{
|
||||
public:
|
||||
QDnsTextRecordPrivate()
|
||||
{ }
|
||||
|
||||
QList<QByteArray> values;
|
||||
};
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
Q_DECLARE_METATYPE(QDnsLookupReply)
|
||||
|
||||
#endif // QDNSLOOKUP_P_H
|
324
src/network/kernel/qdnslookup_unix.cpp
Normal file
324
src/network/kernel/qdnslookup_unix.cpp
Normal file
@ -0,0 +1,324 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qdnslookup_p.h"
|
||||
|
||||
#include <qlibrary.h>
|
||||
#include <qscopedpointer.h>
|
||||
#include <qurl.h>
|
||||
#include <private/qmutexpool_p.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <netdb.h>
|
||||
#if defined(Q_OS_MAC)
|
||||
#include <arpa/nameser.h>
|
||||
#include <arpa/nameser_compat.h>
|
||||
#endif
|
||||
#include <resolv.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
typedef int (*dn_expand_proto)(const unsigned char *, const unsigned char *, const unsigned char *, char *, int);
|
||||
static dn_expand_proto local_dn_expand = 0;
|
||||
typedef void (*res_nclose_proto)(res_state);
|
||||
static res_nclose_proto local_res_nclose = 0;
|
||||
typedef int (*res_ninit_proto)(res_state);
|
||||
static res_ninit_proto local_res_ninit = 0;
|
||||
typedef int (*res_nquery_proto)(res_state, const char *, int, int, unsigned char *, int);
|
||||
static res_nquery_proto local_res_nquery = 0;
|
||||
|
||||
// Custom deleter to close resolver state.
|
||||
|
||||
struct QDnsLookupStateDeleter
|
||||
{
|
||||
static inline void cleanup(struct __res_state *pointer)
|
||||
{
|
||||
local_res_nclose(pointer);
|
||||
}
|
||||
};
|
||||
|
||||
static void resolveLibrary()
|
||||
{
|
||||
QLibrary lib(QLatin1String("resolv"));
|
||||
if (!lib.load())
|
||||
return;
|
||||
|
||||
local_dn_expand = dn_expand_proto(lib.resolve("__dn_expand"));
|
||||
if (!local_dn_expand)
|
||||
local_dn_expand = dn_expand_proto(lib.resolve("dn_expand"));
|
||||
|
||||
local_res_nclose = res_nclose_proto(lib.resolve("__res_nclose"));
|
||||
if (!local_res_nclose)
|
||||
local_res_nclose = res_nclose_proto(lib.resolve("res_9_nclose"));
|
||||
if (!local_res_nclose)
|
||||
local_res_nclose = res_nclose_proto(lib.resolve("res_nclose"));
|
||||
|
||||
local_res_ninit = res_ninit_proto(lib.resolve("__res_ninit"));
|
||||
if (!local_res_ninit)
|
||||
local_res_ninit = res_ninit_proto(lib.resolve("res_9_ninit"));
|
||||
if (!local_res_ninit)
|
||||
local_res_ninit = res_ninit_proto(lib.resolve("res_ninit"));
|
||||
|
||||
local_res_nquery = res_nquery_proto(lib.resolve("__res_nquery"));
|
||||
if (!local_res_nquery)
|
||||
local_res_nquery = res_nquery_proto(lib.resolve("res_9_nquery"));
|
||||
if (!local_res_nquery)
|
||||
local_res_nquery = res_nquery_proto(lib.resolve("res_nquery"));
|
||||
}
|
||||
|
||||
void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, QDnsLookupReply *reply)
|
||||
{
|
||||
// Load dn_expand, res_ninit and res_nquery on demand.
|
||||
static volatile bool triedResolve = false;
|
||||
if (!triedResolve) {
|
||||
QMutexLocker locker(QMutexPool::globalInstanceGet(&local_res_ninit));
|
||||
if (!triedResolve) {
|
||||
resolveLibrary();
|
||||
triedResolve = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If dn_expand, res_ninit or res_nquery is missing, fail.
|
||||
if (!local_dn_expand || !local_res_nclose || !local_res_ninit || !local_res_nquery) {
|
||||
reply->error = QDnsLookup::ResolverError;
|
||||
reply->errorString = tr("Resolver functions not found");
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize state.
|
||||
struct __res_state state;
|
||||
memset(&state, 0, sizeof(state));
|
||||
if (local_res_ninit(&state) < 0) {
|
||||
reply->error = QDnsLookup::ResolverError;
|
||||
reply->errorString = tr("Resolver initialization failed");
|
||||
return;
|
||||
}
|
||||
#ifdef QDNSLOOKUP_DEBUG
|
||||
state.options |= RES_DEBUG;
|
||||
#endif
|
||||
QScopedPointer<struct __res_state, QDnsLookupStateDeleter> state_ptr(&state);
|
||||
|
||||
// Perform DNS query.
|
||||
unsigned char response[PACKETSZ];
|
||||
memset(response, 0, sizeof(response));
|
||||
const int responseLength = local_res_nquery(&state, requestName, C_IN, requestType, response, sizeof(response));
|
||||
|
||||
// Check the response header.
|
||||
HEADER *header = (HEADER*)response;
|
||||
const int answerCount = ntohs(header->ancount);
|
||||
switch (header->rcode) {
|
||||
case NOERROR:
|
||||
break;
|
||||
case FORMERR:
|
||||
reply->error = QDnsLookup::InvalidRequestError;
|
||||
reply->errorString = tr("Server could not process query");
|
||||
return;
|
||||
case SERVFAIL:
|
||||
reply->error = QDnsLookup::ServerFailureError;
|
||||
reply->errorString = tr("Server failure");
|
||||
return;
|
||||
case NXDOMAIN:
|
||||
reply->error = QDnsLookup::NotFoundError;
|
||||
reply->errorString = tr("Non existent domain");
|
||||
return;
|
||||
case REFUSED:
|
||||
reply->error = QDnsLookup::ServerRefusedError;
|
||||
reply->errorString = tr("Server refused to answer");
|
||||
return;
|
||||
default:
|
||||
reply->error = QDnsLookup::InvalidReplyError;
|
||||
reply->errorString = tr("Invalid reply received");
|
||||
return;
|
||||
}
|
||||
|
||||
// Check the reply is valid.
|
||||
if (responseLength < int(sizeof(HEADER))) {
|
||||
reply->error = QDnsLookup::InvalidReplyError;
|
||||
reply->errorString = tr("Invalid reply received");
|
||||
return;
|
||||
}
|
||||
|
||||
// Skip the query host, type (2 bytes) and class (2 bytes).
|
||||
char host[PACKETSZ], answer[PACKETSZ];
|
||||
unsigned char *p = response + sizeof(HEADER);
|
||||
int status = local_dn_expand(response, response + responseLength, p, host, sizeof(host));
|
||||
if (status < 0) {
|
||||
reply->error = QDnsLookup::InvalidReplyError;
|
||||
reply->errorString = tr("Could not expand domain name");
|
||||
return;
|
||||
}
|
||||
p += status + 4;
|
||||
|
||||
// Extract results.
|
||||
int answerIndex = 0;
|
||||
while ((p < response + responseLength) && (answerIndex < answerCount)) {
|
||||
status = local_dn_expand(response, response + responseLength, p, host, sizeof(host));
|
||||
if (status < 0) {
|
||||
reply->error = QDnsLookup::InvalidReplyError;
|
||||
reply->errorString = tr("Could not expand domain name");
|
||||
return;
|
||||
}
|
||||
const QString name = QUrl::fromAce(host);
|
||||
|
||||
p += status;
|
||||
const quint16 type = (p[0] << 8) | p[1];
|
||||
p += 2; // RR type
|
||||
p += 2; // RR class
|
||||
const quint32 ttl = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
|
||||
p += 4;
|
||||
const quint16 size = (p[0] << 8) | p[1];
|
||||
p += 2;
|
||||
|
||||
if (type == QDnsLookup::A) {
|
||||
if (size != 4) {
|
||||
reply->error = QDnsLookup::InvalidReplyError;
|
||||
reply->errorString = tr("Invalid IPv4 address record");
|
||||
return;
|
||||
}
|
||||
const quint32 addr = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
|
||||
QDnsHostAddressRecord record;
|
||||
record.d->name = name;
|
||||
record.d->timeToLive = ttl;
|
||||
record.d->value = QHostAddress(addr);
|
||||
reply->hostAddressRecords.append(record);
|
||||
} else if (type == QDnsLookup::AAAA) {
|
||||
if (size != 16) {
|
||||
reply->error = QDnsLookup::InvalidReplyError;
|
||||
reply->errorString = tr("Invalid IPv6 address record");
|
||||
return;
|
||||
}
|
||||
QDnsHostAddressRecord record;
|
||||
record.d->name = name;
|
||||
record.d->timeToLive = ttl;
|
||||
record.d->value = QHostAddress(p);
|
||||
reply->hostAddressRecords.append(record);
|
||||
} else if (type == QDnsLookup::CNAME) {
|
||||
status = local_dn_expand(response, response + responseLength, p, answer, sizeof(answer));
|
||||
if (status < 0) {
|
||||
reply->error = QDnsLookup::InvalidReplyError;
|
||||
reply->errorString = tr("Invalid canonical name record");
|
||||
return;
|
||||
}
|
||||
QDnsDomainNameRecord record;
|
||||
record.d->name = name;
|
||||
record.d->timeToLive = ttl;
|
||||
record.d->value = QUrl::fromAce(answer);
|
||||
reply->canonicalNameRecords.append(record);
|
||||
} else if (type == QDnsLookup::NS) {
|
||||
status = local_dn_expand(response, response + responseLength, p, answer, sizeof(answer));
|
||||
if (status < 0) {
|
||||
reply->error = QDnsLookup::InvalidReplyError;
|
||||
reply->errorString = tr("Invalid name server record");
|
||||
return;
|
||||
}
|
||||
QDnsDomainNameRecord record;
|
||||
record.d->name = name;
|
||||
record.d->timeToLive = ttl;
|
||||
record.d->value = QUrl::fromAce(answer);
|
||||
reply->nameServerRecords.append(record);
|
||||
} else if (type == QDnsLookup::PTR) {
|
||||
status = local_dn_expand(response, response + responseLength, p, answer, sizeof(answer));
|
||||
if (status < 0) {
|
||||
reply->error = QDnsLookup::InvalidReplyError;
|
||||
reply->errorString = tr("Invalid pointer record");
|
||||
return;
|
||||
}
|
||||
QDnsDomainNameRecord record;
|
||||
record.d->name = name;
|
||||
record.d->timeToLive = ttl;
|
||||
record.d->value = QUrl::fromAce(answer);
|
||||
reply->pointerRecords.append(record);
|
||||
} else if (type == QDnsLookup::MX) {
|
||||
const quint16 preference = (p[0] << 8) | p[1];
|
||||
status = local_dn_expand(response, response + responseLength, p + 2, answer, sizeof(answer));
|
||||
if (status < 0) {
|
||||
reply->error = QDnsLookup::InvalidReplyError;
|
||||
reply->errorString = tr("Invalid mail exchange record");
|
||||
return;
|
||||
}
|
||||
QDnsMailExchangeRecord record;
|
||||
record.d->exchange = QUrl::fromAce(answer);
|
||||
record.d->name = name;
|
||||
record.d->preference = preference;
|
||||
record.d->timeToLive = ttl;
|
||||
reply->mailExchangeRecords.append(record);
|
||||
} else if (type == QDnsLookup::SRV) {
|
||||
const quint16 priority = (p[0] << 8) | p[1];
|
||||
const quint16 weight = (p[2] << 8) | p[3];
|
||||
const quint16 port = (p[4] << 8) | p[5];
|
||||
status = local_dn_expand(response, response + responseLength, p + 6, answer, sizeof(answer));
|
||||
if (status < 0) {
|
||||
reply->error = QDnsLookup::InvalidReplyError;
|
||||
reply->errorString = tr("Invalid service record");
|
||||
return;
|
||||
}
|
||||
QDnsServiceRecord record;
|
||||
record.d->name = name;
|
||||
record.d->target = QUrl::fromAce(answer);
|
||||
record.d->port = port;
|
||||
record.d->priority = priority;
|
||||
record.d->timeToLive = ttl;
|
||||
record.d->weight = weight;
|
||||
reply->serviceRecords.append(record);
|
||||
} else if (type == QDnsLookup::TXT) {
|
||||
unsigned char *txt = p;
|
||||
QDnsTextRecord record;
|
||||
record.d->name = name;
|
||||
record.d->timeToLive = ttl;
|
||||
while (txt < p + size) {
|
||||
const unsigned char length = *txt;
|
||||
txt++;
|
||||
if (txt + length > p + size) {
|
||||
reply->error = QDnsLookup::InvalidReplyError;
|
||||
reply->errorString = tr("Invalid text record");
|
||||
return;
|
||||
}
|
||||
record.d->values << QByteArray((char*)txt, length);
|
||||
txt += length;
|
||||
}
|
||||
reply->textRecords.append(record);
|
||||
}
|
||||
p += size;
|
||||
answerIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
177
src/network/kernel/qdnslookup_win.cpp
Normal file
177
src/network/kernel/qdnslookup_win.cpp
Normal file
@ -0,0 +1,177 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
** This file is part of the QtNetwork module of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include "qdnslookup_p.h"
|
||||
|
||||
#include <qurl.h>
|
||||
#include <private/qmutexpool_p.h>
|
||||
#include <private/qsystemlibrary_p.h>
|
||||
|
||||
#include <windows.h>
|
||||
#include <windns.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
typedef DNS_STATUS (*dns_query_utf8_proto)(PCSTR,WORD,DWORD,PIP4_ARRAY,PDNS_RECORD*,PVOID*);
|
||||
static dns_query_utf8_proto local_dns_query_utf8 = 0;
|
||||
typedef void (*dns_record_list_free_proto)(PDNS_RECORD,DNS_FREE_TYPE);
|
||||
static dns_record_list_free_proto local_dns_record_list_free = 0;
|
||||
|
||||
static void resolveLibrary()
|
||||
{
|
||||
local_dns_query_utf8 = (dns_query_utf8_proto) QSystemLibrary::resolve(QLatin1String("dnsapi"), "DnsQuery_UTF8");
|
||||
local_dns_record_list_free = (dns_record_list_free_proto) QSystemLibrary::resolve(QLatin1String("dnsapi"), "DnsRecordListFree");
|
||||
}
|
||||
|
||||
void QDnsLookupRunnable::query(const int requestType, const QByteArray &requestName, QDnsLookupReply *reply)
|
||||
{
|
||||
// Load DnsQuery_UTF8 and DnsRecordListFree on demand.
|
||||
static volatile bool triedResolve = false;
|
||||
if (!triedResolve) {
|
||||
QMutexLocker locker(QMutexPool::globalInstanceGet(&local_dns_query_utf8));
|
||||
if (!triedResolve) {
|
||||
resolveLibrary();
|
||||
triedResolve = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If DnsQuery_UTF8 or DnsRecordListFree is missing, fail.
|
||||
if (!local_dns_query_utf8 || !local_dns_record_list_free) {
|
||||
reply->error = QDnsLookup::ResolverError,
|
||||
reply->errorString = tr("Resolver functions not found");
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform DNS query.
|
||||
PDNS_RECORD dns_records;
|
||||
const DNS_STATUS status = local_dns_query_utf8(requestName, requestType, DNS_QUERY_STANDARD, NULL, &dns_records, NULL);
|
||||
switch (status) {
|
||||
case ERROR_SUCCESS:
|
||||
break;
|
||||
case DNS_ERROR_RCODE_FORMAT_ERROR:
|
||||
reply->error = QDnsLookup::InvalidRequestError;
|
||||
reply->errorString = tr("Server could not process query");
|
||||
return;
|
||||
case DNS_ERROR_RCODE_SERVER_FAILURE:
|
||||
reply->error = QDnsLookup::ServerFailureError;
|
||||
reply->errorString = tr("Server failure");
|
||||
return;
|
||||
case DNS_ERROR_RCODE_NAME_ERROR:
|
||||
reply->error = QDnsLookup::NotFoundError;
|
||||
reply->errorString = tr("Non existent domain");
|
||||
return;
|
||||
case DNS_ERROR_RCODE_REFUSED:
|
||||
reply->error = QDnsLookup::ServerRefusedError;
|
||||
reply->errorString = tr("Server refused to answer");
|
||||
return;
|
||||
default:
|
||||
reply->error = QDnsLookup::InvalidReplyError;
|
||||
reply->errorString = tr("Invalid reply received");
|
||||
return;
|
||||
}
|
||||
|
||||
// Extract results.
|
||||
for (PDNS_RECORD ptr = dns_records; ptr != NULL; ptr = ptr->pNext) {
|
||||
const QString name = QUrl::fromAce((char*)ptr->pName);
|
||||
if (ptr->wType == QDnsLookup::A) {
|
||||
QDnsHostAddressRecord record;
|
||||
record.d->name = name;
|
||||
record.d->timeToLive = ptr->dwTtl;
|
||||
record.d->value = QHostAddress(ntohl(ptr->Data.A.IpAddress));
|
||||
reply->hostAddressRecords.append(record);
|
||||
} else if (ptr->wType == QDnsLookup::AAAA) {
|
||||
Q_IPV6ADDR addr;
|
||||
memcpy(&addr, &ptr->Data.AAAA.Ip6Address, sizeof(Q_IPV6ADDR));
|
||||
|
||||
QDnsHostAddressRecord record;
|
||||
record.d->name = name;
|
||||
record.d->timeToLive = ptr->dwTtl;
|
||||
record.d->value = QHostAddress(addr);
|
||||
reply->hostAddressRecords.append(record);
|
||||
} else if (ptr->wType == QDnsLookup::CNAME) {
|
||||
QDnsDomainNameRecord record;
|
||||
record.d->name = name;
|
||||
record.d->timeToLive = ptr->dwTtl;
|
||||
record.d->value = QUrl::fromAce((char*)ptr->Data.Cname.pNameHost);
|
||||
reply->canonicalNameRecords.append(record);
|
||||
} else if (ptr->wType == QDnsLookup::MX) {
|
||||
QDnsMailExchangeRecord record;
|
||||
record.d->name = name;
|
||||
record.d->exchange = QUrl::fromAce((char*)ptr->Data.Mx.pNameExchange);
|
||||
record.d->preference = ptr->Data.Mx.wPreference;
|
||||
record.d->timeToLive = ptr->dwTtl;
|
||||
reply->mailExchangeRecords.append(record);
|
||||
} else if (ptr->wType == QDnsLookup::NS) {
|
||||
QDnsDomainNameRecord record;
|
||||
record.d->name = name;
|
||||
record.d->timeToLive = ptr->dwTtl;
|
||||
record.d->value = QUrl::fromAce((char*)ptr->Data.Ns.pNameHost);
|
||||
reply->nameServerRecords.append(record);
|
||||
} else if (ptr->wType == QDnsLookup::PTR) {
|
||||
QDnsDomainNameRecord record;
|
||||
record.d->name = name;
|
||||
record.d->timeToLive = ptr->dwTtl;
|
||||
record.d->value = QUrl::fromAce((char*)ptr->Data.Ptr.pNameHost);
|
||||
reply->pointerRecords.append(record);
|
||||
} else if (ptr->wType == QDnsLookup::SRV) {
|
||||
QDnsServiceRecord record;
|
||||
record.d->name = name;
|
||||
record.d->target = QUrl::fromAce((char*)ptr->Data.Srv.pNameTarget);
|
||||
record.d->port = ptr->Data.Srv.wPort;
|
||||
record.d->priority = ptr->Data.Srv.wPriority;
|
||||
record.d->timeToLive = ptr->dwTtl;
|
||||
record.d->weight = ptr->Data.Srv.wWeight;
|
||||
reply->serviceRecords.append(record);
|
||||
} else if (ptr->wType == QDnsLookup::TXT) {
|
||||
QDnsTextRecord record;
|
||||
record.d->name = name;
|
||||
record.d->timeToLive = ptr->dwTtl;
|
||||
for (unsigned int i = 0; i < ptr->Data.Txt.dwStringCount; ++i) {
|
||||
record.d->values << QByteArray((char*)ptr->Data.Txt.pStringArray[i]);
|
||||
}
|
||||
reply->textRecords.append(record);
|
||||
}
|
||||
}
|
||||
|
||||
local_dns_record_list_free(dns_records, DnsFreeRecordList);
|
||||
}
|
||||
|
||||
QT_END_NAMESPACE
|
@ -1,5 +1,7 @@
|
||||
TEMPLATE=subdirs
|
||||
SUBDIRS=\
|
||||
qdnslookup \
|
||||
qdnslookup_appless \
|
||||
qhostinfo \
|
||||
# qnetworkproxyfactory \ # Uses a hardcoded proxy configuration
|
||||
qauthenticator \
|
||||
|
7
tests/auto/network/kernel/qdnslookup/qdnslookup.pro
Normal file
7
tests/auto/network/kernel/qdnslookup/qdnslookup.pro
Normal file
@ -0,0 +1,7 @@
|
||||
CONFIG += testcase
|
||||
|
||||
TARGET = tst_qdnslookup
|
||||
|
||||
SOURCES += tst_qdnslookup.cpp
|
||||
|
||||
QT = core network testlib
|
274
tests/auto/network/kernel/qdnslookup/tst_qdnslookup.cpp
Normal file
274
tests/auto/network/kernel/qdnslookup/tst_qdnslookup.cpp
Normal file
@ -0,0 +1,274 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
|
||||
#include <QtTest/QtTest>
|
||||
#include <QtNetwork/QDnsLookup>
|
||||
#include <QtNetwork/QHostAddress>
|
||||
|
||||
static bool waitForDone(QDnsLookup *lookup)
|
||||
{
|
||||
if (lookup->isFinished())
|
||||
return true;
|
||||
|
||||
QObject::connect(lookup, SIGNAL(finished()),
|
||||
&QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||
QTestEventLoop::instance().enterLoop(10);
|
||||
return !QTestEventLoop::instance().timeout();
|
||||
}
|
||||
|
||||
class tst_QDnsLookup: public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void lookup_data();
|
||||
void lookup();
|
||||
void lookupReuse();
|
||||
void lookupAbortRetry();
|
||||
};
|
||||
|
||||
void tst_QDnsLookup::lookup_data()
|
||||
{
|
||||
QTest::addColumn<int>("type");
|
||||
QTest::addColumn<QString>("domain");
|
||||
QTest::addColumn<int>("error");
|
||||
QTest::addColumn<QString>("cname");
|
||||
QTest::addColumn<QString>("host");
|
||||
QTest::addColumn<QString>("mx");
|
||||
QTest::addColumn<QString>("ns");
|
||||
QTest::addColumn<QString>("ptr");
|
||||
QTest::addColumn<QString>("srv");
|
||||
QTest::addColumn<QByteArray>("txt");
|
||||
|
||||
QTest::newRow("a-empty") << int(QDnsLookup::A) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << ""<< "" << QByteArray();
|
||||
QTest::newRow("a-notfound") << int(QDnsLookup::A) << "invalid." << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << QByteArray();
|
||||
QTest::newRow("a-idn") << int(QDnsLookup::A) << QString::fromUtf8("alqualondë.troll.no") << int(QDnsLookup::NoError) << "alqualonde.troll.no" << "10.3.3.55" << "" << "" << "" << "" << QByteArray();
|
||||
QTest::newRow("a-single") << int(QDnsLookup::A) << "lupinella.troll.no" << int(QDnsLookup::NoError) << "" << "10.3.4.6" << "" << "" << "" << "" << QByteArray();
|
||||
QTest::newRow("a-multi") << int(QDnsLookup::A) << "multi.dev.troll.no" << int(QDnsLookup::NoError) << "" << "1.2.3.4 1.2.3.5 10.3.3.31" << "" << "" << "" << "" << QByteArray();
|
||||
|
||||
QTest::newRow("aaaa-empty") << int(QDnsLookup::AAAA) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << "" << "" << QByteArray();
|
||||
QTest::newRow("aaaa-notfound") << int(QDnsLookup::AAAA) << "invalid." << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << QByteArray();
|
||||
QTest::newRow("aaaa-single") << int(QDnsLookup::AAAA) << "dns6-test-dev.troll.no" << int(QDnsLookup::NoError) << "" << "2001:470:1f01:115::10" << "" << "" << "" << "" << QByteArray();
|
||||
QTest::newRow("aaaa-multi") << int(QDnsLookup::AAAA) << "multi-dns6-test-dev.troll.no" << int(QDnsLookup::NoError) << "" << "2001:470:1f01:115::11 2001:470:1f01:115::12" << "" << "" << "" << "" << QByteArray();
|
||||
|
||||
QTest::newRow("any-empty") << int(QDnsLookup::ANY) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << "" << "" << QByteArray();
|
||||
QTest::newRow("any-notfound") << int(QDnsLookup::ANY) << "invalid." << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << QByteArray();
|
||||
QTest::newRow("any-ascii") << int(QDnsLookup::ANY) << "fluke.troll.no" << int(QDnsLookup::NoError) << "" << "10.3.3.31" << "" << "" << "" << "" << QByteArray();
|
||||
|
||||
QTest::newRow("mx-empty") << int(QDnsLookup::MX) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << "" << "" << QByteArray();
|
||||
QTest::newRow("mx-notfound") << int(QDnsLookup::MX) << "invalid." << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << QByteArray();
|
||||
QTest::newRow("mx-ascii") << int(QDnsLookup::MX) << "troll.no" << int(QDnsLookup::NoError) << "" << "" << "10 smtp.trolltech.com" << "" << "" << "" << QByteArray();
|
||||
// FIXME: we need an IDN MX record in the troll.no domain
|
||||
QTest::newRow("mx-idn") << int(QDnsLookup::MX) << QString::fromUtf8("råkat.se") << int(QDnsLookup::NoError) << "" << "" << "10 mail.cdr.se" << "" << "" << "" << QByteArray();
|
||||
|
||||
QTest::newRow("ns-empty") << int(QDnsLookup::NS) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << "" << "" << QByteArray();
|
||||
QTest::newRow("ns-notfound") << int(QDnsLookup::NS) << "invalid." << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << QByteArray();
|
||||
QTest::newRow("ns-ascii") << int(QDnsLookup::NS) << "troll.no" << int(QDnsLookup::NoError) << "" << "" << "" << "ns-0.trolltech.net ns-1.trolltech.net ns-i.trolltech.net" << "" << "" << QByteArray();
|
||||
|
||||
QTest::newRow("ptr-empty") << int(QDnsLookup::PTR) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << "" << "" << QByteArray();
|
||||
QTest::newRow("ptr-notfound") << int(QDnsLookup::PTR) << "invalid." << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << QByteArray();
|
||||
// FIXME: we need PTR records in the troll.no domain
|
||||
QTest::newRow("ptr-ascii") << int(QDnsLookup::PTR) << "168.52.238.87.in-addr.arpa" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "gitorious.org" << "" << QByteArray();
|
||||
|
||||
QTest::newRow("srv-empty") << int(QDnsLookup::SRV) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << "" << "" << QByteArray();
|
||||
QTest::newRow("srv-notfound") << int(QDnsLookup::SRV) << "invalid." << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << QByteArray();
|
||||
// FIXME: we need SRV records in the troll.no domain
|
||||
QTest::newRow("srv-idn") << int(QDnsLookup::SRV) << QString::fromUtf8("_xmpp-client._tcp.råkat.se") << int(QDnsLookup::NoError) << "" << "" << "" << "" << "" << "5 0 5224 jabber.cdr.se" << QByteArray();
|
||||
|
||||
QTest::newRow("txt-empty") << int(QDnsLookup::TXT) << "" << int(QDnsLookup::InvalidRequestError) << "" << "" << "" << "" << "" << "" << QByteArray();
|
||||
QTest::newRow("txt-notfound") << int(QDnsLookup::TXT) << "invalid." << int(QDnsLookup::NotFoundError) << "" << "" << "" << "" << "" << "" << QByteArray();
|
||||
// FIXME: we need TXT records in the troll.no domain
|
||||
QTest::newRow("txt-ascii") << int(QDnsLookup::TXT) << "gmail.com" << int(QDnsLookup::NoError) << "" << "" << "" << "" << "" << "" << QByteArray("v=spf1 redirect=_spf.google.com");
|
||||
}
|
||||
|
||||
void tst_QDnsLookup::lookup()
|
||||
{
|
||||
QFETCH(int, type);
|
||||
QFETCH(QString, domain);
|
||||
QFETCH(int, error);
|
||||
QFETCH(QString, cname);
|
||||
QFETCH(QString, host);
|
||||
QFETCH(QString, mx);
|
||||
QFETCH(QString, ns);
|
||||
QFETCH(QString, ptr);
|
||||
QFETCH(QString, srv);
|
||||
QFETCH(QByteArray, txt);
|
||||
|
||||
QDnsLookup lookup;
|
||||
lookup.setType(static_cast<QDnsLookup::Type>(type));
|
||||
lookup.setName(domain);
|
||||
lookup.lookup();
|
||||
QVERIFY(waitForDone(&lookup));
|
||||
QVERIFY(lookup.isFinished());
|
||||
QCOMPARE(int(lookup.error()), error);
|
||||
if (error == QDnsLookup::NoError)
|
||||
QVERIFY(lookup.errorString().isEmpty());
|
||||
QCOMPARE(int(lookup.type()), type);
|
||||
QCOMPARE(lookup.name(), domain);
|
||||
|
||||
// canonical names
|
||||
if (!cname.isEmpty()) {
|
||||
QVERIFY(!lookup.canonicalNameRecords().isEmpty());
|
||||
const QDnsDomainNameRecord cnameRecord = lookup.canonicalNameRecords().first();
|
||||
QCOMPARE(cnameRecord.name(), domain);
|
||||
QCOMPARE(cnameRecord.value(), cname);
|
||||
} else {
|
||||
QVERIFY(lookup.canonicalNameRecords().isEmpty());
|
||||
}
|
||||
|
||||
// host addresses
|
||||
const QString hostName = cname.isEmpty() ? domain : cname;
|
||||
QStringList addresses;
|
||||
foreach (const QDnsHostAddressRecord &record, lookup.hostAddressRecords()) {
|
||||
QCOMPARE(record.name(), hostName);
|
||||
addresses << record.value().toString().toLower();
|
||||
}
|
||||
addresses.sort();
|
||||
QCOMPARE(addresses.join(" "), host);
|
||||
|
||||
// mail exchanges
|
||||
QStringList mailExchanges;
|
||||
foreach (const QDnsMailExchangeRecord &record, lookup.mailExchangeRecords()) {
|
||||
QCOMPARE(record.name(), domain);
|
||||
mailExchanges << QString("%1 %2").arg(QString::number(record.preference()), record.exchange());
|
||||
}
|
||||
QCOMPARE(mailExchanges.join(" "), mx);
|
||||
|
||||
// name servers
|
||||
QStringList nameServers;
|
||||
foreach (const QDnsDomainNameRecord &record, lookup.nameServerRecords()) {
|
||||
QCOMPARE(record.name(), domain);
|
||||
nameServers << record.value();
|
||||
}
|
||||
nameServers.sort();
|
||||
QCOMPARE(nameServers.join(" "), ns);
|
||||
|
||||
// pointers
|
||||
if (!ptr.isEmpty()) {
|
||||
QVERIFY(!lookup.pointerRecords().isEmpty());
|
||||
const QDnsDomainNameRecord ptrRecord = lookup.pointerRecords().first();
|
||||
QCOMPARE(ptrRecord.name(), domain);
|
||||
QCOMPARE(ptrRecord.value(), ptr);
|
||||
} else {
|
||||
QVERIFY(lookup.pointerRecords().isEmpty());
|
||||
}
|
||||
|
||||
// services
|
||||
QStringList services;
|
||||
foreach (const QDnsServiceRecord &record, lookup.serviceRecords()) {
|
||||
QCOMPARE(record.name(), domain);
|
||||
services << QString("%1 %2 %3 %4").arg(
|
||||
QString::number(record.priority()),
|
||||
QString::number(record.weight()),
|
||||
QString::number(record.port()),
|
||||
record.target());
|
||||
}
|
||||
QCOMPARE(services.join(" "), srv);
|
||||
|
||||
// text
|
||||
if (!txt.isEmpty()) {
|
||||
QVERIFY(!lookup.textRecords().isEmpty());
|
||||
const QDnsTextRecord firstRecord = lookup.textRecords().first();
|
||||
QCOMPARE(firstRecord.name(), domain);
|
||||
QCOMPARE(firstRecord.values().size(), 1);
|
||||
QCOMPARE(firstRecord.values().first(), txt);
|
||||
} else {
|
||||
QVERIFY(lookup.textRecords().isEmpty());
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QDnsLookup::lookupReuse()
|
||||
{
|
||||
QDnsLookup lookup;
|
||||
|
||||
// first lookup
|
||||
lookup.setType(QDnsLookup::A);
|
||||
lookup.setName("lupinella.troll.no");
|
||||
lookup.lookup();
|
||||
QVERIFY(waitForDone(&lookup));
|
||||
QVERIFY(lookup.isFinished());
|
||||
QCOMPARE(int(lookup.error()), int(QDnsLookup::NoError));
|
||||
QVERIFY(!lookup.hostAddressRecords().isEmpty());
|
||||
QCOMPARE(lookup.hostAddressRecords().first().name(), QString("lupinella.troll.no"));
|
||||
QCOMPARE(lookup.hostAddressRecords().first().value(), QHostAddress("10.3.4.6"));
|
||||
|
||||
// second lookup
|
||||
lookup.setType(QDnsLookup::AAAA);
|
||||
lookup.setName("dns6-test-dev.troll.no");
|
||||
lookup.lookup();
|
||||
QVERIFY(waitForDone(&lookup));
|
||||
QVERIFY(lookup.isFinished());
|
||||
QCOMPARE(int(lookup.error()), int(QDnsLookup::NoError));
|
||||
QVERIFY(!lookup.hostAddressRecords().isEmpty());
|
||||
QCOMPARE(lookup.hostAddressRecords().first().name(), QString("dns6-test-dev.troll.no"));
|
||||
QCOMPARE(lookup.hostAddressRecords().first().value(), QHostAddress("2001:470:1f01:115::10"));
|
||||
}
|
||||
|
||||
|
||||
void tst_QDnsLookup::lookupAbortRetry()
|
||||
{
|
||||
QDnsLookup lookup;
|
||||
|
||||
// try and abort the lookup
|
||||
lookup.setType(QDnsLookup::A);
|
||||
lookup.setName("lupinella.troll.no");
|
||||
lookup.lookup();
|
||||
lookup.abort();
|
||||
QVERIFY(waitForDone(&lookup));
|
||||
QVERIFY(lookup.isFinished());
|
||||
QCOMPARE(int(lookup.error()), int(QDnsLookup::OperationCancelledError));
|
||||
QVERIFY(lookup.hostAddressRecords().isEmpty());
|
||||
|
||||
// retry a different lookup
|
||||
lookup.setType(QDnsLookup::AAAA);
|
||||
lookup.setName("dns6-test-dev.troll.no");
|
||||
lookup.lookup();
|
||||
QVERIFY(waitForDone(&lookup));
|
||||
QVERIFY(lookup.isFinished());
|
||||
QCOMPARE(int(lookup.error()), int(QDnsLookup::NoError));
|
||||
QVERIFY(!lookup.hostAddressRecords().isEmpty());
|
||||
QCOMPARE(lookup.hostAddressRecords().first().name(), QString("dns6-test-dev.troll.no"));
|
||||
QCOMPARE(lookup.hostAddressRecords().first().value(), QHostAddress("2001:470:1f01:115::10"));
|
||||
}
|
||||
|
||||
QTEST_MAIN(tst_QDnsLookup)
|
||||
#include "tst_qdnslookup.moc"
|
@ -0,0 +1,7 @@
|
||||
CONFIG += testcase
|
||||
|
||||
TARGET = tst_qdnslookup_appless
|
||||
|
||||
SOURCES += tst_qdnslookup_appless.cpp
|
||||
|
||||
QT = core network testlib
|
@ -0,0 +1,92 @@
|
||||
/****************************************************************************
|
||||
**
|
||||
** Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
|
||||
** Contact: http://www.qt-project.org/
|
||||
**
|
||||
** This file is part of the test suite of the Qt Toolkit.
|
||||
**
|
||||
** $QT_BEGIN_LICENSE:LGPL$
|
||||
** GNU Lesser General Public License Usage
|
||||
** This file may be used under the terms of the GNU Lesser General Public
|
||||
** License version 2.1 as published by the Free Software Foundation and
|
||||
** appearing in the file LICENSE.LGPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU Lesser
|
||||
** General Public License version 2.1 requirements will be met:
|
||||
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
||||
**
|
||||
** In addition, as a special exception, Nokia gives you certain additional
|
||||
** rights. These rights are described in the Nokia Qt LGPL Exception
|
||||
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||
**
|
||||
** GNU General Public License Usage
|
||||
** Alternatively, this file may be used under the terms of the GNU General
|
||||
** Public License version 3.0 as published by the Free Software Foundation
|
||||
** and appearing in the file LICENSE.GPL included in the packaging of this
|
||||
** file. Please review the following information to ensure the GNU General
|
||||
** Public License version 3.0 requirements will be met:
|
||||
** http://www.gnu.org/copyleft/gpl.html.
|
||||
**
|
||||
** Other Usage
|
||||
** Alternatively, this file may be used in accordance with the terms and
|
||||
** conditions contained in a signed written agreement between you and Nokia.
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
**
|
||||
** $QT_END_LICENSE$
|
||||
**
|
||||
****************************************************************************/
|
||||
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtNetwork/QDnsLookup>
|
||||
#include <QtTest/QtTest>
|
||||
|
||||
class tst_QDnsLookup_Appless : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void noApplication();
|
||||
void recreateApplication();
|
||||
void destroyApplicationDuringLookup();
|
||||
};
|
||||
|
||||
void tst_QDnsLookup_Appless::noApplication()
|
||||
{
|
||||
QTest::ignoreMessage(QtWarningMsg, "QDnsLookup requires a QCoreApplication");
|
||||
QDnsLookup dns(QDnsLookup::A, "troll.no");
|
||||
dns.lookup();
|
||||
}
|
||||
|
||||
void tst_QDnsLookup_Appless::recreateApplication()
|
||||
{
|
||||
int argc = 0;
|
||||
char **argv = 0;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
QCoreApplication app(argc, argv);
|
||||
QDnsLookup dns(QDnsLookup::A, "lupinella.troll.no");
|
||||
dns.lookup();
|
||||
if (!dns.isFinished()) {
|
||||
QObject::connect(&dns, SIGNAL(finished()),
|
||||
&QTestEventLoop::instance(), SLOT(exitLoop()));
|
||||
QTestEventLoop::instance().enterLoop(10);
|
||||
}
|
||||
QVERIFY(dns.isFinished());
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QDnsLookup_Appless::destroyApplicationDuringLookup()
|
||||
{
|
||||
int argc = 0;
|
||||
char **argv = 0;
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
QCoreApplication app(argc, argv);
|
||||
QDnsLookup dns(QDnsLookup::A, "lupinella.troll.no");
|
||||
dns.lookup();
|
||||
}
|
||||
}
|
||||
|
||||
QTEST_APPLESS_MAIN(tst_QDnsLookup_Appless)
|
||||
#include "tst_qdnslookup_appless.moc"
|
Loading…
Reference in New Issue
Block a user