Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qnetworkinformation.cpp
Go to the documentation of this file.
1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5// #define DEBUG_LOADING
6
8#include <QtNetwork/private/qnetworkinformation_p.h>
9#include <QtNetwork/qnetworkinformation.h>
10
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>
16
17#include <algorithm>
18#include <memory>
19
20QT_BEGIN_NAMESPACE
21
22using namespace Qt::StringLiterals;
23
24Q_DECLARE_LOGGING_CATEGORY(lcNetInfo)
25Q_LOGGING_CATEGORY(lcNetInfo, "qt.network.info");
26
28{
29 void operator()(QNetworkInformation *information) { delete information; }
30};
31
32Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, qniLoader,
33 (QNetworkInformationBackendFactory_iid,
34 QStringLiteral("/networkinformation")))
35
36struct QStaticNetworkInformationDataHolder
37{
38 QMutex instanceMutex;
39 std::unique_ptr<QNetworkInformation, QNetworkInformationDeleter> instanceHolder;
40 QList<QNetworkInformationBackendFactory *> factories;
41};
42Q_GLOBAL_STATIC(QStaticNetworkInformationDataHolder, dataHolder);
43
44static void networkInfoCleanup()
45{
46 if (!dataHolder.exists())
47 return;
48 QMutexLocker locker(&dataHolder->instanceMutex);
49 QNetworkInformation *instance = dataHolder->instanceHolder.get();
50 if (!instance)
51 return;
52
53 dataHolder->instanceHolder.reset();
54}
55
58public:
59 QString name() const override { return u"dummy"_s; }
61 {
62 return {};
63 }
64};
65
67{
68 Q_DECLARE_PUBLIC(QNetworkInformation)
69public:
73
75 static QNetworkInformation *create(QStringView name);
78 {
79 if (!dataHolder())
80 return nullptr;
81 QMutexLocker locker(&dataHolder->instanceMutex);
82 return dataHolder->instanceHolder.get();
83 }
85 static void addToList(QNetworkInformationBackendFactory *factory);
86 static void removeFromList(QNetworkInformationBackendFactory *factory);
87
88private:
89 static bool initializeList();
90
91 std::unique_ptr<QNetworkInformationBackend> backend;
92};
93
94bool QNetworkInformationPrivate::initializeList()
95{
96 if (!qniLoader())
97 return false;
98 if (!dataHolder())
99 return false;
100 Q_CONSTINIT static QBasicMutex mutex;
101 QMutexLocker initLocker(&mutex);
102
103#if QT_CONFIG(library)
104 qniLoader->update();
105#endif
106 const int pluginCount = qniLoader->metaData().size();
107 for (int i = 0; i < pluginCount; ++i)
108 qniLoader->instance(i);
109 initLocker.unlock();
110
111 // Now sort the list on number of features available (then name)
112 const auto featuresNameOrder = [](QNetworkInformationBackendFactory *a,
113 QNetworkInformationBackendFactory *b) {
114 if (!a || !b)
115 return a && !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);
121 };
122 QMutexLocker instanceLocker(&dataHolder->instanceMutex);
123 std::sort(dataHolder->factories.begin(), dataHolder->factories.end(), featuresNameOrder);
124
125 return !dataHolder->factories.isEmpty();
126}
127
128void QNetworkInformationPrivate::addToList(QNetworkInformationBackendFactory *factory)
129{
130 // @note: factory is in the base class ctor
131 if (!dataHolder())
132 return;
133 QMutexLocker locker(&dataHolder->instanceMutex);
134 dataHolder->factories.append(factory);
135}
136
137void QNetworkInformationPrivate::removeFromList(QNetworkInformationBackendFactory *factory)
138{
139 // @note: factory is in the base class dtor
140 if (!dataHolder.exists())
141 return;
142 QMutexLocker locker(&dataHolder->instanceMutex);
143 dataHolder->factories.removeAll(factory);
144}
145
146QStringList QNetworkInformationPrivate::backendNames()
147{
148 if (!dataHolder())
149 return {};
150 if (!initializeList())
151 return {};
152
153 QMutexLocker locker(&dataHolder->instanceMutex);
154 const QList copy = dataHolder->factories;
155 locker.unlock();
156
157 QStringList result;
158 result.reserve(copy.size());
159 for (const auto *factory : copy)
160 result << factory->name();
161 return result;
162}
163
164QNetworkInformation *QNetworkInformationPrivate::create(QStringView name)
165{
166 if (name.isEmpty())
167 return nullptr;
168 if (!dataHolder())
169 return nullptr;
170#ifdef DEBUG_LOADING
171 qDebug().nospace() << "create() called with name=\"" << name
172 << "\". instanceHolder initialized? " << !!dataHolder->instanceHolder;
173#endif
174 if (!initializeList()) {
175#ifdef DEBUG_LOADING
176 qDebug("Failed to initialize list, returning.");
177#endif
178 return nullptr;
179 }
180
181 QMutexLocker locker(&dataHolder->instanceMutex);
182 if (dataHolder->instanceHolder)
183 return dataHolder->instanceHolder.get();
184
185
186 const auto nameMatches = [name](QNetworkInformationBackendFactory *factory) {
187 return factory->name().compare(name, Qt::CaseInsensitive) == 0;
188 };
189 auto it = std::find_if(dataHolder->factories.cbegin(), dataHolder->factories.cend(),
190 nameMatches);
191 if (it == dataHolder->factories.cend()) {
192#ifdef DEBUG_LOADING
193 if (dataHolder->factories.isEmpty()) {
194 qDebug("No plugins available");
195 } else {
196 QString listNames;
197 listNames.reserve(8 * dataHolder->factories.count());
198 for (const auto *factory : std::as_const(dataHolder->factories))
199 listNames += factory->name() + ", "_L1;
200 listNames.chop(2);
201 qDebug().nospace() << "Couldn't find " << name << " in list with names: { "
202 << listNames << " }";
203 }
204#endif
205 return nullptr;
206 }
207#ifdef DEBUG_LOADING
208 qDebug() << "Creating instance using loader named " << (*it)->name();
209#endif
210 QNetworkInformationBackend *backend = (*it)->create((*it)->featuresSupported());
211 if (!backend)
212 return nullptr;
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();
217}
218
219QNetworkInformation *QNetworkInformationPrivate::create(QNetworkInformation::Features features)
220{
221 if (!dataHolder())
222 return nullptr;
223#ifdef DEBUG_LOADING
224 qDebug().nospace() << "create() called with features=\"" << features
225 << "\". instanceHolder initialized? " << !!dataHolder->instanceHolder;
226#endif
227 if (features == 0)
228 return nullptr;
229
230 if (!initializeList()) {
231#ifdef DEBUG_LOADING
232 qDebug("Failed to initialize list, returning.");
233#endif
234 return nullptr;
235 }
236 QMutexLocker locker(&dataHolder->instanceMutex);
237 if (dataHolder->instanceHolder)
238 return dataHolder->instanceHolder.get();
239
240 const auto supportsRequestedFeatures = [features](QNetworkInformationBackendFactory *factory) {
241 return factory && factory->featuresSupported().testFlags(features);
242 };
243
244 for (auto it = dataHolder->factories.cbegin(), end = dataHolder->factories.cend(); it != end;
245 ++it) {
246 it = std::find_if(it, end, supportsRequestedFeatures);
247 if (it == end) {
248#ifdef DEBUG_LOADING
249 if (dataHolder->factories.isEmpty()) {
250 qDebug("No plugins available");
251 } else {
252 QStringList names;
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;
258 }
259#endif
260 break;
261 }
262#ifdef DEBUG_LOADING
263 qDebug() << "Creating instance using loader named" << (*it)->name();
264#endif
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();
269 }
270#ifdef DEBUG_LOADING
271 else {
272 qDebug() << "The factory returned a nullptr";
273 }
274#endif
275 }
276#ifdef DEBUG_LOADING
277 qDebug() << "Couldn't find/create an appropriate backend.";
278#endif
279 return nullptr;
280}
281
282QNetworkInformation *QNetworkInformationPrivate::createDummy()
283{
284 if (!dataHolder())
285 return nullptr;
286
287 QMutexLocker locker(&dataHolder->instanceMutex);
288 if (dataHolder->instanceHolder)
289 return dataHolder->instanceHolder.get();
290
291 QNetworkInformationBackend *backend = new QNetworkInformationDummyBackend;
292 dataHolder->instanceHolder.reset(new QNetworkInformation(backend));
293 return dataHolder->instanceHolder.get();
294}
295
296/*!
297 \class QNetworkInformationBackend
298 \internal (Semi-private)
299 \brief QNetworkInformationBackend provides the interface with
300 which QNetworkInformation does all of its actual work.
301
302 Deriving from and implementing this class makes it a candidate
303 for use with QNetworkInformation. The derived class must, on
304 updates, call setters in the QNetworkInformationBackend which
305 will update the values and emit signals if the value has changed.
306
307 \sa QNetworkInformationBackendFactory
308*/
309
310/*!
311 \internal
312 Destroys base backend class.
313*/
314QNetworkInformationBackend::~QNetworkInformationBackend() = default;
315
316/*!
317 \fn QNetworkInformationBackend::name()
318
319 Backend name, return the same in
320 QNetworkInformationBackendFactory::name().
321*/
322
323/*!
324 \fn QNetworkInformation::Features QNetworkInformationBackend::featuresSupported()
325
326 Features supported, return the same in
327 QNetworkInformationBackendFactory::featuresSupported().
328*/
329
330/*!
331 \fn void QNetworkInformationBackend::reachabilityChanged(NetworkInformation::Reachability reachability)
332
333 You should not emit this signal manually, call setReachability()
334 instead which will emit this signal when the value changes.
335
336 \sa setReachability
337*/
338
339/*!
340 \fn void QNetworkInformationBackend::setReachability(QNetworkInformation::Reachability reachability)
341
342 Call this when reachability has changed. It will automatically
343 emit reachabilityChanged().
344
345 \sa setReachability
346*/
347
348/*!
349 \class QNetworkInformationBackendFactory
350 \internal (Semi-private)
351 \brief QNetworkInformationBackendFactory provides the interface
352 for creating instances of QNetworkInformationBackend.
353
354 Deriving from and implementing this class will let you register
355 your plugin with QNetworkInformation. It must provide some basic
356 information for querying information about the backend, and must
357 also create the backend if requested. If some pre-conditions for
358 the backend is not met it must return \nullptr.
359*/
360
361/*!
362 \internal
363 Adds the factory to an internal list.
364*/
365QNetworkInformationBackendFactory::QNetworkInformationBackendFactory()
366{
367 QNetworkInformationPrivate::addToList(this);
368}
369
370/*!
371 \internal
372 Removes the factory from an internal list.
373*/
374QNetworkInformationBackendFactory::~QNetworkInformationBackendFactory()
375{
376 QNetworkInformationPrivate::removeFromList(this);
377}
378
379/*!
380 \fn QString QNetworkInformationBackendFactory::name()
381
382 Backend name, return the same in
383 QNetworkInformationBackend::name().
384*/
385
386/*!
387 \fn QNetworkInformation::Features QNetworkInformationBackendFactory::featuresSupported()
388
389 Features supported, return the same in
390 QNetworkInformationBackend::featuresSupported().
391 The factory should not promise support for features that wouldn't
392 be available after creating the backend.
393*/
394
395/*!
396 \fn QNetworkInformationBackend *QNetworkInformationBackendFactory::create()
397
398 Create and return an instance of QNetworkInformationBackend. It
399 will be deallocated by QNetworkInformation on shutdown. If some
400 precondition is not met, meaning the backend would not function
401 correctly, then you must return \nullptr.
402*/
403
404/*!
405 \class QNetworkInformation
406 \inmodule QtNetwork
407 \since 6.1
408 \brief QNetworkInformation exposes various network information
409 through native backends.
410
411 QNetworkInformation provides a cross-platform interface to
412 network-related information through plugins.
413
414 Various plugins can have various functionality supported, and so
415 you can load plugins based on which features are needed.
416
417 In most cases, the recommended approach is to load the
418 platform-specific backend by calling loadDefaultBackend(). This will
419 automatically select the most appropriate backend available on the
420 current platform and is suitable for the majority of applications.
421
422 \snippet code/src_network_kernel_qnetworkinformation.cpp file
423
424 For more advanced uses cases, developers may prefer to load a backend
425 based on specific capabilities or preferences. loadBackendByFeatures()
426 allows selecting a backend that supports a specific set of features,
427 such as reporting the transport mediom or signal strength. Alternatively,
428 loadBackendByName() allows loading a plugin by its name, which can include
429 platform-specific or custom backend implementations.
430
431 QNetworkInformation is a singleton and stays alive from the first
432 successful load until destruction of the QCoreApplication object.
433 If you destroy and re-create the QCoreApplication object you must load it
434 again to reinitialize the plugin.
435
436 \note Because the class is a singleton while also relying on
437 QCoreApplication, QNetworkInformation should always first be loaded
438 in the same thread as the QCoreApplication object. This is because the
439 object will also be destroyed in this thread, and various backend-specific
440 components may rely on being destroyed in the same thread as it is created.
441
442 One possible use case for QNetworkInformation is to monitor network
443 connectivity status. reachability() provides an indication of whether the
444 system is considered online, based on information reported by the
445 underlying operating system or plugin. However, this information may not
446 always be accurate. For example, on Windows, the online check may rely on
447 connectivity to a Microsoft-owned server; if that server is unreachable
448 (e.g., due to firewall rules), the system may incorrectly report that it is
449 offline. As such, reachability() should not be used as a definitive
450 pre-check before attempting a network connection, but rather as a general
451 signal of connectivity state.
452
453 To use reachability() effectively, the application must also understand
454 what kind of destination it is trying to reach. For example, if the target
455 is a local IP address, then Reachability::Local or Reachability::Site may
456 be sufficient. If the destination is on the public internet, then
457 Reachability::Online is required. Without this context, interpretring the
458 reported reachability may lead to incorrect assumptions about actual
459 network access.
460
461 \warning Only Linux and Windows provide support for the finer-grained
462 Reachability::Site and Reachability::Local options. On Android and Apple
463 platforms reachability() is limited to reporting only Online, Offline or
464 Unknown. Therefore, any logic that relies on detecting Local or Site level
465 connectivity must include appropriate platform checks or fallbacks.
466
467 \snippet code/src_network_kernel_qnetworkinformation_reachability.cpp 0
468 \dots
469 \snippet code/src_network_kernel_qnetworkinformation_reachability.cpp 1
470 \dots
471
472 \sa QNetworkInformation::Feature
473*/
474
475/*!
476 \enum QNetworkInformation::Feature
477
478 Lists all of the features that a plugin may currently support.
479 This can be used in QNetworkInformation::loadBackendByFeatures().
480
481 \value Reachability
482 If the plugin supports this feature then the \c reachability property
483 will provide useful results. Otherwise it will always return
484 \c{Reachability::Unknown}.
485 See also QNetworkInformation::Reachability.
486
487 \value CaptivePortal
488 If the plugin supports this feature then the \c isBehindCaptivePortal
489 property will provide useful results. Otherwise it will always return
490 \c{false}.
491
492 \value TransportMedium
493 If the plugin supports this feature then the \c transportMedium
494 property will provide useful results. Otherwise it will always return
495 \c{TransportMedium::Unknown}.
496 See also QNetworkInformation::TransportMedium.
497
498 \value Metered
499 If the plugin supports this feature then the \c isMetered
500 property will provide useful results. Otherwise it will always return
501 \c{false}.
502*/
503
504/*!
505 \enum QNetworkInformation::Reachability
506
507 \value Unknown
508 If this value is returned then we may be connected but the OS
509 has still not confirmed full connectivity, or this feature
510 is not supported.
511 \value Disconnected
512 Indicates that the system may have no connectivity at all.
513 \value Local
514 Indicates that the system is connected to a network, but it
515 might only be able to access devices on the local network.
516 \value Site
517 Indicates that the system is connected to a network, but it
518 might only be able to access devices on the local subnet or an
519 intranet.
520 \value Online
521 Indicates that the system is connected to a network and
522 able to access the Internet.
523
524 \sa QNetworkInformation::reachability
525*/
526
527/*!
528 \enum QNetworkInformation::TransportMedium
529 \since 6.3
530
531 Lists the currently recognized media with which one can connect to the
532 internet.
533
534 \value Unknown
535 Returned if either the OS reports no active medium, the active medium is
536 not recognized by Qt, or the TransportMedium feature is not supported.
537 \value Ethernet
538 Indicates that the currently active connection is using ethernet.
539 Note: This value may also be returned when Windows is connected to a
540 Bluetooth personal area network.
541 \value Cellular
542 Indicates that the currently active connection is using a cellular
543 network.
544 \value WiFi
545 Indicates that the currently active connection is using Wi-Fi.
546 \value Bluetooth
547 Indicates that the currently active connection is connected using
548 Bluetooth.
549
550 \sa QNetworkInformation::transportMedium
551*/
552
553/*!
554 \internal ctor
555*/
556QNetworkInformation::QNetworkInformation(QNetworkInformationBackend *backend)
557 : QObject(*(new QNetworkInformationPrivate(backend)))
558{
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);
567
568 QThread *main = nullptr;
569
570 if (QCoreApplication::instance())
571 main = QCoreApplication::instance()->thread();
572
573 if (main && thread() != main)
574 moveToThread(main);
575}
576
577/*!
578 \internal dtor
579*/
580QNetworkInformation::~QNetworkInformation() = default;
581
582/*!
583 \property QNetworkInformation::reachability
584 \brief The current state of the system's network connectivity.
585
586 Indicates the level of connectivity that can be expected. Do note
587 that this is only based on what the plugin/operating system
588 reports. In certain scenarios this is known to be wrong. For
589 example, on Windows the 'Online' check, by default, is performed
590 by Windows connecting to a Microsoft-owned server. If this server
591 is for any reason blocked then it will assume it does not have
592 Online reachability. Because of this you should not use this as a
593 pre-check before attempting to make a connection.
594*/
595
596QNetworkInformation::Reachability QNetworkInformation::reachability() const
597{
598 return d_func()->backend->reachability();
599}
600
601/*!
602 \property QNetworkInformation::isBehindCaptivePortal
603 \brief Lets you know if the user's device is behind a captive portal.
604 \since 6.2
605
606 This property indicates if the user's device is currently known to be
607 behind a captive portal. This functionality relies on the operating system's
608 detection of captive portals and is not supported on systems that don't
609 report this. On systems where this is not supported this will always return
610 \c{false}.
611*/
612bool QNetworkInformation::isBehindCaptivePortal() const
613{
614 return d_func()->backend->behindCaptivePortal();
615}
616
617/*!
618 \property QNetworkInformation::transportMedium
619 \brief The currently active transport medium for the application
620 \since 6.3
621
622 This property returns the currently active transport medium for the
623 application, on operating systems where such information is available.
624
625 When the current transport medium changes a signal is emitted, this can,
626 for instance, occur when a user leaves the range of a WiFi network, unplugs
627 their ethernet cable or enables Airplane mode.
628*/
629QNetworkInformation::TransportMedium QNetworkInformation::transportMedium() const
630{
631 return d_func()->backend->transportMedium();
632}
633
634/*!
635 \property QNetworkInformation::isMetered
636 \brief Check if the current connection is metered
637 \since 6.3
638
639 This property returns whether the current connection is (known to be)
640 metered or not. You can use this as a guiding factor to decide whether your
641 application should perform certain network requests or uploads.
642 For instance, you may not want to upload logs or diagnostics while this
643 property is \c true.
644
645 \snippet code/src_network_kernel_qnetworkinformation_metering.cpp 0
646 \dots
647 \snippet code/src_network_kernel_qnetworkinformation_metering.cpp 1
648 \dots
649 \snippet code/src_network_kernel_qnetworkinformation_metering.cpp 2
650 \dots
651 \snippet code/src_network_kernel_qnetworkinformation_metering.cpp 3
652*/
653bool QNetworkInformation::isMetered() const
654{
655 return d_func()->backend->isMetered();
656}
657
658/*!
659 Returns the name of the currently loaded backend.
660*/
661QString QNetworkInformation::backendName() const
662{
663 return d_func()->backend->name();
664}
665
666/*!
667 Returns \c true if the currently loaded backend supports
668 \a features.
669*/
670bool QNetworkInformation::supports(Features features) const
671{
672 return (d_func()->backend->featuresSupported() & features) == features;
673}
674
675/*!
676 \since 6.3
677
678 Returns all the supported features of the current backend.
679*/
680QNetworkInformation::Features QNetworkInformation::supportedFeatures() const
681{
682 return d_func()->backend->featuresSupported();
683}
684
685/*!
686 \since 6.3
687
688 Attempts to load the platform-default backend.
689
690 \note Starting with 6.7 this tries to load any backend that supports
691 \l{QNetworkInformation::Feature::Reachability}{Reachability} if the
692 platform-default backend is not available or fails to load.
693 If this also fails it will fall back to a backend that only returns
694 the default values for all properties.
695
696 This platform-to-plugin mapping is as follows:
697
698 \table
699 \header
700 \li Platform
701 \li Plugin-name
702 \row
703 \li Windows
704 \li networklistmanager
705 \row
706 \li Apple (macOS/iOS)
707 \li applenetworkinformation
708 \row
709 \li Android
710 \li android
711 \row
712 \li Linux
713 \li networkmanager
714 \endtable
715
716 This function is provided for convenience where the logic earlier
717 is good enough. If you require a specific plugin then you should call
718 loadBackendByName() or loadBackendByFeatures() directly instead.
719
720 Determines a suitable backend to load and returns \c true if this backend
721 is already loaded or on successful loading of it. Returns \c false if any
722 other backend has already been loaded, or if loading of the selected
723 backend fails.
724
725 \sa instance(), loadBackendByName(), loadBackendByFeatures()
726*/
727bool QNetworkInformation::loadDefaultBackend()
728{
729 int index = -1;
730#ifdef Q_OS_WIN
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;
740#endif
741 if (index != -1 && loadBackendByName(QNetworkInformationBackend::PluginNames[index]))
742 return true;
743 // We assume reachability is the most commonly wanted feature, and try to
744 // load the backend that advertises the most features including that:
745 if (loadBackendByFeatures(Feature::Reachability))
746 return true;
747
748 // Fall back to the dummy backend
749 return loadBackendByName(u"dummy");
750}
751
752/*!
753 \since 6.4
754
755 Attempts to load a backend whose name matches \a backend
756 (case insensitively).
757
758 Returns \c true if it managed to load the requested backend or
759 if it was already loaded. Returns \c false otherwise.
760
761 \sa instance
762*/
763bool QNetworkInformation::loadBackendByName(QStringView backend)
764{
765 if (backend == u"dummy")
766 return QNetworkInformationPrivate::createDummy() != nullptr;
767
768 auto loadedBackend = QNetworkInformationPrivate::create(backend);
769 return loadedBackend && loadedBackend->backendName().compare(backend, Qt::CaseInsensitive) == 0;
770}
771
772#if QT_DEPRECATED_SINCE(6,4)
773/*!
774 \deprecated [6.4] Use loadBackendByName() instead.
775
776 \sa loadBackendByName(), loadDefaultBackend(), loadBackendByFeatures()
777*/
778bool QNetworkInformation::load(QStringView backend)
779{
780 return loadBackendByName(backend);
781}
782#endif // QT_DEPRECATED_SINCE(6,4)
783
784/*!
785 \since 6.4
786 Load a backend which supports \a features.
787
788 Returns \c true if it managed to load the requested backend or
789 if it was already loaded. Returns \c false otherwise.
790
791 \sa instance
792*/
793bool QNetworkInformation::loadBackendByFeatures(Features features)
794{
795 auto loadedBackend = QNetworkInformationPrivate::create(features);
796 return loadedBackend && loadedBackend->supports(features);
797}
798
799#if QT_DEPRECATED_SINCE(6,4)
800/*!
801 \deprecated [6.4] Use loadBackendByFeatures() instead.
802
803 \sa loadBackendByName(), loadDefaultBackend(), loadBackendByFeatures()
804*/
805bool QNetworkInformation::load(Features features)
806{
807 return loadBackendByFeatures(features);
808}
809#endif // QT_DEPRECATED_SINCE(6,4)
810
811/*!
812 Returns a list of the names of all currently available backends.
813*/
814QStringList QNetworkInformation::availableBackends()
815{
816 return QNetworkInformationPrivate::backendNames();
817}
818
819/*!
820 Returns a pointer to the instance of the QNetworkInformation,
821 if any. If this method is called before a backend is loaded,
822 it returns a null pointer.
823
824 \sa loadBackendByName(), loadDefaultBackend(), loadBackendByFeatures()
825*/
826QNetworkInformation *QNetworkInformation::instance()
827{
828 return QNetworkInformationPrivate::instance();
829}
830
831QT_END_NAMESPACE
832
833#include "moc_qnetworkinformation.cpp"
834#include "moc_qnetworkinformation_p.cpp"
835#include "qnetworkinformation.moc"
static QNetworkInformation * create(QStringView name)
static QNetworkInformation * createDummy()
static void addToList(QNetworkInformationBackendFactory *factory)
static QNetworkInformation * instance()
static void removeFromList(QNetworkInformationBackendFactory *factory)
static void networkInfoCleanup()
Q_GLOBAL_STATIC(QStaticNetworkInformationDataHolder, dataHolder)
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 } }))
void operator()(QNetworkInformation *information)