102 emit resultsReady(info);
110 auto result =
new QHostInfoResult(
this);
113 QMetaObject::invokeMethod(result,
114 &QHostInfoResult::finalizePostResultsReady,
115 Qt::QueuedConnection,
120
121
122void QHostInfoResult::finalizePostResultsReady(
const QHostInfo &info)
128 void *args[] = {
nullptr,
const_cast<QHostInfo *>(&info) };
129 slotObj->call(
const_cast<QObject *>(receiver.data()), args);
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
195 Q_CONSTINIT
static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(0);
196 return 1 + counter.fetchAndAddRelaxed(1);
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232int QHostInfo::lookupHost(
const QString &name,
const QObject *receiver,
const char *member)
234 if (!receiver || !member) {
235 qWarning(
"QHostInfo::lookupHost: both the receiver and the member to invoke must be non-null");
238 return QHostInfo::lookupHostImpl(name, receiver,
nullptr, member);
242
243
244
245
246
247
248
249
250
251
254
255
256
257
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
318
319
320
321
322
323void QHostInfo::abortHostLookup(
int id)
325 theHostInfoLookupManager()->abortLookup(id);
329
330
331
332
333
334
335
336
337
338
339
340
341
342QHostInfo QHostInfo::fromName(
const QString &name)
344#if defined QHOSTINFO_DEBUG
345 qDebug(
"QHostInfo::fromName(\"%s\")",name.toLatin1().constData());
349 return QHostInfoAgent::lookup(name);
351 QHostInfo hostInfo = QHostInfoAgent::fromName(name);
352 QHostInfoLookupManager* manager = theHostInfoLookupManager();
353 manager->cache.put(name, hostInfo);
359QHostInfo QHostInfoAgent::reverseLookup(
const QHostAddress &address)
365 sockaddr *sa =
nullptr;
367 if (address.protocol() == QHostAddress::IPv4Protocol) {
368 sa =
reinterpret_cast<sockaddr *>(&sa4);
369 saSize =
sizeof(sa4);
370 memset(&sa4, 0,
sizeof(sa4));
371 sa4.sin_family = AF_INET;
372 sa4.sin_addr.s_addr = htonl(address.toIPv4Address());
374 sa =
reinterpret_cast<sockaddr *>(&sa6);
375 saSize =
sizeof(sa6);
376 memset(&sa6, 0,
sizeof(sa6));
377 sa6.sin6_family = AF_INET6;
378 memcpy(&sa6.sin6_addr, address.toIPv6Address().c,
sizeof(sa6.sin6_addr));
381 char hbuf[NI_MAXHOST];
382 if (sa && getnameinfo(sa, saSize, hbuf,
sizeof(hbuf),
nullptr, 0, 0) == 0)
383 results.setHostName(QString::fromLatin1(hbuf));
385 if (results.hostName().isEmpty())
386 results.setHostName(address.toString());
387 results.setAddresses(QList<QHostAddress>() << address);
393
394
395QHostInfo QHostInfoAgent::lookup(
const QString &hostName)
400 QByteArray aceHostname = QUrl::toAce(hostName);
401 results.setHostName(hostName);
402 if (aceHostname.isEmpty()) {
403 results.setError(QHostInfo::HostNotFound);
404 results.setErrorString(hostName.isEmpty() ?
405 QCoreApplication::translate(
"QHostInfoAgent",
"No host name given") :
406 QCoreApplication::translate(
"QHostInfoAgent",
"Invalid hostname"));
410 addrinfo *res =
nullptr;
411 struct addrinfo hints;
412 memset(&hints, 0,
sizeof(hints));
413 hints.ai_family = PF_UNSPEC;
415 hints.ai_flags = Q_ADDRCONFIG;
418 int result = getaddrinfo(aceHostname.constData(),
nullptr, &hints, &res);
420 if (result == EAI_BADFLAGS) {
423 result = getaddrinfo(aceHostname.constData(),
nullptr, &hints, &res);
428 addrinfo *node = res;
429 QList<QHostAddress> addresses;
431#ifdef QHOSTINFO_DEBUG
432 qDebug() <<
"getaddrinfo node: flags:" << node->ai_flags <<
"family:" << node->ai_family
433 <<
"ai_socktype:" << node->ai_socktype <<
"ai_protocol:" << node->ai_protocol
434 <<
"ai_addrlen:" << node->ai_addrlen;
436 switch (node->ai_family) {
439 addr.setAddress(ntohl(((sockaddr_in *) node->ai_addr)->sin_addr.s_addr));
440 if (!addresses.contains(addr))
441 addresses.append(addr);
446 sockaddr_in6 *sa6 = (sockaddr_in6 *) node->ai_addr;
447 addr.setAddress(sa6->sin6_addr.s6_addr);
448 if (sa6->sin6_scope_id)
449 addr.setScopeId(QString::number(sa6->sin6_scope_id));
450 if (!addresses.contains(addr))
451 addresses.append(addr);
455 results.setError(QHostInfo::UnknownError);
456 results.setErrorString(QCoreApplication::translate(
"QHostInfoAgent",
"Unknown address type"));
458 node = node->ai_next;
460 if (addresses.isEmpty()) {
463 results.setError(QHostInfo::UnknownError);
464 results.setErrorString(QCoreApplication::translate(
"QHostInfoAgent",
"Unknown address type"));
467 results.setAddresses(addresses);
472 case WSAHOST_NOT_FOUND:
482 results.setError(QHostInfo::HostNotFound);
483 results.setErrorString(QCoreApplication::translate(
"QHostInfoAgent",
"Host not found"));
486 results.setError(QHostInfo::UnknownError);
488 results.setErrorString(QString::fromWCharArray(gai_strerror(result)));
490 results.setErrorString(QString::fromLocal8Bit(gai_strerror(result)));
496#if defined(QHOSTINFO_DEBUG)
497 if (results.error() != QHostInfo::NoError) {
498 qDebug(
"QHostInfoAgent::fromName(): error #%d %s",
499 h_errno, results.errorString().toLatin1().constData());
502 QList<QHostAddress> addresses = results.addresses();
503 for (
int i = 0; i < addresses.count(); ++i) {
504 if (i != 0) tmp +=
", "_L1;
505 tmp += addresses.at(i).toString();
507 qDebug(
"QHostInfoAgent::fromName(): found %i entries for \"%s\": {%s}",
508 addresses.count(), aceHostname.constData(),
509 tmp.toLatin1().constData());
517
518
519
520
521
522
523
524
525
526
527
530
531
532
533
534QHostInfo::QHostInfo(
int id)
535 : d_ptr(
new QHostInfoPrivate)
542
543
544QHostInfo::QHostInfo(
const QHostInfo &other)
545 : d_ptr(
new QHostInfoPrivate(*other.d_ptr))
550
551
552
553
554
555
556
557
558
559
562
563
564
565QHostInfo &QHostInfo::operator=(
const QHostInfo &other)
570 Q_ASSERT(d_ptr && other.d_ptr);
571 *d_ptr = *other.d_ptr;
576
577
578QHostInfo::~QHostInfo()
584
585
586
587
588
589
590
591
592
593QList<QHostAddress> QHostInfo::addresses()
const
595 Q_D(
const QHostInfo);
600
601
602
603
604void QHostInfo::setAddresses(
const QList<QHostAddress> &addresses)
607 d->addrs = addresses;
611
612
613
614
615QString QHostInfo::hostName()
const
617 Q_D(
const QHostInfo);
622
623
624
625
626void QHostInfo::setHostName(
const QString &hostName)
629 d->hostName = hostName;
633
634
635
636
637
638QHostInfo::HostInfoError QHostInfo::error()
const
640 Q_D(
const QHostInfo);
645
646
647
648
649void QHostInfo::setError(HostInfoError error)
656
657
658
659
660int QHostInfo::lookupId()
const
662 Q_D(
const QHostInfo);
667
668
669
670
671void QHostInfo::setLookupId(
int id)
678
679
680
681
682
683QString QHostInfo::errorString()
const
685 Q_D(
const QHostInfo);
690
691
692
693
694
695void QHostInfo::setErrorString(
const QString &str)
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717QString QHostInfo::localHostName()
719 return QSysInfo::machineHostName();
723
724
725
726
727
728
729
730
731
732
735
736
737
738
739
740
741
742
743int QHostInfo::lookupHostImpl(
const QString &name,
744 const QObject *receiver,
745 QtPrivate::QSlotObjectBase *slotObjRaw,
748 QtPrivate::SlotObjUniquePtr slotObj{slotObjRaw};
749#if defined QHOSTINFO_DEBUG
750 qDebug(
"QHostInfo::lookupHostImpl(\"%s\", %p, %p, %s)",
751 name.toLatin1().constData(), receiver, slotObj.get(), member ? member + 1 : 0);
753 Q_ASSERT(!member != !slotObj);
754 Q_ASSERT(receiver || slotObj);
755 Q_ASSERT(!member || receiver);
756 const bool isUsingStringBasedSlot =
static_cast<
bool>(member);
758 if (!QAbstractEventDispatcher::instance()) {
759 qWarning(
"QHostInfo::lookupHost() called with no event dispatcher");
763 qRegisterMetaType<QHostInfo>();
767 if (Q_UNLIKELY(name.isEmpty())) {
768 QHostInfo hostInfo(id);
769 hostInfo.setError(QHostInfo::HostNotFound);
770 hostInfo.setErrorString(QCoreApplication::translate(
"QHostInfo",
"No host name given"));
772 QHostInfoResult result(receiver, std::move(slotObj));
773 if (isUsingStringBasedSlot) {
774 QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)),
775 receiver, member, Qt::QueuedConnection);
777 result.postResultsReady(hostInfo);
787 QHostInfo hostInfo = QHostInfoAgent::lookup(name);
788 hostInfo.setLookupId(id);
790 QHostInfoResult result(receiver, std::move(slotObj));
791 if (isUsingStringBasedSlot) {
792 QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)),
793 receiver, member, Qt::QueuedConnection);
795 result.postResultsReady(hostInfo);
797 QHostInfoLookupManager *manager = theHostInfoLookupManager();
799 if (Q_LIKELY(manager)) {
801 if (manager->cache.isEnabled()) {
804 QHostInfo info = manager->cache.get(name, &valid);
806 info.setLookupId(id);
807 QHostInfoResult result(receiver, std::move(slotObj));
808 if (isUsingStringBasedSlot) {
809 QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)),
810 receiver, member, Qt::QueuedConnection);
812 result.postResultsReady(info);
818 QHostInfoRunnable *runnable =
new QHostInfoRunnable(name, id, receiver, std::move(slotObj));
819 if (isUsingStringBasedSlot) {
820 QObject::connect(runnable->resultEmitter.get(), SIGNAL(resultsReady(QHostInfo)),
821 receiver, member, Qt::QueuedConnection);
823 manager->scheduleLookup(runnable);
829QHostInfoRunnable::QHostInfoRunnable(
const QString &hn,
int i,
const QObject *receiver,
830 QtPrivate::SlotObjUniquePtr slotObj)
831 : toBeLookedUp{hn}, id{i}, resultEmitter{
new QHostInfoResult(receiver, std::move(slotObj))}
836QHostInfoRunnable::~QHostInfoRunnable()
840 QObjectPrivate::deleteInOwnThread(resultEmitter.release());
844void QHostInfoRunnable::run()
849 if (manager->wasAborted(id))
857 if (manager->cache.isEnabled()) {
860 hostInfo = manager->cache.get(toBeLookedUp, &valid);
863 hostInfo = QHostInfoAgent::fromName(toBeLookedUp);
864 manager->cache.put(toBeLookedUp, hostInfo);
868 hostInfo = QHostInfoAgent::fromName(toBeLookedUp);
872 if (manager->wasAborted(id))
876 hostInfo.setLookupId(id);
877 resultEmitter->postResultsReady(hostInfo);
882 QMutexLocker locker(&manager->mutex);
883 const auto partitionBegin = std::stable_partition(manager->postponedLookups.rbegin(), manager->postponedLookups.rend(),
884 ToBeLookedUpEquals(toBeLookedUp)).base();
885 const auto partitionEnd = manager->postponedLookups.end();
886 for (
auto it = partitionBegin; it != partitionEnd; ++it) {
887 QHostInfoRunnable* postponed = *it;
889 hostInfo.setLookupId(postponed->id);
890 postponed->resultEmitter->postResultsReady(hostInfo);
893 manager->postponedLookups.erase(partitionBegin, partitionEnd);
900QHostInfoLookupManager::QHostInfoLookupManager() : wasDeleted(
false)
903 QObject::connect(QCoreApplication::instance(), &QObject::destroyed,
904 &threadPool, [&](QObject *) { threadPool.waitForDone(); },
905 Qt::DirectConnection);
906 threadPool.setMaxThreadCount(20);
910QHostInfoLookupManager::~QHostInfoLookupManager()
912 QMutexLocker locker(&mutex);
920void QHostInfoLookupManager::clear()
923 QMutexLocker locker(&mutex);
924 qDeleteAll(scheduledLookups);
925 qDeleteAll(finishedLookups);
927 qDeleteAll(postponedLookups);
928 postponedLookups.clear();
930 scheduledLookups.clear();
931 finishedLookups.clear();
935 threadPool.waitForDone();
941void QHostInfoLookupManager::rescheduleWithMutexHeld()
950 if (!finishedLookups.isEmpty()) {
952 for (
int i = 0; i < finishedLookups.size(); i++) {
953 abortedLookups.removeAll(finishedLookups.at(i)->id);
956 finishedLookups.clear();
960 auto isAlreadyRunning = [
this](QHostInfoRunnable *lookup) {
961 return std::any_of(currentLookups.cbegin(), currentLookups.cend(), ToBeLookedUpEquals(lookup->toBeLookedUp));
965 postponedLookups.erase(separate_if(postponedLookups.begin(),
966 postponedLookups.end(),
967 postponedLookups.begin(),
968 std::front_inserter(scheduledLookups),
969 isAlreadyRunning).first,
970 postponedLookups.end());
973 scheduledLookups.erase(separate_if(scheduledLookups.begin(),
974 scheduledLookups.end(),
975 std::back_inserter(postponedLookups),
976 scheduledLookups.begin(),
977 isAlreadyRunning).second,
978 scheduledLookups.end());
980 const int availableThreads = std::max(threadPool.maxThreadCount(), 1) - currentLookups.size();
981 if (availableThreads > 0) {
982 int readyToStartCount = qMin(availableThreads, scheduledLookups.size());
983 auto it = scheduledLookups.begin();
984 while (readyToStartCount--) {
986 threadPool.start(*it);
987 currentLookups.push_back(std::move(*it));
990 scheduledLookups.erase(scheduledLookups.begin(), it);
993 if (!scheduledLookups.isEmpty())
994 scheduledLookups.takeFirst()->run();
999void QHostInfoLookupManager::scheduleLookup(QHostInfoRunnable *r)
1001 QMutexLocker locker(&
this->mutex);
1006 scheduledLookups.enqueue(r);
1007 rescheduleWithMutexHeld();
1011void QHostInfoLookupManager::abortLookup(
int id)
1013 QMutexLocker locker(&
this->mutex);
1021#if QT_CONFIG(thread)
1023 for (
int i = 0; i < postponedLookups.size(); i++) {
1024 if (postponedLookups.at(i)->id == id) {
1025 delete postponedLookups.takeAt(i);
1032 for (
int i = 0; i < scheduledLookups.size(); i++) {
1033 if (scheduledLookups.at(i)->id == id) {
1034 delete scheduledLookups.takeAt(i);
1039 if (!abortedLookups.contains(id))
1040 abortedLookups.append(id);
1044bool QHostInfoLookupManager::wasAborted(
int id)
1046 QMutexLocker locker(&
this->mutex);
1051 return abortedLookups.contains(id);
1055void QHostInfoLookupManager::lookupFinished(QHostInfoRunnable *r)
1057 QMutexLocker locker(&
this->mutex);
1062#if QT_CONFIG(thread)
1063 currentLookups.removeOne(r);
1065 finishedLookups.append(r);
1066 rescheduleWithMutexHeld();
1078 QHostInfo info = manager->cache.get(name, valid);
1085 *id = QHostInfo::lookupHostImpl(name, receiver,
nullptr, member);