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 | |
50 | QT_BEGIN_NAMESPACE |
51 | |
52 | #if QT_CONFIG(thread) |
53 | Q_GLOBAL_STATIC(QDnsLookupThreadPool, theDnsLookupThreadPool); |
54 | #endif |
55 | |
56 | static 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 | |
66 | static 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 | |
95 | static 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 | |
108 | static 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 | |
158 | const 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 | |
267 | QDnsLookup::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 | |
277 | QDnsLookup::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 | |
293 | QDnsLookup::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 | |
310 | QDnsLookup::~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 | |
319 | QDnsLookup::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 | |
329 | QString 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 | |
338 | bool 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 | |
351 | QString QDnsLookup::name() const |
352 | { |
353 | return d_func()->name; |
354 | } |
355 | |
356 | void 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 | |
370 | QDnsLookup::Type QDnsLookup::type() const |
371 | { |
372 | return d_func()->type; |
373 | } |
374 | |
375 | void 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 | |
389 | QHostAddress QDnsLookup::nameserver() const |
390 | { |
391 | return d_func()->nameserver; |
392 | } |
393 | |
394 | void 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 | |
407 | QList<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 | |
416 | QList<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 | |
429 | QList<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 | |
438 | QList<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 | |
447 | QList<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 | |
460 | QList<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 | |
469 | QList<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 | |
480 | void 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 | |
499 | void 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 | |
532 | QDnsDomainNameRecord::QDnsDomainNameRecord() |
533 | : d(new QDnsDomainNameRecordPrivate) |
534 | { |
535 | } |
536 | |
537 | /*! |
538 | Constructs a copy of \a other. |
539 | */ |
540 | |
541 | QDnsDomainNameRecord::QDnsDomainNameRecord(const QDnsDomainNameRecord &other) |
542 | : d(other.d) |
543 | { |
544 | } |
545 | |
546 | /*! |
547 | Destroys a domain name record. |
548 | */ |
549 | |
550 | QDnsDomainNameRecord::~QDnsDomainNameRecord() |
551 | { |
552 | } |
553 | |
554 | /*! |
555 | Returns the name for this record. |
556 | */ |
557 | |
558 | QString 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 | |
567 | quint32 QDnsDomainNameRecord::timeToLive() const |
568 | { |
569 | return d->timeToLive; |
570 | } |
571 | |
572 | /*! |
573 | Returns the value for this domain name record. |
574 | */ |
575 | |
576 | QString 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 | |
586 | QDnsDomainNameRecord &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 | |
617 | QDnsHostAddressRecord::QDnsHostAddressRecord() |
618 | : d(new QDnsHostAddressRecordPrivate) |
619 | { |
620 | } |
621 | |
622 | /*! |
623 | Constructs a copy of \a other. |
624 | */ |
625 | |
626 | QDnsHostAddressRecord::QDnsHostAddressRecord(const QDnsHostAddressRecord &other) |
627 | : d(other.d) |
628 | { |
629 | } |
630 | |
631 | /*! |
632 | Destroys a host address record. |
633 | */ |
634 | |
635 | QDnsHostAddressRecord::~QDnsHostAddressRecord() |
636 | { |
637 | } |
638 | |
639 | /*! |
640 | Returns the name for this record. |
641 | */ |
642 | |
643 | QString 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 | |
652 | quint32 QDnsHostAddressRecord::timeToLive() const |
653 | { |
654 | return d->timeToLive; |
655 | } |
656 | |
657 | /*! |
658 | Returns the value for this host address record. |
659 | */ |
660 | |
661 | QHostAddress 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 | |
671 | QDnsHostAddressRecord &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 | |
704 | QDnsMailExchangeRecord::QDnsMailExchangeRecord() |
705 | : d(new QDnsMailExchangeRecordPrivate) |
706 | { |
707 | } |
708 | |
709 | /*! |
710 | Constructs a copy of \a other. |
711 | */ |
712 | |
713 | QDnsMailExchangeRecord::QDnsMailExchangeRecord(const QDnsMailExchangeRecord &other) |
714 | : d(other.d) |
715 | { |
716 | } |
717 | |
718 | /*! |
719 | Destroys a mail exchange record. |
720 | */ |
721 | |
722 | QDnsMailExchangeRecord::~QDnsMailExchangeRecord() |
723 | { |
724 | } |
725 | |
726 | /*! |
727 | Returns the domain name of the mail exchange for this record. |
728 | */ |
729 | |
730 | QString QDnsMailExchangeRecord::exchange() const |
731 | { |
732 | return d->exchange; |
733 | } |
734 | |
735 | /*! |
736 | Returns the name for this record. |
737 | */ |
738 | |
739 | QString QDnsMailExchangeRecord::name() const |
740 | { |
741 | return d->name; |
742 | } |
743 | |
744 | /*! |
745 | Returns the preference for this record. |
746 | */ |
747 | |
748 | quint16 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 | |
757 | quint32 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 | |
767 | QDnsMailExchangeRecord &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 | |
800 | QDnsServiceRecord::QDnsServiceRecord() |
801 | : d(new QDnsServiceRecordPrivate) |
802 | { |
803 | } |
804 | |
805 | /*! |
806 | Constructs a copy of \a other. |
807 | */ |
808 | |
809 | QDnsServiceRecord::QDnsServiceRecord(const QDnsServiceRecord &other) |
810 | : d(other.d) |
811 | { |
812 | } |
813 | |
814 | /*! |
815 | Destroys a service record. |
816 | */ |
817 | |
818 | QDnsServiceRecord::~QDnsServiceRecord() |
819 | { |
820 | } |
821 | |
822 | /*! |
823 | Returns the name for this record. |
824 | */ |
825 | |
826 | QString 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 | |
835 | quint16 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 | |
847 | quint16 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 | |
856 | QString 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 | |
865 | quint32 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 | |
878 | quint16 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 | |
888 | QDnsServiceRecord &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 | |
921 | QDnsTextRecord::QDnsTextRecord() |
922 | : d(new QDnsTextRecordPrivate) |
923 | { |
924 | } |
925 | |
926 | /*! |
927 | Constructs a copy of \a other. |
928 | */ |
929 | |
930 | QDnsTextRecord::QDnsTextRecord(const QDnsTextRecord &other) |
931 | : d(other.d) |
932 | { |
933 | } |
934 | |
935 | /*! |
936 | Destroys a text record. |
937 | */ |
938 | |
939 | QDnsTextRecord::~QDnsTextRecord() |
940 | { |
941 | } |
942 | |
943 | /*! |
944 | Returns the name for this text record. |
945 | */ |
946 | |
947 | QString 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 | |
956 | quint32 QDnsTextRecord::timeToLive() const |
957 | { |
958 | return d->timeToLive; |
959 | } |
960 | |
961 | /*! |
962 | Returns the values for this text record. |
963 | */ |
964 | |
965 | QList<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 | |
975 | QDnsTextRecord &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 | |
987 | void 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 | |
1001 | void 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) |
1024 | QDnsLookupThreadPool::QDnsLookupThreadPool() |
1025 | : signalsConnected(false) |
1026 | { |
1027 | // Run up to 5 lookups in parallel. |
1028 | setMaxThreadCount(5); |
1029 | } |
1030 | |
1031 | void 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 | |
1054 | void QDnsLookupThreadPool::_q_applicationDestroyed() |
1055 | { |
1056 | waitForDone(); |
1057 | signalsConnected = false; |
1058 | } |
1059 | #endif // QT_CONFIG(thread) |
1060 | QT_END_NAMESPACE |
1061 | |
1062 | #include "moc_qdnslookup.cpp" |
1063 | |