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>
23using namespace Qt::StringLiterals;
25Q_DECLARE_LOGGING_CATEGORY(lcNetInfo)
26Q_LOGGING_CATEGORY(lcNetInfo,
"qt.network.info");
30 void operator()(QNetworkInformation *information) {
delete information; }
34 (QNetworkInformationBackendFactory_iid,
35 QStringLiteral(
"/networkinformation")))
37struct QStaticNetworkInformationDataHolder
40 std::unique_ptr<QNetworkInformation, QNetworkInformationDeleter> instanceHolder;
41 QList<QNetworkInformationBackendFactory *> factories;
47 if (!dataHolder.exists())
49 QMutexLocker locker(&dataHolder->instanceMutex);
50 QNetworkInformation *instance = dataHolder->instanceHolder.get();
54 dataHolder->instanceHolder.reset();
69 Q_DECLARE_PUBLIC(QNetworkInformation)
82 QMutexLocker locker(&dataHolder->instanceMutex);
83 return dataHolder->instanceHolder.get();
86 static void addToList(QNetworkInformationBackendFactory *factory);
90 static bool initializeList();
92 std::unique_ptr<QNetworkInformationBackend> backend;
101 Q_CONSTINIT
static QBasicMutex mutex;
102 QMutexLocker initLocker(&mutex);
104#if QT_CONFIG(library)
109 while (qniLoader->instance(index))
114 const auto featuresNameOrder = [](QNetworkInformationBackendFactory *a,
115 QNetworkInformationBackendFactory *b) {
118 auto aFeaturesSupported = qPopulationCount(
unsigned(a->featuresSupported()));
119 auto bFeaturesSupported = qPopulationCount(
unsigned(b->featuresSupported()));
120 return aFeaturesSupported > bFeaturesSupported
121 || (aFeaturesSupported == bFeaturesSupported
122 && a->name().compare(b->name(), Qt::CaseInsensitive) < 0);
124 QMutexLocker instanceLocker(&dataHolder->instanceMutex);
125 std::sort(dataHolder->factories.begin(), dataHolder->factories.end(), featuresNameOrder);
127 return !dataHolder->factories.isEmpty();
135 QMutexLocker locker(&dataHolder->instanceMutex);
136 dataHolder->factories.append(factory);
142 if (!dataHolder.exists())
144 QMutexLocker locker(&dataHolder->instanceMutex);
145 dataHolder->factories.removeAll(factory);
152 if (!initializeList())
155 QMutexLocker locker(&dataHolder->instanceMutex);
156 const QList copy = dataHolder->factories;
160 result.reserve(copy.size());
161 for (
const auto *factory : copy)
162 result << factory->name();
173 qDebug().nospace() <<
"create() called with name=\"" << name
174 <<
"\". instanceHolder initialized? " << !!dataHolder->instanceHolder;
176 if (!initializeList()) {
178 qDebug(
"Failed to initialize list, returning.");
183 QMutexLocker locker(&dataHolder->instanceMutex);
184 if (dataHolder->instanceHolder)
185 return dataHolder->instanceHolder.get();
188 const auto nameMatches = [name](QNetworkInformationBackendFactory *factory) {
189 return factory->name().compare(name, Qt::CaseInsensitive) == 0;
191 auto it = std::find_if(dataHolder->factories.cbegin(), dataHolder->factories.cend(),
193 if (it == dataHolder->factories.cend()) {
195 if (dataHolder->factories.isEmpty()) {
196 qDebug(
"No plugins available");
199 listNames.reserve(8 * dataHolder->factories.count());
200 for (
const auto *factory : std::as_const(dataHolder->factories))
201 listNames += factory->name() +
", "_L1;
203 qDebug().nospace() <<
"Couldn't find " << name <<
" in list with names: { "
204 << listNames <<
" }";
210 qDebug() <<
"Creating instance using loader named " << (*it)->name();
212 QNetworkInformationBackend *backend = (*it)->create((*it)->featuresSupported());
215 dataHolder->instanceHolder.reset(
new QNetworkInformation(backend));
216 Q_ASSERT(name.isEmpty()
217 || dataHolder->instanceHolder->backendName().compare(name, Qt::CaseInsensitive) == 0);
218 return dataHolder->instanceHolder.get();
226 qDebug().nospace() <<
"create() called with features=\"" << features
227 <<
"\". instanceHolder initialized? " << !!dataHolder->instanceHolder;
232 if (!initializeList()) {
234 qDebug(
"Failed to initialize list, returning.");
238 QMutexLocker locker(&dataHolder->instanceMutex);
239 if (dataHolder->instanceHolder)
240 return dataHolder->instanceHolder.get();
242 const auto supportsRequestedFeatures = [features](QNetworkInformationBackendFactory *factory) {
243 return factory && factory->featuresSupported().testFlags(features);
246 for (
auto it = dataHolder->factories.cbegin(), end = dataHolder->factories.cend(); it != end;
248 it =
std::find_if(it, end, supportsRequestedFeatures);
251 if (dataHolder->factories.isEmpty()) {
252 qDebug(
"No plugins available");
255 names.reserve(dataHolder->factories.count());
256 for (
const auto *factory : std::as_const(dataHolder->factories))
257 names += factory->name();
258 qDebug() <<
"None of the following backends has all the requested features:"
259 << names << features;
265 qDebug() <<
"Creating instance using loader named" << (*it)->name();
267 if (QNetworkInformationBackend *backend = (*it)->create(features)) {
268 dataHolder->instanceHolder.reset(
new QNetworkInformation(backend));
269 Q_ASSERT(dataHolder->instanceHolder->supports(features));
270 return dataHolder->instanceHolder.get();
274 qDebug() <<
"The factory returned a nullptr";
279 qDebug() <<
"Couldn't find/create an appropriate backend.";
289 QMutexLocker locker(&dataHolder->instanceMutex);
290 if (dataHolder->instanceHolder)
291 return dataHolder->instanceHolder.get();
294 dataHolder->instanceHolder.reset(
new QNetworkInformation(backend));
295 return dataHolder->instanceHolder.get();
299
300
301
302
303
304
305
306
307
308
309
310
313
314
315
316QNetworkInformationBackend::~QNetworkInformationBackend() =
default;
319
320
321
322
323
326
327
328
329
330
333
334
335
336
337
338
339
342
343
344
345
346
347
348
351
352
353
354
355
356
357
358
359
360
361
364
365
366
367QNetworkInformationBackendFactory::QNetworkInformationBackendFactory()
369 QNetworkInformationPrivate::addToList(
this);
373
374
375
376QNetworkInformationBackendFactory::~QNetworkInformationBackendFactory()
378 QNetworkInformationPrivate::removeFromList(
this);
382
383
384
385
386
389
390
391
392
393
394
395
398
399
400
401
402
403
404
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
474
475
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
503
504
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
556
557
558QNetworkInformation::QNetworkInformation(QNetworkInformationBackend *backend)
559 : QObject(*(
new QNetworkInformationPrivate(backend)))
561 connect(backend, &QNetworkInformationBackend::reachabilityChanged,
this,
562 &QNetworkInformation::reachabilityChanged);
563 connect(backend, &QNetworkInformationBackend::behindCaptivePortalChanged,
this,
564 &QNetworkInformation::isBehindCaptivePortalChanged);
565 connect(backend, &QNetworkInformationBackend::transportMediumChanged,
this,
566 &QNetworkInformation::transportMediumChanged);
567 connect(backend, &QNetworkInformationBackend::isMeteredChanged,
this,
568 &QNetworkInformation::isMeteredChanged);
570 QThread *main =
nullptr;
572 if (QCoreApplication::instance())
573 main = QCoreApplication::instance()->thread();
575 if (main && thread() != main)
580
581
582QNetworkInformation::~QNetworkInformation() =
default;
585
586
587
588
589
590
591
592
593
594
595
596
598QNetworkInformation::Reachability QNetworkInformation::reachability()
const
600 return d_func()->backend->reachability();
604
605
606
607
608
609
610
611
612
613
614bool QNetworkInformation::isBehindCaptivePortal()
const
616 return d_func()->backend->behindCaptivePortal();
620
621
622
623
624
625
626
627
628
629
630
631QNetworkInformation::TransportMedium QNetworkInformation::transportMedium()
const
633 return d_func()->backend->transportMedium();
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655bool QNetworkInformation::isMetered()
const
657 return d_func()->backend->isMetered();
661
662
663QString QNetworkInformation::backendName()
const
665 return d_func()->backend->name();
669
670
671
672bool QNetworkInformation::supports(Features features)
const
674 return (d_func()->backend->featuresSupported() & features) == features;
678
679
680
681
682QNetworkInformation::Features QNetworkInformation::supportedFeatures()
const
684 return d_func()->backend->featuresSupported();
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
727
728
729bool QNetworkInformation::loadDefaultBackend()
733 index = QNetworkInformationBackend::PluginNamesWindowsIndex;
734#elif defined(Q_OS_DARWIN)
735 index = QNetworkInformationBackend::PluginNamesAppleIndex;
736#elif defined(Q_OS_ANDROID)
737 index = QNetworkInformationBackend::PluginNamesAndroidIndex;
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 } }))