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 plugins 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// see comment in ../platformdefs_win.h.
41#define WIN32_LEAN_AND_MEAN 1
42
43#include "qnetworksession_impl.h"
44#include "qbearerengine_impl.h"
45
46#include <QtNetwork/qnetworksession.h>
47#include <QtNetwork/private/qnetworkconfigmanager_p.h>
48
49#include <QtCore/qdatetime.h>
50#include <QtCore/qdebug.h>
51#include <QtCore/qmutex.h>
52#include <QtCore/qstringlist.h>
53
54QT_BEGIN_NAMESPACE
55
56static QBearerEngineImpl *getEngineFromId(const QString &id)
57{
58 QNetworkConfigurationManagerPrivate *priv = qNetworkConfigurationManagerPrivate();
59 if (priv) {
60 const auto engines = priv->engines();
61 for (QBearerEngine *engine : engines) {
62 QBearerEngineImpl *engineImpl = qobject_cast<QBearerEngineImpl *>(engine);
63 if (engineImpl && engineImpl->hasIdentifier(id))
64 return engineImpl;
65 }
66 }
67
68 return 0;
69}
70
71class QNetworkSessionManagerPrivate : public QObject
72{
73 Q_OBJECT
74
75public:
76 QNetworkSessionManagerPrivate(QObject *parent = 0) : QObject(parent) {}
77 ~QNetworkSessionManagerPrivate() {}
78
79 inline void forceSessionClose(const QNetworkConfiguration &config)
80 { emit forcedSessionClose(config); }
81
82Q_SIGNALS:
83 void forcedSessionClose(const QNetworkConfiguration &config);
84};
85
86Q_GLOBAL_STATIC(QNetworkSessionManagerPrivate, sessionManager);
87
88void QNetworkSessionPrivateImpl::syncStateWithInterface()
89{
90 connect(sessionManager(), SIGNAL(forcedSessionClose(QNetworkConfiguration)),
91 this, SLOT(forcedSessionClose(QNetworkConfiguration)));
92
93 opened = false;
94 isOpen = false;
95 state = QNetworkSession::Invalid;
96 lastError = QNetworkSession::UnknownSessionError;
97
98 qRegisterMetaType<QBearerEngineImpl::ConnectionError>();
99
100 switch (publicConfig.type()) {
101 case QNetworkConfiguration::InternetAccessPoint:
102 activeConfig = publicConfig;
103 engine = getEngineFromId(activeConfig.identifier());
104 if (engine) {
105 qRegisterMetaType<QNetworkConfigurationPrivatePointer>();
106 connect(engine, SIGNAL(configurationChanged(QNetworkConfigurationPrivatePointer)),
107 this, SLOT(configurationChanged(QNetworkConfigurationPrivatePointer)),
108 Qt::QueuedConnection);
109 connect(engine, SIGNAL(connectionError(QString,QBearerEngineImpl::ConnectionError)),
110 this, SLOT(connectionError(QString,QBearerEngineImpl::ConnectionError)),
111 Qt::QueuedConnection);
112 }
113 break;
114 case QNetworkConfiguration::ServiceNetwork:
115 serviceConfig = publicConfig;
116 // Defer setting engine and signals until open().
117 Q_FALLTHROUGH();
118 case QNetworkConfiguration::UserChoice:
119 // Defer setting serviceConfig and activeConfig until open().
120 Q_FALLTHROUGH();
121 default:
122 engine = 0;
123 }
124
125 networkConfigurationsChanged();
126}
127
128void QNetworkSessionPrivateImpl::open()
129{
130 if (serviceConfig.isValid()) {
131 lastError = QNetworkSession::OperationNotSupportedError;
132 emit QNetworkSessionPrivate::error(lastError);
133 } else if (!isOpen) {
134 if ((activeConfig.state() & QNetworkConfiguration::Discovered) != QNetworkConfiguration::Discovered) {
135 lastError = QNetworkSession::InvalidConfigurationError;
136 state = QNetworkSession::Invalid;
137 emit stateChanged(state);
138 emit QNetworkSessionPrivate::error(lastError);
139 return;
140 }
141 opened = true;
142
143 if ((activeConfig.state() & QNetworkConfiguration::Active) != QNetworkConfiguration::Active &&
144 (activeConfig.state() & QNetworkConfiguration::Discovered) == QNetworkConfiguration::Discovered) {
145 state = QNetworkSession::Connecting;
146 emit stateChanged(state);
147
148 engine->connectToId(activeConfig.identifier());
149 }
150
151 isOpen = (activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active;
152 if (isOpen)
153 emit quitPendingWaitsForOpened();
154 }
155}
156
157void QNetworkSessionPrivateImpl::close()
158{
159 if (serviceConfig.isValid()) {
160 lastError = QNetworkSession::OperationNotSupportedError;
161 emit QNetworkSessionPrivate::error(lastError);
162 } else if (isOpen) {
163 opened = false;
164 isOpen = false;
165 emit closed();
166 }
167}
168
169void QNetworkSessionPrivateImpl::stop()
170{
171 if (serviceConfig.isValid()) {
172 lastError = QNetworkSession::OperationNotSupportedError;
173 emit QNetworkSessionPrivate::error(lastError);
174 } else {
175 if ((activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
176 state = QNetworkSession::Closing;
177 emit stateChanged(state);
178
179 engine->disconnectFromId(activeConfig.identifier());
180
181 sessionManager()->forceSessionClose(activeConfig);
182 }
183
184 opened = false;
185 isOpen = false;
186 emit closed();
187 }
188}
189
190void QNetworkSessionPrivateImpl::migrate()
191{
192}
193
194void QNetworkSessionPrivateImpl::accept()
195{
196}
197
198void QNetworkSessionPrivateImpl::ignore()
199{
200}
201
202void QNetworkSessionPrivateImpl::reject()
203{
204}
205
206#ifndef QT_NO_NETWORKINTERFACE
207QNetworkInterface QNetworkSessionPrivateImpl::currentInterface() const
208{
209 if (!engine || state != QNetworkSession::Connected || !publicConfig.isValid())
210 return QNetworkInterface();
211
212 QString iface = engine->getInterfaceFromId(activeConfig.identifier());
213 if (iface.isEmpty())
214 return QNetworkInterface();
215 return QNetworkInterface::interfaceFromName(iface);
216}
217#endif
218
219QVariant QNetworkSessionPrivateImpl::sessionProperty(const QString &key) const
220{
221 if (key == QLatin1String("AutoCloseSessionTimeout")) {
222 if (engine && engine->requiresPolling() &&
223 !(engine->capabilities() & QNetworkConfigurationManager::CanStartAndStopInterfaces)) {
224 return sessionTimeout >= 0 ? sessionTimeout * 10000 : -1;
225 }
226 }
227
228 return QVariant();
229}
230
231void QNetworkSessionPrivateImpl::setSessionProperty(const QString &key, const QVariant &value)
232{
233 if (key == QLatin1String("AutoCloseSessionTimeout")) {
234 if (engine && engine->requiresPolling() &&
235 !(engine->capabilities() & QNetworkConfigurationManager::CanStartAndStopInterfaces)) {
236 int timeout = value.toInt();
237 if (timeout >= 0) {
238 connect(engine, SIGNAL(updateCompleted()),
239 this, SLOT(decrementTimeout()), Qt::UniqueConnection);
240 sessionTimeout = timeout / 10000; // convert to poll intervals
241 } else {
242 disconnect(engine, SIGNAL(updateCompleted()), this, SLOT(decrementTimeout()));
243 sessionTimeout = -1;
244 }
245 }
246 }
247}
248
249QString QNetworkSessionPrivateImpl::errorString() const
250{
251 switch (lastError) {
252 case QNetworkSession::UnknownSessionError:
253 return tr("Unknown session error.");
254 case QNetworkSession::SessionAbortedError:
255 return tr("The session was aborted by the user or system.");
256 case QNetworkSession::OperationNotSupportedError:
257 return tr("The requested operation is not supported by the system.");
258 case QNetworkSession::InvalidConfigurationError:
259 return tr("The specified configuration cannot be used.");
260 case QNetworkSession::RoamingError:
261 return tr("Roaming was aborted or is not possible.");
262 default:
263 break;
264 }
265
266 return QString();
267}
268
269QNetworkSession::SessionError QNetworkSessionPrivateImpl::error() const
270{
271 return lastError;
272}
273
274quint64 QNetworkSessionPrivateImpl::bytesWritten() const
275{
276 if (engine && state == QNetworkSession::Connected)
277 return engine->bytesWritten(activeConfig.identifier());
278 return Q_UINT64_C(0);
279}
280
281quint64 QNetworkSessionPrivateImpl::bytesReceived() const
282{
283 if (engine && state == QNetworkSession::Connected)
284 return engine->bytesReceived(activeConfig.identifier());
285 return Q_UINT64_C(0);
286}
287
288quint64 QNetworkSessionPrivateImpl::activeTime() const
289{
290 if (state == QNetworkSession::Connected && startTime != Q_UINT64_C(0))
291 return QDateTime::currentSecsSinceEpoch() - startTime;
292 return Q_UINT64_C(0);
293}
294
295QNetworkSession::UsagePolicies QNetworkSessionPrivateImpl::usagePolicies() const
296{
297 return currentPolicies;
298}
299
300void QNetworkSessionPrivateImpl::setUsagePolicies(QNetworkSession::UsagePolicies newPolicies)
301{
302 if (newPolicies != currentPolicies) {
303 currentPolicies = newPolicies;
304 emit usagePoliciesChanged(currentPolicies);
305 }
306}
307
308void QNetworkSessionPrivateImpl::updateStateFromServiceNetwork()
309{
310 QNetworkSession::State oldState = state;
311
312 const auto configs = serviceConfig.children();
313 for (const QNetworkConfiguration &config : configs) {
314 if ((config.state() & QNetworkConfiguration::Active) != QNetworkConfiguration::Active)
315 continue;
316
317 if (activeConfig != config) {
318 if (engine) {
319 disconnect(engine, SIGNAL(connectionError(QString,QBearerEngineImpl::ConnectionError)),
320 this, SLOT(connectionError(QString,QBearerEngineImpl::ConnectionError)));
321 }
322
323 activeConfig = config;
324 engine = getEngineFromId(activeConfig.identifier());
325
326 if (engine) {
327 connect(engine, SIGNAL(connectionError(QString,QBearerEngineImpl::ConnectionError)),
328 this, SLOT(connectionError(QString,QBearerEngineImpl::ConnectionError)),
329 Qt::QueuedConnection);
330 }
331 emit newConfigurationActivated();
332 }
333
334 state = QNetworkSession::Connected;
335 if (state != oldState)
336 emit stateChanged(state);
337
338 return;
339 }
340
341 if (serviceConfig.children().isEmpty())
342 state = QNetworkSession::NotAvailable;
343 else
344 state = QNetworkSession::Disconnected;
345
346 if (state != oldState)
347 emit stateChanged(state);
348}
349
350void QNetworkSessionPrivateImpl::updateStateFromActiveConfig()
351{
352 if (!engine)
353 return;
354
355 QNetworkSession::State oldState = state;
356 state = engine->sessionStateForId(activeConfig.identifier());
357
358 bool oldActive = isOpen;
359 isOpen = (state == QNetworkSession::Connected) ? opened : false;
360
361 if (!oldActive && isOpen)
362 emit quitPendingWaitsForOpened();
363 if (oldActive && !isOpen)
364 emit closed();
365
366 if (oldState != state)
367 emit stateChanged(state);
368}
369
370void QNetworkSessionPrivateImpl::networkConfigurationsChanged()
371{
372 if (serviceConfig.isValid())
373 updateStateFromServiceNetwork();
374 else
375 updateStateFromActiveConfig();
376
377 if (engine)
378 startTime = engine->startTime(activeConfig.identifier());
379}
380
381void QNetworkSessionPrivateImpl::configurationChanged(QNetworkConfigurationPrivatePointer config)
382{
383 if (serviceConfig.isValid() &&
384 (config->id == serviceConfig.identifier() || config->id == activeConfig.identifier())) {
385 updateStateFromServiceNetwork();
386 } else if (config->id == activeConfig.identifier()) {
387 updateStateFromActiveConfig();
388 }
389}
390
391void QNetworkSessionPrivateImpl::forcedSessionClose(const QNetworkConfiguration &config)
392{
393 if (activeConfig == config) {
394 opened = false;
395 isOpen = false;
396
397 emit closed();
398
399 lastError = QNetworkSession::SessionAbortedError;
400 emit QNetworkSessionPrivate::error(lastError);
401 }
402}
403
404void QNetworkSessionPrivateImpl::connectionError(const QString &id, QBearerEngineImpl::ConnectionError error)
405{
406 if (activeConfig.identifier() == id) {
407 networkConfigurationsChanged();
408 switch (error) {
409 case QBearerEngineImpl::OperationNotSupported:
410 lastError = QNetworkSession::OperationNotSupportedError;
411 opened = false;
412 break;
413 case QBearerEngineImpl::InterfaceLookupError:
414 case QBearerEngineImpl::ConnectError:
415 case QBearerEngineImpl::DisconnectionError:
416 default:
417 lastError = QNetworkSession::UnknownSessionError;
418 }
419
420 emit QNetworkSessionPrivate::error(lastError);
421 }
422}
423
424void QNetworkSessionPrivateImpl::decrementTimeout()
425{
426 if (--sessionTimeout <= 0) {
427 disconnect(engine, SIGNAL(updateCompleted()), this, SLOT(decrementTimeout()));
428 sessionTimeout = -1;
429 close();
430 }
431}
432
433QT_END_NAMESPACE
434
435#include "qnetworksession_impl.moc"
436