100 emit resultsReady(info);
108 auto result =
new QHostInfoResult(
this);
111 QMetaObject::invokeMethod(result,
112 &QHostInfoResult::finalizePostResultsReady,
113 Qt::QueuedConnection,
118
119
120void QHostInfoResult::finalizePostResultsReady(
const QHostInfo &info)
126 void *args[] = {
nullptr,
const_cast<QHostInfo *>(&info) };
127 slotObj->call(
const_cast<QObject *>(receiver.data()), args);
134
135
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
193 Q_CONSTINIT
static QBasicAtomicInt counter = Q_BASIC_ATOMIC_INITIALIZER(0);
194 return 1 + counter.fetchAndAddRelaxed(1);
198
199
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
229int QHostInfo::lookupHost(
const QString &name,
const QObject *receiver,
const char *member)
231 if (!receiver || !member) {
232 qWarning(
"QHostInfo::lookupHost: both the receiver and the member to invoke must be non-null");
235 return QHostInfo::lookupHostImpl(name, receiver,
nullptr, member);
239
240
241
242
243
244
245
246
247
248
251
252
253
254
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
279
280
281
282
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
313
314
315
316
317void QHostInfo::abortHostLookup(
int id)
319 theHostInfoLookupManager()->abortLookup(id);
323
324
325
326
327
328
329
330
331
332
333
334
335QHostInfo QHostInfo::fromName(
const QString &name)
337#if defined QHOSTINFO_DEBUG
338 qDebug(
"QHostInfo::fromName(\"%s\")",name.toLatin1().constData());
342 return QHostInfoAgent::lookup(name);
344 QHostInfo hostInfo = QHostInfoAgent::fromName(name);
345 QHostInfoLookupManager* manager = theHostInfoLookupManager();
346 manager->cache.put(name, hostInfo);
352QHostInfo QHostInfoAgent::reverseLookup(
const QHostAddress &address)
358 sockaddr *sa =
nullptr;
360 if (address.protocol() == QAbstractSocket::IPv4Protocol) {
361 sa =
reinterpret_cast<sockaddr *>(&sa4);
362 saSize =
sizeof(sa4);
363 memset(&sa4, 0,
sizeof(sa4));
364 sa4.sin_family = AF_INET;
365 sa4.sin_addr.s_addr = htonl(address.toIPv4Address());
367 sa =
reinterpret_cast<sockaddr *>(&sa6);
368 saSize =
sizeof(sa6);
369 memset(&sa6, 0,
sizeof(sa6));
370 sa6.sin6_family = AF_INET6;
371 memcpy(&sa6.sin6_addr, address.toIPv6Address().c,
sizeof(sa6.sin6_addr));
374 char hbuf[NI_MAXHOST];
375 if (sa && getnameinfo(sa, saSize, hbuf,
sizeof(hbuf),
nullptr, 0, 0) == 0)
376 results.setHostName(QString::fromLatin1(hbuf));
378 if (results.hostName().isEmpty())
379 results.setHostName(address.toString());
380 results.setAddresses(QList<QHostAddress>() << address);
386
387
388QHostInfo QHostInfoAgent::lookup(
const QString &hostName)
393 QByteArray aceHostname = QUrl::toAce(hostName);
394 results.setHostName(hostName);
395 if (aceHostname.isEmpty()) {
396 results.setError(QHostInfo::HostNotFound);
397 results.setErrorString(hostName.isEmpty() ?
398 QCoreApplication::translate(
"QHostInfoAgent",
"No host name given") :
399 QCoreApplication::translate(
"QHostInfoAgent",
"Invalid hostname"));
403 addrinfo *res =
nullptr;
404 struct addrinfo hints;
405 memset(&hints, 0,
sizeof(hints));
406 hints.ai_family = PF_UNSPEC;
408 hints.ai_flags = Q_ADDRCONFIG;
411 int result = getaddrinfo(aceHostname.constData(),
nullptr, &hints, &res);
413 if (result == EAI_BADFLAGS) {
416 result = getaddrinfo(aceHostname.constData(),
nullptr, &hints, &res);
421 addrinfo *node = res;
422 QList<QHostAddress> addresses;
424#ifdef QHOSTINFO_DEBUG
425 qDebug() <<
"getaddrinfo node: flags:" << node->ai_flags <<
"family:" << node->ai_family
426 <<
"ai_socktype:" << node->ai_socktype <<
"ai_protocol:" << node->ai_protocol
427 <<
"ai_addrlen:" << node->ai_addrlen;
429 switch (node->ai_family) {
432 addr.setAddress(ntohl(((sockaddr_in *) node->ai_addr)->sin_addr.s_addr));
433 if (!addresses.contains(addr))
434 addresses.append(addr);
439 sockaddr_in6 *sa6 = (sockaddr_in6 *) node->ai_addr;
440 addr.setAddress(sa6->sin6_addr.s6_addr);
441 if (sa6->sin6_scope_id)
442 addr.setScopeId(QString::number(sa6->sin6_scope_id));
443 if (!addresses.contains(addr))
444 addresses.append(addr);
448 results.setError(QHostInfo::UnknownError);
449 results.setErrorString(QCoreApplication::translate(
"QHostInfoAgent",
"Unknown address type"));
451 node = node->ai_next;
453 if (addresses.isEmpty()) {
456 results.setError(QHostInfo::UnknownError);
457 results.setErrorString(QCoreApplication::translate(
"QHostInfoAgent",
"Unknown address type"));
460 results.setAddresses(addresses);
465 case WSAHOST_NOT_FOUND:
475 results.setError(QHostInfo::HostNotFound);
476 results.setErrorString(QCoreApplication::translate(
"QHostInfoAgent",
"Host not found"));
479 results.setError(QHostInfo::UnknownError);
481 results.setErrorString(QString::fromWCharArray(gai_strerror(result)));
483 results.setErrorString(QString::fromLocal8Bit(gai_strerror(result)));
489#if defined(QHOSTINFO_DEBUG)
490 if (results.error() != QHostInfo::NoError) {
491 qDebug(
"QHostInfoAgent::fromName(): error #%d %s",
492 h_errno, results.errorString().toLatin1().constData());
495 QList<QHostAddress> addresses = results.addresses();
496 for (
int i = 0; i < addresses.count(); ++i) {
497 if (i != 0) tmp +=
", "_L1;
498 tmp += addresses.at(i).toString();
500 qDebug(
"QHostInfoAgent::fromName(): found %i entries for \"%s\": {%s}",
501 addresses.count(), aceHostname.constData(),
502 tmp.toLatin1().constData());
510
511
512
513
514
515
516
517
518
519
520
523
524
525
526
527QHostInfo::QHostInfo(
int id)
528 : d_ptr(
new QHostInfoPrivate)
535
536
537QHostInfo::QHostInfo(
const QHostInfo &other)
538 : d_ptr(
new QHostInfoPrivate(*other.d_ptr))
543
544
545
546
547
548
549
550
551
552
555
556
557
558QHostInfo &QHostInfo::operator=(
const QHostInfo &other)
563 Q_ASSERT(d_ptr && other.d_ptr);
564 *d_ptr = *other.d_ptr;
569
570
571QHostInfo::~QHostInfo()
577
578
579
580
581
582
583
584
585
586QList<QHostAddress> QHostInfo::addresses()
const
588 Q_D(
const QHostInfo);
593
594
595
596
597void QHostInfo::setAddresses(
const QList<QHostAddress> &addresses)
600 d->addrs = addresses;
604
605
606
607
608QString QHostInfo::hostName()
const
610 Q_D(
const QHostInfo);
615
616
617
618
619void QHostInfo::setHostName(
const QString &hostName)
622 d->hostName = hostName;
626
627
628
629
630
631QHostInfo::HostInfoError QHostInfo::error()
const
633 Q_D(
const QHostInfo);
638
639
640
641
642void QHostInfo::setError(HostInfoError error)
649
650
651
652
653int QHostInfo::lookupId()
const
655 Q_D(
const QHostInfo);
660
661
662
663
664void QHostInfo::setLookupId(
int id)
671
672
673
674
675
676QString QHostInfo::errorString()
const
678 Q_D(
const QHostInfo);
683
684
685
686
687
688void QHostInfo::setErrorString(
const QString &str)
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709QString QHostInfo::localHostName()
711 return QSysInfo::machineHostName();
715
716
717
718
719
720
721
722
723
726
727
728
729
730
731
732
733
734int QHostInfo::lookupHostImpl(
const QString &name,
735 const QObject *receiver,
736 QtPrivate::QSlotObjectBase *slotObjRaw,
739 QtPrivate::SlotObjUniquePtr slotObj{slotObjRaw};
740#if defined QHOSTINFO_DEBUG
741 qDebug(
"QHostInfo::lookupHostImpl(\"%s\", %p, %p, %s)",
742 name.toLatin1().constData(), receiver, slotObj.get(), member ? member + 1 : 0);
744 Q_ASSERT(!member != !slotObj);
745 Q_ASSERT(receiver || slotObj);
746 Q_ASSERT(!member || receiver);
747 const bool isUsingStringBasedSlot =
static_cast<
bool>(member);
749 if (!QAbstractEventDispatcher::instance()) {
750 qWarning(
"QHostInfo::lookupHost() called with no event dispatcher");
754 qRegisterMetaType<QHostInfo>();
758 if (Q_UNLIKELY(name.isEmpty())) {
759 QHostInfo hostInfo(id);
760 hostInfo.setError(QHostInfo::HostNotFound);
761 hostInfo.setErrorString(QCoreApplication::translate(
"QHostInfo",
"No host name given"));
763 QHostInfoResult result(receiver, std::move(slotObj));
764 if (isUsingStringBasedSlot) {
765 QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)),
766 receiver, member, Qt::QueuedConnection);
768 result.postResultsReady(hostInfo);
778 QHostInfo hostInfo = QHostInfoAgent::lookup(name);
779 hostInfo.setLookupId(id);
781 QHostInfoResult result(receiver, std::move(slotObj));
782 if (isUsingStringBasedSlot) {
783 QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)),
784 receiver, member, Qt::QueuedConnection);
786 result.postResultsReady(hostInfo);
788 QHostInfoLookupManager *manager = theHostInfoLookupManager();
790 if (Q_LIKELY(manager)) {
792 if (manager->cache.isEnabled()) {
795 QHostInfo info = manager->cache.get(name, &valid);
797 info.setLookupId(id);
798 QHostInfoResult result(receiver, std::move(slotObj));
799 if (isUsingStringBasedSlot) {
800 QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)),
801 receiver, member, Qt::QueuedConnection);
803 result.postResultsReady(info);
809 QHostInfoRunnable *runnable =
new QHostInfoRunnable(name, id, receiver, std::move(slotObj));
810 if (isUsingStringBasedSlot) {
811 QObject::connect(&runnable->resultEmitter, SIGNAL(resultsReady(QHostInfo)),
812 receiver, member, Qt::QueuedConnection);
814 manager->scheduleLookup(runnable);
820QHostInfoRunnable::QHostInfoRunnable(
const QString &hn,
int i,
const QObject *receiver,
821 QtPrivate::SlotObjUniquePtr slotObj)
822 : toBeLookedUp{hn}, id{i}, resultEmitter{receiver, std::move(slotObj)}
827QHostInfoRunnable::~QHostInfoRunnable()
831void QHostInfoRunnable::run()
834 const auto sg = qScopeGuard([&] { manager->lookupFinished(
this); });
836 if (manager->wasAborted(id))
844 if (manager->cache.isEnabled()) {
847 hostInfo = manager->cache.get(toBeLookedUp, &valid);
850 hostInfo = QHostInfoAgent::fromName(toBeLookedUp);
851 manager->cache.put(toBeLookedUp, hostInfo);
855 hostInfo = QHostInfoAgent::fromName(toBeLookedUp);
859 if (manager->wasAborted(id))
863 hostInfo.setLookupId(id);
864 resultEmitter.postResultsReady(hostInfo);
869 QMutexLocker locker(&manager->mutex);
870 const auto partitionBegin = std::stable_partition(manager->postponedLookups.rbegin(), manager->postponedLookups.rend(),
871 ToBeLookedUpEquals(toBeLookedUp)).base();
872 const auto partitionEnd = manager->postponedLookups.end();
873 for (
auto it = partitionBegin; it != partitionEnd; ++it) {
874 QHostInfoRunnable* postponed = *it;
876 hostInfo.setLookupId(postponed->id);
877 postponed->resultEmitter.postResultsReady(hostInfo);
880 manager->postponedLookups.erase(partitionBegin, partitionEnd);
887QHostInfoLookupManager::QHostInfoLookupManager() : wasDeleted(
false)
890 QObject::connect(QCoreApplication::instance(), &QObject::destroyed,
891 &threadPool, [&](QObject *) { threadPool.waitForDone(); },
892 Qt::DirectConnection);
893 threadPool.setMaxThreadCount(20);
897QHostInfoLookupManager::~QHostInfoLookupManager()
899 QMutexLocker locker(&mutex);
907void QHostInfoLookupManager::clear()
910 QMutexLocker locker(&mutex);
911 qDeleteAll(scheduledLookups);
912 qDeleteAll(finishedLookups);
914 qDeleteAll(postponedLookups);
915 postponedLookups.clear();
917 scheduledLookups.clear();
918 finishedLookups.clear();
922 threadPool.waitForDone();
928void QHostInfoLookupManager::rescheduleWithMutexHeld()
937 if (!finishedLookups.isEmpty()) {
939 for (
int i = 0; i < finishedLookups.size(); i++) {
940 abortedLookups.removeAll(finishedLookups.at(i)->id);
943 finishedLookups.clear();
947 auto isAlreadyRunning = [
this](QHostInfoRunnable *lookup) {
948 return std::any_of(currentLookups.cbegin(), currentLookups.cend(), ToBeLookedUpEquals(lookup->toBeLookedUp));
952 postponedLookups.erase(separate_if(postponedLookups.begin(),
953 postponedLookups.end(),
954 postponedLookups.begin(),
955 std::front_inserter(scheduledLookups),
956 isAlreadyRunning).first,
957 postponedLookups.end());
960 scheduledLookups.erase(separate_if(scheduledLookups.begin(),
961 scheduledLookups.end(),
962 std::back_inserter(postponedLookups),
963 scheduledLookups.begin(),
964 isAlreadyRunning).second,
965 scheduledLookups.end());
967 const int availableThreads = std::max(threadPool.maxThreadCount(), 1) - currentLookups.size();
968 if (availableThreads > 0) {
969 int readyToStartCount = qMin(availableThreads, scheduledLookups.size());
970 auto it = scheduledLookups.begin();
971 while (readyToStartCount--) {
973 threadPool.start(*it);
974 currentLookups.push_back(std::move(*it));
977 scheduledLookups.erase(scheduledLookups.begin(), it);
980 if (!scheduledLookups.isEmpty())
981 scheduledLookups.takeFirst()->run();
986void QHostInfoLookupManager::scheduleLookup(QHostInfoRunnable *r)
988 QMutexLocker locker(&
this->mutex);
993 scheduledLookups.enqueue(r);
994 rescheduleWithMutexHeld();
998void QHostInfoLookupManager::abortLookup(
int id)
1000 QMutexLocker locker(&
this->mutex);
1008#if QT_CONFIG(thread)
1010 for (
int i = 0; i < postponedLookups.size(); i++) {
1011 if (postponedLookups.at(i)->id == id) {
1012 delete postponedLookups.takeAt(i);
1019 for (
int i = 0; i < scheduledLookups.size(); i++) {
1020 if (scheduledLookups.at(i)->id == id) {
1021 delete scheduledLookups.takeAt(i);
1026 if (!abortedLookups.contains(id))
1027 abortedLookups.append(id);
1031bool QHostInfoLookupManager::wasAborted(
int id)
1033 QMutexLocker locker(&
this->mutex);
1038 return abortedLookups.contains(id);
1042void QHostInfoLookupManager::lookupFinished(QHostInfoRunnable *r)
1044 QMutexLocker locker(&
this->mutex);
1049#if QT_CONFIG(thread)
1050 currentLookups.removeOne(r);
1052 finishedLookups.append(r);
1053 rescheduleWithMutexHeld();
1064 if (manager && manager->cache.isEnabled()) {
1065 QHostInfo info = manager->cache.get(name, valid);
1072 *id = QHostInfo::lookupHostImpl(name, receiver,
nullptr, member);