1/****************************************************************************
2**
3** Copyright (C) 2012 Jeremy Lainé <jeremy.laine@m4x.org>
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtNetwork module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qdnslookup.h"
41#include "qdnslookup_p.h"
42
43#include <qcoreapplication.h>
44#include <qdatetime.h>
45#include <qrandom.h>
46#include <qurl.h>
47
48#include <algorithm>
49
50QT_BEGIN_NAMESPACE
51
52#if QT_CONFIG(thread)
53Q_GLOBAL_STATIC(QDnsLookupThreadPool, theDnsLookupThreadPool);
54#endif
55
56static bool qt_qdnsmailexchangerecord_less_than(const QDnsMailExchangeRecord &r1, const QDnsMailExchangeRecord &r2)
57{
58 // Lower numbers are more preferred than higher ones.
59 return r1.preference() < r2.preference();
60}
61
62/*
63 Sorts a list of QDnsMailExchangeRecord objects according to RFC 5321.
64*/
65
66static void qt_qdnsmailexchangerecord_sort(QList<QDnsMailExchangeRecord> &records)
67{
68 // If we have no more than one result, we are done.
69 if (records.size() <= 1)
70 return;
71
72 // Order the records by preference.
73 std::sort(records.begin(), records.end(), qt_qdnsmailexchangerecord_less_than);
74
75 int i = 0;
76 while (i < records.size()) {
77
78 // Determine the slice of records with the current preference.
79 QList<QDnsMailExchangeRecord> slice;
80 const quint16 slicePreference = records.at(i).preference();
81 for (int j = i; j < records.size(); ++j) {
82 if (records.at(j).preference() != slicePreference)
83 break;
84 slice << records.at(j);
85 }
86
87 // Randomize the slice of records.
88 while (!slice.isEmpty()) {
89 const unsigned int pos = QRandomGenerator::global()->bounded(int(slice.size()));
90 records[i++] = slice.takeAt(pos);
91 }
92 }
93}
94
95static bool qt_qdnsservicerecord_less_than(const QDnsServiceRecord &r1, const QDnsServiceRecord &r2)
96{
97 // Order by priority, or if the priorities are equal,
98 // put zero weight records first.
99 return r1.priority() < r2.priority()
100 || (r1.priority() == r2.priority()
101 && r1.weight() == 0 && r2.weight() > 0);
102}
103
104/*
105 Sorts a list of QDnsServiceRecord objects according to RFC 2782.
106*/
107
108static void qt_qdnsservicerecord_sort(QList<QDnsServiceRecord> &records)
109{
110 // If we have no more than one result, we are done.
111 if (records.size() <= 1)
112 return;
113
114 // Order the records by priority, and for records with an equal
115 // priority, put records with a zero weight first.
116 std::sort(records.begin(), records.end(), qt_qdnsservicerecord_less_than);
117
118 int i = 0;
119 while (i < records.size()) {
120
121 // Determine the slice of records with the current priority.
122 QList<QDnsServiceRecord> slice;
123 const quint16 slicePriority = records.at(i).priority();
124 unsigned int sliceWeight = 0;
125 for (int j = i; j < records.size(); ++j) {
126 if (records.at(j).priority() != slicePriority)
127 break;
128 sliceWeight += records.at(j).weight();
129 slice << records.at(j);
130 }
131#ifdef QDNSLOOKUP_DEBUG
132 qDebug("qt_qdnsservicerecord_sort() : priority %i (size: %i, total weight: %i)",
133 slicePriority, slice.size(), sliceWeight);
134#endif
135
136 // Order the slice of records.
137 while (!slice.isEmpty()) {
138 const unsigned int weightThreshold = QRandomGenerator::global()->bounded(sliceWeight + 1);
139 unsigned int summedWeight = 0;
140 for (int j = 0; j < slice.size(); ++j) {
141 summedWeight += slice.at(j).weight();
142 if (summedWeight >= weightThreshold) {
143#ifdef QDNSLOOKUP_DEBUG
144 qDebug("qt_qdnsservicerecord_sort() : adding %s %i (weight: %i)",
145 qPrintable(slice.at(j).target()), slice.at(j).port(),
146 slice.at(j).weight());
147#endif
148 // Adjust the slice weight and take the current record.
149 sliceWeight -= slice.at(j).weight();
150 records[i++] = slice.takeAt(j);
151 break;
152 }
153 }
154 }
155 }
156}
157
158const char *QDnsLookupPrivate::msgNoIpV6NameServerAdresses =
159 QT_TRANSLATE_NOOP("QDnsLookupRunnable", "IPv6 addresses for nameservers are currently not supported");
160
161/*!
162 \class QDnsLookup
163 \brief The QDnsLookup class represents a DNS lookup.
164 \since 5.0
165
166 \inmodule QtNetwork
167 \ingroup network
168
169 QDnsLookup uses the mechanisms provided by the operating system to perform
170 DNS lookups. To perform a lookup you need to specify a \l name and \l type
171 then invoke the \l{QDnsLookup::lookup()}{lookup()} slot. The
172 \l{QDnsLookup::finished()}{finished()} signal will be emitted upon
173 completion.
174
175 For example, you can determine which servers an XMPP chat client should
176 connect to for a given domain with:
177
178 \snippet code/src_network_kernel_qdnslookup.cpp 0
179
180 Once the request finishes you can handle the results with:
181
182 \snippet code/src_network_kernel_qdnslookup.cpp 1
183
184 \note If you simply want to find the IP address(es) associated with a host
185 name, or the host name associated with an IP address you should use
186 QHostInfo instead.
187*/
188
189/*!
190 \enum QDnsLookup::Error
191
192 Indicates all possible error conditions found during the
193 processing of the DNS lookup.
194
195 \value NoError no error condition.
196
197 \value ResolverError there was an error initializing the system's
198 DNS resolver.
199
200 \value OperationCancelledError the lookup was aborted using the abort()
201 method.
202
203 \value InvalidRequestError the requested DNS lookup was invalid.
204
205 \value InvalidReplyError the reply returned by the server was invalid.
206
207 \value ServerFailureError the server encountered an internal failure
208 while processing the request (SERVFAIL).
209
210 \value ServerRefusedError the server refused to process the request for
211 security or policy reasons (REFUSED).
212
213 \value NotFoundError the requested domain name does not exist
214 (NXDOMAIN).
215*/
216
217/*!
218 \enum QDnsLookup::Type
219
220 Indicates the type of DNS lookup that was performed.
221
222 \value A IPv4 address records.
223
224 \value AAAA IPv6 address records.
225
226 \value ANY any records.
227
228 \value CNAME canonical name records.
229
230 \value MX mail exchange records.
231
232 \value NS name server records.
233
234 \value PTR pointer records.
235
236 \value SRV service records.
237
238 \value TXT text records.
239*/
240
241/*!
242 \fn void QDnsLookup::finished()
243
244 This signal is emitted when the reply has finished processing.
245*/
246
247/*!
248 \fn void QDnsLookup::nameChanged(const QString &name)
249
250 This signal is emitted when the lookup \l name changes.
251 \a name is the new lookup name.
252*/
253
254/*!
255 \fn void QDnsLookup::typeChanged(Type type)
256
257 This signal is emitted when the lookup \l type changes.
258 \a type is the new lookup type.
259*/
260
261/*!
262 Constructs a QDnsLookup object and sets \a parent as the parent object.
263
264 The \l type property will default to QDnsLookup::A.
265*/
266
267QDnsLookup::QDnsLookup(QObject *parent)
268 : QObject(*new QDnsLookupPrivate, parent)
269{
270 qRegisterMetaType<QDnsLookupReply>();
271}
272/*!
273 Constructs a QDnsLookup object for the given \a type and \a name and sets
274 \a parent as the parent object.
275*/
276
277QDnsLookup::QDnsLookup(Type type, const QString &name, QObject *parent)
278 : QObject(*new QDnsLookupPrivate, parent)
279{
280 Q_D(QDnsLookup);
281 qRegisterMetaType<QDnsLookupReply>();
282 d->name = name;
283 d->type = type;
284}
285
286/*!
287 \fn QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent)
288 \since 5.4
289 Constructs a QDnsLookup object for the given \a type, \a name and
290 \a nameserver and sets \a parent as the parent object.
291*/
292
293QDnsLookup::QDnsLookup(Type type, const QString &name, const QHostAddress &nameserver, QObject *parent)
294 : QObject(*new QDnsLookupPrivate, parent)
295{
296 Q_D(QDnsLookup);
297 qRegisterMetaType<QDnsLookupReply>();
298 d->name = name;
299 d->type = type;
300 d->nameserver = nameserver;
301}
302
303/*!
304 Destroys the QDnsLookup object.
305
306 It is safe to delete a QDnsLookup object even if it is not finished, you
307 will simply never receive its results.
308*/
309
310QDnsLookup::~QDnsLookup()
311{
312}
313
314/*!
315 \property QDnsLookup::error
316 \brief the type of error that occurred if the DNS lookup failed, or NoError.
317*/
318
319QDnsLookup::Error QDnsLookup::error() const
320{
321 return d_func()->reply.error;
322}
323
324/*!
325 \property QDnsLookup::errorString
326 \brief a human-readable description of the error if the DNS lookup failed.
327*/
328
329QString QDnsLookup::errorString() const
330{
331 return d_func()->reply.errorString;
332}
333
334/*!
335 Returns whether the reply has finished or was aborted.
336*/
337
338bool QDnsLookup::isFinished() const
339{
340 return d_func()->isFinished;
341}
342
343/*!
344 \property QDnsLookup::name
345 \brief the name to lookup.
346
347 \note The name will be encoded using IDNA, which means it's unsuitable for
348 querying SRV records compatible with the DNS-SD specification.
349*/
350
351QString QDnsLookup::name() const
352{
353 return d_func()->name;
354}
355
356void QDnsLookup::setName(const QString &name)
357{
358 Q_D(QDnsLookup);
359 if (name != d->name) {
360 d->name = name;
361 emit nameChanged(name);
362 }
363}
364
365/*!
366 \property QDnsLookup::type
367 \brief the type of DNS lookup.
368*/
369
370QDnsLookup::Type QDnsLookup::type() const
371{
372 return d_func()->type;
373}
374
375void QDnsLookup::setType(Type type)
376{
377 Q_D(QDnsLookup);
378 if (type != d->type) {
379 d->type = type;
380 emit typeChanged(type);
381 }
382}
383
384/*!
385 \property QDnsLookup::nameserver
386 \brief the nameserver to use for DNS lookup.
387*/
388
389QHostAddress QDnsLookup::nameserver() const
390{
391 return d_func()->nameserver;
392}
393
394void QDnsLookup::setNameserver(const QHostAddress &nameserver)
395{
396 Q_D(QDnsLookup);
397 if (nameserver != d->nameserver) {
398 d->nameserver = nameserver;
399 emit nameserverChanged(nameserver);
400 }
401}
402
403/*!
404 Returns the list of canonical name records associated with this lookup.
405*/
406
407QList<QDnsDomainNameRecord> QDnsLookup::canonicalNameRecords() const
408{
409 return d_func()->reply.canonicalNameRecords;
410}
411
412/*!
413 Returns the list of host address records associated with this lookup.
414*/
415
416QList<QDnsHostAddressRecord> QDnsLookup::hostAddressRecords() const
417{
418 return d_func()->reply.hostAddressRecords;
419}
420
421/*!
422 Returns the list of mail exchange records associated with this lookup.
423
424 The records are sorted according to
425 \l{http://www.rfc-editor.org/rfc/rfc5321.txt}{RFC 5321}, so if you use them
426 to connect to servers, you should try them in the order they are listed.
427*/
428
429QList<QDnsMailExchangeRecord> QDnsLookup::mailExchangeRecords() const
430{
431 return d_func()->reply.mailExchangeRecords;
432}
433
434/*!
435 Returns the list of name server records associated with this lookup.
436*/
437
438QList<QDnsDomainNameRecord> QDnsLookup::nameServerRecords() const
439{
440 return d_func()->reply.nameServerRecords;
441}
442
443/*!
444 Returns the list of pointer records associated with this lookup.
445*/
446
447QList<QDnsDomainNameRecord> QDnsLookup::pointerRecords() const
448{
449 return d_func()->reply.pointerRecords;
450}
451
452/*!
453 Returns the list of service records associated with this lookup.
454
455 The records are sorted according to
456 \l{http://www.rfc-editor.org/rfc/rfc2782.txt}{RFC 2782}, so if you use them
457 to connect to servers, you should try them in the order they are listed.
458*/
459
460QList<QDnsServiceRecord> QDnsLookup::serviceRecords() const
461{
462 return d_func()->reply.serviceRecords;
463}
464
465/*!
466 Returns the list of text records associated with this lookup.
467*/
468
469QList<QDnsTextRecord> QDnsLookup::textRecords() const
470{
471 return d_func()->reply.textRecords;
472}
473
474/*!
475 Aborts the DNS lookup operation.
476
477 If the lookup is already finished, does nothing.
478*/
479
480void QDnsLookup::abort()
481{
482 Q_D(QDnsLookup);
483 if (d->runnable) {
484 d->runnable = nullptr;
485 d->reply = QDnsLookupReply();
486 d->reply.error = QDnsLookup::OperationCancelledError;
487 d->reply.errorString = tr("Operation cancelled");
488 d->isFinished = true;
489 emit finished();
490 }
491}
492
493/*!
494 Performs the DNS lookup.
495
496 The \l{QDnsLookup::finished()}{finished()} signal is emitted upon completion.
497*/
498
499void QDnsLookup::lookup()
500{
501 Q_D(QDnsLookup);
502 d->isFinished = false;
503 d->reply = QDnsLookupReply();
504 d->runnable = new QDnsLookupRunnable(d->type, QUrl::toAce(d->name), d->nameserver);
505 connect(d->runnable, SIGNAL(finished(QDnsLookupReply)),
506 this, SLOT(_q_lookupFinished(QDnsLookupReply)),
507 Qt::BlockingQueuedConnection);
508#if QT_CONFIG(thread)
509 theDnsLookupThreadPool()->start(d->runnable);
510#endif
511}
512
513/*!
514 \class QDnsDomainNameRecord
515 \brief The QDnsDomainNameRecord class stores information about a domain
516 name record.
517
518 \inmodule QtNetwork
519 \ingroup network
520 \ingroup shared
521
522 When performing a name server lookup, zero or more records will be returned.
523 Each record is represented by a QDnsDomainNameRecord instance.
524
525 \sa QDnsLookup
526*/
527
528/*!
529 Constructs an empty domain name record object.
530*/
531
532QDnsDomainNameRecord::QDnsDomainNameRecord()
533 : d(new QDnsDomainNameRecordPrivate)
534{
535}
536
537/*!
538 Constructs a copy of \a other.
539*/
540
541QDnsDomainNameRecord::QDnsDomainNameRecord(const QDnsDomainNameRecord &other)
542 : d(other.d)
543{
544}
545
546/*!
547 Destroys a domain name record.
548*/
549
550QDnsDomainNameRecord::~QDnsDomainNameRecord()
551{
552}
553
554/*!
555 Returns the name for this record.
556*/
557
558QString QDnsDomainNameRecord::name() const
559{
560 return d->name;
561}
562
563/*!
564 Returns the duration in seconds for which this record is valid.
565*/
566
567quint32 QDnsDomainNameRecord::timeToLive() const
568{
569 return d->timeToLive;
570}
571
572/*!
573 Returns the value for this domain name record.
574*/
575
576QString QDnsDomainNameRecord::value() const
577{
578 return d->value;
579}
580
581/*!
582 Assigns the data of the \a other object to this record object,
583 and returns a reference to it.
584*/
585
586QDnsDomainNameRecord &QDnsDomainNameRecord::operator=(const QDnsDomainNameRecord &other)
587{
588 d = other.d;
589 return *this;
590}
591/*!
592 \fn void QDnsDomainNameRecord::swap(QDnsDomainNameRecord &other)
593
594 Swaps this domain-name record instance with \a other. This
595 function is very fast and never fails.
596*/
597
598/*!
599 \class QDnsHostAddressRecord
600 \brief The QDnsHostAddressRecord class stores information about a host
601 address record.
602
603 \inmodule QtNetwork
604 \ingroup network
605 \ingroup shared
606
607 When performing an address lookup, zero or more records will be
608 returned. Each record is represented by a QDnsHostAddressRecord instance.
609
610 \sa QDnsLookup
611*/
612
613/*!
614 Constructs an empty host address record object.
615*/
616
617QDnsHostAddressRecord::QDnsHostAddressRecord()
618 : d(new QDnsHostAddressRecordPrivate)
619{
620}
621
622/*!
623 Constructs a copy of \a other.
624*/
625
626QDnsHostAddressRecord::QDnsHostAddressRecord(const QDnsHostAddressRecord &other)
627 : d(other.d)
628{
629}
630
631/*!
632 Destroys a host address record.
633*/
634
635QDnsHostAddressRecord::~QDnsHostAddressRecord()
636{
637}
638
639/*!
640 Returns the name for this record.
641*/
642
643QString QDnsHostAddressRecord::name() const
644{
645 return d->name;
646}
647
648/*!
649 Returns the duration in seconds for which this record is valid.
650*/
651
652quint32 QDnsHostAddressRecord::timeToLive() const
653{
654 return d->timeToLive;
655}
656
657/*!
658 Returns the value for this host address record.
659*/
660
661QHostAddress QDnsHostAddressRecord::value() const
662{
663 return d->value;
664}
665
666/*!
667 Assigns the data of the \a other object to this record object,
668 and returns a reference to it.
669*/
670
671QDnsHostAddressRecord &QDnsHostAddressRecord::operator=(const QDnsHostAddressRecord &other)
672{
673 d = other.d;
674 return *this;
675}
676/*!
677 \fn void QDnsHostAddressRecord::swap(QDnsHostAddressRecord &other)
678
679 Swaps this host address record instance with \a other. This
680 function is very fast and never fails.
681*/
682
683/*!
684 \class QDnsMailExchangeRecord
685 \brief The QDnsMailExchangeRecord class stores information about a DNS MX record.
686
687 \inmodule QtNetwork
688 \ingroup network
689 \ingroup shared
690
691 When performing a lookup on a service, zero or more records will be
692 returned. Each record is represented by a QDnsMailExchangeRecord instance.
693
694 The meaning of the fields is defined in
695 \l{http://www.rfc-editor.org/rfc/rfc1035.txt}{RFC 1035}.
696
697 \sa QDnsLookup
698*/
699
700/*!
701 Constructs an empty mail exchange record object.
702*/
703
704QDnsMailExchangeRecord::QDnsMailExchangeRecord()
705 : d(new QDnsMailExchangeRecordPrivate)
706{
707}
708
709/*!
710 Constructs a copy of \a other.
711*/
712
713QDnsMailExchangeRecord::QDnsMailExchangeRecord(const QDnsMailExchangeRecord &other)
714 : d(other.d)
715{
716}
717
718/*!
719 Destroys a mail exchange record.
720*/
721
722QDnsMailExchangeRecord::~QDnsMailExchangeRecord()
723{
724}
725
726/*!
727 Returns the domain name of the mail exchange for this record.
728*/
729
730QString QDnsMailExchangeRecord::exchange() const
731{
732 return d->exchange;
733}
734
735/*!
736 Returns the name for this record.
737*/
738
739QString QDnsMailExchangeRecord::name() const
740{
741 return d->name;
742}
743
744/*!
745 Returns the preference for this record.
746*/
747
748quint16 QDnsMailExchangeRecord::preference() const
749{
750 return d->preference;
751}
752
753/*!
754 Returns the duration in seconds for which this record is valid.
755*/
756
757quint32 QDnsMailExchangeRecord::timeToLive() const
758{
759 return d->timeToLive;
760}
761
762/*!
763 Assigns the data of the \a other object to this record object,
764 and returns a reference to it.
765*/
766
767QDnsMailExchangeRecord &QDnsMailExchangeRecord::operator=(const QDnsMailExchangeRecord &other)
768{
769 d = other.d;
770 return *this;
771}
772/*!
773 \fn void QDnsMailExchangeRecord::swap(QDnsMailExchangeRecord &other)
774
775 Swaps this mail exchange record with \a other. This function is
776 very fast and never fails.
777*/
778
779/*!
780 \class QDnsServiceRecord
781 \brief The QDnsServiceRecord class stores information about a DNS SRV record.
782
783 \inmodule QtNetwork
784 \ingroup network
785 \ingroup shared
786
787 When performing a lookup on a service, zero or more records will be
788 returned. Each record is represented by a QDnsServiceRecord instance.
789
790 The meaning of the fields is defined in
791 \l{http://www.rfc-editor.org/rfc/rfc2782.txt}{RFC 2782}.
792
793 \sa QDnsLookup
794*/
795
796/*!
797 Constructs an empty service record object.
798*/
799
800QDnsServiceRecord::QDnsServiceRecord()
801 : d(new QDnsServiceRecordPrivate)
802{
803}
804
805/*!
806 Constructs a copy of \a other.
807*/
808
809QDnsServiceRecord::QDnsServiceRecord(const QDnsServiceRecord &other)
810 : d(other.d)
811{
812}
813
814/*!
815 Destroys a service record.
816*/
817
818QDnsServiceRecord::~QDnsServiceRecord()
819{
820}
821
822/*!
823 Returns the name for this record.
824*/
825
826QString QDnsServiceRecord::name() const
827{
828 return d->name;
829}
830
831/*!
832 Returns the port on the target host for this service record.
833*/
834
835quint16 QDnsServiceRecord::port() const
836{
837 return d->port;
838}
839
840/*!
841 Returns the priority for this service record.
842
843 A client must attempt to contact the target host with the lowest-numbered
844 priority.
845*/
846
847quint16 QDnsServiceRecord::priority() const
848{
849 return d->priority;
850}
851
852/*!
853 Returns the domain name of the target host for this service record.
854*/
855
856QString QDnsServiceRecord::target() const
857{
858 return d->target;
859}
860
861/*!
862 Returns the duration in seconds for which this record is valid.
863*/
864
865quint32 QDnsServiceRecord::timeToLive() const
866{
867 return d->timeToLive;
868}
869
870/*!
871 Returns the weight for this service record.
872
873 The weight field specifies a relative weight for entries with the same
874 priority. Entries with higher weights should be selected with a higher
875 probability.
876*/
877
878quint16 QDnsServiceRecord::weight() const
879{
880 return d->weight;
881}
882
883/*!
884 Assigns the data of the \a other object to this record object,
885 and returns a reference to it.
886*/
887
888QDnsServiceRecord &QDnsServiceRecord::operator=(const QDnsServiceRecord &other)
889{
890 d = other.d;
891 return *this;
892}
893/*!
894 \fn void QDnsServiceRecord::swap(QDnsServiceRecord &other)
895
896 Swaps this service record instance with \a other. This function is
897 very fast and never fails.
898*/
899
900/*!
901 \class QDnsTextRecord
902 \brief The QDnsTextRecord class stores information about a DNS TXT record.
903
904 \inmodule QtNetwork
905 \ingroup network
906 \ingroup shared
907
908 When performing a text lookup, zero or more records will be
909 returned. Each record is represented by a QDnsTextRecord instance.
910
911 The meaning of the fields is defined in
912 \l{http://www.rfc-editor.org/rfc/rfc1035.txt}{RFC 1035}.
913
914 \sa QDnsLookup
915*/
916
917/*!
918 Constructs an empty text record object.
919*/
920
921QDnsTextRecord::QDnsTextRecord()
922 : d(new QDnsTextRecordPrivate)
923{
924}
925
926/*!
927 Constructs a copy of \a other.
928*/
929
930QDnsTextRecord::QDnsTextRecord(const QDnsTextRecord &other)
931 : d(other.d)
932{
933}
934
935/*!
936 Destroys a text record.
937*/
938
939QDnsTextRecord::~QDnsTextRecord()
940{
941}
942
943/*!
944 Returns the name for this text record.
945*/
946
947QString QDnsTextRecord::name() const
948{
949 return d->name;
950}
951
952/*!
953 Returns the duration in seconds for which this record is valid.
954*/
955
956quint32 QDnsTextRecord::timeToLive() const
957{
958 return d->timeToLive;
959}
960
961/*!
962 Returns the values for this text record.
963*/
964
965QList<QByteArray> QDnsTextRecord::values() const
966{
967 return d->values;
968}
969
970/*!
971 Assigns the data of the \a other object to this record object,
972 and returns a reference to it.
973*/
974
975QDnsTextRecord &QDnsTextRecord::operator=(const QDnsTextRecord &other)
976{
977 d = other.d;
978 return *this;
979}
980/*!
981 \fn void QDnsTextRecord::swap(QDnsTextRecord &other)
982
983 Swaps this text record instance with \a other. This function is
984 very fast and never fails.
985*/
986
987void QDnsLookupPrivate::_q_lookupFinished(const QDnsLookupReply &_reply)
988{
989 Q_Q(QDnsLookup);
990 if (runnable == q->sender()) {
991#ifdef QDNSLOOKUP_DEBUG
992 qDebug("DNS reply for %s: %i (%s)", qPrintable(name), _reply.error, qPrintable(_reply.errorString));
993#endif
994 reply = _reply;
995 runnable = nullptr;
996 isFinished = true;
997 emit q->finished();
998 }
999}
1000
1001void QDnsLookupRunnable::run()
1002{
1003 QDnsLookupReply reply;
1004
1005 // Validate input.
1006 if (requestName.isEmpty()) {
1007 reply.error = QDnsLookup::InvalidRequestError;
1008 reply.errorString = tr("Invalid domain name");
1009 emit finished(reply);
1010 return;
1011 }
1012
1013 // Perform request.
1014 query(requestType, requestName, nameserver, &reply);
1015
1016 // Sort results.
1017 qt_qdnsmailexchangerecord_sort(reply.mailExchangeRecords);
1018 qt_qdnsservicerecord_sort(reply.serviceRecords);
1019
1020 emit finished(reply);
1021}
1022
1023#if QT_CONFIG(thread)
1024QDnsLookupThreadPool::QDnsLookupThreadPool()
1025 : signalsConnected(false)
1026{
1027 // Run up to 5 lookups in parallel.
1028 setMaxThreadCount(5);
1029}
1030
1031void QDnsLookupThreadPool::start(QRunnable *runnable)
1032{
1033 // Ensure threads complete at application destruction.
1034 if (!signalsConnected) {
1035 QMutexLocker signalsLocker(&signalsMutex);
1036 if (!signalsConnected) {
1037 QCoreApplication *app = QCoreApplication::instance();
1038 if (!app) {
1039 qWarning("QDnsLookup requires a QCoreApplication");
1040 delete runnable;
1041 return;
1042 }
1043
1044 moveToThread(app->thread());
1045 connect(app, SIGNAL(destroyed()),
1046 SLOT(_q_applicationDestroyed()), Qt::DirectConnection);
1047 signalsConnected = true;
1048 }
1049 }
1050
1051 QThreadPool::start(runnable);
1052}
1053
1054void QDnsLookupThreadPool::_q_applicationDestroyed()
1055{
1056 waitForDone();
1057 signalsConnected = false;
1058}
1059#endif // QT_CONFIG(thread)
1060QT_END_NAMESPACE
1061
1062#include "moc_qdnslookup.cpp"
1063