7#include <QtNetwork/private/qnetworkinformation_p.h>
8#include <QtNetwork/qnetworkinformation.h>
10#include <QtCore/private/qobject_p.h>
11#include <QtCore/qcoreapplication.h>
12#include <QtCore/qmutex.h>
13#include <QtCore/qthread.h>
14#include <QtCore/private/qfactoryloader_p.h>
21Q_DECLARE_LOGGING_CATEGORY(lcNetInfo)
22Q_LOGGING_CATEGORY(lcNetInfo,
"qt.network.info");
26 void operator()(QNetworkInformation *information) {
delete information; }
30 (QNetworkInformationBackendFactory_iid,
31 QStringLiteral(
"/networkinformation")))
33struct QStaticNetworkInformationDataHolder
36 std::unique_ptr<QNetworkInformation, QNetworkInformationDeleter> instanceHolder;
37 QList<QNetworkInformationBackendFactory *> factories;
43 if (!dataHolder.exists())
45 QMutexLocker locker(&dataHolder->instanceMutex);
46 QNetworkInformation *instance = dataHolder->instanceHolder.get();
50 dataHolder->instanceHolder.reset();
53using namespace Qt::Literals::StringLiterals;
67 Q_DECLARE_PUBLIC(QNetworkInformation)
80 QMutexLocker locker(&dataHolder->instanceMutex);
81 return dataHolder->instanceHolder.get();
84 static void addToList(QNetworkInformationBackendFactory *factory);
88 static bool initializeList();
90 std::unique_ptr<QNetworkInformationBackend> backend;
99 Q_CONSTINIT
static QBasicMutex mutex;
100 QMutexLocker initLocker(&mutex);
102#if QT_CONFIG(library)
107 while (qniLoader->instance(index))
112 const auto featuresNameOrder = [](QNetworkInformationBackendFactory *a,
113 QNetworkInformationBackendFactory *b) {
116 auto aFeaturesSupported = qPopulationCount(
unsigned(a->featuresSupported()));
117 auto bFeaturesSupported = qPopulationCount(
unsigned(b->featuresSupported()));
118 return aFeaturesSupported > bFeaturesSupported
119 || (aFeaturesSupported == bFeaturesSupported
120 && a->name().compare(b->name(), Qt::CaseInsensitive) < 0);
122 QMutexLocker instanceLocker(&dataHolder->instanceMutex);
123 std::sort(dataHolder->factories.begin(), dataHolder->factories.end(), featuresNameOrder);
125 return !dataHolder->factories.isEmpty();
133 QMutexLocker locker(&dataHolder->instanceMutex);
134 dataHolder->factories.append(factory);
140 if (!dataHolder.exists())
142 QMutexLocker locker(&dataHolder->instanceMutex);
143 dataHolder->factories.removeAll(factory);
150 if (!initializeList())
153 QMutexLocker locker(&dataHolder->instanceMutex);
154 const QList copy = dataHolder->factories;
158 result.reserve(copy.size());
159 for (
const auto *factory : copy)
160 result << factory->name();
171 qDebug().nospace() <<
"create() called with name=\"" << name
172 <<
"\". instanceHolder initialized? " << !!dataHolder->instanceHolder;
174 if (!initializeList()) {
176 qDebug(
"Failed to initialize list, returning.");
181 QMutexLocker locker(&dataHolder->instanceMutex);
182 if (dataHolder->instanceHolder)
183 return dataHolder->instanceHolder.get();
186 const auto nameMatches = [name](QNetworkInformationBackendFactory *factory) {
187 return factory->name().compare(name, Qt::CaseInsensitive) == 0;
189 auto it = std::find_if(dataHolder->factories.cbegin(), dataHolder->factories.cend(),
191 if (it == dataHolder->factories.cend()) {
193 if (dataHolder->factories.isEmpty()) {
194 qDebug(
"No plugins available");
197 listNames.reserve(8 * dataHolder->factories.count());
198 for (
const auto *factory : std::as_const(dataHolder->factories))
199 listNames += factory->name() +
", "_L1;
201 qDebug().nospace() <<
"Couldn't find " << name <<
" in list with names: { "
202 << listNames <<
" }";
208 qDebug() <<
"Creating instance using loader named " << (*it)->name();
210 QNetworkInformationBackend *backend = (*it)->create((*it)->featuresSupported());
213 dataHolder->instanceHolder.reset(
new QNetworkInformation(backend));
214 Q_ASSERT(name.isEmpty()
215 || dataHolder->instanceHolder->backendName().compare(name, Qt::CaseInsensitive) == 0);
216 return dataHolder->instanceHolder.get();
224 qDebug().nospace() <<
"create() called with features=\"" << features
225 <<
"\". instanceHolder initialized? " << !!dataHolder->instanceHolder;
230 if (!initializeList()) {
232 qDebug(
"Failed to initialize list, returning.");
236 QMutexLocker locker(&dataHolder->instanceMutex);
237 if (dataHolder->instanceHolder)
238 return dataHolder->instanceHolder.get();
240 const auto supportsRequestedFeatures = [features](QNetworkInformationBackendFactory *factory) {
241 return factory && factory->featuresSupported().testFlags(features);
244 for (
auto it = dataHolder->factories.cbegin(), end = dataHolder->factories.cend(); it != end;
246 it =
std::find_if(it, end, supportsRequestedFeatures);
249 if (dataHolder->factories.isEmpty()) {
250 qDebug(
"No plugins available");
253 names.reserve(dataHolder->factories.count());
254 for (
const auto *factory : std::as_const(dataHolder->factories))
255 names += factory->name();
256 qDebug() <<
"None of the following backends has all the requested features:"
257 << names << features;
263 qDebug() <<
"Creating instance using loader named" << (*it)->name();
265 if (QNetworkInformationBackend *backend = (*it)->create(features)) {
266 dataHolder->instanceHolder.reset(
new QNetworkInformation(backend));
267 Q_ASSERT(dataHolder->instanceHolder->supports(features));
268 return dataHolder->instanceHolder.get();
272 qDebug() <<
"The factory returned a nullptr";
277 qDebug() <<
"Couldn't find/create an appropriate backend.";
287 QMutexLocker locker(&dataHolder->instanceMutex);
288 if (dataHolder->instanceHolder)
289 return dataHolder->instanceHolder.get();
292 dataHolder->instanceHolder.reset(
new QNetworkInformation(backend));
293 return dataHolder->instanceHolder.get();
297
298
299
300
301
302
303
304
305
306
307
308
311
312
313
314QNetworkInformationBackend::~QNetworkInformationBackend() =
default;
317
318
319
320
321
324
325
326
327
328
331
332
333
334
335
336
337
340
341
342
343
344
345
346
349
350
351
352
353
354
355
356
357
358
359
362
363
364
365QNetworkInformationBackendFactory::QNetworkInformationBackendFactory()
367 QNetworkInformationPrivate::addToList(
this);
371
372
373
374QNetworkInformationBackendFactory::~QNetworkInformationBackendFactory()
376 QNetworkInformationPrivate::removeFromList(
this);
380
381
382
383
384
387
388
389
390
391
392
393
396
397
398
399
400
401
402
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
510
511
512QNetworkInformation::QNetworkInformation(QNetworkInformationBackend *backend)
513 : QObject(*(
new QNetworkInformationPrivate(backend)))
515 connect(backend, &QNetworkInformationBackend::reachabilityChanged,
this,
516 &QNetworkInformation::reachabilityChanged);
517 connect(backend, &QNetworkInformationBackend::behindCaptivePortalChanged,
this,
518 &QNetworkInformation::isBehindCaptivePortalChanged);
519 connect(backend, &QNetworkInformationBackend::transportMediumChanged,
this,
520 &QNetworkInformation::transportMediumChanged);
521 connect(backend, &QNetworkInformationBackend::isMeteredChanged,
this,
522 &QNetworkInformation::isMeteredChanged);
524 QThread *main =
nullptr;
526 if (QCoreApplication::instance())
527 main = QCoreApplication::instance()->thread();
529 if (main && thread() != main)
534
535
536QNetworkInformation::~QNetworkInformation() =
default;
539
540
541
542
543
544
545
546
547
548
549
550
552QNetworkInformation::Reachability QNetworkInformation::reachability()
const
554 return d_func()->backend->reachability();
558
559
560
561
562
563
564
565
566
567
568bool QNetworkInformation::isBehindCaptivePortal()
const
570 return d_func()->backend->behindCaptivePortal();
574
575
576
577
578
579
580
581
582
583
584
585QNetworkInformation::TransportMedium QNetworkInformation::transportMedium()
const
587 return d_func()->backend->transportMedium();
591
592
593
594
595
596
597
598
599
600
601bool QNetworkInformation::isMetered()
const
603 return d_func()->backend->isMetered();
607
608
609QString QNetworkInformation::backendName()
const
611 return d_func()->backend->name();
615
616
617
618bool QNetworkInformation::supports(Features features)
const
620 return (d_func()->backend->featuresSupported() & features) == features;
624
625
626
627
628QNetworkInformation::Features QNetworkInformation::supportedFeatures()
const
630 return d_func()->backend->featuresSupported();
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675bool QNetworkInformation::loadDefaultBackend()
679 index = QNetworkInformationBackend::PluginNamesWindowsIndex;
680#elif defined(Q_OS_DARWIN)
681 index = QNetworkInformationBackend::PluginNamesAppleIndex;
682#elif defined(Q_OS_ANDROID)
683 index = QNetworkInformationBackend::PluginNamesAndroidIndex;
684#elif defined(Q_OS_LINUX)
685 index = QNetworkInformationBackend::PluginNamesLinuxIndex;
687 if (index != -1 && loadBackendByName(QNetworkInformationBackend::PluginNames[index]))
691 if (loadBackendByFeatures(Feature::Reachability))
695 return loadBackendByName(u"dummy");
699
700
701
702
703
704
705
706
707
708
709bool QNetworkInformation::loadBackendByName(QStringView backend)
711 if (backend == u"dummy")
712 return QNetworkInformationPrivate::createDummy() !=
nullptr;
714 auto loadedBackend = QNetworkInformationPrivate::create(backend);
715 return loadedBackend && loadedBackend->backendName().compare(backend, Qt::CaseInsensitive) == 0;
718#if QT_DEPRECATED_SINCE(6
,4
)
720
721
722
723
724bool QNetworkInformation::load(QStringView backend)
726 return loadBackendByName(backend);
731
732
733
734
735
736
737
738
739bool QNetworkInformation::loadBackendByFeatures(Features features)
741 auto loadedBackend = QNetworkInformationPrivate::create(features);
742 return loadedBackend && loadedBackend->supports(features);
745#if QT_DEPRECATED_SINCE(6
,4
)
747
748
749
750
751bool QNetworkInformation::load(Features features)
753 return loadBackendByFeatures(features);
758
759
760QStringList QNetworkInformation::availableBackends()
762 return QNetworkInformationPrivate::backendNames();
766
767
768
769
770
771QNetworkInformation *QNetworkInformation::instance()
773 return QNetworkInformationPrivate::instance();
778#include "moc_qnetworkinformation.cpp"
779#include "moc_qnetworkinformation_p.cpp"
780#include "qnetworkinformation.moc"
Q_GLOBAL_STATIC_WITH_ARGS(PermissionStatusHash, g_permissionStatusHash,({ { qMetaTypeId< QCameraPermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QMicrophonePermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QBluetoothPermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QContactsPermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QCalendarPermission >(), Qt::PermissionStatus::Undetermined }, { qMetaTypeId< QLocationPermission >(), Qt::PermissionStatus::Undetermined } }))