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 | |
4 | // #define DEBUG_LOADING |
5 | |
6 | #include "qnetworkinformation.h" |
7 | #include <QtNetwork/private/qnetworkinformation_p.h> |
8 | #include <QtNetwork/qnetworkinformation.h> |
9 | |
10 | #include <QtCore/private/qobject_p.h> |
11 | #include <QtCore/qcoreapplication.h> |
12 | #include <QtCore/qmutex.h> |
13 | #include <QtCore/qthread.h> |
14 | #include <QtCore/private/qfactoryloader_p.h> |
15 | |
16 | #include <algorithm> |
17 | #include <memory> |
18 | #include <mutex> |
19 | |
20 | QT_BEGIN_NAMESPACE |
21 | Q_DECLARE_LOGGING_CATEGORY(lcNetInfo) |
22 | Q_LOGGING_CATEGORY(lcNetInfo, "qt.network.info"); |
23 | |
24 | struct QNetworkInformationDeleter |
25 | { |
26 | void operator()(QNetworkInformation *information) { delete information; } |
27 | }; |
28 | |
29 | Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, qniLoader, |
30 | (QNetworkInformationBackendFactory_iid, |
31 | QStringLiteral("/networkinformation"))) |
32 | |
33 | struct QStaticNetworkInformationDataHolder |
34 | { |
35 | QMutex instanceMutex; |
36 | std::unique_ptr<QNetworkInformation, QNetworkInformationDeleter> instanceHolder; |
37 | QList<QNetworkInformationBackendFactory *> factories; |
38 | }; |
39 | Q_GLOBAL_STATIC(QStaticNetworkInformationDataHolder, dataHolder); |
40 | |
41 | static void networkInfoCleanup() |
42 | { |
43 | if (!dataHolder.exists()) |
44 | return; |
45 | QMutexLocker locker(&dataHolder->instanceMutex); |
46 | QNetworkInformation *instance = dataHolder->instanceHolder.get(); |
47 | if (!instance) |
48 | return; |
49 | |
50 | dataHolder->instanceHolder.reset(); |
51 | } |
52 | |
53 | using namespace Qt::Literals::StringLiterals; |
54 | |
55 | class QNetworkInformationDummyBackend : public QNetworkInformationBackend { |
56 | Q_OBJECT |
57 | public: |
58 | QString name() const override { return u"dummy"_s; } |
59 | QNetworkInformation::Features featuresSupported() const override |
60 | { |
61 | return {}; |
62 | } |
63 | }; |
64 | |
65 | class QNetworkInformationPrivate : public QObjectPrivate |
66 | { |
67 | Q_DECLARE_PUBLIC(QNetworkInformation) |
68 | public: |
69 | QNetworkInformationPrivate(QNetworkInformationBackend *backend) : backend(backend) { |
70 | qAddPostRoutine(&networkInfoCleanup); |
71 | } |
72 | |
73 | static QNetworkInformation *create(QNetworkInformation::Features features); |
74 | static QNetworkInformation *create(QStringView name); |
75 | static QNetworkInformation *createDummy(); |
76 | static QNetworkInformation *instance() |
77 | { |
78 | if (!dataHolder()) |
79 | return nullptr; |
80 | QMutexLocker locker(&dataHolder->instanceMutex); |
81 | return dataHolder->instanceHolder.get(); |
82 | } |
83 | static QStringList backendNames(); |
84 | static void addToList(QNetworkInformationBackendFactory *factory); |
85 | static void removeFromList(QNetworkInformationBackendFactory *factory); |
86 | |
87 | private: |
88 | static bool initializeList(); |
89 | |
90 | std::unique_ptr<QNetworkInformationBackend> backend; |
91 | }; |
92 | |
93 | bool QNetworkInformationPrivate::initializeList() |
94 | { |
95 | if (!qniLoader()) |
96 | return false; |
97 | if (!dataHolder()) |
98 | return false; |
99 | Q_CONSTINIT static QBasicMutex mutex; |
100 | QMutexLocker initLocker(&mutex); |
101 | |
102 | #if QT_CONFIG(library) |
103 | qniLoader->update(); |
104 | #endif |
105 | // Instantiates the plugins (and registers the factories) |
106 | int index = 0; |
107 | while (qniLoader->instance(index)) |
108 | ++index; |
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(v: unsigned(a->featuresSupported())); |
117 | auto bFeaturesSupported = qPopulationCount(v: unsigned(b->featuresSupported())); |
118 | return aFeaturesSupported > bFeaturesSupported |
119 | || (aFeaturesSupported == bFeaturesSupported |
120 | && a->name().compare(s: b->name(), cs: Qt::CaseInsensitive) < 0); |
121 | }; |
122 | QMutexLocker instanceLocker(&dataHolder->instanceMutex); |
123 | std::sort(first: dataHolder->factories.begin(), last: dataHolder->factories.end(), comp: featuresNameOrder); |
124 | |
125 | return !dataHolder->factories.isEmpty(); |
126 | } |
127 | |
128 | void 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(t: factory); |
135 | } |
136 | |
137 | void 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(t: factory); |
144 | } |
145 | |
146 | QStringList 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(asize: copy.size()); |
159 | for (const auto *factory : copy) |
160 | result << factory->name(); |
161 | return result; |
162 | } |
163 | |
164 | QNetworkInformation *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(s: name, cs: Qt::CaseInsensitive) == 0; |
188 | }; |
189 | auto it = std::find_if(first: dataHolder->factories.cbegin(), last: dataHolder->factories.cend(), |
190 | pred: 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(requiredFeatures: (*it)->featuresSupported()); |
211 | if (!backend) |
212 | return nullptr; |
213 | dataHolder->instanceHolder.reset(p: new QNetworkInformation(backend)); |
214 | Q_ASSERT(name.isEmpty() |
215 | || dataHolder->instanceHolder->backendName().compare(name, Qt::CaseInsensitive) == 0); |
216 | return dataHolder->instanceHolder.get(); |
217 | } |
218 | |
219 | QNetworkInformation *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(flags: features); |
242 | }; |
243 | |
244 | for (auto it = dataHolder->factories.cbegin(), end = dataHolder->factories.cend(); it != end; |
245 | ++it) { |
246 | it = std::find_if(first: it, last: end, pred: 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(requiredFeatures: features)) { |
266 | dataHolder->instanceHolder.reset(p: 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 | |
282 | QNetworkInformation *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(p: 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 | */ |
314 | QNetworkInformationBackend::~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 | */ |
365 | QNetworkInformationBackendFactory::QNetworkInformationBackendFactory() |
366 | { |
367 | QNetworkInformationPrivate::addToList(factory: this); |
368 | } |
369 | |
370 | /*! |
371 | \internal |
372 | Removes the factory from an internal list. |
373 | */ |
374 | QNetworkInformationBackendFactory::~QNetworkInformationBackendFactory() |
375 | { |
376 | QNetworkInformationPrivate::removeFromList(factory: 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 | QNetworkInformation is a singleton and stays alive from the first |
418 | successful load() until destruction of the QCoreApplication object. |
419 | If you destroy and re-create the QCoreApplication object you must call |
420 | load() again. |
421 | |
422 | \sa QNetworkInformation::Feature |
423 | */ |
424 | |
425 | /*! |
426 | \enum QNetworkInformation::Feature |
427 | |
428 | Lists all of the features that a plugin may currently support. |
429 | This can be used in QNetworkInformation::load(). |
430 | |
431 | \value Reachability |
432 | If the plugin supports this feature then the \c reachability property |
433 | will provide useful results. Otherwise it will always return |
434 | \c{Reachability::Unknown}. |
435 | See also QNetworkInformation::Reachability. |
436 | |
437 | \value CaptivePortal |
438 | If the plugin supports this feature then the \c isBehindCaptivePortal |
439 | property will provide useful results. Otherwise it will always return |
440 | \c{false}. |
441 | |
442 | \value TransportMedium |
443 | If the plugin supports this feature then the \c transportMedium |
444 | property will provide useful results. Otherwise it will always return |
445 | \c{TransportMedium::Unknown}. |
446 | See also QNetworkInformation::TransportMedium. |
447 | |
448 | \value Metered |
449 | If the plugin supports this feature then the \c isMetered |
450 | property will provide useful results. Otherwise it will always return |
451 | \c{false}. |
452 | */ |
453 | |
454 | /*! |
455 | \enum QNetworkInformation::Reachability |
456 | |
457 | \value Unknown |
458 | If this value is returned then we may be connected but the OS |
459 | has still not confirmed full connectivity, or this feature |
460 | is not supported. |
461 | \value Disconnected |
462 | Indicates that the system may have no connectivity at all. |
463 | \value Local |
464 | Indicates that the system is connected to a network, but it |
465 | might only be able to access devices on the local network. |
466 | \value Site |
467 | Indicates that the system is connected to a network, but it |
468 | might only be able to access devices on the local subnet or an |
469 | intranet. |
470 | \value Online |
471 | Indicates that the system is connected to a network and |
472 | able to access the Internet. |
473 | |
474 | \sa QNetworkInformation::reachability |
475 | */ |
476 | |
477 | /*! |
478 | \enum QNetworkInformation::TransportMedium |
479 | \since 6.3 |
480 | |
481 | Lists the currently recognized media with which one can connect to the |
482 | internet. |
483 | |
484 | \value Unknown |
485 | Returned if either the OS reports no active medium, the active medium is |
486 | not recognized by Qt, or the TransportMedium feature is not supported. |
487 | \value Ethernet |
488 | Indicates that the currently active connection is using ethernet. |
489 | Note: This value may also be returned when Windows is connected to a |
490 | Bluetooth personal area network. |
491 | \value Cellular |
492 | Indicates that the currently active connection is using a cellular |
493 | network. |
494 | \value WiFi |
495 | Indicates that the currently active connection is using Wi-Fi. |
496 | \value Bluetooth |
497 | Indicates that the currently active connection is connected using |
498 | Bluetooth. |
499 | |
500 | \sa QNetworkInformation::transportMedium |
501 | */ |
502 | |
503 | /*! |
504 | \internal ctor |
505 | */ |
506 | QNetworkInformation::QNetworkInformation(QNetworkInformationBackend *backend) |
507 | : QObject(*(new QNetworkInformationPrivate(backend))) |
508 | { |
509 | connect(sender: backend, signal: &QNetworkInformationBackend::reachabilityChanged, context: this, |
510 | slot: &QNetworkInformation::reachabilityChanged); |
511 | connect(sender: backend, signal: &QNetworkInformationBackend::behindCaptivePortalChanged, context: this, |
512 | slot: &QNetworkInformation::isBehindCaptivePortalChanged); |
513 | connect(sender: backend, signal: &QNetworkInformationBackend::transportMediumChanged, context: this, |
514 | slot: &QNetworkInformation::transportMediumChanged); |
515 | connect(sender: backend, signal: &QNetworkInformationBackend::isMeteredChanged, context: this, |
516 | slot: &QNetworkInformation::isMeteredChanged); |
517 | |
518 | QThread *main = nullptr; |
519 | |
520 | if (QCoreApplication::instance()) |
521 | main = QCoreApplication::instance()->thread(); |
522 | |
523 | if (main && thread() != main) |
524 | moveToThread(thread: main); |
525 | } |
526 | |
527 | /*! |
528 | \internal dtor |
529 | */ |
530 | QNetworkInformation::~QNetworkInformation() = default; |
531 | |
532 | /*! |
533 | \property QNetworkInformation::reachability |
534 | \brief The current state of the system's network connectivity. |
535 | |
536 | Indicates the level of connectivity that can be expected. Do note |
537 | that this is only based on what the plugin/operating system |
538 | reports. In certain scenarios this is known to be wrong. For |
539 | example, on Windows the 'Online' check, by default, is performed |
540 | by Windows connecting to a Microsoft-owned server. If this server |
541 | is for any reason blocked then it will assume it does not have |
542 | Online reachability. Because of this you should not use this as a |
543 | pre-check before attempting to make a connection. |
544 | */ |
545 | |
546 | QNetworkInformation::Reachability QNetworkInformation::reachability() const |
547 | { |
548 | return d_func()->backend->reachability(); |
549 | } |
550 | |
551 | /*! |
552 | \property QNetworkInformation::isBehindCaptivePortal |
553 | \brief Lets you know if the user's device is behind a captive portal. |
554 | \since 6.2 |
555 | |
556 | This property indicates if the user's device is currently known to be |
557 | behind a captive portal. This functionality relies on the operating system's |
558 | detection of captive portals and is not supported on systems that don't |
559 | report this. On systems where this is not supported this will always return |
560 | \c{false}. |
561 | */ |
562 | bool QNetworkInformation::isBehindCaptivePortal() const |
563 | { |
564 | return d_func()->backend->behindCaptivePortal(); |
565 | } |
566 | |
567 | /*! |
568 | \property QNetworkInformation::transportMedium |
569 | \brief The currently active transport medium for the application |
570 | \since 6.3 |
571 | |
572 | This property returns the currently active transport medium for the |
573 | application, on operating systems where such information is available. |
574 | |
575 | When the current transport medium changes a signal is emitted, this can, |
576 | for instance, occur when a user leaves the range of a WiFi network, unplugs |
577 | their ethernet cable or enables Airplane mode. |
578 | */ |
579 | QNetworkInformation::TransportMedium QNetworkInformation::transportMedium() const |
580 | { |
581 | return d_func()->backend->transportMedium(); |
582 | } |
583 | |
584 | /*! |
585 | \property QNetworkInformation::isMetered |
586 | \brief Check if the current connection is metered |
587 | \since 6.3 |
588 | |
589 | This property returns whether the current connection is (known to be) |
590 | metered or not. You can use this as a guiding factor to decide whether your |
591 | application should perform certain network requests or uploads. |
592 | For instance, you may not want to upload logs or diagnostics while this |
593 | property is \c true. |
594 | */ |
595 | bool QNetworkInformation::isMetered() const |
596 | { |
597 | return d_func()->backend->isMetered(); |
598 | } |
599 | |
600 | /*! |
601 | Returns the name of the currently loaded backend. |
602 | */ |
603 | QString QNetworkInformation::backendName() const |
604 | { |
605 | return d_func()->backend->name(); |
606 | } |
607 | |
608 | /*! |
609 | Returns \c true if the currently loaded backend supports |
610 | \a features. |
611 | */ |
612 | bool QNetworkInformation::supports(Features features) const |
613 | { |
614 | return (d_func()->backend->featuresSupported() & features) == features; |
615 | } |
616 | |
617 | /*! |
618 | \since 6.3 |
619 | |
620 | Returns all the supported features of the current backend. |
621 | */ |
622 | QNetworkInformation::Features QNetworkInformation::supportedFeatures() const |
623 | { |
624 | return d_func()->backend->featuresSupported(); |
625 | } |
626 | |
627 | /*! |
628 | \since 6.3 |
629 | |
630 | Attempts to load the platform-default backend. |
631 | |
632 | \note Starting with 6.7 this tries to load any backend that supports |
633 | \l{QNetworkInformation::Feature::Reachability}{Reachability} if the |
634 | platform-default backend is not available or fails to load. |
635 | If this also fails it will fall back to a backend that only returns |
636 | the default values for all properties. |
637 | |
638 | This platform-to-plugin mapping is as follows: |
639 | |
640 | \table |
641 | \header |
642 | \li Platform |
643 | \li Plugin-name |
644 | \row |
645 | \li Windows |
646 | \li networklistmanager |
647 | \row |
648 | \li Apple (macOS/iOS) |
649 | \li scnetworkreachability |
650 | \row |
651 | \li Android |
652 | \li android |
653 | \row |
654 | \li Linux |
655 | \li networkmanager |
656 | \endtable |
657 | |
658 | This function is provided for convenience where the logic earlier |
659 | is good enough. If you require a specific plugin then you should call |
660 | loadBackendByName() or loadBackendByFeatures() directly instead. |
661 | |
662 | Determines a suitable backend to load and returns \c true if this backend |
663 | is already loaded or on successful loading of it. Returns \c false if any |
664 | other backend has already been loaded, or if loading of the selected |
665 | backend fails. |
666 | |
667 | \sa instance(), load() |
668 | */ |
669 | bool QNetworkInformation::loadDefaultBackend() |
670 | { |
671 | int index = -1; |
672 | #ifdef Q_OS_WIN |
673 | index = QNetworkInformationBackend::PluginNamesWindowsIndex; |
674 | #elif defined(Q_OS_DARWIN) |
675 | index = QNetworkInformationBackend::PluginNamesAppleIndex; |
676 | #elif defined(Q_OS_ANDROID) |
677 | index = QNetworkInformationBackend::PluginNamesAndroidIndex; |
678 | #elif defined(Q_OS_LINUX) |
679 | index = QNetworkInformationBackend::PluginNamesLinuxIndex; |
680 | #endif |
681 | if (index != -1 && loadBackendByName(backend: QNetworkInformationBackend::PluginNames[index])) |
682 | return true; |
683 | // We assume reachability is the most commonly wanted feature, and try to |
684 | // load the backend that advertises the most features including that: |
685 | if (loadBackendByFeatures(features: Feature::Reachability)) |
686 | return true; |
687 | |
688 | // Fall back to the dummy backend |
689 | return loadBackendByName(backend: u"dummy"); |
690 | } |
691 | |
692 | /*! |
693 | \since 6.4 |
694 | |
695 | Attempts to load a backend whose name matches \a backend |
696 | (case insensitively). |
697 | |
698 | Returns \c true if it managed to load the requested backend or |
699 | if it was already loaded. Returns \c false otherwise. |
700 | |
701 | \sa instance |
702 | */ |
703 | bool QNetworkInformation::loadBackendByName(QStringView backend) |
704 | { |
705 | if (backend == u"dummy") |
706 | return QNetworkInformationPrivate::createDummy() != nullptr; |
707 | |
708 | auto loadedBackend = QNetworkInformationPrivate::create(name: backend); |
709 | return loadedBackend && loadedBackend->backendName().compare(s: backend, cs: Qt::CaseInsensitive) == 0; |
710 | } |
711 | |
712 | #if QT_DEPRECATED_SINCE(6,4) |
713 | /*! |
714 | \deprecated [6.4] Use loadBackendByName() instead. |
715 | |
716 | \sa loadBackendByName(), loadDefaultBackend(), loadBackendByFeatures() |
717 | */ |
718 | bool QNetworkInformation::load(QStringView backend) |
719 | { |
720 | return loadBackendByName(backend); |
721 | } |
722 | #endif // QT_DEPRECATED_SINCE(6,4) |
723 | |
724 | /*! |
725 | \since 6.4 |
726 | Load a backend which supports \a features. |
727 | |
728 | Returns \c true if it managed to load the requested backend or |
729 | if it was already loaded. Returns \c false otherwise. |
730 | |
731 | \sa instance |
732 | */ |
733 | bool QNetworkInformation::loadBackendByFeatures(Features features) |
734 | { |
735 | auto loadedBackend = QNetworkInformationPrivate::create(features); |
736 | return loadedBackend && loadedBackend->supports(features); |
737 | } |
738 | |
739 | #if QT_DEPRECATED_SINCE(6,4) |
740 | /*! |
741 | \deprecated [6.4] Use loadBackendByFeatures() instead. |
742 | |
743 | \sa loadBackendByName(), loadDefaultBackend(), loadBackendByFeatures() |
744 | */ |
745 | bool QNetworkInformation::load(Features features) |
746 | { |
747 | return loadBackendByFeatures(features); |
748 | } |
749 | #endif // QT_DEPRECATED_SINCE(6,4) |
750 | |
751 | /*! |
752 | Returns a list of the names of all currently available backends. |
753 | */ |
754 | QStringList QNetworkInformation::availableBackends() |
755 | { |
756 | return QNetworkInformationPrivate::backendNames(); |
757 | } |
758 | |
759 | /*! |
760 | Returns a pointer to the instance of the QNetworkInformation, |
761 | if any. |
762 | |
763 | \sa load() |
764 | */ |
765 | QNetworkInformation *QNetworkInformation::instance() |
766 | { |
767 | return QNetworkInformationPrivate::instance(); |
768 | } |
769 | |
770 | QT_END_NAMESPACE |
771 | |
772 | #include "moc_qnetworkinformation.cpp" |
773 | #include "moc_qnetworkinformation_p.cpp" |
774 | #include "qnetworkinformation.moc" |
775 |
Definitions
- lcNetInfo
- QNetworkInformationDeleter
- operator()
- qniLoader
- QStaticNetworkInformationDataHolder
- dataHolder
- networkInfoCleanup
- QNetworkInformationDummyBackend
- name
- featuresSupported
- QNetworkInformationPrivate
- QNetworkInformationPrivate
- instance
- initializeList
- addToList
- removeFromList
- backendNames
- create
- create
- createDummy
- ~QNetworkInformationBackend
- QNetworkInformationBackendFactory
- ~QNetworkInformationBackendFactory
- QNetworkInformation
- ~QNetworkInformation
- reachability
- isBehindCaptivePortal
- transportMedium
- isMetered
- backendName
- supports
- supportedFeatures
- loadDefaultBackend
- loadBackendByName
- load
- loadBackendByFeatures
- load
- availableBackends
Learn Advanced QML with KDAB
Find out more