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 #include "qnetworkmanagerengine.h"
41 #include "qnetworkmanagerservice.h"
42 #include "../qnetworksession_impl.h"
43 
44 #include <QtNetwork/private/qnetworkconfiguration_p.h>
45 
46 #include <QtNetwork/qnetworksession.h>
47 
48 #include <QtCore/qdebug.h>
49 
50 #include <QtDBus>
51 #include <QDBusConnection>
52 #include <QDBusError>
53 #include <QDBusInterface>
54 #include <QDBusMessage>
55 #include <QDBusReply>
56 #include "../linux_common/qofonoservice_linux_p.h"
57 
58 #ifndef QT_NO_DBUS
59 
60 QT_BEGIN_NAMESPACE
61 
QNetworkManagerEngine(QObject * parent)62 QNetworkManagerEngine::QNetworkManagerEngine(QObject *parent)
63 :   QBearerEngineImpl(parent),
64     managerInterface(NULL),
65     systemSettings(NULL),
66     ofonoManager(NULL),
67     nmAvailable(false)
68 {
69     qDBusRegisterMetaType<QNmSettingsMap>();
70 
71     nmWatcher = new QDBusServiceWatcher(NM_DBUS_SERVICE,QDBusConnection::systemBus(),
72             QDBusServiceWatcher::WatchForRegistration |
73             QDBusServiceWatcher::WatchForUnregistration, this);
74     connect(nmWatcher, SIGNAL(serviceRegistered(QString)),
75             this, SLOT(nmRegistered(QString)));
76     connect(nmWatcher, SIGNAL(serviceUnregistered(QString)),
77             this, SLOT(nmUnRegistered(QString)));
78 
79     ofonoWatcher = new QDBusServiceWatcher("org.ofono",QDBusConnection::systemBus(),
80             QDBusServiceWatcher::WatchForRegistration |
81             QDBusServiceWatcher::WatchForUnregistration, this);
82     connect(ofonoWatcher, SIGNAL(serviceRegistered(QString)),
83             this, SLOT(ofonoRegistered(QString)));
84     connect(ofonoWatcher, SIGNAL(serviceUnregistered(QString)),
85             this, SLOT(ofonoUnRegistered(QString)));
86 
87     QDBusConnectionInterface *interface = QDBusConnection::systemBus().interface();
88 
89     if (!interface) return;
90 
91     if (interface->isServiceRegistered("org.ofono"))
92         QMetaObject::invokeMethod(this, "ofonoRegistered", Qt::QueuedConnection);
93 
94     if (interface->isServiceRegistered(NM_DBUS_SERVICE))
95         QMetaObject::invokeMethod(this, "nmRegistered", Qt::QueuedConnection);
96 }
97 
~QNetworkManagerEngine()98 QNetworkManagerEngine::~QNetworkManagerEngine()
99 {
100     qDeleteAll(connections);
101     connections.clear();
102     qDeleteAll(accessPoints);
103     accessPoints.clear();
104     qDeleteAll(wirelessDevices);
105     wirelessDevices.clear();
106     qDeleteAll(activeConnectionsList);
107     activeConnectionsList.clear();
108     qDeleteAll(interfaceDevices);
109     interfaceDevices.clear();
110 
111     connectionInterfaces.clear();
112 
113     qDeleteAll(ofonoContextManagers);
114     ofonoContextManagers.clear();
115 
116     qDeleteAll(wiredDevices);
117     wiredDevices.clear();
118 }
119 
initialize()120 void QNetworkManagerEngine::initialize()
121 {
122     if (nmAvailable)
123         setupConfigurations();
124 }
125 
setupConfigurations()126 void QNetworkManagerEngine::setupConfigurations()
127 {
128     QMutexLocker locker(&mutex);
129     // Get active connections.
130     const auto acPaths = managerInterface->activeConnections();
131     for (const QDBusObjectPath &acPath : acPaths) {
132 
133         if (activeConnectionsList.contains(acPath.path()))
134             continue;
135 
136         QNetworkManagerConnectionActive *activeConnection =
137                 new QNetworkManagerConnectionActive(acPath.path(),this);
138         activeConnectionsList.insert(acPath.path(), activeConnection);
139         connect(activeConnection, SIGNAL(propertiesChanged(QMap<QString,QVariant>)),
140                 this, SLOT(activeConnectionPropertiesChanged(QMap<QString,QVariant>)));
141 
142         QStringList devices = activeConnection->devices();
143         if (!devices.isEmpty()) {
144             QNetworkManagerInterfaceDevice device(devices.at(0),this);
145             connectionInterfaces.insert(activeConnection->connection().path(),device.networkInterface());
146         }
147     }
148 
149     // Get connections.
150     const auto settingsPaths = systemSettings->listConnections();
151     for (const QDBusObjectPath &settingsPath : settingsPaths) {
152         locker.unlock();
153         if (!hasIdentifier(settingsPath.path()))
154             newConnection(settingsPath, systemSettings); //add system connection configs
155         locker.relock();
156     }
157 
158     Q_EMIT updateCompleted();
159 }
160 
networkManagerAvailable() const161 bool QNetworkManagerEngine::networkManagerAvailable() const
162 {
163     return nmAvailable;
164 }
165 
getInterfaceFromId(const QString & settingsPath)166 QString QNetworkManagerEngine::getInterfaceFromId(const QString &settingsPath)
167 {
168     return connectionInterfaces.value(settingsPath);
169 }
170 
hasIdentifier(const QString & id)171 bool QNetworkManagerEngine::hasIdentifier(const QString &id)
172 {
173     QMutexLocker locker(&mutex);
174     return accessPointConfigurations.contains(id);
175 }
176 
connectToId(const QString & id)177 void QNetworkManagerEngine::connectToId(const QString &id)
178 {
179     QMutexLocker locker(&mutex);
180 
181     QNetworkManagerSettingsConnection *connection = connectionFromId(id);
182 
183     if (!connection)
184         return;
185 
186     NMDeviceType connectionType = connection->getType();
187 
188     QString dbusDevicePath;
189     const QString settingsPath = connection->path();
190     QString specificPath = configuredAccessPoints.key(settingsPath);
191 
192     if (isConnectionActive(settingsPath))
193         return;
194 
195     for (auto i = interfaceDevices.cbegin(), end = interfaceDevices.cend(); i != end; ++i) {
196         const auto type = i.value()->deviceType();
197         if (type == DEVICE_TYPE_ETHERNET || type == DEVICE_TYPE_WIFI || type == DEVICE_TYPE_MODEM) {
198             if (type == connectionType) {
199                 dbusDevicePath = i.key();
200                 break;
201             }
202         }
203     }
204 
205     if (specificPath.isEmpty())
206         specificPath = "/";
207 
208     managerInterface->activateConnection(QDBusObjectPath(settingsPath),
209                                   QDBusObjectPath(dbusDevicePath), QDBusObjectPath(specificPath));
210 }
211 
disconnectFromId(const QString & id)212 void QNetworkManagerEngine::disconnectFromId(const QString &id)
213 {
214     QMutexLocker locker(&mutex);
215 
216     QNetworkManagerSettingsConnection *connection = connectionFromId(id);
217 
218     if (!connection)
219         return;
220 
221     QNmSettingsMap map = connection->getSettings();
222     bool connectionAutoconnect = map.value("connection").value("autoconnect",true).toBool(); //if not present is true !!
223     if (connectionAutoconnect) { //autoconnect connections will simply be reconnected by nm
224         emit connectionError(id, QBearerEngineImpl::OperationNotSupported);
225         return;
226     }
227 
228     for (auto i = activeConnectionsList.cbegin(), end = activeConnectionsList.cend(); i != end; ++i) {
229         if (id == i.value()->connection().path() && accessPointConfigurations.contains(id)) {
230             managerInterface->deactivateConnection(QDBusObjectPath(i.key()));
231             break;
232         }
233     }
234 }
235 
requestUpdate()236 void QNetworkManagerEngine::requestUpdate()
237 {
238     if (managerInterface && managerInterface->wirelessEnabled()) {
239         for (auto *wirelessDevice : qAsConst(wirelessDevices))
240             wirelessDevice->requestScan();
241     }
242     QMetaObject::invokeMethod(this, "updateCompleted", Qt::QueuedConnection);
243 }
244 
interfacePropertiesChanged(const QMap<QString,QVariant> & properties)245 void QNetworkManagerEngine::interfacePropertiesChanged(const QMap<QString, QVariant> &properties)
246 {
247     QMutexLocker locker(&mutex);
248 
249     for (auto i = properties.cbegin(), end = properties.cend(); i != end; ++i) {
250         if (i.key() == QLatin1String("ActiveConnections")) {
251             // Active connections changed, update configurations.
252 
253             const auto activeConnections = qdbus_cast<QList<QDBusObjectPath> >(qvariant_cast<QDBusArgument>(i.value()));
254 
255             QStringList identifiers = accessPointConfigurations.keys();
256             QStringList priorActiveConnections = activeConnectionsList.keys();
257 
258             for (const QDBusObjectPath &acPath : activeConnections) {
259                 priorActiveConnections.removeOne(acPath.path());
260                 QNetworkManagerConnectionActive *activeConnection =
261                     activeConnectionsList.value(acPath.path());
262 
263                 if (!activeConnection) {
264                     activeConnection = new QNetworkManagerConnectionActive(acPath.path(),this);
265                     activeConnectionsList.insert(acPath.path(), activeConnection);
266 
267                     connect(activeConnection, SIGNAL(propertiesChanged(QMap<QString,QVariant>)),
268                             this, SLOT(activeConnectionPropertiesChanged(QMap<QString,QVariant>)));
269                 }
270 
271                 const QString id = activeConnection->connection().path();
272 
273                 identifiers.removeOne(id);
274 
275                 QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
276                 if (ptr) {
277                     ptr->mutex.lock();
278                     if (activeConnection->state() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED &&
279                             (ptr->state & QNetworkConfiguration::Active) != QNetworkConfiguration::Active) {
280 
281                         ptr->state |= QNetworkConfiguration::Active;
282 
283                         if (activeConnectionsList.value(id) && activeConnectionsList.value(id)->defaultRoute()
284                                 && managerInterface->state() < QNetworkManagerInterface::NM_STATE_CONNECTED_GLOBAL) {
285                             ptr->purpose = QNetworkConfiguration::PrivatePurpose;
286                         }
287                         ptr->mutex.unlock();
288 
289                         locker.unlock();
290                         emit configurationChanged(ptr);
291                         locker.relock();
292                     } else {
293                         ptr->mutex.unlock();
294                     }
295                 }
296             }
297 
298             while (!priorActiveConnections.isEmpty())
299                 delete activeConnectionsList.take(priorActiveConnections.takeFirst());
300 
301             while (!identifiers.isEmpty()) {
302                 QNetworkConfigurationPrivatePointer ptr =
303                     accessPointConfigurations.value(identifiers.takeFirst());
304 
305                 ptr->mutex.lock();
306                 if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
307                     QNetworkConfiguration::StateFlags flag = QNetworkConfiguration::Defined;
308                     ptr->state = (flag | QNetworkConfiguration::Discovered);
309                     ptr->mutex.unlock();
310 
311                     locker.unlock();
312                     emit configurationChanged(ptr);
313                     locker.relock();
314                 } else {
315                     ptr->mutex.unlock();
316                 }
317             }
318         }
319     }
320 }
321 
activeConnectionPropertiesChanged(const QMap<QString,QVariant> & properties)322 void QNetworkManagerEngine::activeConnectionPropertiesChanged(const QMap<QString, QVariant> &properties)
323 {
324     QMutexLocker locker(&mutex);
325 
326     Q_UNUSED(properties)
327 
328     QNetworkManagerConnectionActive *activeConnection = qobject_cast<QNetworkManagerConnectionActive *>(sender());
329 
330     if (!activeConnection)
331         return;
332 
333     const QString id = activeConnection->connection().path();
334 
335     QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
336     if (ptr) {
337         if (properties.contains(QStringLiteral("State"))) {
338             ptr->mutex.lock();
339             if (properties.value("State").toUInt() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
340                 QStringList devices = activeConnection->devices();
341                 if (!devices.isEmpty()) {
342                     QNetworkManagerInterfaceDevice device(devices.at(0),this);
343                     connectionInterfaces.insert(id,device.networkInterface());
344                 }
345 
346                 ptr->state |= QNetworkConfiguration::Active;
347                 ptr->mutex.unlock();
348 
349                 locker.unlock();
350                 emit configurationChanged(ptr);
351                 locker.relock();
352             } else {
353                 connectionInterfaces.remove(id);
354                 ptr->mutex.unlock();
355             }
356         }
357     }
358 }
359 
deviceConnectionsChanged(const QStringList & connectionsList)360 void QNetworkManagerEngine::deviceConnectionsChanged(const QStringList &connectionsList)
361 {
362     QMutexLocker locker(&mutex);
363     for (int i = 0; i < connections.count(); ++i) {
364         if (connectionsList.contains(connections.at(i)->path()))
365             continue;
366 
367         const QString settingsPath = connections.at(i)->path();
368 
369         QNetworkConfigurationPrivatePointer ptr =
370             accessPointConfigurations.value(settingsPath);
371         ptr->mutex.lock();
372         QNetworkConfiguration::StateFlags flag = QNetworkConfiguration::Defined;
373         ptr->state = (flag | QNetworkConfiguration::Discovered);
374         ptr->mutex.unlock();
375 
376         locker.unlock();
377         emit configurationChanged(ptr);
378         locker.relock();
379         Q_EMIT updateCompleted();
380     }
381 }
382 
wiredCarrierChanged(bool carrier)383 void QNetworkManagerEngine::wiredCarrierChanged(bool carrier)
384 {
385     QNetworkManagerInterfaceDeviceWired *deviceWired = qobject_cast<QNetworkManagerInterfaceDeviceWired *>(sender());
386     if (!deviceWired)
387         return;
388     QMutexLocker locker(&mutex);
389     const auto settingsPaths = systemSettings->listConnections();
390     for (const QDBusObjectPath &settingsPath : settingsPaths) {
391         for (int i = 0; i < connections.count(); ++i) {
392             QNetworkManagerSettingsConnection *connection = connections.at(i);
393             if (connection->getType() == DEVICE_TYPE_ETHERNET
394                     && settingsPath.path() == connection->path()) {
395                 QNetworkConfigurationPrivatePointer ptr =
396                         accessPointConfigurations.value(settingsPath.path());
397 
398                 if (ptr) {
399                     ptr->mutex.lock();
400                     if (carrier)
401                         ptr->state |= QNetworkConfiguration::Discovered;
402                     else
403                         ptr->state = QNetworkConfiguration::Defined;
404                     ptr->mutex.unlock();
405                     locker.unlock();
406                     emit configurationChanged(ptr);
407                     return;
408                 }
409             }
410         }
411     }
412 }
413 
newConnection(const QDBusObjectPath & path,QNetworkManagerSettings * settings)414 void QNetworkManagerEngine::newConnection(const QDBusObjectPath &path,
415                                           QNetworkManagerSettings *settings)
416 {
417     QMutexLocker locker(&mutex);
418     if (!settings)
419         settings = qobject_cast<QNetworkManagerSettings *>(sender());
420 
421     if (!settings) {
422         return;
423     }
424 
425     QNetworkManagerSettingsConnection *connection =
426         new QNetworkManagerSettingsConnection(settings->service(),
427                                               path.path(),this);
428     const QString settingsPath = connection->path();
429     if (accessPointConfigurations.contains(settingsPath)) {
430         return;
431     }
432 
433     connections.append(connection);
434 
435     connect(connection,SIGNAL(removed(QString)),this,SLOT(removeConnection(QString)));
436     connect(connection,SIGNAL(updated()),this,SLOT(updateConnection()));
437     connection->setConnections();
438 
439     NMDeviceType deviceType = connection->getType();
440 
441     if (deviceType == DEVICE_TYPE_WIFI) {
442         QString apPath;
443         for (int i = 0; i < accessPoints.count(); ++i) {
444             if (connection->getSsid() == accessPoints.at(i)->ssid()) {
445                 // remove the corresponding accesspoint from configurations
446                 apPath = accessPoints.at(i)->path();
447                 QNetworkConfigurationPrivatePointer ptr
448                         = accessPointConfigurations.take(apPath);
449                 if (ptr) {
450                     locker.unlock();
451                     emit configurationRemoved(ptr);
452                     locker.relock();
453                 }
454             }
455         }
456         if (!configuredAccessPoints.contains(settingsPath))
457             configuredAccessPoints.insert(apPath,settingsPath);
458     }
459 
460     QNetworkConfigurationPrivate *cpPriv =
461         parseConnection(settingsPath, connection->getSettings());
462 
463     // Check if connection is active.
464     if (isConnectionActive(settingsPath))
465         cpPriv->state |= QNetworkConfiguration::Active;
466 
467     if (deviceType == DEVICE_TYPE_ETHERNET) {
468         for (auto interfaceDevice : qAsConst(interfaceDevices)) {
469              if (interfaceDevice->deviceType() == deviceType) {
470                  auto *wiredDevice = wiredDevices.value(interfaceDevice->path());
471                  if (wiredDevice && wiredDevice->carrier()) {
472                      cpPriv->state |= QNetworkConfiguration::Discovered;
473                  }
474              }
475          }
476      }
477 
478     QNetworkConfigurationPrivatePointer ptr(cpPriv);
479     accessPointConfigurations.insert(ptr->id, ptr);
480     locker.unlock();
481     emit configurationAdded(ptr);
482 }
483 
isConnectionActive(const QString & settingsPath) const484 bool QNetworkManagerEngine::isConnectionActive(const QString &settingsPath) const
485 {
486     for (QNetworkManagerConnectionActive *activeConnection : activeConnectionsList) {
487         if (activeConnection->connection().path() == settingsPath) {
488             const auto state = activeConnection->state();
489             if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING
490                     || state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
491                 return true;
492             } else {
493                 break;
494             }
495         }
496     }
497 
498     QNetworkManagerSettingsConnection *settingsConnection = connectionFromId(settingsPath);
499     if (settingsConnection && settingsConnection->getType() == DEVICE_TYPE_MODEM) {
500         return isActiveContext(settingsConnection->path());
501     }
502 
503     return false;
504 }
505 
removeConnection(const QString & path)506 void QNetworkManagerEngine::removeConnection(const QString &path)
507 {
508     QMutexLocker locker(&mutex);
509 
510     QNetworkManagerSettingsConnection *connection =
511         qobject_cast<QNetworkManagerSettingsConnection *>(sender());
512 
513     if (!connection)
514         return;
515 
516     connection->deleteLater();
517     connections.removeAll(connection);
518 
519     const QString id = path;
520 
521     QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(id);
522 
523     if (ptr) {
524         locker.unlock();
525         emit configurationRemoved(ptr);
526         locker.relock();
527     }
528 
529     // add base AP back into configurations
530 
531     // removed along with all AP props code...
532 }
533 
updateConnection()534 void QNetworkManagerEngine::updateConnection()
535 {
536     QMutexLocker locker(&mutex);
537 
538     QNetworkManagerSettingsConnection *connection =
539         qobject_cast<QNetworkManagerSettingsConnection *>(sender());
540     if (!connection)
541         return;
542     const QString settingsPath = connection->path();
543 
544     QNetworkConfigurationPrivate *cpPriv = parseConnection(settingsPath, connection->getSettings());
545 
546     // Check if connection is active.
547     const auto acPaths = managerInterface->activeConnections();
548     for (const QDBusObjectPath &acPath : acPaths) {
549         QNetworkManagerConnectionActive activeConnection(acPath.path());
550 
551         if (activeConnection.connection().path() == settingsPath &&
552             activeConnection.state() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
553             cpPriv->state |= QNetworkConfiguration::Active;
554             break;
555         }
556     }
557 
558     QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(cpPriv->id);
559 
560     ptr->mutex.lock();
561 
562     ptr->isValid = cpPriv->isValid;
563     ptr->name = cpPriv->name;
564     ptr->id = cpPriv->id;
565     ptr->state = cpPriv->state;
566 
567     ptr->mutex.unlock();
568 
569     locker.unlock();
570     emit configurationChanged(ptr);
571     locker.relock();
572     delete cpPriv;
573 }
574 
activationFinished(QDBusPendingCallWatcher * watcher)575 void QNetworkManagerEngine::activationFinished(QDBusPendingCallWatcher *watcher)
576 {
577     QMutexLocker locker(&mutex);
578     QDBusPendingReply<QDBusObjectPath> reply(*watcher);
579     watcher->deleteLater();
580 
581     if (!reply.isError()) {
582         QDBusObjectPath result = reply.value();
583 
584         QNetworkManagerConnectionActive activeConnection(result.path());
585 
586         const QString id = activeConnection.connection().path();
587 
588         QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
589         if (ptr) {
590             ptr->mutex.lock();
591             if (activeConnection.state() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED &&
592                 ptr->state != QNetworkConfiguration::Active) {
593                 ptr->state |= QNetworkConfiguration::Active;
594                 ptr->mutex.unlock();
595 
596                 locker.unlock();
597                 emit configurationChanged(ptr);
598                 locker.relock();
599             } else {
600                 ptr->mutex.unlock();
601             }
602         }
603     }
604 }
605 
parseConnection(const QString & settingsPath,const QNmSettingsMap & map)606 QNetworkConfigurationPrivate *QNetworkManagerEngine::parseConnection(const QString &settingsPath,
607                                                                      const QNmSettingsMap &map)
608 {
609     QMutexLocker locker(&mutex);
610     QNetworkConfigurationPrivate *cpPriv = new QNetworkConfigurationPrivate;
611     cpPriv->name = map.value("connection").value("id").toString();
612     cpPriv->isValid = true;
613     cpPriv->id = settingsPath;
614     cpPriv->type = QNetworkConfiguration::InternetAccessPoint;
615 
616     cpPriv->purpose = QNetworkConfiguration::PublicPurpose;
617 
618     cpPriv->state = QNetworkConfiguration::Defined;
619     const QString connectionType = map.value("connection").value("type").toString();
620 
621     if (connectionType == QLatin1String("802-3-ethernet")) {
622         cpPriv->bearerType = QNetworkConfiguration::BearerEthernet;
623 
624         const auto devicePaths = managerInterface->getDevices();
625         for (const QDBusObjectPath &devicePath : devicePaths) {
626             QNetworkManagerInterfaceDevice device(devicePath.path(),this);
627             if (device.deviceType() == DEVICE_TYPE_ETHERNET) {
628                 QNetworkManagerInterfaceDeviceWired *wiredDevice = wiredDevices.value(device.path());
629                 if (wiredDevice && wiredDevice->carrier()) {
630                     cpPriv->state |= QNetworkConfiguration::Discovered;
631                     break;
632                 }
633             }
634         }
635     } else if (connectionType == QLatin1String("802-11-wireless")) {
636         cpPriv->bearerType = QNetworkConfiguration::BearerWLAN;
637 
638         const QString connectionSsid = map.value("802-11-wireless").value("ssid").toString();
639         for (int i = 0; i < accessPoints.count(); ++i) {
640             if (connectionSsid == accessPoints.at(i)->ssid()
641                     && map.value("802-11-wireless").value("seen-bssids").toStringList().contains(accessPoints.at(i)->hwAddress())) {
642                 cpPriv->state |= QNetworkConfiguration::Discovered;
643                 if (!configuredAccessPoints.contains(accessPoints.at(i)->path())) {
644                     configuredAccessPoints.insert(accessPoints.at(i)->path(),settingsPath);
645 
646                     const QString accessPointId = accessPoints.at(i)->path();
647                     QNetworkConfigurationPrivatePointer ptr =
648                         accessPointConfigurations.take(accessPointId);
649 
650                     if (ptr) {
651                         locker.unlock();
652                         emit configurationRemoved(ptr);
653                         locker.relock();
654                     }
655                 }
656                 break;
657             }
658         }
659     } else if (connectionType == QLatin1String("gsm")) {
660 
661         const QString connectionPath = map.value("connection").value("id").toString();
662         cpPriv->name = contextName(connectionPath);
663         cpPriv->bearerType = currentBearerType(connectionPath);
664 
665         if (ofonoManager && ofonoManager->isValid()) {
666             const QString contextPart = connectionPath.section('/', -1);
667             for (auto i = ofonoContextManagers.cbegin(), end = ofonoContextManagers.cend(); i != end; ++i) {
668                 const QString path = i.key() + QLatin1Char('/') +contextPart;
669                 if (isActiveContext(path)) {
670                     cpPriv->state |= QNetworkConfiguration::Active;
671                     break;
672                 }
673             }
674         }
675     }
676 
677     return cpPriv;
678 }
679 
isActiveContext(const QString & contextPath) const680 bool QNetworkManagerEngine::isActiveContext(const QString &contextPath) const
681 {
682     if (ofonoManager && ofonoManager->isValid()) {
683         const QString contextPart = contextPath.section('/', -1);
684         for (QOfonoDataConnectionManagerInterface *iface : ofonoContextManagers) {
685             const PathPropertiesList list = iface->contextsWithProperties();
686             for (int i = 0; i < list.size(); ++i) {
687                 if (list.at(i).path.path().contains(contextPart)) {
688                     return list.at(i).properties.value(QStringLiteral("Active")).toBool();
689 
690                 }
691             }
692         }
693     }
694     return false;
695 }
696 
connectionFromId(const QString & id) const697 QNetworkManagerSettingsConnection *QNetworkManagerEngine::connectionFromId(const QString &id) const
698 {
699     for (int i = 0; i < connections.count(); ++i) {
700         QNetworkManagerSettingsConnection *connection = connections.at(i);
701         if (id == connection->path())
702             return connection;
703     }
704 
705     return 0;
706 }
707 
sessionStateForId(const QString & id)708 QNetworkSession::State QNetworkManagerEngine::sessionStateForId(const QString &id)
709 {
710     QMutexLocker locker(&mutex);
711     QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
712 
713     if (!ptr)
714         return QNetworkSession::Invalid;
715 
716     if (!ptr->isValid)
717         return QNetworkSession::Invalid;
718 
719     for (QNetworkManagerConnectionActive *activeConnection : qAsConst(activeConnectionsList)) {
720         const QString identifier = activeConnection->connection().path();
721 
722         if (id == identifier) {
723             switch (activeConnection->state()) {
724             case 0:
725                 return QNetworkSession::Disconnected;
726             case 1:
727                 return QNetworkSession::Connecting;
728             case 2:
729                 return QNetworkSession::Connected;
730             }
731         }
732     }
733 
734     if ((ptr->state & QNetworkConfiguration::Discovered) == QNetworkConfiguration::Discovered)
735         return QNetworkSession::Disconnected;
736     else if ((ptr->state & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined)
737         return QNetworkSession::NotAvailable;
738     else if ((ptr->state & QNetworkConfiguration::Undefined) == QNetworkConfiguration::Undefined)
739         return QNetworkSession::NotAvailable;
740 
741     return QNetworkSession::Invalid;
742 }
743 
bytesWritten(const QString & id)744 quint64 QNetworkManagerEngine::bytesWritten(const QString &id)
745 {
746     QMutexLocker locker(&mutex);
747 
748     QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
749     if (ptr && (ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
750         const QString networkInterface = connectionInterfaces.value(id);
751         if (!networkInterface.isEmpty()) {
752             const QString devFile = QLatin1String("/sys/class/net/") +
753                                     networkInterface +
754                                     QLatin1String("/statistics/tx_bytes");
755 
756             quint64 result = Q_UINT64_C(0);
757 
758             QFile tx(devFile);
759             if (tx.open(QIODevice::ReadOnly | QIODevice::Text)) {
760                 QTextStream in(&tx);
761                 in >> result;
762                 tx.close();
763             }
764 
765             return result;
766         }
767     }
768 
769     return Q_UINT64_C(0);
770 }
771 
bytesReceived(const QString & id)772 quint64 QNetworkManagerEngine::bytesReceived(const QString &id)
773 {
774     QMutexLocker locker(&mutex);
775 
776     QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id);
777     if (ptr && (ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
778         const QString networkInterface = connectionInterfaces.value(id);
779         if (!networkInterface.isEmpty()) {
780             const QString devFile = QLatin1String("/sys/class/net/") +
781                                     networkInterface +
782                                     QLatin1String("/statistics/rx_bytes");
783 
784             quint64 result = Q_UINT64_C(0);
785 
786             QFile tx(devFile);
787             if (tx.open(QIODevice::ReadOnly | QIODevice::Text)) {
788                 QTextStream in(&tx);
789                 in >> result;
790                 tx.close();
791             }
792 
793             return result;
794         }
795     }
796 
797     return Q_UINT64_C(0);
798 }
799 
startTime(const QString & id)800 quint64 QNetworkManagerEngine::startTime(const QString &id)
801 {
802     QMutexLocker locker(&mutex);
803 
804     QNetworkManagerSettingsConnection *connection = connectionFromId(id);
805     if (connection)
806         return connection->getTimestamp();
807     else
808         return Q_UINT64_C(0);
809 }
810 
capabilities() const811 QNetworkConfigurationManager::Capabilities QNetworkManagerEngine::capabilities() const
812 {
813     return QNetworkConfigurationManager::ForcedRoaming |
814             QNetworkConfigurationManager::DataStatistics |
815             QNetworkConfigurationManager::CanStartAndStopInterfaces;
816 }
817 
createSessionBackend()818 QNetworkSessionPrivate *QNetworkManagerEngine::createSessionBackend()
819 {
820     return new QNetworkSessionPrivateImpl;
821 }
822 
defaultConfiguration()823 QNetworkConfigurationPrivatePointer QNetworkManagerEngine::defaultConfiguration()
824 {
825     for (QNetworkManagerConnectionActive *activeConnection : qAsConst(activeConnectionsList)) {
826         if ((activeConnection->defaultRoute() || activeConnection->default6Route())) {
827             return accessPointConfigurations.value(activeConnection->connection().path());
828         }
829     }
830 
831     return QNetworkConfigurationPrivatePointer();
832 }
833 
currentBearerType(const QString & id) const834 QNetworkConfiguration::BearerType QNetworkManagerEngine::currentBearerType(const QString &id) const
835 {
836     QString contextPart = id.section('/', -1);
837     for (auto i = ofonoContextManagers.begin(), end = ofonoContextManagers.end(); i != end; ++i) {
838         QString contextPath = i.key() + QLatin1Char('/') +contextPart;
839 
840         if (i.value()->contexts().contains(contextPath)) {
841 
842             QString bearer = i.value()->bearer();
843 
844             if (bearer == QLatin1String("gsm")) {
845                 return QNetworkConfiguration::Bearer2G;
846             } else if (bearer == QLatin1String("edge")) {
847                 return QNetworkConfiguration::Bearer2G;
848             } else if (bearer == QLatin1String("umts")) {
849                 return QNetworkConfiguration::BearerWCDMA;
850             } else if (bearer == QLatin1String("hspa")
851                        || bearer == QLatin1String("hsdpa")
852                        || bearer == QLatin1String("hsupa")) {
853                 return QNetworkConfiguration::BearerHSPA;
854             } else if (bearer == QLatin1String("lte")) {
855                 return QNetworkConfiguration::BearerLTE;
856             }
857         }
858     }
859 
860     return QNetworkConfiguration::BearerUnknown;
861 }
862 
contextName(const QString & path) const863 QString QNetworkManagerEngine::contextName(const QString &path) const
864 {
865     QString contextPart = path.section('/', -1);
866     for (QOfonoDataConnectionManagerInterface *iface : ofonoContextManagers) {
867         const PathPropertiesList list = iface->contextsWithProperties();
868         for (int i = 0; i < list.size(); ++i) {
869             if (list.at(i).path.path().contains(contextPart)) {
870                 return list.at(i).properties.value(QStringLiteral("Name")).toString();
871             }
872         }
873     }
874     return path;
875 }
876 
nmRegistered(const QString &)877 void QNetworkManagerEngine::nmRegistered(const QString &)
878 {
879     if (ofonoManager) {
880         delete ofonoManager;
881         ofonoManager = NULL;
882     }
883     managerInterface = new QNetworkManagerInterface(this);
884     systemSettings = new QNetworkManagerSettings(NM_DBUS_SERVICE, this);
885 
886     connect(managerInterface, SIGNAL(activationFinished(QDBusPendingCallWatcher*)),
887             this, SLOT(activationFinished(QDBusPendingCallWatcher*)));
888     connect(managerInterface, SIGNAL(propertiesChanged(QMap<QString,QVariant>)),
889             this, SLOT(interfacePropertiesChanged(QMap<QString,QVariant>)));
890     managerInterface->setConnections();
891 
892     connect(systemSettings, SIGNAL(newConnection(QDBusObjectPath)),
893             this, SLOT(newConnection(QDBusObjectPath)));
894     systemSettings->setConnections();
895     nmAvailable = true;
896 
897     setupConfigurations();
898 }
899 
nmUnRegistered(const QString &)900 void QNetworkManagerEngine::nmUnRegistered(const QString &)
901 {
902     if (systemSettings) {
903         delete systemSettings;
904         systemSettings = NULL;
905     }
906     if (managerInterface) {
907         delete managerInterface;
908         managerInterface = NULL;
909     }
910 }
911 
ofonoRegistered(const QString &)912 void QNetworkManagerEngine::ofonoRegistered(const QString &)
913 {
914     if (ofonoManager) {
915         delete ofonoManager;
916         ofonoManager = NULL;
917     }
918     ofonoManager = new QOfonoManagerInterface(this);
919     if (ofonoManager && ofonoManager->isValid()) {
920         const auto modems = ofonoManager->getModems();
921         for (const QString &modem : modems) {
922             QOfonoDataConnectionManagerInterface *ofonoContextManager
923                     = new QOfonoDataConnectionManagerInterface(modem,this);
924             ofonoContextManagers.insert(modem, ofonoContextManager);
925         }
926     }
927 }
928 
ofonoUnRegistered(const QString &)929 void QNetworkManagerEngine::ofonoUnRegistered(const QString &)
930 {
931     ofonoContextManagers.clear();
932 }
933 
934 QT_END_NAMESPACE
935 
936 #endif // QT_NO_DBUS
937