diff options
author | Aaron McCarthy <aaron.mccarthy@nokia.com> | 2009-12-09 05:44:52 (GMT) |
---|---|---|
committer | Aaron McCarthy <aaron.mccarthy@nokia.com> | 2010-01-04 01:07:51 (GMT) |
commit | 7858758772ad01e6a772cb048e4f1eda7f4ec9c3 (patch) | |
tree | d8a81f486ee01f494991c89529d06f4e2fa16167 /src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp | |
parent | ee8b1156400791a077280138863336ea93a774a7 (diff) | |
download | Qt-7858758772ad01e6a772cb048e4f1eda7f4ec9c3.zip Qt-7858758772ad01e6a772cb048e4f1eda7f4ec9c3.tar.gz Qt-7858758772ad01e6a772cb048e4f1eda7f4ec9c3.tar.bz2 |
Rework NetworkManager backend.
Diffstat (limited to 'src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp')
-rw-r--r-- | src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp | 654 |
1 files changed, 654 insertions, 0 deletions
diff --git a/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp new file mode 100644 index 0000000..3de20a3 --- /dev/null +++ b/src/plugins/bearer/networkmanager/qnetworkmanagerengine.cpp @@ -0,0 +1,654 @@ +/**************************************************************************** +** +** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the plugins of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** No Commercial Usage +** This file contains pre-release code and may not be distributed. +** You may use this file in accordance with the terms and conditions +** contained in the Technology Preview License Agreement accompanying +** this package. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** If you have questions regarding the use of this file, please contact +** Nokia at qt-info@nokia.com. +** +** +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qnetworkmanagerengine.h" +#include "qnetworkmanagerservice.h" + +#include <QtNetwork/private/qnetworkconfiguration_p.h> + +#include <QtNetwork/qnetworksession.h> + +#include <QtCore/qdebug.h> + +#include <NetworkManager/NetworkManager.h> +#include <QtDBus> +#include <QDBusConnection> +#include <QDBusError> +#include <QDBusInterface> +#include <QDBusMessage> +#include <QDBusReply> + +QT_BEGIN_NAMESPACE + +QNetworkManagerEngine::QNetworkManagerEngine(QObject *parent) +: QNetworkSessionEngine(parent), + interface(new QNetworkManagerInterface(this)), + systemSettings(new QNetworkManagerSettings(NM_DBUS_SERVICE_SYSTEM_SETTINGS, this)), + userSettings(new QNetworkManagerSettings(NM_DBUS_SERVICE_USER_SETTINGS, this)) +{ + interface->setConnections(); + connect(interface, SIGNAL(deviceAdded(QDBusObjectPath)), + this, SLOT(deviceAdded(QDBusObjectPath))); + connect(interface, SIGNAL(deviceRemoved(QDBusObjectPath)), + this, SLOT(deviceRemoved(QDBusObjectPath))); +#if 0 + connect(interface, SIGNAL(stateChanged(const QString,quint32)), + this, SIGNAL(configurationsChanged())); +#endif + connect(interface, SIGNAL(activationFinished(QDBusPendingCallWatcher*)), + this, SLOT(activationFinished(QDBusPendingCallWatcher*))); + connect(interface, SIGNAL(propertiesChanged(QString,QMap<QString,QVariant>)), + this, SLOT(interfacePropertiesChanged(QString,QMap<QString,QVariant>))); + + qDBusRegisterMetaType<QNmSettingsMap>(); + + systemSettings->setConnections(); + connect(systemSettings, SIGNAL(newConnection(QDBusObjectPath)), + this, SLOT(newConnection(QDBusObjectPath))); + + userSettings->setConnections(); + connect(userSettings, SIGNAL(newConnection(QDBusObjectPath)), + this, SLOT(newConnection(QDBusObjectPath))); + + // Get current list of access points. + foreach (const QDBusObjectPath &devicePath, interface->getDevices()) + deviceAdded(devicePath); + + // Get connections. + foreach (const QDBusObjectPath &settingsPath, systemSettings->listConnections()) + newConnection(settingsPath, systemSettings); + foreach (const QDBusObjectPath &settingsPath, userSettings->listConnections()) + newConnection(settingsPath, userSettings); + + // Get active connections. + foreach (const QDBusObjectPath &acPath, interface->activeConnections()) { + QNetworkManagerConnectionActive *activeConnection = + new QNetworkManagerConnectionActive(acPath.path()); + activeConnections.insert(acPath.path(), activeConnection); + + activeConnection->setConnections(); + connect(activeConnection, SIGNAL(propertiesChanged(QString,QMap<QString,QVariant>)), + this, SLOT(activeConnectionPropertiesChanged(QString,QMap<QString,QVariant>))); + } +} + +QNetworkManagerEngine::~QNetworkManagerEngine() +{ +} + +void QNetworkManagerEngine::doRequestUpdate() +{ +} + +QString QNetworkManagerEngine::getInterfaceFromId(const QString &id) +{ + foreach (const QDBusObjectPath &acPath, interface->activeConnections()) { + QNetworkManagerConnectionActive activeConnection(acPath.path()); + + const QString identifier = QString::number(qHash(activeConnection.serviceName() + ' ' + + activeConnection.connection().path())); + + if (id == identifier) { + QList<QDBusObjectPath> devices = activeConnection.devices(); + + if (devices.isEmpty()) + continue; + + if (devices.count() > 1) + qDebug() << "multiple network interfaces for" << id; + + QNetworkManagerInterfaceDevice device(devices.at(0).path()); + return device.interface().name(); + } + } + + return QString(); +} + +bool QNetworkManagerEngine::hasIdentifier(const QString &id) +{ + if (connectionFromId(id)) + return true; + + for (int i = 0; i < accessPoints.count(); ++i) { + QNetworkManagerInterfaceAccessPoint *accessPoint = accessPoints.at(i); + + const QString identifier = + QString::number(qHash(accessPoint->connectionInterface()->path())); + + if (id == identifier) + return true; + } + + return false; +} + +QString QNetworkManagerEngine::bearerName(const QString &id) +{ + QNetworkManagerSettingsConnection *connection = connectionFromId(id); + + if (!connection) + return QString(); + + QNmSettingsMap map = connection->getSettings(); + const QString connectionType = map.value("connection").value("type").toString(); + + if (connectionType == "802-3-ethernet") + return QLatin1String("Ethernet"); + else if (connectionType == "802-11-wireless") + return QLatin1String("WLAN"); + else if (connectionType == "gsm") + return QLatin1String("2G"); + else if (connectionType == "cdma") + return QLatin1String("CDMA2000"); + else + return QString(); +} + +void QNetworkManagerEngine::connectToId(const QString &id) +{ + QNetworkManagerSettingsConnection *connection = connectionFromId(id); + + if (!connection) + return; + + QNmSettingsMap map = connection->getSettings(); + const QString connectionType = map.value("connection").value("type").toString(); + + QString dbusDevicePath; + foreach (const QDBusObjectPath &devicePath, interface->getDevices()) { + QNetworkManagerInterfaceDevice device(devicePath.path()); + if (device.deviceType() == DEVICE_TYPE_802_3_ETHERNET && + connectionType == QLatin1String("802-3-ethernet")) { + dbusDevicePath = devicePath.path(); + break; + } else if (device.deviceType() == DEVICE_TYPE_802_11_WIRELESS && + connectionType == QLatin1String("802-11-wireless")) { + dbusDevicePath = devicePath.path(); + break; + } + } + + const QString service = connection->connectionInterface()->service(); + const QString settingsPath = connection->connectionInterface()->path(); + + interface->activateConnection(service, QDBusObjectPath(settingsPath), + QDBusObjectPath(dbusDevicePath), QDBusObjectPath("/")); +} + +void QNetworkManagerEngine::disconnectFromId(const QString &id) +{ + foreach (const QDBusObjectPath &acPath, interface->activeConnections()) { + QNetworkManagerConnectionActive activeConnection(acPath.path()); + + const QString identifier = QString::number(qHash(activeConnection.serviceName() + ' ' + + activeConnection.connection().path())); + + if (id == identifier && accessPointConfigurations.contains(id)) { + interface->deactivateConnection(acPath); + break; + } + } +} + +void QNetworkManagerEngine::requestUpdate() +{ + QTimer::singleShot(0, this, SLOT(doRequestUpdate())); +} + +void QNetworkManagerEngine::interfacePropertiesChanged(const QString &path, + const QMap<QString, QVariant> &properties) +{ + QMapIterator<QString, QVariant> i(properties); + while (i.hasNext()) { + i.next(); + + if (i.key() == QLatin1String("ActiveConnections")) { + // Active connections changed, update configurations. + + QList<QDBusObjectPath> activeConnections = + qdbus_cast<QList<QDBusObjectPath> >(i.value().value<QDBusArgument>()); + + QStringList identifiers = accessPointConfigurations.keys(); + foreach (const QString &id, identifiers) + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + + QStringList priorActiveConnections = this->activeConnections.keys(); + + foreach (const QDBusObjectPath &acPath, activeConnections) { + priorActiveConnections.removeOne(acPath.path()); + QNetworkManagerConnectionActive *activeConnection = + this->activeConnections.value(acPath.path()); + if (!activeConnection) { + activeConnection = new QNetworkManagerConnectionActive(acPath.path()); + this->activeConnections.insert(acPath.path(), activeConnection); + + activeConnection->setConnections(); + connect(activeConnection, SIGNAL(propertiesChanged(QString,QMap<QString,QVariant>)), + this, SLOT(activeConnectionPropertiesChanged(QString,QMap<QString,QVariant>))); + } + + const QString id = QString::number(qHash(activeConnection->serviceName() + ' ' + + activeConnection->connection().path())); + + identifiers.removeOne(id); + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + if (ptr) { + if (activeConnection->state() == 2 && + ptr->state != QNetworkConfiguration::Active) { + ptr->state = QNetworkConfiguration::Active; + emit configurationChanged(ptr); + } + } + } + + while (!priorActiveConnections.isEmpty()) + delete this->activeConnections.take(priorActiveConnections.takeFirst()); + + while (!identifiers.isEmpty()) { + // These configurations are not active + QNetworkConfigurationPrivatePointer ptr = + accessPointConfigurations.value(identifiers.takeFirst()); + + if ((ptr->state & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { + ptr->state = QNetworkConfiguration::Discovered; + emit configurationChanged(ptr); + } + } + } + } +} + +void QNetworkManagerEngine::activeConnectionPropertiesChanged(const QString &path, + const QMap<QString, QVariant> &properties) +{ + QNetworkManagerConnectionActive *activeConnection = activeConnections.value(path); + + if (!activeConnection) + return; + + const QString id = QString::number(qHash(activeConnection->serviceName() + ' ' + + activeConnection->connection().path())); + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + if (ptr) { + if (activeConnection->state() == 2 && + ptr->state != QNetworkConfiguration::Active) { + ptr->state = QNetworkConfiguration::Active; + emit configurationChanged(ptr); + } + } +} + +void QNetworkManagerEngine::deviceAdded(const QDBusObjectPath &path) +{ + QNetworkManagerInterfaceDevice device(path.path()); + if (device.deviceType() == DEVICE_TYPE_802_11_WIRELESS) { + QNetworkManagerInterfaceDeviceWireless *wirelessDevice = + new QNetworkManagerInterfaceDeviceWireless(device.connectionInterface()->path()); + wirelessDevices.insert(path.path(), wirelessDevice); + + wirelessDevice->setConnections(); + connect(wirelessDevice, SIGNAL(accessPointAdded(QString,QDBusObjectPath)), + this, SLOT(newAccessPoint(QString,QDBusObjectPath))); + connect(wirelessDevice, SIGNAL(accessPointRemoved(QString,QDBusObjectPath)), + this, SLOT(removeAccessPoint(QString,QDBusObjectPath))); + connect(wirelessDevice, SIGNAL(propertiesChanged(QString,QMap<QString,QVariant>)), + this, SLOT(devicePropertiesChanged(QString,QMap<QString,QVariant>))); + + foreach (const QDBusObjectPath &apPath, wirelessDevice->getAccessPoints()) + newAccessPoint(QString(), apPath); + } +} + +void QNetworkManagerEngine::deviceRemoved(const QDBusObjectPath &path) +{ + delete wirelessDevices.value(path.path()); +} + +void QNetworkManagerEngine::newConnection(const QDBusObjectPath &path, + QNetworkManagerSettings *settings) +{ + if (!settings) + settings = qobject_cast<QNetworkManagerSettings *>(sender()); + + if (!settings) + return; + + QNetworkManagerSettingsConnection *connection = + new QNetworkManagerSettingsConnection(settings->connectionInterface()->service(), + path.path()); + connections.append(connection); + + connect(connection, SIGNAL(removed(QString)), this, SLOT(removeConnection(QString))); + connect(connection, SIGNAL(updated(const QNmSettingsMap&)), + this, SLOT(updateConnection(const QNmSettingsMap&))); + + const QString service = connection->connectionInterface()->service(); + const QString settingsPath = connection->connectionInterface()->path(); + + QNetworkConfigurationPrivate *cpPriv = + parseConnection(service, settingsPath, connection->getSettings()); + + // Check if connection is active. + foreach (const QDBusObjectPath &acPath, interface->activeConnections()) { + QNetworkManagerConnectionActive activeConnection(acPath.path()); + + if (activeConnection.serviceName() == service && + activeConnection.connection().path() == settingsPath && + activeConnection.state() == 2) { + cpPriv->state |= QNetworkConfiguration::Active; + break; + } + } + + QNetworkConfigurationPrivatePointer ptr(cpPriv); + accessPointConfigurations.insert(ptr->id, ptr); + emit configurationAdded(ptr); +} + +void QNetworkManagerEngine::removeConnection(const QString &path) +{ + QNetworkManagerSettingsConnection *connection = + qobject_cast<QNetworkManagerSettingsConnection *>(sender()); + if (!connection) + return; + + connections.removeAll(connection); + + const QString id = QString::number(qHash(connection->connectionInterface()->service() + ' ' + + connection->connectionInterface()->path())); + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(id); + ptr->isValid = false; + emit configurationRemoved(ptr); +} + +void QNetworkManagerEngine::updateConnection(const QNmSettingsMap &settings) +{ + QNetworkManagerSettingsConnection *connection = + qobject_cast<QNetworkManagerSettingsConnection *>(sender()); + if (!connection) + return; + + const QString service = connection->connectionInterface()->service(); + const QString settingsPath = connection->connectionInterface()->path(); + + qDebug() << "Should parse connection directly into existing configuration"; + QNetworkConfigurationPrivate *cpPriv = parseConnection(service, settingsPath, settings); + + // Check if connection is active. + foreach (const QDBusObjectPath &acPath, interface->activeConnections()) { + QNetworkManagerConnectionActive activeConnection(acPath.path()); + + if (activeConnection.serviceName() == service && + activeConnection.connection().path() == settingsPath && + activeConnection.state() == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { + cpPriv->state |= QNetworkConfiguration::Active; + break; + } + } + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(cpPriv->id); + + ptr->isValid = cpPriv->isValid; + ptr->name = cpPriv->name; + ptr->id = cpPriv->id; + ptr->state = cpPriv->state; + + emit configurationChanged(ptr); + delete cpPriv; +} + +void QNetworkManagerEngine::activationFinished(QDBusPendingCallWatcher *watcher) +{ + QDBusPendingReply<QDBusObjectPath> reply = *watcher; + if (reply.isError()) { + qDebug() << "error connecting NM connection"; + } else { + QDBusObjectPath result = reply.value(); + + QNetworkManagerConnectionActive activeConnection(result.path()); + + const QString id = QString::number(qHash(activeConnection.serviceName() + ' ' + + activeConnection.connection().path())); + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + if (ptr) { + if (activeConnection.state() == 2 && + ptr->state != QNetworkConfiguration::Active) { + ptr->state = QNetworkConfiguration::Active; + emit configurationChanged(ptr); + } + } + } +} + +void QNetworkManagerEngine::newAccessPoint(const QString &path, const QDBusObjectPath &objectPath) +{ + QNetworkManagerInterfaceAccessPoint *accessPoint = + new QNetworkManagerInterfaceAccessPoint(objectPath.path()); + accessPoints.append(accessPoint); + + accessPoint->setConnections(); + connect(accessPoint, SIGNAL(propertiesChanged(QMap<QString,QVariant>)), + this, SLOT(updateAccessPoint(QMap<QString,QVariant>))); + + // Check if configuration for this SSID already exists. + for (int i = 0; i < accessPoints.count(); ++i) { + if (accessPoint != accessPoints.at(i) && + accessPoint->ssid() == accessPoints.at(i)->ssid()) { + return; + } + } + + // Check if configuration exists for connection. + for (int i = 0; i < connections.count(); ++i) { + QNetworkManagerSettingsConnection *connection = connections.at(i); + + if (accessPoint->ssid() == connection->getSsid()) { + const QString service = connection->connectionInterface()->service(); + const QString settingsPath = connection->connectionInterface()->path(); + const QString connectionId = QString::number(qHash(service + ' ' + settingsPath)); + + QNetworkConfigurationPrivatePointer ptr = + accessPointConfigurations.value(connectionId); + ptr->state = QNetworkConfiguration::Discovered; + emit configurationChanged(ptr); + return; + } + } + + // New access point. + QNetworkConfigurationPrivatePointer ptr(new QNetworkConfigurationPrivate); + + ptr->name = accessPoint->ssid(); + ptr->isValid = true; + ptr->id = QString::number(qHash(objectPath.path())); + ptr->type = QNetworkConfiguration::InternetAccessPoint; + ptr->purpose = QNetworkConfiguration::PublicPurpose; + ptr->state = QNetworkConfiguration::Undefined; + + accessPointConfigurations.insert(ptr->id, ptr); + emit configurationAdded(ptr); +} + +void QNetworkManagerEngine::removeAccessPoint(const QString &path, + const QDBusObjectPath &objectPath) +{ + for (int i = 0; i < accessPoints.count(); ++i) { + QNetworkManagerInterfaceAccessPoint *accessPoint = accessPoints.at(i); + + if (accessPoint->connectionInterface()->path() == objectPath.path()) { + accessPoints.removeOne(accessPoint); + + if (configuredAccessPoints.contains(accessPoint)) { + // find connection and change state to Defined + configuredAccessPoints.removeOne(accessPoint); + qDebug() << "At least one connection is no longer discovered."; + } else { + // emit configurationRemoved(cpPriv); + qDebug() << "An unconfigured wifi access point was removed."; + } + + break; + } + } +} + +void QNetworkManagerEngine::updateAccessPoint(const QMap<QString, QVariant> &map) +{ + QNetworkManagerInterfaceAccessPoint *accessPoint = + qobject_cast<QNetworkManagerInterfaceAccessPoint *>(sender()); + if (!accessPoint) + return; + + qDebug() << "update access point" << accessPoint; +} + +QNetworkConfigurationPrivate *QNetworkManagerEngine::parseConnection(const QString &service, + const QString &settingsPath, + const QNmSettingsMap &map) +{ + QNetworkConfigurationPrivate *cpPriv = new QNetworkConfigurationPrivate; + cpPriv->name = map.value("connection").value("id").toString(); + cpPriv->isValid = true; + cpPriv->id = QString::number(qHash(service + ' ' + settingsPath)); + cpPriv->type = QNetworkConfiguration::InternetAccessPoint; + + cpPriv->purpose = QNetworkConfiguration::PublicPurpose; + + cpPriv->state = QNetworkConfiguration::Defined; + + const QString connectionType = map.value("connection").value("type").toString(); + + if (connectionType == QLatin1String("802-3-ethernet")) { + foreach (const QDBusObjectPath &devicePath, interface->getDevices()) { + QNetworkManagerInterfaceDevice device(devicePath.path()); + if (device.deviceType() == DEVICE_TYPE_802_3_ETHERNET) { + QNetworkManagerInterfaceDeviceWired wiredDevice(device.connectionInterface()->path()); + if (wiredDevice.carrier()) { + cpPriv->state |= QNetworkConfiguration::Discovered; + break; + } + + } + } + } else if (connectionType == QLatin1String("802-11-wireless")) { + const QString connectionSsid = map.value("802-11-wireless").value("ssid").toString(); + + for (int i = 0; i < accessPoints.count(); ++i) { + if (connectionSsid == accessPoints.at(i)->ssid()) { + cpPriv->state |= QNetworkConfiguration::Discovered; + if (!configuredAccessPoints.contains(accessPoints.at(i))) { + configuredAccessPoints.append(accessPoints.at(i)); + + const QString accessPointId = + QString::number(qHash(accessPoints.at(i)->connectionInterface()->path())); + QNetworkConfigurationPrivatePointer ptr = + accessPointConfigurations.take(accessPointId); + emit configurationRemoved(ptr); + } + break; + } + } + } + + return cpPriv; +} + +QNetworkManagerSettingsConnection *QNetworkManagerEngine::connectionFromId(const QString &id) const +{ + for (int i = 0; i < connections.count(); ++i) { + QNetworkManagerSettingsConnection *connection = connections.at(i); + const QString service = connection->connectionInterface()->service(); + const QString settingsPath = connection->connectionInterface()->path(); + + const QString identifier = QString::number(qHash(service + ' ' + settingsPath)); + + if (id == identifier) + return connection; + } + + return 0; +} + +QNetworkSession::State QNetworkManagerEngine::sessionStateForId(const QString &id) +{ + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(id); + + if (!ptr) + return QNetworkSession::Invalid; + + if (!ptr->isValid) + return QNetworkSession::Invalid; + + foreach (const QString &acPath, activeConnections.keys()) { + QNetworkManagerConnectionActive *activeConnection = activeConnections.value(acPath); + + const QString identifier = QString::number(qHash(activeConnection->serviceName() + ' ' + + activeConnection->connection().path())); + + if (id == identifier) { + switch (activeConnection->state()) { + case 0: + return QNetworkSession::Disconnected; + case 1: + return QNetworkSession::Connecting; + case 2: + return QNetworkSession::Connected; + } + } + } + + if ((ptr->state & QNetworkConfiguration::Discovered) == QNetworkConfiguration::Discovered) + return QNetworkSession::Disconnected; + else if ((ptr->state & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined) + return QNetworkSession::NotAvailable; + else if ((ptr->state & QNetworkConfiguration::Undefined) == QNetworkConfiguration::Undefined) + return QNetworkSession::NotAvailable; + + return QNetworkSession::Invalid; +} + +QT_END_NAMESPACE + |