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
|
TEMPLATE = subdirs
|
||||||
SUBDIRS = \
|
SUBDIRS = \
|
||||||
|
dnslookup \
|
||||||
download \
|
download \
|
||||||
downloadmanager
|
downloadmanager
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@ INCLUDEPATH += $$PWD
|
|||||||
|
|
||||||
HEADERS += kernel/qauthenticator.h \
|
HEADERS += kernel/qauthenticator.h \
|
||||||
kernel/qauthenticator_p.h \
|
kernel/qauthenticator_p.h \
|
||||||
|
kernel/qdnslookup.h \
|
||||||
|
kernel/qdnslookup_p.h \
|
||||||
kernel/qhostaddress.h \
|
kernel/qhostaddress.h \
|
||||||
kernel/qhostinfo.h \
|
kernel/qhostinfo.h \
|
||||||
kernel/qhostinfo_p.h \
|
kernel/qhostinfo_p.h \
|
||||||
@ -14,15 +16,16 @@ HEADERS += kernel/qauthenticator.h \
|
|||||||
kernel/qnetworkinterface_p.h
|
kernel/qnetworkinterface_p.h
|
||||||
|
|
||||||
SOURCES += kernel/qauthenticator.cpp \
|
SOURCES += kernel/qauthenticator.cpp \
|
||||||
|
kernel/qdnslookup.cpp \
|
||||||
kernel/qhostaddress.cpp \
|
kernel/qhostaddress.cpp \
|
||||||
kernel/qhostinfo.cpp \
|
kernel/qhostinfo.cpp \
|
||||||
kernel/qurlinfo.cpp \
|
kernel/qurlinfo.cpp \
|
||||||
kernel/qnetworkproxy.cpp \
|
kernel/qnetworkproxy.cpp \
|
||||||
kernel/qnetworkinterface.cpp
|
kernel/qnetworkinterface.cpp
|
||||||
|
|
||||||
unix: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/qhostinfo_win.cpp kernel/qnetworkinterface_win.cpp
|
win32:SOURCES += kernel/qdnslookup_win.cpp kernel/qhostinfo_win.cpp kernel/qnetworkinterface_win.cpp
|
||||||
integrity:SOURCES += kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp
|
integrity:SOURCES += kernel/qdnslookup_unix.cpp kernel/qhostinfo_unix.cpp kernel/qnetworkinterface_unix.cpp
|
||||||
|
|
||||||
mac:LIBS_PRIVATE += -framework SystemConfiguration -framework CoreFoundation
|
mac:LIBS_PRIVATE += -framework SystemConfiguration -framework CoreFoundation
|
||||||
mac:SOURCES += kernel/qnetworkproxy_mac.cpp
|
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
|
TEMPLATE=subdirs
|
||||||
SUBDIRS=\
|
SUBDIRS=\
|
||||||
|
qdnslookup \
|
||||||
|
qdnslookup_appless \
|
||||||
qhostinfo \
|
qhostinfo \
|
||||||
# qnetworkproxyfactory \ # Uses a hardcoded proxy configuration
|
# qnetworkproxyfactory \ # Uses a hardcoded proxy configuration
|
||||||
qauthenticator \
|
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…
x
Reference in New Issue
Block a user