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
231int QHostInfo::lookupHost(
const QString &name,
const QObject *receiver,
const char *member)
233 if (!receiver || !member) {
234 qWarning(
"QHostInfo::lookupHost: both the receiver and the member to invoke must be non-null");
237 return QHostInfo::lookupHostImpl(name, receiver,
nullptr, member);
241
242
243
244
245
246
247
248
249
250
253
254
255
256
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
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
311
312
315
316
317
318
319void QHostInfo::abortHostLookup(
int id)
321 theHostInfoLookupManager()->abortLookup(id);
325
326
327
328
329
330
331
332
333
334
335
336
337QHostInfo QHostInfo::fromName(
const QString &name)
339#if defined QHOSTINFO_DEBUG
340 qDebug(
"QHostInfo::fromName(\"%s\")",name.toLatin1().constData());
344 return QHostInfoAgent::lookup(name);
346 QHostInfo hostInfo = QHostInfoAgent::fromName(name);
347 QHostInfoLookupManager* manager = theHostInfoLookupManager();
348 manager->cache.put(name, hostInfo);
354QHostInfo QHostInfoAgent::reverseLookup(
const QHostAddress &address)
360 sockaddr *sa =
nullptr;
362 if (address.protocol() == QHostAddress::IPv4Protocol) {
363 sa =
reinterpret_cast<sockaddr *>(&sa4);
364 saSize =
sizeof(sa4);
365 memset(&sa4, 0,
sizeof(sa4));
366 sa4.sin_family = AF_INET;
367 sa4.sin_addr.s_addr = htonl(address.toIPv4Address());
369 sa =
reinterpret_cast<sockaddr *>(&sa6);
370 saSize =
sizeof(sa6);
371 memset(&sa6, 0,
sizeof(sa6));
372 sa6.sin6_family = AF_INET6;
373 memcpy(&sa6.sin6_addr, address.toIPv6Address().c,
sizeof(sa6.sin6_addr));
376 char hbuf[NI_MAXHOST];
377 if (sa && getnameinfo(sa, saSize, hbuf,
sizeof(hbuf),
nullptr, 0, 0) == 0)
378 results.setHostName(QString::fromLatin1(hbuf));
380 if (results.hostName().isEmpty())
381 results.setHostName(address.toString());
382 results.setAddresses(QList<QHostAddress>() << address);
388
389
390QHostInfo QHostInfoAgent::lookup(
const QString &hostName)
395 QByteArray aceHostname = QUrl::toAce(hostName);
396 results.setHostName(hostName);
397 if (aceHostname.isEmpty()) {
398 results.setError(QHostInfo::HostNotFound);
399 results.setErrorString(hostName.isEmpty() ?
400 QCoreApplication::translate(
"QHostInfoAgent",
"No host name given") :
401 QCoreApplication::translate(
"QHostInfoAgent",
"Invalid hostname"));
405 addrinfo *res =
nullptr;
406 struct addrinfo hints;
407 memset(&hints, 0,
sizeof(hints));
408 hints.ai_family = PF_UNSPEC;
410 hints.ai_flags = Q_ADDRCONFIG;
413 int result = getaddrinfo(aceHostname.constData(),
nullptr, &hints, &res);
415 if (result == EAI_BADFLAGS) {
418 result = getaddrinfo(aceHostname.constData(),
nullptr, &hints, &res);
423 addrinfo *node = res;
424 QList<QHostAddress> addresses;
426#ifdef QHOSTINFO_DEBUG
427 qDebug() <<
"getaddrinfo node: flags:" << node->ai_flags <<
"family:" << node->ai_family
428 <<
"ai_socktype:" << node->ai_socktype <<
"ai_protocol:" << node->ai_protocol
429 <<
"ai_addrlen:" << node->ai_addrlen;
431 switch (node->ai_family) {
434 addr.setAddress(ntohl(((sockaddr_in *) node->ai_addr)->sin_addr.s_addr));
435 if (!addresses.contains(addr))
436 addresses.append(addr);
441 sockaddr_in6 *sa6 = (sockaddr_in6 *) node->ai_addr;
442 addr.setAddress(sa6->sin6_addr.s6_addr);
443 if (sa6->sin6_scope_id)
444 addr.setScopeId(QString::number(sa6->sin6_scope_id));
445 if (!addresses.contains(addr))
446 addresses.append(addr);
450 results.setError(QHostInfo::UnknownError);
451 results.setErrorString(QCoreApplication::translate(
"QHostInfoAgent",
"Unknown address type"));
453 node = node->ai_next;
455 if (addresses.isEmpty()) {
458 results.setError(QHostInfo::UnknownError);
459 results.setErrorString(QCoreApplication::translate(
"QHostInfoAgent",
"Unknown address type"));
462 results.setAddresses(addresses);
467 case WSAHOST_NOT_FOUND:
477 results.setError(QHostInfo::HostNotFound);
478 results.setErrorString(QCoreApplication::translate(
"QHostInfoAgent",
"Host not found"));
481 results.setError(QHostInfo::UnknownError);
483 results.setErrorString(QString::fromWCharArray(gai_strerror(result)));
485 results.setErrorString(QString::fromLocal8Bit(gai_strerror(result)));
491#if defined(QHOSTINFO_DEBUG)
492 if (results.error() != QHostInfo::NoError) {
493 qDebug(
"QHostInfoAgent::fromName(): error #%d %s",
494 h_errno, results.errorString().toLatin1().constData());
497 QList<QHostAddress> addresses = results.addresses();
498 for (
int i = 0; i < addresses.count(); ++i) {
499 if (i != 0) tmp +=
", "_L1;
500 tmp += addresses.at(i).toString();
502 qDebug(
"QHostInfoAgent::fromName(): found %i entries for \"%s\": {%s}",
503 addresses.count(), aceHostname.constData(),
504 tmp.toLatin1().constData());
512
513
514
515
516
517
518
519
520
521
522
525
526
527
528
529QHostInfo::QHostInfo(
int id)
530 : d_ptr(
new QHostInfoPrivate)
537
538
539QHostInfo::QHostInfo(
const QHostInfo &other)
540 : d_ptr(
new QHostInfoPrivate(*other.d_ptr))
545
546
547
548
549
550
551
552
553
554
557
558
559
560QHostInfo &QHostInfo::operator=(
const QHostInfo &other)
565 Q_ASSERT(d_ptr && other.d_ptr);
566 *d_ptr = *other.d_ptr;
571
572
573QHostInfo::~QHostInfo()
579
580
581
582
583
584
585
586
587
588QList<QHostAddress> QHostInfo::addresses()
const
590 Q_D(
const QHostInfo);
595
596
597
598
599void QHostInfo::setAddresses(
const QList<QHostAddress> &addresses)
602 d->addrs = addresses;
606
607
608
609
610QString QHostInfo::hostName()
const
612 Q_D(
const QHostInfo);
617
618
619
620
621void QHostInfo::setHostName(
const QString &hostName)
624 d->hostName = hostName;
628
629
630
631
632
633QHostInfo::HostInfoError QHostInfo::error()
const
635 Q_D(
const QHostInfo);
640
641
642
643
644void QHostInfo::setError(HostInfoError error)
651
652
653
654
655int QHostInfo::lookupId()
const
657 Q_D(
const QHostInfo);
662
663
664
665
666void QHostInfo::setLookupId(
int id)
673
674
675
676
677
678QString QHostInfo::errorString()
const
680 Q_D(
const QHostInfo);
685
686
687
688
689
690void QHostInfo::setErrorString(
const QString &str)
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711QString QHostInfo::localHostName()
713 return QSysInfo::machineHostName();
717
718
719
720
721
722
723
724
725
728
729
730
731
732
733
734
735
736int QHostInfo::lookupHostImpl(
const QString &name,
737 const QObject *receiver,
738 QtPrivate::QSlotObjectBase *slotObjRaw,
741 QtPrivate::SlotObjUniquePtr slotObj{slotObjRaw};
742#if defined QHOSTINFO_DEBUG
743 qDebug(
"QHostInfo::lookupHostImpl(\"%s\", %p, %p, %s)",
744 name.toLatin1().constData(), receiver, slotObj.get(), member ? member + 1 : 0);
746 Q_ASSERT(!member != !slotObj);
747 Q_ASSERT(receiver || slotObj);
748 Q_ASSERT(!member || receiver);
749 const bool isUsingStringBasedSlot =
static_cast<
bool>(member);
751 if (!QAbstractEventDispatcher::instance()) {
752 qWarning(
"QHostInfo::lookupHost() called with no event dispatcher");
756 qRegisterMetaType<QHostInfo>();
760 if (Q_UNLIKELY(name.isEmpty())) {
761 QHostInfo hostInfo(id);
762 hostInfo.setError(QHostInfo::HostNotFound);
763 hostInfo.setErrorString(QCoreApplication::translate(
"QHostInfo",
"No host name given"));
765 QHostInfoResult result(receiver, std::move(slotObj));
766 if (isUsingStringBasedSlot) {
767 QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)),
768 receiver, member, Qt::QueuedConnection);
770 result.postResultsReady(hostInfo);
780 QHostInfo hostInfo = QHostInfoAgent::lookup(name);
781 hostInfo.setLookupId(id);
783 QHostInfoResult result(receiver, std::move(slotObj));
784 if (isUsingStringBasedSlot) {
785 QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)),
786 receiver, member, Qt::QueuedConnection);
788 result.postResultsReady(hostInfo);
790 QHostInfoLookupManager *manager = theHostInfoLookupManager();
792 if (Q_LIKELY(manager)) {
794 if (manager->cache.isEnabled()) {
797 QHostInfo info = manager->cache.get(name, &valid);
799 info.setLookupId(id);
800 QHostInfoResult result(receiver, std::move(slotObj));
801 if (isUsingStringBasedSlot) {
802 QObject::connect(&result, SIGNAL(resultsReady(QHostInfo)),
803 receiver, member, Qt::QueuedConnection);
805 result.postResultsReady(info);
811 QHostInfoRunnable *runnable =
new QHostInfoRunnable(name, id, receiver, std::move(slotObj));
812 if (isUsingStringBasedSlot) {
813 QObject::connect(runnable->resultEmitter.get(), SIGNAL(resultsReady(QHostInfo)),
814 receiver, member, Qt::QueuedConnection);
816 manager->scheduleLookup(runnable);
822QHostInfoRunnable::QHostInfoRunnable(
const QString &hn,
int i,
const QObject *receiver,
823 QtPrivate::SlotObjUniquePtr slotObj)
824 : toBeLookedUp{hn}, id{i}, resultEmitter{
new QHostInfoResult(receiver, std::move(slotObj))}
829QHostInfoRunnable::~QHostInfoRunnable()
833 QObjectPrivate::deleteInOwnThread(resultEmitter.release());
837void QHostInfoRunnable::run()
842 if (manager->wasAborted(id))
850 if (manager->cache.isEnabled()) {
853 hostInfo = manager->cache.get(toBeLookedUp, &valid);
856 hostInfo = QHostInfoAgent::fromName(toBeLookedUp);
857 manager->cache.put(toBeLookedUp, hostInfo);
861 hostInfo = QHostInfoAgent::fromName(toBeLookedUp);
865 if (manager->wasAborted(id))
869 hostInfo.setLookupId(id);
870 resultEmitter->postResultsReady(hostInfo);
875 QMutexLocker locker(&manager->mutex);
876 const auto partitionBegin = std::stable_partition(manager->postponedLookups.rbegin(), manager->postponedLookups.rend(),
877 ToBeLookedUpEquals(toBeLookedUp)).base();
878 const auto partitionEnd = manager->postponedLookups.end();
879 for (
auto it = partitionBegin; it != partitionEnd; ++it) {
880 QHostInfoRunnable* postponed = *it;
882 hostInfo.setLookupId(postponed->id);
883 postponed->resultEmitter->postResultsReady(hostInfo);
886 manager->postponedLookups.erase(partitionBegin, partitionEnd);
893QHostInfoLookupManager::QHostInfoLookupManager() : wasDeleted(
false)
896 QObject::connect(QCoreApplication::instance(), &QObject::destroyed,
897 &threadPool, [&](QObject *) { threadPool.waitForDone(); },
898 Qt::DirectConnection);
899 threadPool.setMaxThreadCount(20);
903QHostInfoLookupManager::~QHostInfoLookupManager()
905 QMutexLocker locker(&mutex);
913void QHostInfoLookupManager::clear()
916 QMutexLocker locker(&mutex);
917 qDeleteAll(scheduledLookups);
918 qDeleteAll(finishedLookups);
920 qDeleteAll(postponedLookups);
921 postponedLookups.clear();
923 scheduledLookups.clear();
924 finishedLookups.clear();
928 threadPool.waitForDone();
934void QHostInfoLookupManager::rescheduleWithMutexHeld()
943 if (!finishedLookups.isEmpty()) {
945 for (
int i = 0; i < finishedLookups.size(); i++) {
946 abortedLookups.removeAll(finishedLookups.at(i)->id);
949 finishedLookups.clear();
953 auto isAlreadyRunning = [
this](QHostInfoRunnable *lookup) {
954 return std::any_of(currentLookups.cbegin(), currentLookups.cend(), ToBeLookedUpEquals(lookup->toBeLookedUp));
958 postponedLookups.erase(separate_if(postponedLookups.begin(),
959 postponedLookups.end(),
960 postponedLookups.begin(),
961 std::front_inserter(scheduledLookups),
962 isAlreadyRunning).first,
963 postponedLookups.end());
966 scheduledLookups.erase(separate_if(scheduledLookups.begin(),
967 scheduledLookups.end(),
968 std::back_inserter(postponedLookups),
969 scheduledLookups.begin(),
970 isAlreadyRunning).second,
971 scheduledLookups.end());
973 const int availableThreads = std::max(threadPool.maxThreadCount(), 1) - currentLookups.size();
974 if (availableThreads > 0) {
975 int readyToStartCount = qMin(availableThreads, scheduledLookups.size());
976 auto it = scheduledLookups.begin();
977 while (readyToStartCount--) {
979 threadPool.start(*it);
980 currentLookups.push_back(std::move(*it));
983 scheduledLookups.erase(scheduledLookups.begin(), it);
986 if (!scheduledLookups.isEmpty())
987 scheduledLookups.takeFirst()->run();
992void QHostInfoLookupManager::scheduleLookup(QHostInfoRunnable *r)
994 QMutexLocker locker(&
this->mutex);
999 scheduledLookups.enqueue(r);
1000 rescheduleWithMutexHeld();
1004void QHostInfoLookupManager::abortLookup(
int id)
1006 QMutexLocker locker(&
this->mutex);
1014#if QT_CONFIG(thread)
1016 for (
int i = 0; i < postponedLookups.size(); i++) {
1017 if (postponedLookups.at(i)->id == id) {
1018 delete postponedLookups.takeAt(i);
1025 for (
int i = 0; i < scheduledLookups.size(); i++) {
1026 if (scheduledLookups.at(i)->id == id) {
1027 delete scheduledLookups.takeAt(i);
1032 if (!abortedLookups.contains(id))
1033 abortedLookups.append(id);
1037bool QHostInfoLookupManager::wasAborted(
int id)
1039 QMutexLocker locker(&
this->mutex);
1044 return abortedLookups.contains(id);
1048void QHostInfoLookupManager::lookupFinished(QHostInfoRunnable *r)
1050 QMutexLocker locker(&
this->mutex);
1055#if QT_CONFIG(thread)
1056 currentLookups.removeOne(r);
1058 finishedLookups.append(r);
1059 rescheduleWithMutexHeld();
1071 QHostInfo info = manager->cache.get(name, valid);
1078 *id = QHostInfo::lookupHostImpl(name, receiver,
nullptr, member);