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

source code of qtbase/src/network/kernel/qnetworkinformation.cpp