1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtNetwork module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include <QtNetwork/private/qtnetworkglobal_p.h>
41
42#include "qnetworkconfigmanager.h"
43
44#include "qnetworkconfigmanager_p.h"
45#include "qbearerengine_p.h"
46
47#include <QtCore/qstringlist.h>
48#include <QtCore/qcoreapplication.h>
49#include <QtCore/qmutex.h>
50#include <QtCore/qthread.h>
51#include <QtCore/private/qcoreapplication_p.h>
52
53#ifndef QT_NO_BEARERMANAGEMENT
54
55QT_BEGIN_NAMESPACE
56
57static QBasicAtomicPointer<QNetworkConfigurationManagerPrivate> connManager_ptr;
58static QBasicAtomicInt appShutdown;
59
60static void connManager_prepare()
61{
62 int shutdown = appShutdown.fetchAndStoreAcquire(newValue: 0);
63 Q_ASSERT(shutdown == 0 || shutdown == 1);
64 Q_UNUSED(shutdown);
65}
66
67static void connManager_cleanup()
68{
69 // this is not atomic or thread-safe!
70 int shutdown = appShutdown.fetchAndStoreAcquire(newValue: 1);
71 Q_ASSERT(shutdown == 0);
72 Q_UNUSED(shutdown);
73 QNetworkConfigurationManagerPrivate *cmp = connManager_ptr.fetchAndStoreAcquire(newValue: nullptr);
74 if (cmp)
75 cmp->cleanup();
76}
77
78void QNetworkConfigurationManagerPrivate::addPreAndPostRoutine()
79{
80 qAddPreRoutine(connManager_prepare);
81 qAddPostRoutine(connManager_cleanup);
82}
83
84QNetworkConfigurationManagerPrivate *qNetworkConfigurationManagerPrivate()
85{
86 QNetworkConfigurationManagerPrivate *ptr = connManager_ptr.loadAcquire();
87 int shutdown = appShutdown.loadAcquire();
88 if (!ptr && !shutdown) {
89 static QBasicMutex connManager_mutex;
90 QMutexLocker locker(&connManager_mutex);
91 if (!(ptr = connManager_ptr.loadAcquire())) {
92 ptr = new QNetworkConfigurationManagerPrivate;
93
94 if (QCoreApplicationPrivate::mainThread() == QThread::currentThread()) {
95 // right thread or no main thread yet
96 ptr->addPreAndPostRoutine();
97 ptr->initialize();
98 } else {
99 // wrong thread, we need to make the main thread do this
100 QObject *obj = new QObject;
101 QObject::connect(sender: obj, SIGNAL(destroyed()), receiver: ptr, SLOT(addPreAndPostRoutine()), Qt::DirectConnection);
102 ptr->initialize(); // this moves us to the right thread
103 obj->moveToThread(thread: QCoreApplicationPrivate::mainThread());
104 obj->deleteLater();
105 }
106
107 connManager_ptr.storeRelease(newValue: ptr);
108 }
109 }
110 return ptr;
111}
112
113/*!
114 \class QNetworkConfigurationManager
115 \obsolete
116
117 \brief The QNetworkConfigurationManager class manages the network configurations provided
118 by the system.
119
120 \since 4.7
121
122 \inmodule QtNetwork
123 \ingroup network
124
125 QNetworkConfigurationManager provides access to the network configurations known to the system and
126 enables applications to detect the system capabilities (with regards to network sessions) at runtime.
127
128 A QNetworkConfiguration abstracts a set of configuration options describing how a
129 network interface has to be configured to connect to a particular target network.
130 QNetworkConfigurationManager maintains and updates the global list of
131 QNetworkConfigurations. Applications can access and filter this list via
132 allConfigurations(). If a new configuration is added or an existing one is removed or changed
133 the configurationAdded(), configurationRemoved() and configurationChanged() signals are emitted
134 respectively.
135
136 The defaultConfiguration() can be used when intending to immediately create a new
137 network session without caring about the particular configuration. It returns
138 a \l QNetworkConfiguration::Discovered configuration. If there are not any
139 discovered ones an invalid configuration is returned.
140
141 Some configuration updates may require some time to perform updates. A WLAN scan is
142 such an example. Unless the platform performs internal updates it may be required to
143 manually trigger configuration updates via QNetworkConfigurationManager::updateConfigurations().
144 The completion of the update process is indicated by emitting the updateCompleted()
145 signal. The update process ensures that every existing QNetworkConfiguration instance
146 is updated. There is no need to ask for a renewed configuration list via allConfigurations().
147
148 \sa QNetworkConfiguration
149*/
150
151/*!
152 \fn void QNetworkConfigurationManager::configurationAdded(const QNetworkConfiguration &config)
153
154 This signal is emitted whenever a new network configuration is added to the system. The new
155 configuration is specified by \a config.
156*/
157
158/*!
159 \fn void QNetworkConfigurationManager::configurationRemoved(const QNetworkConfiguration &config)
160
161 This signal is emitted when a configuration is about to be removed from the system. The removed
162 configuration, specified by \a config, is invalid but retains name and identifier.
163*/
164
165/*!
166 \fn void QNetworkConfigurationManager::updateCompleted()
167
168 This signal is emitted when the configuration update has been completed. Such an update can
169 be initiated via \l updateConfigurations().
170*/
171
172/*! \fn void QNetworkConfigurationManager::configurationChanged(const QNetworkConfiguration &config)
173
174 This signal is emitted when the \l {QNetworkConfiguration::state()}{state} of \a config changes.
175*/
176
177/*!
178 \fn void QNetworkConfigurationManager::onlineStateChanged(bool isOnline)
179
180 This signal is emitted when the device changes from online to offline mode or vice versa.
181 \a isOnline represents the new state of the device.
182
183 The state is considered to be online for as long as
184 \l{allConfigurations()}{allConfigurations}(QNetworkConfiguration::Active) returns a list with
185 at least one entry.
186*/
187
188/*!
189 \enum QNetworkConfigurationManager::Capability
190
191 Specifies the system capabilities of the bearer API. The possible values are:
192
193 \value CanStartAndStopInterfaces Network sessions and their underlying access points can be
194 started and stopped. If this flag is not set QNetworkSession
195 can only monitor but not influence the state of access points.
196 On some platforms this feature may require elevated user
197 permissions. This option is platform specific and may not
198 always be available.
199 \value DirectConnectionRouting Network sessions and their sockets can be bound to a
200 particular network interface. Any packet that passes through
201 the socket goes to the specified network interface and thus
202 disregards standard routing table entries. This may be useful
203 when two interfaces can reach overlapping IP ranges or an
204 application has specific needs in regards to target networks.
205 This option is platform specific and may not always be
206 available.
207 \value SystemSessionSupport If this flag is set the underlying platform ensures that a
208 network interface is not shut down until the last network
209 session has been \l{QNetworkSession::close()}{closed()}. This
210 works across multiple processes. If the platform session
211 support is missing this API can only ensure the above behavior
212 for network sessions within the same process.
213 In general mobile platforms have such
214 support whereas most desktop platform lack this capability.
215 \value ApplicationLevelRoaming The system gives applications control over the systems roaming
216 behavior. Applications can initiate roaming (in case the
217 current link is not suitable) and are consulted if the system
218 has identified a more suitable access point.
219 \value ForcedRoaming The system disconnects an existing access point and reconnects
220 via a more suitable one. The application does not have any
221 control over this process and has to reconnect its active
222 sockets.
223 \value DataStatistics If this flag is set QNetworkSession can provide statistics
224 about transmitted and received data.
225 \value NetworkSessionRequired If this flag is set the platform requires that a network
226 session is created before network operations can be performed.
227*/
228
229/*!
230 Constructs a QNetworkConfigurationManager with the given \a parent.
231
232 Note that to ensure a valid list of current configurations immediately available, updating
233 is done during construction which causes some delay.
234*/
235QNetworkConfigurationManager::QNetworkConfigurationManager(QObject *parent)
236 : QObject(parent)
237{
238 QNetworkConfigurationManagerPrivate *priv = qNetworkConfigurationManagerPrivate();
239 if (priv) {
240 connect(sender: priv, SIGNAL(configurationAdded(QNetworkConfiguration)),
241 receiver: this, SIGNAL(configurationAdded(QNetworkConfiguration)));
242 connect(sender: priv, SIGNAL(configurationRemoved(QNetworkConfiguration)),
243 receiver: this, SIGNAL(configurationRemoved(QNetworkConfiguration)));
244 connect(sender: priv, SIGNAL(configurationChanged(QNetworkConfiguration)),
245 receiver: this, SIGNAL(configurationChanged(QNetworkConfiguration)));
246 connect(sender: priv, SIGNAL(onlineStateChanged(bool)),
247 receiver: this, SIGNAL(onlineStateChanged(bool)));
248 connect(sender: priv, SIGNAL(configurationUpdateComplete()),
249 receiver: this, SIGNAL(updateCompleted()));
250
251 priv->enablePolling();
252 }
253}
254
255/*!
256 Frees the resources associated with the QNetworkConfigurationManager object.
257*/
258QNetworkConfigurationManager::~QNetworkConfigurationManager()
259{
260 QNetworkConfigurationManagerPrivate *priv = qNetworkConfigurationManagerPrivate();
261 if (priv)
262 priv->disablePolling();
263}
264
265
266/*!
267 Returns the default configuration to be used. This function always returns a discovered
268 configuration; otherwise an invalid configuration.
269
270 In some cases it may be required to call updateConfigurations() and wait for the
271 updateCompleted() signal before calling this function.
272
273 \sa allConfigurations()
274*/
275QNetworkConfiguration QNetworkConfigurationManager::defaultConfiguration() const
276{
277 QNetworkConfigurationManagerPrivate *priv = qNetworkConfigurationManagerPrivate();
278 if (priv)
279 return priv->defaultConfiguration();
280
281 return QNetworkConfiguration();
282}
283
284/*!
285 Returns the list of configurations which comply with the given \a filter.
286
287 By default this function returns all (defined and undefined) configurations.
288
289 A wireless network with a particular SSID may only be accessible in a
290 certain area despite the fact that the system has a valid configuration
291 for it. Therefore the filter flag may be used to limit the list to
292 discovered and possibly connected configurations only.
293
294 If \a filter is set to zero this function returns all possible configurations.
295
296 Note that this function returns the states for all configurations as they are known at
297 the time of this function call. If for instance a configuration of type WLAN is defined
298 the system may have to perform a WLAN scan in order to determine whether it is
299 actually available. To obtain the most accurate state updateConfigurations() should
300 be used to update each configuration's state. Note that such an update may require
301 some time. It's completion is signalled by updateCompleted(). In the absence of a
302 configuration update this function returns the best estimate at the time of the call.
303 Therefore, if WLAN configurations are of interest, it is recommended that
304 updateConfigurations() is called once after QNetworkConfigurationManager
305 instantiation (WLAN scans are too time consuming to perform in constructor).
306 After this the data is kept automatically up-to-date as the system reports
307 any changes.
308*/
309QList<QNetworkConfiguration> QNetworkConfigurationManager::allConfigurations(QNetworkConfiguration::StateFlags filter) const
310{
311 QNetworkConfigurationManagerPrivate *priv = qNetworkConfigurationManagerPrivate();
312 if (priv)
313 return priv->allConfigurations(filter);
314
315 return QList<QNetworkConfiguration>();
316}
317
318/*!
319 Returns the QNetworkConfiguration for \a identifier; otherwise returns an
320 invalid QNetworkConfiguration.
321
322 \sa QNetworkConfiguration::identifier()
323*/
324QNetworkConfiguration QNetworkConfigurationManager::configurationFromIdentifier(const QString &identifier) const
325{
326 QNetworkConfigurationManagerPrivate *priv = qNetworkConfigurationManagerPrivate();
327 if (priv)
328 return priv->configurationFromIdentifier(identifier);
329
330 return QNetworkConfiguration();
331}
332
333/*!
334 Returns \c true if the system is considered to be connected to another device via an active
335 network interface; otherwise returns \c false.
336
337 This is equivalent to the following code snippet:
338
339 \snippet code/src_network_bearer_qnetworkconfigmanager.cpp 0
340
341 \sa onlineStateChanged()
342*/
343bool QNetworkConfigurationManager::isOnline() const
344{
345 QNetworkConfigurationManagerPrivate *priv = qNetworkConfigurationManagerPrivate();
346 if (priv)
347 return priv->isOnline();
348
349 return false;
350}
351
352/*!
353 Returns the capabilities supported by the current platform.
354*/
355QNetworkConfigurationManager::Capabilities QNetworkConfigurationManager::capabilities() const
356{
357 QNetworkConfigurationManagerPrivate *priv = qNetworkConfigurationManagerPrivate();
358 if (priv)
359 return priv->capabilities();
360
361 return {};
362}
363
364/*!
365 Initiates an update of all configurations. This may be used to initiate WLAN scans or other
366 time consuming updates which may be required to obtain the correct state for configurations.
367
368 This call is asynchronous. On completion of this update the updateCompleted() signal is
369 emitted. If new configurations are discovered or old ones were removed or changed the update
370 process may trigger the emission of one or multiple configurationAdded(),
371 configurationRemoved() and configurationChanged() signals.
372
373 If a configuration state changes as a result of this update all existing QNetworkConfiguration
374 instances are updated automatically.
375
376 \sa allConfigurations()
377*/
378void QNetworkConfigurationManager::updateConfigurations()
379{
380 QNetworkConfigurationManagerPrivate *priv = qNetworkConfigurationManagerPrivate();
381 if (priv)
382 priv->performAsyncConfigurationUpdate();
383}
384
385QT_END_NAMESPACE
386
387#include "moc_qnetworkconfigmanager.cpp"
388
389#endif // QT_NO_BEARERMANAGEMENT
390

source code of qtbase/src/network/bearer/qnetworkconfigmanager.cpp