8#include <QtNetwork/private/qnetworkinformation_p.h>
9#include <QtNetwork/qnetworkinformation.h>
11#include <QtCore/private/qobject_p.h>
12#include <QtCore/qcoreapplication.h>
13#include <QtCore/qmutex.h>
14#include <QtCore/qthread.h>
15#include <QtCore/private/qfactoryloader_p.h>
22using namespace Qt::StringLiterals;
24Q_DECLARE_LOGGING_CATEGORY(lcNetInfo)
25Q_LOGGING_CATEGORY(lcNetInfo,
"qt.network.info");
29 void operator()(QNetworkInformation *information) {
delete information; }
33 (QNetworkInformationBackendFactory_iid,
34 QStringLiteral(
"/networkinformation")))
36struct QStaticNetworkInformationDataHolder
39 std::unique_ptr<QNetworkInformation, QNetworkInformationDeleter> instanceHolder;
40 QList<QNetworkInformationBackendFactory *> factories;
46 if (!dataHolder.exists())
48 QMutexLocker locker(&dataHolder->instanceMutex);
49 QNetworkInformation *instance = dataHolder->instanceHolder.get();
53 dataHolder->instanceHolder.reset();
68 Q_DECLARE_PUBLIC(QNetworkInformation)
81 QMutexLocker locker(&dataHolder->instanceMutex);
82 return dataHolder->instanceHolder.get();
85 static void addToList(QNetworkInformationBackendFactory *factory);
89 static bool initializeList();
91 std::unique_ptr<QNetworkInformationBackend> backend;
100 Q_CONSTINIT
static QBasicMutex mutex;
101 QMutexLocker initLocker(&mutex);
103#if QT_CONFIG(library)
106 const int pluginCount = qniLoader->metaData().size();
107 for (
int i = 0; i < pluginCount; ++i)
108 qniLoader->instance(i);
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
430
431
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
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
554
555
556QNetworkInformation::QNetworkInformation(QNetworkInformationBackend *backend)
557 : QObject(*(
new QNetworkInformationPrivate(backend)))
559 connect(backend, &QNetworkInformationBackend::reachabilityChanged,
this,
560 &QNetworkInformation::reachabilityChanged);
561 connect(backend, &QNetworkInformationBackend::behindCaptivePortalChanged,
this,
562 &QNetworkInformation::isBehindCaptivePortalChanged);
563 connect(backend, &QNetworkInformationBackend::transportMediumChanged,
this,
564 &QNetworkInformation::transportMediumChanged);
565 connect(backend, &QNetworkInformationBackend::isMeteredChanged,
this,
566 &QNetworkInformation::isMeteredChanged);
568 QThread *main =
nullptr;
570 if (QCoreApplication::instance())
571 main = QCoreApplication::instance()->thread();
573 if (main && thread() != main)
578
579
580QNetworkInformation::~QNetworkInformation() =
default;
583
584
585
586
587
588
589
590
591
592
593
594
596QNetworkInformation::Reachability QNetworkInformation::reachability()
const
598 return d_func()->backend->reachability();
602
603
604
605
606
607
608
609
610
611
612bool QNetworkInformation::isBehindCaptivePortal()
const
614 return d_func()->backend->behindCaptivePortal();
618
619
620
621
622
623
624
625
626
627
628
629QNetworkInformation::TransportMedium QNetworkInformation::transportMedium()
const
631 return d_func()->backend->transportMedium();
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653bool QNetworkInformation::isMetered()
const
655 return d_func()->backend->isMetered();
659
660
661QString QNetworkInformation::backendName()
const
663 return d_func()->backend->name();
667
668
669
670bool QNetworkInformation::supports(Features features)
const
672 return (d_func()->backend->featuresSupported() & features) == features;
676
677
678
679
680QNetworkInformation::Features QNetworkInformation::supportedFeatures()
const
682 return d_func()->backend->featuresSupported();
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727bool QNetworkInformation::loadDefaultBackend()
731 index = QNetworkInformationBackend::PluginNamesWindowsIndex;
732#elif defined(Q_OS_DARWIN)
733 index = QNetworkInformationBackend::PluginNamesAppleIndex;
734#elif defined(Q_OS_ANDROID)
735 index = QNetworkInformationBackend::PluginNamesAndroidIndex;
736#elif defined(Q_OS_HARMONY)
737 index = QNetworkInformationBackend::PluginNamesOhosIndex;
738#elif defined(Q_OS_LINUX)
739 index = QNetworkInformationBackend::PluginNamesLinuxIndex;
741 if (index != -1 && loadBackendByName(QNetworkInformationBackend::PluginNames[index]))
745 if (loadBackendByFeatures(Feature::Reachability))
749 return loadBackendByName(u"dummy");
753
754
755
756
757
758
759
760
761
762
763bool QNetworkInformation::loadBackendByName(QStringView backend)
765 if (backend == u"dummy")
766 return QNetworkInformationPrivate::createDummy() !=
nullptr;
768 auto loadedBackend = QNetworkInformationPrivate::create(backend);
769 return loadedBackend && loadedBackend->backendName().compare(backend, Qt::CaseInsensitive) == 0;
772#if QT_DEPRECATED_SINCE(6
,4
)
774
775
776
777
778bool QNetworkInformation::load(QStringView backend)
780 return loadBackendByName(backend);
785
786
787
788
789
790
791
792
793bool QNetworkInformation::loadBackendByFeatures(Features features)
795 auto loadedBackend = QNetworkInformationPrivate::create(features);
796 return loadedBackend && loadedBackend->supports(features);
799#if QT_DEPRECATED_SINCE(6
,4
)
801
802
803
804
805bool QNetworkInformation::load(Features features)
807 return loadBackendByFeatures(features);
812
813
814QStringList QNetworkInformation::availableBackends()
816 return QNetworkInformationPrivate::backendNames();
820
821
822
823
824
825
826QNetworkInformation *QNetworkInformation::instance()
828 return QNetworkInformationPrivate::instance();
833#include "moc_qnetworkinformation.cpp"
834#include "moc_qnetworkinformation_p.cpp"
835#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 } }))