summaryrefslogtreecommitdiffstats
path: root/src/network/kernel/qdnslookup.cpp
diff options
context:
space:
mode:
authorJeremy Lainé <jeremy.laine@m4x.org>2012-01-23 18:25:39 +0100
committerQt by Nokia <qt-info@nokia.com>2012-01-30 16:39:46 +0100
commite54dc7c2b5b9aa14989f26a718eb99d7516af4a0 (patch)
tree248372c55bede52c63ab0cc367cdfc8c350ba619 /src/network/kernel/qdnslookup.cpp
parentd9468a975210ecb58ff199e931f47df5b99b267f (diff)
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>
Diffstat (limited to 'src/network/kernel/qdnslookup.cpp')
-rw-r--r--src/network/kernel/qdnslookup.cpp988
1 files changed, 988 insertions, 0 deletions
diff --git a/src/network/kernel/qdnslookup.cpp b/src/network/kernel/qdnslookup.cpp
new file mode 100644
index 0000000000..f4b143a5fc
--- /dev/null
+++ b/src/network/kernel/qdnslookup.cpp
@@ -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"