diff options
Diffstat (limited to 'src/plugins/bearer/icd')
-rw-r--r-- | src/plugins/bearer/icd/icd.pro | 2 | ||||
-rw-r--r-- | src/plugins/bearer/icd/monitor.cpp | 84 | ||||
-rw-r--r-- | src/plugins/bearer/icd/monitor.h | 114 | ||||
-rw-r--r-- | src/plugins/bearer/icd/qicdengine.cpp | 841 | ||||
-rw-r--r-- | src/plugins/bearer/icd/qicdengine.h | 31 | ||||
-rw-r--r-- | src/plugins/bearer/icd/qnetworksession_impl.cpp | 778 | ||||
-rw-r--r-- | src/plugins/bearer/icd/qnetworksession_impl.h | 73 |
7 files changed, 1106 insertions, 817 deletions
diff --git a/src/plugins/bearer/icd/icd.pro b/src/plugins/bearer/icd/icd.pro index f411de2..c7337f5 100644 --- a/src/plugins/bearer/icd/icd.pro +++ b/src/plugins/bearer/icd/icd.pro @@ -7,12 +7,10 @@ QMAKE_CXXFLAGS += $$QT_CFLAGS_ICD LIBS += $$QT_LIBS_ICD HEADERS += qicdengine.h \ - monitor.h \ qnetworksession_impl.h SOURCES += main.cpp \ qicdengine.cpp \ - monitor.cpp \ qnetworksession_impl.cpp #DEFINES += BEARER_MANAGEMENT_DEBUG diff --git a/src/plugins/bearer/icd/monitor.cpp b/src/plugins/bearer/icd/monitor.cpp deleted file mode 100644 index 5b0af7e..0000000 --- a/src/plugins/bearer/icd/monitor.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 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 "monitor.h" -#include "qicdengine.h" - -#include <wlancond.h> -#include <libicd-network-wlan-dev.h> -#include <maemo_icd.h> -#include <iapconf.h> - - -void IapMonitor::setup(QIcdEngine *d_ptr) -{ - if (first_call) { - d = d_ptr; - first_call = false; - } -} - - -void IapMonitor::cleanup() -{ - if (!first_call) { - timers.removeAll(); - first_call = true; - } -} - - -void IapMonitor::iapAdded(const QString &iap_id) -{ - /* We cannot know when the IAP is fully added to db, so a timer is - * installed instead. When the timer expires we hope that IAP is added ok. - */ - QString id = iap_id; - timers.add(id, d); -} - - -void IapMonitor::iapRemoved(const QString &iap_id) -{ - QString id = iap_id; - d->deleteConfiguration(id); -} - diff --git a/src/plugins/bearer/icd/monitor.h b/src/plugins/bearer/icd/monitor.h deleted file mode 100644 index 10ffb30..0000000 --- a/src/plugins/bearer/icd/monitor.h +++ /dev/null @@ -1,114 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 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$ -** -****************************************************************************/ - -#ifndef MONITOR_H -#define MONITOR_H - -#include <QtCore/qhash.h> -#include <QtCore/qtimer.h> - -#include <gconf/gconf.h> -#include <gconf/gconf-client.h> - -#include <iapmonitor.h> - -class QIcdEngine; - -/* The IapAddTimer is a helper class that makes sure we update - * the configuration only after all db additions to certain - * iap are finished (after a certain timeout) - */ -class _IapAddTimer : public QObject -{ - Q_OBJECT - -public: - _IapAddTimer() {} - ~_IapAddTimer() - { - if (timer.isActive()) { - QObject::disconnect(&timer, SIGNAL(timeout()), this, SLOT(timeout())); - timer.stop(); - } - } - - void add(QString& iap_id, QIcdEngine *d); - - QString iap_id; - QTimer timer; - QIcdEngine *d; - -public Q_SLOTS: - void timeout(); -}; - -class IapAddTimer { - QHash<QString, _IapAddTimer* > timers; - -public: - IapAddTimer() {} - ~IapAddTimer() {} - - void add(QString& iap_id, QIcdEngine *d); - void del(QString& iap_id); - void removeAll(); -}; - -class IapMonitor : public Maemo::IAPMonitor -{ -public: - IapMonitor() : first_call(true) { } - - void setup(QIcdEngine *d); - void cleanup(); - -protected: - void iapAdded(const QString &iapId); - void iapRemoved(const QString &iapId); - -private: - bool first_call; - - QIcdEngine *d; - IapAddTimer timers; -}; - -#endif // MONITOR_H diff --git a/src/plugins/bearer/icd/qicdengine.cpp b/src/plugins/bearer/icd/qicdengine.cpp index 7a4cb9d..a6cf0c2 100644 --- a/src/plugins/bearer/icd/qicdengine.cpp +++ b/src/plugins/bearer/icd/qicdengine.cpp @@ -40,12 +40,12 @@ ****************************************************************************/ #include "qicdengine.h" -#include "monitor.h" #include "qnetworksession_impl.h" +#include <wlancond.h> #include <libicd-network-wlan-dev.h> -#include <maemo_icd.h> #include <iapconf.h> +#include <iapmonitor.h> QT_BEGIN_NAMESPACE @@ -70,6 +70,208 @@ QString IcdNetworkConfigurationPrivate::bearerName() const } } +/* The IapAddTimer is a helper class that makes sure we update + * the configuration only after all db additions to certain + * iap are finished (after a certain timeout) + */ +class _IapAddTimer : public QObject +{ + Q_OBJECT + +public: + _IapAddTimer() {} + ~_IapAddTimer() + { + if (timer.isActive()) { + QObject::disconnect(&timer, SIGNAL(timeout()), this, SLOT(timeout())); + timer.stop(); + } + } + + void add(QString& iap_id, QIcdEngine *d); + + QString iap_id; + QTimer timer; + QIcdEngine *d; + +public Q_SLOTS: + void timeout(); +}; + + +void _IapAddTimer::add(QString& id, QIcdEngine *d_ptr) +{ + iap_id = id; + d = d_ptr; + + if (timer.isActive()) { + QObject::disconnect(&timer, SIGNAL(timeout()), this, SLOT(timeout())); + timer.stop(); + } + timer.setSingleShot(true); + QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(timeout())); + timer.start(1500); +} + + +void _IapAddTimer::timeout() +{ + d->addConfiguration(iap_id); +} + + +class IapAddTimer { + QHash<QString, _IapAddTimer* > timers; + +public: + IapAddTimer() {} + ~IapAddTimer() {} + + void add(QString& iap_id, QIcdEngine *d); + void del(QString& iap_id); + void removeAll(); +}; + + +void IapAddTimer::removeAll() +{ + QHashIterator<QString, _IapAddTimer* > i(timers); + while (i.hasNext()) { + i.next(); + _IapAddTimer *t = i.value(); + delete t; + } + timers.clear(); +} + + +void IapAddTimer::add(QString& iap_id, QIcdEngine *d) +{ + if (timers.contains(iap_id)) { + _IapAddTimer *iap = timers.value(iap_id); + iap->add(iap_id, d); + } else { + _IapAddTimer *iap = new _IapAddTimer; + iap->add(iap_id, d); + timers.insert(iap_id, iap); + } +} + +void IapAddTimer::del(QString& iap_id) +{ + if (timers.contains(iap_id)) { + _IapAddTimer *iap = timers.take(iap_id); + delete iap; + } +} + + +class IapMonitor : public Maemo::IAPMonitor +{ +public: + IapMonitor() : first_call(true) { } + + void setup(QIcdEngine *d); + void cleanup(); + +protected: + void iapAdded(const QString &iapId); + void iapRemoved(const QString &iapId); + +private: + bool first_call; + + QIcdEngine *d; + IapAddTimer timers; +}; + +void IapMonitor::setup(QIcdEngine *d_ptr) +{ + if (first_call) { + d = d_ptr; + first_call = false; + } +} + + +void IapMonitor::cleanup() +{ + if (!first_call) { + timers.removeAll(); + first_call = true; + } +} + + +void IapMonitor::iapAdded(const QString &iap_id) +{ + /* We cannot know when the IAP is fully added to db, so a timer is + * installed instead. When the timer expires we hope that IAP is added ok. + */ + QString id = iap_id; + timers.add(id, d); +} + + +void IapMonitor::iapRemoved(const QString &iap_id) +{ + QString id = iap_id; + d->deleteConfiguration(id); +} + +QIcdEngine::QIcdEngine(QObject *parent) +: QBearerEngine(parent), iapMonitor(new IapMonitor), m_dbusInterface(0), + firstUpdate(true), m_scanGoingOn(false) +{ + QMetaObject::invokeMethod(this, "doRequestUpdate", Qt::QueuedConnection); + init(); +} + +QIcdEngine::~QIcdEngine() +{ + cleanup(); + delete iapMonitor; +} + +QNetworkConfigurationManager::Capabilities QIcdEngine::capabilities() const +{ + return QNetworkConfigurationManager::CanStartAndStopInterfaces | + QNetworkConfigurationManager::DataStatistics | + QNetworkConfigurationManager::ForcedRoaming | + QNetworkConfigurationManager::NetworkSessionRequired; +} + +void QIcdEngine::init() +{ + // Setup DBus Interface for ICD + m_dbusInterface = new QDBusInterface(ICD_DBUS_API_INTERFACE, + ICD_DBUS_API_PATH, + ICD_DBUS_API_INTERFACE, + QDBusConnection::systemBus(), + this); + connect(&m_scanTimer, SIGNAL(timeout()), this, SLOT(finishAsyncConfigurationUpdate())); + m_scanTimer.setSingleShot(true); + + /* Turn on IAP state monitoring */ + startListeningStateSignalsForAllConnections(); + + /* Turn on IAP add/remove monitoring */ + iapMonitor->setup(this); + + /* We create a default configuration which is a pseudo config */ + QNetworkConfigurationPrivate *cpPriv = new IcdNetworkConfigurationPrivate; + cpPriv->name = "UserChoice"; + cpPriv->state = QNetworkConfiguration::Discovered; + cpPriv->isValid = true; + cpPriv->id = OSSO_IAP_ANY; + cpPriv->type = QNetworkConfiguration::UserChoice; + cpPriv->purpose = QNetworkConfiguration::UnknownPurpose; + cpPriv->roamingSupported = false; + + QNetworkConfigurationPrivatePointer ptr(cpPriv); + userChoiceConfigurations.insert(cpPriv->id, ptr); +} + static inline QString network_attrs_to_security(uint network_attrs) { uint cap = 0; @@ -85,38 +287,40 @@ static inline QString network_attrs_to_security(uint network_attrs) return ""; } -QIcdEngine::QIcdEngine(QObject *parent) -: QBearerEngine(parent), iapMonitor(new IapMonitor) -{ - /* Turn on IAP monitoring */ - iapMonitor->setup(this); - doRequestUpdate(); -} +struct SSIDInfo { + QString iap_id; + QString wlan_security; +}; -QIcdEngine::~QIcdEngine() -{ -} -bool QIcdEngine::hasIdentifier(const QString &id) +void QIcdEngine::deleteConfiguration(const QString &iap_id) { QMutexLocker locker(&mutex); - return accessPointConfigurations.contains(id) || - snapConfigurations.contains(id) || - userChoiceConfigurations.contains(id); -} - -void QIcdEngine::requestUpdate() -{ - QMutexLocker locker(&mutex); + /* Called when IAPs are deleted in db, in this case we do not scan + * or read all the IAPs from db because it might take too much power + * (multiple applications would need to scan and read all IAPs from db) + */ + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(iap_id); + if (ptr) { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "IAP" << iap_id << "was removed from storage."; +#endif - QTimer::singleShot(0, this, SLOT(doRequestUpdate())); + locker.unlock(); + emit configurationRemoved(ptr); + } else { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("IAP: %s, already missing from the known list", iap_id.toAscii().data()); +#endif + } } + static uint32_t getNetworkAttrs(bool is_iap_id, - QString& iap_id, - QString& iap_type, + const QString &iap_id, + const QString &iap_type, QString security_method) { guint network_attr = 0; @@ -158,45 +362,171 @@ static uint32_t getNetworkAttrs(bool is_iap_id, return (uint32_t)network_attr; } -void QIcdEngine::doRequestUpdate() + +void QIcdEngine::addConfiguration(QString& iap_id) { + // Note: When new IAP is created, this function gets called multiple times + // in a row. + // For example: Empty type & name for WLAN was stored into newly + // created IAP data in gconf when this function gets + // called for the first time. + // WLAN type & name are updated into IAP data in gconf + // as soon as WLAN connection is up and running. + // => And this function gets called again. + QMutexLocker locker(&mutex); - QStringList previous = accessPointConfigurations.keys(); + if (!accessPointConfigurations.contains(iap_id)) { + Maemo::IAPConf saved_iap(iap_id); + QString iap_type = saved_iap.value("type").toString(); + QString iap_name = saved_iap.value("name").toString(); + QByteArray ssid = saved_iap.value("wlan_ssid").toByteArray(); + if (!iap_type.isEmpty() && !iap_name.isEmpty()) { + // Check if new IAP is actually Undefined WLAN configuration + // Note: SSID is used as an iap id for Undefined WLAN configurations + // => configuration must be searched using SSID + if (!ssid.isEmpty() && accessPointConfigurations.contains(ssid)) { + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(ssid); + if (ptr) { + ptr->mutex.lock(); + ptr->id = iap_id; + toIcdConfig(ptr)->iap_type = iap_type; + toIcdConfig(ptr)->network_attrs = getNetworkAttrs(true, iap_id, iap_type, QString()); + toIcdConfig(ptr)->network_id = ssid; + toIcdConfig(ptr)->service_id = saved_iap.value("service_id").toString(); + toIcdConfig(ptr)->service_type = saved_iap.value("service_type").toString(); + if (m_onlineIapId == iap_id) { + ptr->state = QNetworkConfiguration::Active; + } else { + ptr->state = QNetworkConfiguration::Defined; + } + ptr->mutex.unlock(); + accessPointConfigurations.insert(iap_id, ptr); - /* All the scanned access points */ - QList<Maemo::IcdScanResult> scanned; + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + } + } else { + IcdNetworkConfigurationPrivate *cpPriv = new IcdNetworkConfigurationPrivate; + cpPriv->name = saved_iap.value("name").toString(); + if (cpPriv->name.isEmpty()) + cpPriv->name = iap_id; + cpPriv->isValid = true; + cpPriv->id = iap_id; + cpPriv->iap_type = iap_type; + cpPriv->network_attrs = getNetworkAttrs(true, iap_id, iap_type, QString()); + cpPriv->service_id = saved_iap.value("service_id").toString(); + cpPriv->service_type = saved_iap.value("service_type").toString(); + if (iap_type.startsWith(QLatin1String("WLAN"))) { + QByteArray ssid = saved_iap.value("wlan_ssid").toByteArray(); + if (ssid.isEmpty()) { + qWarning() << "Cannot get ssid for" << iap_id; + } + cpPriv->network_id = ssid; + } + cpPriv->type = QNetworkConfiguration::InternetAccessPoint; + if (m_onlineIapId == iap_id) { + cpPriv->state = QNetworkConfiguration::Active; + } else { + cpPriv->state = QNetworkConfiguration::Defined; + } - /* We create a default configuration which is a pseudo config */ - if (!userChoiceConfigurations.contains(OSSO_IAP_ANY)) { - QNetworkConfigurationPrivatePointer ptr(new IcdNetworkConfigurationPrivate); + QNetworkConfigurationPrivatePointer ptr(cpPriv); + accessPointConfigurations.insert(iap_id, ptr); - ptr->name = QLatin1String("UserChoice"); - ptr->state = QNetworkConfiguration::Discovered; - ptr->isValid = true; - ptr->id = OSSO_IAP_ANY; - ptr->type = QNetworkConfiguration::UserChoice; - ptr->purpose = QNetworkConfiguration::UnknownPurpose; - ptr->roamingSupported = false; +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug("IAP: %s, name: %s, added to known list", iap_id.toAscii().data(), cpPriv->name.toAscii().data()); +#endif + locker.unlock(); + emit configurationAdded(ptr); + locker.relock(); + } + } else { + qWarning("IAP %s does not have \"type\" or \"name\" fields defined, skipping this IAP.", iap_id.toAscii().data()); + } + } else { +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "IAP" << iap_id << "already in db."; +#endif - userChoiceConfigurations.insert(ptr->id, ptr); + /* Check if the data in db changed and update configuration accordingly + */ + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iap_id); + if (ptr) { + Maemo::IAPConf changed_iap(iap_id); + QString iap_type = changed_iap.value("type").toString(); + bool update_needed = false; /* if IAP type or ssid changed, we need to change the state */ + + QMutexLocker configLocker(&ptr->mutex); + + toIcdConfig(ptr)->network_attrs = getNetworkAttrs(true, iap_id, iap_type, QString()); + toIcdConfig(ptr)->service_id = changed_iap.value("service_id").toString(); + toIcdConfig(ptr)->service_type = changed_iap.value("service_type").toString(); + + if (!iap_type.isEmpty()) { + ptr->name = changed_iap.value("name").toString(); + if (ptr->name.isEmpty()) + ptr->name = iap_id; + ptr->isValid = true; + if (toIcdConfig(ptr)->iap_type != iap_type) { + toIcdConfig(ptr)->iap_type = iap_type; + update_needed = true; + } + if (iap_type.startsWith(QLatin1String("WLAN"))) { + QByteArray ssid = changed_iap.value("wlan_ssid").toByteArray(); + if (ssid.isEmpty()) { + qWarning() << "Cannot get ssid for" << iap_id; + } + if (toIcdConfig(ptr)->network_id != ssid) { + toIcdConfig(ptr)->network_id = ssid; + update_needed = true; + } + } + } + + if (update_needed) { + ptr->type = QNetworkConfiguration::InternetAccessPoint; + if (m_onlineIapId == iap_id) { + if (ptr->state < QNetworkConfiguration::Active) { + ptr->state = QNetworkConfiguration::Active; + + configLocker.unlock(); + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + } + } else if (ptr->state < QNetworkConfiguration::Defined) { + ptr->state = QNetworkConfiguration::Defined; - locker.unlock(); - emit configurationAdded(ptr); - locker.relock(); + configLocker.unlock(); + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + } + } + } else { + qWarning("Cannot find IAP %s from current configuration although it should be there.", iap_id.toAscii().data()); + } } +} + +void QIcdEngine::doRequestUpdate(QList<Maemo::IcdScanResult> scanned) +{ + QMutexLocker locker(&mutex); + + /* Contains all known iap_ids from storage */ + QList<QString> knownConfigs = accessPointConfigurations.keys(); + + /* Contains all known WLAN network ids (like ssid) from storage */ + QMultiHash<QByteArray, SSIDInfo* > notDiscoveredWLANConfigs; - /* We return currently configured IAPs in the first run and do the WLAN - * scan in subsequent runs. - */ QList<QString> all_iaps; Maemo::IAPConf::getAll(all_iaps); - foreach (QString iap_id, all_iaps) { + foreach (const QString &iap_id, all_iaps) { QByteArray ssid; - previous.removeAll(iap_id); - Maemo::IAPConf saved_ap(iap_id); bool is_temporary = saved_ap.value("temporary").toBool(); if (is_temporary) { @@ -207,12 +537,16 @@ void QIcdEngine::doRequestUpdate() } QString iap_type = saved_ap.value("type").toString(); - if (iap_type.startsWith("WLAN")) { + if (iap_type.startsWith(QLatin1String("WLAN"))) { ssid = saved_ap.value("wlan_ssid").toByteArray(); if (ssid.isEmpty()) continue; QString security_method = saved_ap.value("wlan_security").toString(); + SSIDInfo *info = new SSIDInfo; + info->iap_id = iap_id; + info->wlan_security = security_method; + notDiscoveredWLANConfigs.insert(ssid, info); } else if (iap_type.isEmpty()) { continue; } else { @@ -227,10 +561,10 @@ void QIcdEngine::doRequestUpdate() cpPriv->name = saved_ap.value("name").toString(); if (cpPriv->name.isEmpty()) { - if (!ssid.isEmpty() && ssid.size() > 0) - cpPriv->name = ssid.data(); - else - cpPriv->name = iap_id; + if (!ssid.isEmpty() && ssid.size() > 0) + cpPriv->name = ssid.data(); + else + cpPriv->name = iap_id; } cpPriv->isValid = true; cpPriv->id = iap_id; @@ -255,6 +589,7 @@ void QIcdEngine::doRequestUpdate() !ssid.isEmpty() ? ssid.data() : "-"); #endif } else { + knownConfigs.removeOne(iap_id); #ifdef BEARER_MANAGEMENT_DEBUG qDebug("IAP: %s, ssid: %s, already exists in the known list", iap_id.toAscii().data(), !ssid.isEmpty() ? ssid.data() : "-"); @@ -262,47 +597,16 @@ void QIcdEngine::doRequestUpdate() } } - if (sender()) { - QStringList scannedNetworkTypes; - QStringList networkTypesToScan; - QString error; - Maemo::Icd icd(ICD_SHORT_SCAN_TIMEOUT); - - scannedNetworkTypes = icd.scan(ICD_SCAN_REQUEST_ACTIVE, - networkTypesToScan, - scanned, - error); - if (!error.isEmpty()) { -#ifdef BEARER_MANAGEMENT_DEBUG - qDebug() << "Network scanning failed" << error; -#endif - } else { -#ifdef BEARER_MANAGEMENT_DEBUG - if (!scanned.isEmpty()) - qDebug() << "Scan returned" << scanned.size() << "networks"; - else - qDebug() << "Scan returned nothing."; -#endif - } - } - /* This is skipped in the first update as scanned size is zero */ if (!scanned.isEmpty()) { for (int i=0; i<scanned.size(); ++i) { const Maemo::IcdScanResult ap = scanned.at(i); - QByteArray scanned_ssid = ap.scan.network_id; - if (ap.scan.network_attrs & ICD_NW_ATTR_IAPNAME) { /* The network_id is IAP id, so the IAP is a known one */ QString iapid = ap.scan.network_id.data(); - - previous.removeAll(iapid); - - if (accessPointConfigurations.contains(iapid)) { - QNetworkConfigurationPrivatePointer ptr = - accessPointConfigurations.value(iapid); - + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iapid); + if (ptr) { bool changed = false; ptr->mutex.lock(); @@ -324,7 +628,7 @@ void QIcdEngine::doRequestUpdate() #ifdef BEARER_MANAGEMENT_DEBUG qDebug("IAP: %s, ssid: %s, discovered", - iapid.toAscii().data(), scanned_ssid.data()); + iapid.toAscii().data(), toIcdConfig(ptr)->network_id.data()); #endif ptr->mutex.unlock(); @@ -337,101 +641,350 @@ void QIcdEngine::doRequestUpdate() if (!ap.scan.network_type.startsWith(QLatin1String("WLAN"))) continue; // not a wlan AP + + /* Remove scanned AP from discovered WLAN configurations so that we can + * emit configurationRemoved signal later + */ + ptr->mutex.lock(); + QList<SSIDInfo* > known_iaps = notDiscoveredWLANConfigs.values(toIcdConfig(ptr)->network_id); +rescan_list: + if (!known_iaps.isEmpty()) { + for (int k=0; k<known_iaps.size(); ++k) { + SSIDInfo *iap = known_iaps.at(k); + + if (iap->wlan_security == + network_attrs_to_security(ap.scan.network_attrs)) { + /* Remove IAP from the list */ + notDiscoveredWLANConfigs.remove(toIcdConfig(ptr)->network_id, iap); +#ifdef BEARER_MANAGEMENT_DEBUG + qDebug() << "Removed IAP" << iap->iap_id << "from unknown config"; +#endif + known_iaps.removeAt(k); + delete iap; + goto rescan_list; + } + } + } + ptr->mutex.unlock(); } } else { - IcdNetworkConfigurationPrivate *cpPriv = new IcdNetworkConfigurationPrivate; - - QString hrs = scanned_ssid.data(); - - cpPriv->name = ap.network_name.isEmpty() ? hrs : ap.network_name; - cpPriv->isValid = true; - // Note: id is now ssid, it should be set to IAP id if the IAP is saved - cpPriv->id = scanned_ssid.data(); - cpPriv->network_id = scanned_ssid; - cpPriv->iap_type = ap.scan.network_type; - if (cpPriv->iap_type.isEmpty()) - cpPriv->iap_type = QLatin1String("WLAN"); - cpPriv->network_attrs = ap.scan.network_attrs; - cpPriv->service_id = ap.scan.service_id; - cpPriv->service_type = ap.scan.service_type; - cpPriv->service_attrs = ap.scan.service_attrs; - - cpPriv->type = QNetworkConfiguration::InternetAccessPoint; - cpPriv->state = QNetworkConfiguration::Undefined; + /* Non saved access point data */ + QByteArray scanned_ssid = ap.scan.network_id; + if (!accessPointConfigurations.contains(scanned_ssid)) { + IcdNetworkConfigurationPrivate *cpPriv = new IcdNetworkConfigurationPrivate; + QString hrs = scanned_ssid.data(); + + cpPriv->name = ap.network_name.isEmpty() ? hrs : ap.network_name; + cpPriv->isValid = true; + cpPriv->id = scanned_ssid.data(); // Note: id is now ssid, it should be set to IAP id if the IAP is saved + cpPriv->network_id = scanned_ssid; + cpPriv->iap_type = ap.scan.network_type; + cpPriv->network_attrs = ap.scan.network_attrs; + cpPriv->service_id = ap.scan.service_id; + cpPriv->service_type = ap.scan.service_type; + cpPriv->service_attrs = ap.scan.service_attrs; + + cpPriv->type = QNetworkConfiguration::InternetAccessPoint; + cpPriv->state = QNetworkConfiguration::Undefined; #ifdef BEARER_MANAGEMENT_DEBUG - qDebug() << "IAP with network id" << cpPriv->id << "was found in the scan."; + qDebug() << "IAP with network id" << cpPriv->id << "was found in the scan."; #endif - previous.removeAll(cpPriv->id); + QNetworkConfigurationPrivatePointer ptr(cpPriv); + accessPointConfigurations.insert(ptr->id, ptr); - QNetworkConfigurationPrivatePointer ptr(cpPriv); - accessPointConfigurations.insert(ptr->id, ptr); + locker.unlock(); + emit configurationAdded(ptr); + locker.relock(); + } else { + knownConfigs.removeOne(scanned_ssid); + } + } + } + } + + if (!firstUpdate) { + // Update Defined status to all defined WLAN IAPs which + // could not be found when access points were scanned + QHashIterator<QByteArray, SSIDInfo* > i(notDiscoveredWLANConfigs); + while (i.hasNext()) { + i.next(); + SSIDInfo *iap = i.value(); + QString iap_id = iap->iap_id; + //qDebug() << i.key() << ": " << iap_id; + + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iap_id); + if (ptr) { + QMutexLocker configLocker(&ptr->mutex); + + // WLAN AccessPoint configuration could not be Discovered + // => Make sure that configuration state is Defined + if (ptr->state > QNetworkConfiguration::Defined) { + ptr->state = QNetworkConfiguration::Defined; + + configLocker.unlock(); + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + } + } + } + /* Remove non existing iaps since last update */ + foreach (const QString &oldIface, knownConfigs) { + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(oldIface); + if (ptr) { locker.unlock(); - emit configurationAdded(ptr); + emit configurationRemoved(ptr); locker.relock(); + //if we would have SNAP support we would have to remove the references + //from existing ServiceNetworks to the removed access point configuration } } } - while (!previous.isEmpty()) { - QNetworkConfigurationPrivatePointer ptr = - accessPointConfigurations.take(previous.takeFirst()); + QMutableHashIterator<QByteArray, SSIDInfo* > i(notDiscoveredWLANConfigs); + while (i.hasNext()) { + i.next(); + SSIDInfo *iap = i.value(); + delete iap; + i.remove(); + } + if (!firstUpdate) { locker.unlock(); - emit configurationRemoved(ptr); + emit updateCompleted(); locker.relock(); } - if (sender()) { - locker.unlock(); - emit updateCompleted(); + if (firstUpdate) + firstUpdate = false; +} + +QNetworkConfigurationPrivatePointer QIcdEngine::defaultConfiguration() +{ + QMutexLocker locker(&mutex); + + // Here we just return [ANY] request to icd and let the icd decide which IAP to connect. + return userChoiceConfigurations.value(OSSO_IAP_ANY); +} + +void QIcdEngine::startListeningStateSignalsForAllConnections() +{ + QMutexLocker locker(&mutex); + + // Start listening ICD_DBUS_API_STATE_SIG signals + m_dbusInterface->connection().connect(ICD_DBUS_API_INTERFACE, + ICD_DBUS_API_PATH, + ICD_DBUS_API_INTERFACE, + ICD_DBUS_API_STATE_SIG, + this, SLOT(connectionStateSignalsSlot(QDBusMessage))); + + // Calling ICD_DBUS_API_STATE_REQ makes sure that initial state will be updated immediately + m_gettingInitialConnectionState = true; + m_dbusInterface->call(ICD_DBUS_API_STATE_REQ); +} + +void QIcdEngine::connectionStateSignalsSlot(QDBusMessage msg) +{ + QMutexLocker locker(&mutex); + + QList<QVariant> arguments = msg.arguments(); + if (arguments[1].toUInt() != 0 || arguments.count() < 8) { + return; } + + QString iapid = arguments[5].toByteArray().data(); + uint icd_connection_state = arguments[7].toUInt(); + + switch (icd_connection_state) { + case ICD_STATE_CONNECTED: + { + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iapid); + if (ptr) { + QMutexLocker configLocker(&ptr->mutex); + + ptr->type = QNetworkConfiguration::InternetAccessPoint; + if (ptr->state != QNetworkConfiguration::Active) { + ptr->state = QNetworkConfiguration::Active; + if (!m_gettingInitialConnectionState) { + configLocker.unlock(); + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + } + m_onlineIapId = iapid; + } + } else { + // This gets called when new WLAN IAP is created using Connection dialog + // At this point Undefined WLAN configuration has SSID as iap id + // => Because of that configuration can not be found from + // accessPointConfigurations using correct iap id + m_onlineIapId = iapid; + } + break; + } + case ICD_STATE_DISCONNECTED: + { + QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.value(iapid); + if (ptr) { + QMutexLocker configLocker(&ptr->mutex); + + ptr->type = QNetworkConfiguration::InternetAccessPoint; + if (ptr->state == QNetworkConfiguration::Active) { + ptr->state = QNetworkConfiguration::Discovered; + if (!m_gettingInitialConnectionState) { + configLocker.unlock(); + locker.unlock(); + emit configurationChanged(ptr); + locker.relock(); + + // Note: If ICD switches used IAP from one to another: + // 1) new IAP is reported to be online first + // 2) old IAP is reported to be offline then + // => Device can be reported to be offline only + // if last known online IAP is reported to be disconnected + if (iapid == m_onlineIapId) { + // It's known that there is only one global ICD connection + // => Because ICD state was reported to be DISCONNECTED, Device is offline + m_onlineIapId.clear(); + } + } + } + } else { + // Disconnected IAP was not found from accessPointConfigurations + // => Reason: Online IAP was removed which resulted ICD to disconnect + if (iapid == m_onlineIapId) { + // It's known that there is only one global ICD connection + // => Because ICD state was reported to be DISCONNECTED, Device is offline + m_onlineIapId.clear(); + } + } + break; + } + default: + break; + } + + locker.unlock(); + emit iapStateChanged(iapid, icd_connection_state); + locker.relock(); + + m_gettingInitialConnectionState = false; } -void QIcdEngine::deleteConfiguration(const QString &iap_id) +void QIcdEngine::requestUpdate() { QMutexLocker locker(&mutex); - /* Called when IAPs are deleted in db, in this case we do not scan - * or read all the IAPs from db because it might take too much power - * (multiple applications would need to scan and read all IAPs from db) - */ - QNetworkConfigurationPrivatePointer ptr = accessPointConfigurations.take(iap_id); - if (ptr) { -#ifdef BEARER_MANAGEMENT_DEBUG - qDebug() << "IAP" << iap_id << "was removed from storage."; -#endif + if (m_scanGoingOn) { + return; + } + m_scanGoingOn = true; + + m_dbusInterface->connection().connect(ICD_DBUS_API_INTERFACE, + ICD_DBUS_API_PATH, + ICD_DBUS_API_INTERFACE, + ICD_DBUS_API_SCAN_SIG, + this, SLOT(asyncUpdateConfigurationsSlot(QDBusMessage))); + + QDBusMessage msg = m_dbusInterface->call(ICD_DBUS_API_SCAN_REQ, + (uint)ICD_SCAN_REQUEST_ACTIVE); + m_typesToBeScanned = msg.arguments()[0].value<QStringList>(); + m_scanTimer.start(ICD_SHORT_SCAN_TIMEOUT); +} - locker.unlock(); - emit configurationRemoved(ptr); - } else { -#ifdef BEARER_MANAGEMENT_DEBUG - qDebug("IAP: %s, already missing from the known list", iap_id.toAscii().data()); -#endif +void QIcdEngine::cancelAsyncConfigurationUpdate() +{ + QMutexLocker locker(&mutex); + + if (!m_scanGoingOn) { + return; + } + m_scanGoingOn = false; + + if (m_scanTimer.isActive()) { + m_scanTimer.stop(); } + + m_dbusInterface->connection().disconnect(ICD_DBUS_API_INTERFACE, + ICD_DBUS_API_PATH, + ICD_DBUS_API_INTERFACE, + ICD_DBUS_API_SCAN_SIG, + this, SLOT(asyncUpdateConfigurationsSlot(QDBusMessage))); + + // Stop scanning rounds by calling ICD_DBUS_API_SCAN_CANCEL + // <=> If ICD_DBUS_API_SCAN_CANCEL is not called, new scanning round will + // be started after the module scan timeout. + m_dbusInterface->call(ICD_DBUS_API_SCAN_CANCEL); } -QNetworkConfigurationManager::Capabilities QIcdEngine::capabilities() const +void QIcdEngine::finishAsyncConfigurationUpdate() { - return QNetworkConfigurationManager::CanStartAndStopInterfaces | - QNetworkConfigurationManager::DataStatistics | - QNetworkConfigurationManager::ForcedRoaming | - QNetworkConfigurationManager::NetworkSessionRequired; + QMutexLocker locker(&mutex); + + cancelAsyncConfigurationUpdate(); + doRequestUpdate(m_scanResult); + m_scanResult.clear(); } -QNetworkSessionPrivate *QIcdEngine::createSessionBackend() +void QIcdEngine::asyncUpdateConfigurationsSlot(QDBusMessage msg) { - return new QNetworkSessionPrivateImpl(this); + QMutexLocker locker(&mutex); + + QList<QVariant> arguments = msg.arguments(); + uint icd_scan_status = arguments.takeFirst().toUInt(); + if (icd_scan_status == ICD_SCAN_COMPLETE) { + m_typesToBeScanned.removeOne(arguments[6].toString()); + if (!m_typesToBeScanned.count()) { + finishAsyncConfigurationUpdate(); + } + } else { + Maemo::IcdScanResult scanResult; + scanResult.status = icd_scan_status; + scanResult.timestamp = arguments.takeFirst().toUInt(); + scanResult.scan.service_type = arguments.takeFirst().toString(); + scanResult.service_name = arguments.takeFirst().toString(); + scanResult.scan.service_attrs = arguments.takeFirst().toUInt(); + scanResult.scan.service_id = arguments.takeFirst().toString(); + scanResult.service_priority = arguments.takeFirst().toInt(); + scanResult.scan.network_type = arguments.takeFirst().toString(); + scanResult.network_name = arguments.takeFirst().toString(); + scanResult.scan.network_attrs = arguments.takeFirst().toUInt(); + scanResult.scan.network_id = arguments.takeFirst().toByteArray(); + scanResult.network_priority = arguments.takeFirst().toInt(); + scanResult.signal_strength = arguments.takeFirst().toInt(); + scanResult.station_id = arguments.takeFirst().toString(); + scanResult.signal_dB = arguments.takeFirst().toInt(); + + m_scanResult.append(scanResult); + } } -QNetworkConfigurationPrivatePointer QIcdEngine::defaultConfiguration() +void QIcdEngine::cleanup() +{ + if (m_scanGoingOn) { + m_scanTimer.stop(); + m_dbusInterface->call(ICD_DBUS_API_SCAN_CANCEL); + } + iapMonitor->cleanup(); +} + +bool QIcdEngine::hasIdentifier(const QString &id) { QMutexLocker locker(&mutex); - // Here we just return [ANY] request to icd and let the icd decide which IAP to connect. - return userChoiceConfigurations.value(OSSO_IAP_ANY); + return accessPointConfigurations.contains(id) || + snapConfigurations.contains(id) || + userChoiceConfigurations.contains(id); } +QNetworkSessionPrivate *QIcdEngine::createSessionBackend() +{ + return new QNetworkSessionPrivateImpl(this); +} + +#include "qicdengine.moc" + QT_END_NAMESPACE diff --git a/src/plugins/bearer/icd/qicdengine.h b/src/plugins/bearer/icd/qicdengine.h index 50cda62..a2e9a2f 100644 --- a/src/plugins/bearer/icd/qicdengine.h +++ b/src/plugins/bearer/icd/qicdengine.h @@ -44,10 +44,15 @@ #include <QtNetwork/private/qbearerengine_p.h> +#include <QtCore/qtimer.h> + +#include <maemo_icd.h> + QT_BEGIN_NAMESPACE class QNetworkConfigurationPrivate; class IapMonitor; +class QDBusInterface; class IcdNetworkConfigurationPrivate : public QNetworkConfigurationPrivate { @@ -118,11 +123,35 @@ public: emit configurationChanged(ptr); } + void init(); + void cleanup(); + + void addConfiguration(QString &iap_id); + +Q_SIGNALS: + void iapStateChanged(const QString& iapid, uint icd_connection_state); + private Q_SLOTS: - void doRequestUpdate(); + void doRequestUpdate(QList<Maemo::IcdScanResult> scanned = QList<Maemo::IcdScanResult>()); + void cancelAsyncConfigurationUpdate(); + void finishAsyncConfigurationUpdate(); + void asyncUpdateConfigurationsSlot(QDBusMessage msg); + void connectionStateSignalsSlot(QDBusMessage msg); + +private: + void startListeningStateSignalsForAllConnections(); private: IapMonitor *iapMonitor; + QDBusInterface *m_dbusInterface; + QTimer m_scanTimer; + QString m_onlineIapId; + QStringList m_typesToBeScanned; + QList<Maemo::IcdScanResult> m_scanResult; + + bool firstUpdate; + bool m_gettingInitialConnectionState; + bool m_scanGoingOn; }; QT_END_NAMESPACE diff --git a/src/plugins/bearer/icd/qnetworksession_impl.cpp b/src/plugins/bearer/icd/qnetworksession_impl.cpp index 5bf95dc..2928a31 100644 --- a/src/plugins/bearer/icd/qnetworksession_impl.cpp +++ b/src/plugins/bearer/icd/qnetworksession_impl.cpp @@ -44,294 +44,146 @@ #include <QHash> -#include <dbus/dbus.h> -#include <dbus/dbus-glib-lowlevel.h> - #include <maemo_icd.h> #include <iapconf.h> #include <proxyconf.h> -#include <sys/types.h> #include <ifaddrs.h> -#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> QT_BEGIN_NAMESPACE -static QHash<QString, QVariant> properties; - -static QString get_network_interface(); -static DBusConnection *dbus_connection; -static DBusHandlerResult signal_handler(DBusConnection *connection, - DBusMessage *message, - void *user_data); - -#define ICD_DBUS_MATCH "type='signal'," \ - "interface='" ICD_DBUS_INTERFACE "'," \ - "path='" ICD_DBUS_PATH "'" - - -static inline DBusConnection *get_dbus_conn(DBusError *error) +QDBusArgument &operator<<(QDBusArgument &argument, + const ICd2DetailsDBusStruct &icd2) { - DBusConnection *conn = dbus_bus_get(DBUS_BUS_SYSTEM, error); -#ifdef BEARER_MANAGEMENT_DEBUG - qDebug() << "Listening to bus" << dbus_bus_get_unique_name(conn); -#endif - - return conn; + argument.beginStructure(); + argument << icd2.serviceType; + argument << icd2.serviceAttributes; + argument << icd2.setviceId; + argument << icd2.networkType; + argument << icd2.networkAttributes; + argument << icd2.networkId; + argument.endStructure(); + return argument; } - -/* Helper class that monitors the Icd status messages and - * can change the IAP status accordingly. This is a singleton. - */ -class IcdListener : public QObject -{ - Q_OBJECT - -public: - IcdListener() : first_call(true) { } - friend DBusHandlerResult signal_handler(DBusConnection *connection, - DBusMessage *message, - void *user_data); - void setup(QNetworkSessionPrivateImpl *d); - void cleanup(); - void cleanupSession(QNetworkSessionPrivateImpl *ptr); - - enum IapConnectionStatus { - /* The IAP was connected */ - CONNECTED = 0, - /* The IAP was disconnected */ - DISCONNECTED, - /* The IAP is disconnecting */ - DISCONNECTING, - /* The IAP has a network address, but is not yet fully connected */ - NETWORK_UP - }; - -private: - void icdSignalReceived(QString&, QString&, QString&); - bool first_call; - QHash<QString, QNetworkSessionPrivateImpl *> sessions; -}; - -Q_GLOBAL_STATIC(IcdListener, icdListener); - - -static DBusHandlerResult signal_handler(DBusConnection *, - DBusMessage *message, - void *user_data) +const QDBusArgument &operator>>(const QDBusArgument &argument, + ICd2DetailsDBusStruct &icd2) { - if (dbus_message_is_signal(message, - ICD_DBUS_INTERFACE, - ICD_STATUS_CHANGED_SIG)) { - - IcdListener *icd = (IcdListener *)user_data; - DBusError error; - dbus_error_init(&error); - - char *iap_id = 0; - char *network_type = 0; - char *state = 0; - - if (dbus_message_get_args(message, &error, - DBUS_TYPE_STRING, &iap_id, - DBUS_TYPE_STRING, &network_type, - DBUS_TYPE_STRING, &state, - DBUS_TYPE_INVALID) == FALSE) { -#ifdef BEARER_MANAGEMENT_DEBUG - qDebug() << QString("Failed to parse icd status signal: %1").arg(error.message); -#endif - } else { - QString _iap_id(iap_id); - QString _network_type(network_type); - QString _state(state); - - icd->icdSignalReceived(_iap_id, _network_type, _state); - } - - dbus_error_free(&error); - return DBUS_HANDLER_RESULT_HANDLED; - } - - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + argument.beginStructure(); + argument >> icd2.serviceType; + argument >> icd2.serviceAttributes; + argument >> icd2.setviceId; + argument >> icd2.networkType; + argument >> icd2.networkAttributes; + argument >> icd2.networkId; + argument.endStructure(); + return argument; } - -void IcdListener::setup(QNetworkSessionPrivateImpl *d) +const QDBusArgument &operator>>(const QDBusArgument &argument, + ICd2DetailsList &detailsList) { - if (first_call) { - // We use the old Icd dbus interface like in ConIC - DBusError error; - dbus_error_init(&error); - - dbus_connection = get_dbus_conn(&error); - if (dbus_error_is_set(&error)) { - dbus_error_free(&error); - return; - } - - static struct DBusObjectPathVTable icd_vtable; - icd_vtable.message_function = signal_handler; - - dbus_bus_add_match(dbus_connection, ICD_DBUS_MATCH, &error); - if (dbus_error_is_set(&error)) { - dbus_error_free(&error); - return; - } - - if (dbus_connection_register_object_path(dbus_connection, - ICD_DBUS_PATH, - &icd_vtable, - (void*)this) == FALSE) { - dbus_error_free(&error); - return; - } + argument.beginArray(); + detailsList.clear(); -#ifdef BEARER_MANAGEMENT_DEBUG - qDebug() << "Listening" << ICD_STATUS_CHANGED_SIG << "signal from" << ICD_DBUS_SERVICE; -#endif - first_call = false; - dbus_error_free(&error); - } + while (!argument.atEnd()) { + ICd2DetailsDBusStruct element; + argument >> element; + detailsList.append(element); + } - QString id = d->activeConfig.identifier(); - if (!sessions.contains(id)) { - QNetworkSessionPrivateImpl *ptr = d; - sessions.insert(id, ptr); - } + argument.endArray(); + return argument; } - -void IcdListener::icdSignalReceived(QString& iap_id, -#ifdef BEARER_MANAGEMENT_DEBUG - QString& network_type, -#else - QString&, -#endif - QString& state) +QDBusArgument &operator<<(QDBusArgument &argument, + const ICd2DetailsList &detailsList) { - if (iap_id == OSSO_IAP_SCAN) // icd sends scan status signals which we will ignore - return; - -#ifdef BEARER_MANAGEMENT_DEBUG - qDebug() << "Status received:" << iap_id << "type" << network_type << "state" << state; -#endif - - if (!sessions.contains(iap_id)) { -#ifdef BEARER_MANAGEMENT_DEBUG - qDebug() << "No session for IAP" << iap_id; -#endif - return; - } - - QNetworkSessionPrivateImpl *session = sessions.value(iap_id); - QNetworkConfiguration ap_conf = - QNetworkConfigurationManager().configurationFromIdentifier(iap_id); - if (!ap_conf.isValid()) { -#ifdef BEARER_MANAGEMENT_DEBUG - qDebug() << "Unknown IAP" << iap_id; -#endif - return; - } - - IapConnectionStatus status; - - if (state == "IDLE") { - status = DISCONNECTED; - } else if (state == "CONNECTED") { - status = CONNECTED; - } else if (state == "NETWORKUP") { - status = NETWORK_UP; - } else { - //qDebug() << "Unknown state" << state; - return; - } - - if (status == DISCONNECTED) { - if (ap_conf.state() == QNetworkConfiguration::Active) { - /* The IAP was just disconnected by Icd */ - session->updateState(QNetworkSession::Disconnected); - } else { -#ifdef BEARER_MANAGEMENT_DEBUG - qDebug() << "Got a network disconnect when in state" << ap_conf.state(); -#endif - } - } else if (status == CONNECTED) { - /* The IAP was just connected by Icd */ - session->updateState(QNetworkSession::Connected); - session->updateIdentifier(iap_id); - - if (session->publicConfig.identifier() == OSSO_IAP_ANY) { -#ifdef BEARER_MANAGEMENT_DEBUG - qDebug() << "IAP" << iap_id << "connected when connecting to" << OSSO_IAP_ANY; -#endif - } else { -#ifdef BEARER_MANAGEMENT_DEBUG - qDebug() << "IAP" << iap_id << "connected"; -#endif - } - } - - return; + argument.beginArray(qMetaTypeId<ICd2DetailsDBusStruct>()); + for (int i = 0; i < detailsList.count(); ++i) + argument << detailsList[i]; + argument.endArray(); + return argument; } +static QHash<QString, QVariant> properties; -void IcdListener::cleanup() +static QString get_network_interface(); + +void QNetworkSessionPrivateImpl::iapStateChanged(const QString& iapid, uint icd_connection_state) { - if (!first_call) { - dbus_bus_remove_match(dbus_connection, ICD_DBUS_MATCH, NULL); - dbus_connection_unref(dbus_connection); + if ((publicConfig.type() == QNetworkConfiguration::UserChoice) && opened) { + updateIdentifier(iapid); } -} - -void IcdListener::cleanupSession(QNetworkSessionPrivateImpl *ptr) -{ - if (ptr->publicConfig.type() == QNetworkConfiguration::UserChoice) - (void)sessions.take(ptr->activeConfig.identifier()); - else - (void)sessions.take(ptr->publicConfig.identifier()); + if (((publicConfig.type() == QNetworkConfiguration::UserChoice) && + (activeConfig.identifier() == iapid)) || + (publicConfig.identifier() == iapid)) { + switch (icd_connection_state) { + case ICD_STATE_CONNECTING: + updateState(QNetworkSession::Connecting); + break; + case ICD_STATE_CONNECTED: + updateState(QNetworkSession::Connected); + break; + case ICD_STATE_DISCONNECTING: + updateState(QNetworkSession::Closing); + break; + case ICD_STATE_DISCONNECTED: + updateState(QNetworkSession::Disconnected); + break; + default: + break; + } + } } - void QNetworkSessionPrivateImpl::cleanupSession(void) { - icdListener()->cleanupSession(this); - QObject::disconnect(q, SIGNAL(stateChanged(QNetworkSession::State)), this, SLOT(updateProxies(QNetworkSession::State))); } void QNetworkSessionPrivateImpl::updateState(QNetworkSession::State newState) { - if (newState == state) - return; - - state = newState; - - if (state == QNetworkSession::Disconnected) { - isOpen = false; - currentNetworkInterface.clear(); - if (publicConfig.type() == QNetworkConfiguration::UserChoice) { - IcdNetworkConfigurationPrivate *icdConfig = - toIcdConfig(privateConfiguration(activeConfig)); - - icdConfig->mutex.lock(); - icdConfig->state = QNetworkConfiguration::Defined; - icdConfig->mutex.unlock(); - } - - IcdNetworkConfigurationPrivate *icdConfig = - toIcdConfig(privateConfiguration(publicConfig)); - - icdConfig->mutex.lock(); - icdConfig->state = QNetworkConfiguration::Defined; - icdConfig->mutex.unlock(); - - } else if (state == QNetworkSession::Connected) { - isOpen = true; + if (newState != state) { + if (newState == QNetworkSession::Disconnected) { + if (isOpen) { + // The Session was aborted by the user or system + lastError = QNetworkSession::SessionAbortedError; + emit QNetworkSessionPrivate::error(lastError); + emit closed(); + } + if (m_stopTimer.isActive()) { + // Session was closed by calling stop() + m_stopTimer.stop(); + } + isOpen = false; + opened = false; + currentNetworkInterface.clear(); + if (publicConfig.type() == QNetworkConfiguration::UserChoice) { + copyConfig(publicConfig, activeConfig); + IcdNetworkConfigurationPrivate *icdConfig = + toIcdConfig(privateConfiguration(activeConfig)); + + icdConfig->mutex.lock(); + icdConfig->state = QNetworkConfiguration::Defined; + icdConfig->mutex.unlock(); + } else { + if (!activeConfig.isValid()) { + // Active configuration (IAP) was removed from system + // => Connection was disconnected and configuration became + // invalid + // => Also Session state must be changed to invalid + newState = QNetworkSession::Invalid; + } + } + } else if (newState == QNetworkSession::Connected) { + if (opened) { + isOpen = true; + } if (publicConfig.type() == QNetworkConfiguration::UserChoice) { IcdNetworkConfigurationPrivate *icdConfig = toIcdConfig(privateConfiguration(activeConfig)); @@ -350,11 +202,15 @@ void QNetworkSessionPrivateImpl::updateState(QNetworkSession::State newState) icdConfig->mutex.unlock(); } - emit stateChanged(newState); + if (newState != state) { + state = newState; + emit stateChanged(newState); + } + } } -void QNetworkSessionPrivateImpl::updateIdentifier(QString &newId) +void QNetworkSessionPrivateImpl::updateIdentifier(const QString &newId) { if (publicConfig.type() == QNetworkConfiguration::UserChoice) { IcdNetworkConfigurationPrivate *icdConfig = @@ -479,9 +335,6 @@ QNetworkConfiguration& QNetworkSessionPrivateImpl::copyConfig(QNetworkConfigurat */ void QNetworkSessionPrivateImpl::syncStateWithInterface() { - /* Start to listen Icd status messages. */ - icdListener()->setup(this); - /* Initially we are not active although the configuration might be in * connected state. */ @@ -490,8 +343,8 @@ void QNetworkSessionPrivateImpl::syncStateWithInterface() connect(&manager, SIGNAL(updateCompleted()), this, SLOT(networkConfigurationsChanged())); - connect(&manager, SIGNAL(configurationChanged(QNetworkConfiguration)), - this, SLOT(configurationChanged(QNetworkConfiguration))); + connect(engine, SIGNAL(iapStateChanged(const QString&, uint)), + this, SLOT(iapStateChanged(const QString&, uint))); QObject::connect(q, SIGNAL(stateChanged(QNetworkSession::State)), this, SLOT(updateProxies(QNetworkSession::State))); @@ -500,14 +353,14 @@ void QNetworkSessionPrivateImpl::syncStateWithInterface() switch (publicConfig.type()) { case QNetworkConfiguration::InternetAccessPoint: - activeConfig = publicConfig; + activeConfig = publicConfig; break; case QNetworkConfiguration::ServiceNetwork: - serviceConfig = publicConfig; + serviceConfig = publicConfig; break; case QNetworkConfiguration::UserChoice: // active config will contain correct data after open() has succeeded - copyConfig(publicConfig, activeConfig); + copyConfig(publicConfig, activeConfig); /* We create new configuration that holds the actual configuration * returned by icd. This way publicConfig still contains the @@ -541,7 +394,6 @@ void QNetworkSessionPrivateImpl::syncStateWithInterface() * supports only one connection anyway. */ if (icd.state(state_results) && !state_results.isEmpty()) { - /* If we did not get full state back, then we are not * connected and can skip the next part. */ @@ -554,35 +406,28 @@ void QNetworkSessionPrivateImpl::syncStateWithInterface() */ if (publicConfig.type() == QNetworkConfiguration::UserChoice || publicConfig.identifier() == state_results.first().params.network_id) { - switch (state_results.first().state) { case ICD_STATE_DISCONNECTED: - state = QNetworkSession::Disconnected; - { - QNetworkConfigurationPrivatePointer ptr = privateConfiguration(activeConfig); - if (ptr) { - ptr->mutex.lock(); - ptr->isValid = true; - ptr->mutex.unlock(); - } + state = QNetworkSession::Disconnected; + if (QNetworkConfigurationPrivatePointer ptr = privateConfiguration(activeConfig)) { + ptr->mutex.lock(); + ptr->isValid = true; + ptr->mutex.unlock(); } - break; + break; case ICD_STATE_CONNECTING: - state = QNetworkSession::Connecting; - { - QNetworkConfigurationPrivatePointer ptr = privateConfiguration(activeConfig); - if (ptr) { - ptr->mutex.lock(); - ptr->isValid = true; - ptr->mutex.unlock(); - } + state = QNetworkSession::Connecting; + if (QNetworkConfigurationPrivatePointer ptr = privateConfiguration(activeConfig)) { + ptr->mutex.lock(); + ptr->isValid = true; + ptr->mutex.unlock(); } - break; + break; case ICD_STATE_CONNECTED: - { - if (!state_results.first().error.isEmpty()) - break; - + { + if (!state_results.first().error.isEmpty()) + break; + const QString id = state_results.first().params.network_id; QNetworkConfiguration config = manager.configurationFromIdentifier(id); @@ -607,7 +452,7 @@ void QNetworkSessionPrivateImpl::syncStateWithInterface() ptr->type = QNetworkConfiguration::InternetAccessPoint; ptr->state = QNetworkConfiguration::Active; ptr->isValid = true; - currentNetworkInterface = get_network_interface(); + currentNetworkInterface = get_network_interface(); Maemo::IAPConf iap_name(ptr->id); QString name_value = iap_name.value("name").toString(); @@ -616,8 +461,7 @@ void QNetworkSessionPrivateImpl::syncStateWithInterface() else ptr->name = ptr->id; - - // Add the new active configuration to manager or update the old config + // Add the new active configuration to manager or update the old config if (!engine->hasIdentifier(ptr->id)) { configLocker.unlock(); engine->addSessionConfiguration(ptr); @@ -625,24 +469,21 @@ void QNetworkSessionPrivateImpl::syncStateWithInterface() configLocker.unlock(); engine->changedSessionConfiguration(ptr); } - } - break; + } + break; case ICD_STATE_DISCONNECTING: - state = QNetworkSession::Closing; - { - QNetworkConfigurationPrivatePointer ptr = privateConfiguration(activeConfig); - if (ptr) { - ptr->mutex.lock(); - ptr->isValid = true; - ptr->mutex.unlock(); - } + state = QNetworkSession::Closing; + if (QNetworkConfigurationPrivatePointer ptr = privateConfiguration(activeConfig)) { + ptr->mutex.lock(); + ptr->isValid = true; + ptr->mutex.unlock(); } - break; + break; default: - break; + break; } - } + } } else { #ifdef BEARER_MANAGEMENT_DEBUG qDebug() << "status_req tells icd is not connected"; @@ -733,7 +574,6 @@ void QNetworkSessionPrivateImpl::updateStateFromActiveConfig() state = QNetworkSession::NotAvailable; } else if ((activeConfig.state() & QNetworkConfiguration::Undefined) == QNetworkConfiguration::Undefined) { state = QNetworkSession::NotAvailable; - //clearConfiguration(activeConfig); } bool oldActive = isOpen; @@ -748,7 +588,7 @@ void QNetworkSessionPrivateImpl::updateStateFromActiveConfig() if (oldState != state) { emit stateChanged(state); - if (state == QNetworkSession::Disconnected) { + if (state == QNetworkSession::Disconnected && oldActive) { #ifdef BEARER_MANAGEMENT_DEBUG //qDebug()<<"session aborted error emitted for"<<activeConfig.identifier(); #endif @@ -762,16 +602,6 @@ void QNetworkSessionPrivateImpl::updateStateFromActiveConfig() #endif } - -void QNetworkSessionPrivateImpl::configurationChanged(const QNetworkConfiguration &config) -{ - if (serviceConfig.isValid() && (config == serviceConfig || config == activeConfig)) - updateStateFromServiceNetwork(); - else if (config == activeConfig) - updateStateFromActiveConfig(); -} - - static QString get_network_interface() { Maemo::Icd icd; @@ -808,14 +638,16 @@ static QString get_network_interface() } for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { - family = ifa->ifa_addr->sa_family; - if (family != AF_INET) { - continue; /* Currently only IPv4 is supported by icd dbus interface */ - } - if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == addr.s_addr) { - iface = QString(ifa->ifa_name); - break; - } + if (ifa->ifa_addr) { + family = ifa->ifa_addr->sa_family; + if (family != AF_INET) { + continue; /* Currently only IPv4 is supported by icd dbus interface */ + } + if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == addr.s_addr) { + iface = QString(ifa->ifa_name); + break; + } + } } freeifaddrs(ifaddr); @@ -825,11 +657,18 @@ static QString get_network_interface() void QNetworkSessionPrivateImpl::open() { + if (m_stopTimer.isActive()) { + m_stopTimer.stop(); + } + if (!publicConfig.isValid()) { + lastError = QNetworkSession::InvalidConfigurationError; + emit QNetworkSessionPrivate::error(lastError); + return; + } if (serviceConfig.isValid()) { lastError = QNetworkSession::OperationNotSupportedError; emit QNetworkSessionPrivate::error(lastError); } else if (!isOpen) { - if (publicConfig.type() == QNetworkConfiguration::UserChoice) { /* Caller is trying to connect to default IAP. * At this time we will not know the IAP details so we just @@ -857,189 +696,183 @@ void QNetworkSessionPrivateImpl::open() if ((activeConfig.state() & QNetworkConfiguration::Active) != QNetworkConfiguration::Active) { state = QNetworkSession::Connecting; emit stateChanged(state); - - QTimer::singleShot(0, this, SLOT(do_open())); - return; + QTimer::singleShot(0, this, SLOT(do_open())); + return; } - isOpen = (activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active; if (isOpen) emit quitPendingWaitsForOpened(); } else { - /* We seem to be active so inform caller */ - emit quitPendingWaitsForOpened(); + /* We seem to be active so inform caller */ + emit quitPendingWaitsForOpened(); } } - void QNetworkSessionPrivateImpl::do_open() { icd_connection_flags flags = connectFlags; - bool st; - QString result; QString iap = publicConfig.identifier(); if (state == QNetworkSession::Connected) { #ifdef BEARER_MANAGEMENT_DEBUG - qDebug() << "Already connected to" << activeConfig.identifier(); + qDebug() << "Already connected to" << activeConfig.identifier(); #endif emit stateChanged(QNetworkSession::Connected); - emit quitPendingWaitsForOpened(); + emit quitPendingWaitsForOpened(); return; } - Maemo::IcdConnectResult connect_result; - Maemo::Icd icd(ICD_LONG_CONNECT_TIMEOUT); - QNetworkConfiguration config; if (publicConfig.type() == QNetworkConfiguration::UserChoice) - config = activeConfig; + config = activeConfig; else - config = publicConfig; + config = publicConfig; if (iap == OSSO_IAP_ANY) { #ifdef BEARER_MANAGEMENT_DEBUG - qDebug() << "connecting to default IAP" << iap; + qDebug() << "connecting to default IAP" << iap; #endif - st = icd.connect(flags, connect_result); - + m_connectRequestTimer.start(ICD_LONG_CONNECT_TIMEOUT); + m_dbusInterface->asyncCall(ICD_DBUS_API_CONNECT_REQ, (uint)flags); // Return value ignored + m_asynchCallActive = true; } else { + IcdNetworkConfigurationPrivate *icdConfig = toIcdConfig(privateConfiguration(config)); - QList<Maemo::ConnectParams> params; - Maemo::ConnectParams param; - - IcdNetworkConfigurationPrivate *icdConfig = toIcdConfig(privateConfiguration(config)); - - icdConfig->mutex.lock(); - param.connect.service_type = icdConfig->service_type; - param.connect.service_attrs = icdConfig->service_attrs; - param.connect.service_id = icdConfig->service_id; - param.connect.network_type = icdConfig->iap_type; - param.connect.network_attrs = icdConfig->network_attrs; - if (icdConfig->network_attrs & ICD_NW_ATTR_IAPNAME) - param.connect.network_id = QByteArray(iap.toLatin1()); - else - param.connect.network_id = icdConfig->network_id; - params.append(param); - icdConfig->mutex.unlock(); + icdConfig->mutex.lock(); + ICd2DetailsDBusStruct icd2; + icd2.serviceType = icdConfig->service_type; + icd2.serviceAttributes = icdConfig->service_attrs; + icd2.setviceId = icdConfig->service_id; + icd2.networkType = icdConfig->iap_type; + icd2.networkAttributes = icdConfig->network_attrs; + if (icdConfig->network_attrs & ICD_NW_ATTR_IAPNAME) { + icd2.networkId = QByteArray(iap.toLatin1()); + } else { + icd2.networkId = icdConfig->network_id; + } + icdConfig->mutex.unlock(); #ifdef BEARER_MANAGEMENT_DEBUG - qDebug("connecting to %s/%s/0x%x/%s/0x%x/%s", - param.connect.network_id.data(), - param.connect.network_type.toAscii().constData(), - param.connect.network_attrs, - param.connect.service_type.toAscii().constData(), - param.connect.service_attrs, - param.connect.service_id.toAscii().constData()); + qDebug("connecting to %s/%s/0x%x/%s/0x%x/%s", + icd2.networkId.data(), + icd2.networkType.toAscii().constData(), + icd2.networkAttributes, + icd2.serviceType.toAscii().constData(), + icd2.serviceAttributes, + icd2.setviceId.toAscii().constData()); #endif - st = icd.connect(flags, params, connect_result); - } - if (st) { - result = connect_result.connect.network_id.data(); - QString connected_iap = result; + ICd2DetailsList paramArray; + paramArray.append(icd2); + m_connectRequestTimer.start(ICD_LONG_CONNECT_TIMEOUT); + m_dbusInterface->asyncCall(ICD_DBUS_API_CONNECT_REQ, (uint)flags, QVariant::fromValue(paramArray)); // Return value ignored + m_asynchCallActive = true; + } +} - if (connected_iap.isEmpty()) { +void QNetworkSessionPrivateImpl::stateChange(const QDBusMessage& rep) +{ + if (m_asynchCallActive == true) { + if (m_connectRequestTimer.isActive()) + m_connectRequestTimer.stop(); + m_asynchCallActive = false; + + QString result = rep.arguments().at(5).toString(); // network id or empty string + QString connected_iap = result; + if (connected_iap.isEmpty()) { #ifdef BEARER_MANAGEMENT_DEBUG - qDebug() << "connect to"<< iap << "failed, result is empty"; + qDebug() << "connect to"<< publicConfig.identifier() << "failed, result is empty"; #endif - updateState(QNetworkSession::Disconnected); - emit QNetworkSessionPrivate::error(QNetworkSession::InvalidConfigurationError); - if (publicConfig.type() == QNetworkConfiguration::UserChoice) - cleanupAnyConfiguration(); - return; - } - - /* If the user tried to connect to some specific connection (foo) - * and we were already connected to some other connection (bar), - * then we cannot activate this session although icd has a valid - * connection to somewhere. - */ - if ((publicConfig.type() != QNetworkConfiguration::UserChoice) && - (connected_iap != config.identifier())) { - updateState(QNetworkSession::Disconnected); - emit QNetworkSessionPrivate::error(QNetworkSession::InvalidConfigurationError); - return; - } - - IcdNetworkConfigurationPrivate *icdConfig = toIcdConfig(privateConfiguration(config)); - - /* Did we connect to non saved IAP? */ - icdConfig->mutex.lock(); - if (!(icdConfig->network_attrs & ICD_NW_ATTR_IAPNAME)) { - /* Because the connection succeeded, the IAP is now known. - */ - icdConfig->network_attrs |= ICD_NW_ATTR_IAPNAME; - icdConfig->id = connected_iap; - } + updateState(QNetworkSession::Disconnected); + emit QNetworkSessionPrivate::error(QNetworkSession::InvalidConfigurationError); + if (publicConfig.type() == QNetworkConfiguration::UserChoice) + copyConfig(publicConfig, activeConfig); + return; + } - /* User might have changed the IAP name when a new IAP was saved */ - Maemo::IAPConf iap_name(icdConfig->id); - QString name = iap_name.value("name").toString(); - if (!name.isEmpty()) - icdConfig->name = name; + /* If the user tried to connect to some specific connection (foo) + * and we were already connected to some other connection (bar), + * then we cannot activate this session although icd has a valid + * connection to somewhere. + */ + if ((publicConfig.type() != QNetworkConfiguration::UserChoice) && + (connected_iap != config.identifier())) { + updateState(QNetworkSession::Disconnected); + emit QNetworkSessionPrivate::error(QNetworkSession::InvalidConfigurationError); + return; + } - icdConfig->iap_type = connect_result.connect.network_type; + IcdNetworkConfigurationPrivate *icdConfig = toIcdConfig(privateConfiguration(config)); - icdConfig->isValid = true; - icdConfig->state = QNetworkConfiguration::Active; - icdConfig->type = QNetworkConfiguration::InternetAccessPoint; + /* Did we connect to non saved IAP? */ + icdConfig->mutex.lock(); + if (!(icdConfig->network_attrs & ICD_NW_ATTR_IAPNAME)) { + /* Because the connection succeeded, the IAP is now known. + */ + icdConfig->network_attrs |= ICD_NW_ATTR_IAPNAME; + icdConfig->id = connected_iap; + } - icdConfig->mutex.unlock(); + /* User might have changed the IAP name when a new IAP was saved */ + Maemo::IAPConf iap_name(icdConfig->id); + QString name = iap_name.value("name").toString(); + if (!name.isEmpty()) + icdConfig->name = name; - startTime = QDateTime::currentDateTime(); - updateState(QNetworkSession::Connected); + icdConfig->iap_type = rep.arguments().at(3).toString(); // connect_result.connect.network_type; + icdConfig->isValid = true; + icdConfig->state = QNetworkConfiguration::Active; + icdConfig->type = QNetworkConfiguration::InternetAccessPoint; - currentNetworkInterface = get_network_interface(); + icdConfig->mutex.unlock(); + startTime = QDateTime::currentDateTime(); + updateState(QNetworkSession::Connected); + //currentNetworkInterface = get_network_interface(); #ifdef BEARER_MANAGEMENT_DEBUG - qDebug() << "connected to" << result << config.name() << "at" << currentNetworkInterface; + //qDebug() << "connected to" << result << config.name() << "at" << currentNetworkInterface; #endif - /* We first check if the configuration already exists in the manager - * and if it is not found there, we then insert it. Note that this - * is only done for user choice config only because it can be missing - * from config manager list. - */ - - if (publicConfig.type() == QNetworkConfiguration::UserChoice) { - if (!engine->hasIdentifier(result)) { - engine->addSessionConfiguration(privateConfiguration(config)); - } else { - QNetworkConfigurationPrivatePointer priv = engine->configuration(result); - QNetworkConfiguration reference; - setPrivateConfiguration(reference, priv); - copyConfig(config, reference, false); - config = reference; - activeConfig = reference; - engine->changedSessionConfiguration(privateConfiguration(config)); - } - } - - emit quitPendingWaitsForOpened(); + /* We first check if the configuration already exists in the manager + * and if it is not found there, we then insert it. Note that this + * is only done for user choice config only because it can be missing + * from config manager list. + */ + if (publicConfig.type() == QNetworkConfiguration::UserChoice) { + if (!engine->hasIdentifier(result)) { + engine->addSessionConfiguration(privateConfiguration(config)); + } else { + QNetworkConfigurationPrivatePointer priv = engine->configuration(result); + QNetworkConfiguration reference; + setPrivateConfiguration(reference, priv); + copyConfig(config, reference, false); + privateConfiguration(reference)->id = result; // Note: Id was not copied in copyConfig() function + config = reference; + activeConfig = reference; + engine->changedSessionConfiguration(privateConfiguration(config)); - } else { #ifdef BEARER_MANAGEMENT_DEBUG - qDebug() << "connect to"<< iap << "failed, status:" << connect_result.status; + qDebug()<<"Existing configuration"<<result<<"updated in manager in open"; #endif - updateState(QNetworkSession::Disconnected); - if (publicConfig.type() == QNetworkConfiguration::UserChoice) - cleanupAnyConfiguration(); - emit QNetworkSessionPrivate::error(QNetworkSession::UnknownSessionError); + } + } + + emit quitPendingWaitsForOpened(); } } - -void QNetworkSessionPrivateImpl::cleanupAnyConfiguration() +void QNetworkSessionPrivateImpl::connectTimeout() { -#ifdef BEARER_MANAGEMENT_DEBUG - qDebug()<<"Removing configuration created for" << activeConfig.identifier(); -#endif - activeConfig = publicConfig; + updateState(QNetworkSession::Disconnected); + if (publicConfig.type() == QNetworkConfiguration::UserChoice) + copyConfig(publicConfig, activeConfig); + emit QNetworkSessionPrivate::error(QNetworkSession::UnknownSessionError); } - void QNetworkSessionPrivateImpl::close() { + if (m_connectRequestTimer.isActive()) + m_connectRequestTimer.stop(); + if (serviceConfig.isValid()) { lastError = QNetworkSession::OperationNotSupportedError; emit QNetworkSessionPrivate::error(lastError); @@ -1053,35 +886,37 @@ void QNetworkSessionPrivateImpl::close() void QNetworkSessionPrivateImpl::stop() { + if (m_connectRequestTimer.isActive()) + m_connectRequestTimer.stop(); + if (serviceConfig.isValid()) { lastError = QNetworkSession::OperationNotSupportedError; emit QNetworkSessionPrivate::error(lastError); } else { if ((activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { - state = QNetworkSession::Closing; - emit stateChanged(state); - - Maemo::Icd icd; + if (!m_stopTimer.isActive()) { + Maemo::Icd icd; #ifdef BEARER_MANAGEMENT_DEBUG - qDebug() << "stopping session" << publicConfig.identifier(); + qDebug() << "stopping session" << publicConfig.identifier(); #endif - icd.disconnect(ICD_CONNECTION_FLAG_APPLICATION_EVENT); - startTime = QDateTime(); + state = QNetworkSession::Closing; + emit stateChanged(state); - /* Note that the state will go disconnected in - * updateStateFromActiveConfig() which gets called after - * configurationChanged is emitted (below). - */ + opened = false; + isOpen = false; - QNetworkConfigurationPrivatePointer ptr = privateConfiguration(activeConfig); - ptr->mutex.lock(); - ptr->state = QNetworkConfiguration::Discovered; - ptr->mutex.unlock(); - engine->changedSessionConfiguration(ptr); + icd.disconnect(ICD_CONNECTION_FLAG_APPLICATION_EVENT); + startTime = QDateTime(); - opened = false; - isOpen = false; + /* Note: Session state will change to disconnected + * as soon as QNetworkConfigurationManager sends + * corresponding iapStateChanged signal. + */ + // Make sure that this Session will send closed signal + // even though ICD connection will not ever get closed + m_stopTimer.start(ICD_SHORT_CONNECT_TIMEOUT); // 10 seconds wait + } } else { opened = false; isOpen = false; @@ -1090,6 +925,15 @@ void QNetworkSessionPrivateImpl::stop() } } +void QNetworkSessionPrivateImpl::finishStopBySendingClosedSignal() +{ + if ((activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { + state = QNetworkSession::Connected; + emit stateChanged(state); + } + + emit closed(); +} void QNetworkSessionPrivateImpl::migrate() { @@ -1199,6 +1043,4 @@ void QNetworkSessionPrivateImpl::clearProxyInformation() Maemo::ProxyConf::clear(); } -#include "qnetworksession_impl.moc" - QT_END_NAMESPACE diff --git a/src/plugins/bearer/icd/qnetworksession_impl.h b/src/plugins/bearer/icd/qnetworksession_impl.h index c02faac..d15f401 100644 --- a/src/plugins/bearer/icd/qnetworksession_impl.h +++ b/src/plugins/bearer/icd/qnetworksession_impl.h @@ -57,6 +57,12 @@ #include <QtNetwork/qnetworkconfigmanager.h> #include <QtCore/qdatetime.h> +#include <QtCore/qtimer.h> + +#include <QtDBus/qdbusconnection.h> +#include <QtDBus/qdbusinterface.h> +#include <QtDBus/qdbusmessage.h> +#include <QtDBus/qdbusmetatype.h> #include <icd/dbus_api.h> @@ -64,14 +70,52 @@ QT_BEGIN_NAMESPACE class QIcdEngine; +struct ICd2DetailsDBusStruct +{ + QString serviceType; + uint serviceAttributes; + QString setviceId; + QString networkType; + uint networkAttributes; + QByteArray networkId; +}; + +typedef QList<ICd2DetailsDBusStruct> ICd2DetailsList; + class QNetworkSessionPrivateImpl : public QNetworkSessionPrivate { Q_OBJECT public: QNetworkSessionPrivateImpl(QIcdEngine *engine) - : engine(engine), connectFlags(ICD_CONNECTION_FLAG_USER_EVENT), currentState(QNetworkSession::Invalid) + : engine(engine), + connectFlags(ICD_CONNECTION_FLAG_USER_EVENT), + currentState(QNetworkSession::Invalid), + m_asynchCallActive(false) { + m_stopTimer.setSingleShot(true); + connect(&m_stopTimer, SIGNAL(timeout()), this, SLOT(finishStopBySendingClosedSignal())); + + QDBusConnection systemBus = QDBusConnection::systemBus(); + + m_dbusInterface = new QDBusInterface(ICD_DBUS_API_INTERFACE, + ICD_DBUS_API_PATH, + ICD_DBUS_API_INTERFACE, + systemBus, + this); + + systemBus.connect(ICD_DBUS_API_INTERFACE, + ICD_DBUS_API_PATH, + ICD_DBUS_API_INTERFACE, + ICD_DBUS_API_CONNECT_SIG, + this, + SLOT(stateChange(const QDBusMessage&))); + + qDBusRegisterMetaType<ICd2DetailsDBusStruct>(); + qDBusRegisterMetaType<ICd2DetailsList>(); + + m_connectRequestTimer.setSingleShot(true); + connect(&m_connectRequestTimer, SIGNAL(timeout()), this, SLOT(connectTimeout())); } ~QNetworkSessionPrivateImpl() @@ -114,16 +158,21 @@ private: private Q_SLOTS: void do_open(); void networkConfigurationsChanged(); - void configurationChanged(const QNetworkConfiguration &config); + void iapStateChanged(const QString& iapid, uint icd_connection_state); void updateProxies(QNetworkSession::State newState); + void finishStopBySendingClosedSignal(); + void stateChange(const QDBusMessage& rep); + void connectTimeout(); private: QNetworkConfigurationManager manager; QIcdEngine *engine; + // The config set on QNetworkSession. + QNetworkConfiguration config; + QNetworkConfiguration& copyConfig(QNetworkConfiguration &fromConfig, QNetworkConfiguration &toConfig, bool deepCopy = true); void clearConfiguration(QNetworkConfiguration &config); - void cleanupAnyConfiguration(); bool opened; icd_connection_flags connectFlags; @@ -134,15 +183,31 @@ private: QString currentNetworkInterface; friend class IcdListener; void updateState(QNetworkSession::State); - void updateIdentifier(QString &newId); + void updateIdentifier(const QString &newId); quint64 getStatistics(bool sent) const; void cleanupSession(void); void updateProxyInformation(); void clearProxyInformation(); QNetworkSession::State currentState; + + QDBusInterface *m_dbusInterface; + + QTimer m_stopTimer; + + bool m_asynchCallActive; + QTimer m_connectRequestTimer; }; +// Marshall the ICd2DetailsDBusStruct data into a D-Bus argument +QDBusArgument &operator<<(QDBusArgument &argument, const ICd2DetailsDBusStruct &icd2); + +// Retrieve the ICd2DetailsDBusStruct data from the D-Bus argument +const QDBusArgument &operator>>(const QDBusArgument &argument, ICd2DetailsDBusStruct &icd2); + +Q_DECLARE_METATYPE(ICd2DetailsDBusStruct); +Q_DECLARE_METATYPE(ICd2DetailsList); + QT_END_NAMESPACE #endif //QNETWORKSESSIONPRIVATE_H |