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