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 
55 QT_BEGIN_NAMESPACE
56 
57 static QBasicAtomicPointer<QNetworkConfigurationManagerPrivate> connManager_ptr;
58 static QBasicAtomicInt appShutdown;
59 
connManager_prepare()60 static void connManager_prepare()
61 {
62     int shutdown = appShutdown.fetchAndStoreAcquire(0);
63     Q_ASSERT(shutdown == 0 || shutdown == 1);
64     Q_UNUSED(shutdown);
65 }
66 
connManager_cleanup()67 static void connManager_cleanup()
68 {
69     // this is not atomic or thread-safe!
70     int shutdown = appShutdown.fetchAndStoreAcquire(1);
71     Q_ASSERT(shutdown == 0);
72     Q_UNUSED(shutdown);
73     QNetworkConfigurationManagerPrivate *cmp = connManager_ptr.fetchAndStoreAcquire(nullptr);
74     if (cmp)
75         cmp->cleanup();
76 }
77 
addPreAndPostRoutine()78 void QNetworkConfigurationManagerPrivate::addPreAndPostRoutine()
79 {
80     qAddPreRoutine(connManager_prepare);
81     qAddPostRoutine(connManager_cleanup);
82 }
83 
qNetworkConfigurationManagerPrivate()84 QNetworkConfigurationManagerPrivate *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(obj, SIGNAL(destroyed()), ptr, SLOT(addPreAndPostRoutine()), Qt::DirectConnection);
102                 ptr->initialize(); // this moves us to the right thread
103                 obj->moveToThread(QCoreApplicationPrivate::mainThread());
104                 obj->deleteLater();
105             }
106 
107             connManager_ptr.storeRelease(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 */
QNetworkConfigurationManager(QObject * parent)235 QNetworkConfigurationManager::QNetworkConfigurationManager(QObject *parent)
236     : QObject(parent)
237 {
238     QNetworkConfigurationManagerPrivate *priv = qNetworkConfigurationManagerPrivate();
239     if (priv) {
240         connect(priv, SIGNAL(configurationAdded(QNetworkConfiguration)),
241                 this, SIGNAL(configurationAdded(QNetworkConfiguration)));
242         connect(priv, SIGNAL(configurationRemoved(QNetworkConfiguration)),
243                 this, SIGNAL(configurationRemoved(QNetworkConfiguration)));
244         connect(priv, SIGNAL(configurationChanged(QNetworkConfiguration)),
245                 this, SIGNAL(configurationChanged(QNetworkConfiguration)));
246         connect(priv, SIGNAL(onlineStateChanged(bool)),
247                 this, SIGNAL(onlineStateChanged(bool)));
248         connect(priv, SIGNAL(configurationUpdateComplete()),
249                 this, SIGNAL(updateCompleted()));
250 
251         priv->enablePolling();
252     }
253 }
254 
255 /*!
256     Frees the resources associated with the QNetworkConfigurationManager object.
257 */
~QNetworkConfigurationManager()258 QNetworkConfigurationManager::~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 */
defaultConfiguration() const275 QNetworkConfiguration 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 */
allConfigurations(QNetworkConfiguration::StateFlags filter) const309 QList<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 */
configurationFromIdentifier(const QString & identifier) const324 QNetworkConfiguration 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 */
isOnline() const343 bool 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 */
capabilities() const355 QNetworkConfigurationManager::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 */
updateConfigurations()378 void QNetworkConfigurationManager::updateConfigurations()
379 {
380     QNetworkConfigurationManagerPrivate *priv = qNetworkConfigurationManagerPrivate();
381     if (priv)
382         priv->performAsyncConfigurationUpdate();
383 }
384 
385 QT_END_NAMESPACE
386 
387 #include "moc_qnetworkconfigmanager.cpp"
388 
389 #endif // QT_NO_BEARERMANAGEMENT
390