diff -r cfcbf08528c4 -r 5822d84012fb qtmobility/src/bearer/qnetworksession_maemo.cpp --- a/qtmobility/src/bearer/qnetworksession_maemo.cpp Thu Apr 01 08:30:34 2010 +0300 +++ b/qtmobility/src/bearer/qnetworksession_maemo.cpp Thu Apr 15 08:16:03 2010 +0300 @@ -42,16 +42,12 @@ #include #include "qnetworksession_maemo_p.h" -#include -#include #include #include #include -#include #include -#include #include #include @@ -60,262 +56,73 @@ static QHash 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) -{ - 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; -} - - -/* Helper class that monitors the Icd status messages and - * can change the IAP status accordingly. This is a singleton. - */ -class IcdListener : public QObject +void QNetworkSessionPrivate::iapStateChanged(const QString& iapid, uint icd_connection_state) { - Q_OBJECT - -public: - IcdListener() : first_call(true) { } - friend DBusHandlerResult signal_handler(DBusConnection *connection, - DBusMessage *message, - void *user_data); - void setup(QNetworkSessionPrivate *d); - void cleanup(); - void cleanupSession(QNetworkSessionPrivate *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 sessions; -}; - -Q_GLOBAL_STATIC(IcdListener, icdListener); - - -static DBusHandlerResult signal_handler(DBusConnection *, - DBusMessage *message, - void *user_data) -{ - 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) { - qWarning() << QString("Failed to parse icd status signal: %1").arg(error.message); - } 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; + if ((publicConfig.type() == QNetworkConfiguration::UserChoice) && opened) { + updateIdentifier(iapid); } - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - - -void IcdListener::setup(QNetworkSessionPrivate *d) -{ - 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)) { - qWarning() << "Cannot get dbus connection."; - 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)) { - qWarning() << "Cannot add match" << ICD_DBUS_MATCH; - dbus_error_free(&error); - return; - } - - if (dbus_connection_register_object_path(dbus_connection, - ICD_DBUS_PATH, - &icd_vtable, - (void*)this) == FALSE) { - qWarning() << "Cannot register dbus signal handler, interface"<< ICD_DBUS_INTERFACE << "path" << ICD_DBUS_PATH; - dbus_error_free(&error); - return; - } - -#ifdef BEARER_MANAGEMENT_DEBUG - qDebug() << "Listening" << ICD_STATUS_CHANGED_SIG << "signal from" << ICD_DBUS_SERVICE; -#endif - first_call = false; - dbus_error_free(&error); - } - - QString id = d->activeConfig.identifier(); - if (!sessions.contains(id)) { - QNetworkSessionPrivate *ptr = d; - sessions.insert(id, ptr); + if (((publicConfig.type() == QNetworkConfiguration::UserChoice) && (activeConfig.d->id == iapid)) || + (publicConfig.d->id == 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 IcdListener::icdSignalReceived(QString& iap_id, -#ifdef BEARER_MANAGEMENT_DEBUG - QString& network_type, -#else - QString&, -#endif - QString& state) -{ - 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; - } - - QNetworkSessionPrivate *session = sessions.value(iap_id); - QNetworkConfiguration ap_conf = session->manager.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; -} - - -void IcdListener::cleanup() -{ - if (!first_call) { - dbus_bus_remove_match(dbus_connection, ICD_DBUS_MATCH, NULL); - dbus_connection_unref(dbus_connection); - } -} - - -void IcdListener::cleanupSession(QNetworkSessionPrivate *ptr) -{ - if (ptr->publicConfig.type() == QNetworkConfiguration::UserChoice) - (void)sessions.take(ptr->activeConfig.identifier()); - else - (void)sessions.take(ptr->publicConfig.identifier()); -} - - void QNetworkSessionPrivate::cleanupSession(void) { - icdListener()->cleanupSession(this); - QObject::disconnect(q, SIGNAL(stateChanged(QNetworkSession::State)), this, SLOT(updateProxies(QNetworkSession::State))); } void QNetworkSessionPrivate::updateState(QNetworkSession::State newState) { - if( newState != state) { - state = newState; - - if (state == QNetworkSession::Disconnected) { + if (newState != state) { + if (newState == QNetworkSession::Disconnected) { + if (isOpen) { + // The Session was aborted by the user or system + lastError = QNetworkSession::SessionAbortedError; + emit q->error(lastError); + emit q->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) - activeConfig.d->state = QNetworkConfiguration::Defined; - publicConfig.d->state = QNetworkConfiguration::Defined; - - } else if (state == QNetworkSession::Connected) { - isOpen = true; + if (publicConfig.type() == QNetworkConfiguration::UserChoice) { + copyConfig(publicConfig, activeConfig); + activeConfig.d->state = QNetworkConfiguration::Defined; + } 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) { activeConfig.d->state = QNetworkConfiguration::Active; activeConfig.d->type = QNetworkConfiguration::InternetAccessPoint; @@ -323,12 +130,15 @@ publicConfig.d->state = QNetworkConfiguration::Active; } - emit q->stateChanged(newState); + if (newState != state) { + state = newState; + emit q->stateChanged(newState); + } } } -void QNetworkSessionPrivate::updateIdentifier(QString &newId) +void QNetworkSessionPrivate::updateIdentifier(const QString &newId) { if (publicConfig.type() == QNetworkConfiguration::UserChoice) { activeConfig.d->network_attrs |= ICD_NW_ATTR_IAPNAME; @@ -357,7 +167,7 @@ return 0; } - foreach (Maemo::IcdStatisticsResult res, stats_results) { + foreach (const Maemo::IcdStatisticsResult &res, stats_results) { if (res.params.network_attrs & ICD_NW_ATTR_IAPNAME) { /* network_id is the IAP UUID */ if (QString(res.params.network_id.data()) == activeConfig.identifier()) { @@ -433,9 +243,6 @@ */ void QNetworkSessionPrivate::syncStateWithInterface() { - /* Start to listen Icd status messages. */ - icdListener()->setup(this); - /* Initially we are not active although the configuration might be in * connected state. */ @@ -447,10 +254,10 @@ if (publicConfig.d.data()) { QNetworkConfigurationManagerPrivate* mgr = (QNetworkConfigurationManagerPrivate*)publicConfig.d.data()->manager; if (mgr) { - QObject::connect(mgr, SIGNAL(configurationChanged(QNetworkConfiguration)), - this, SLOT(configurationChanged(QNetworkConfiguration))); + connect(mgr, SIGNAL(iapStateChanged(const QString&, uint)), + this, SLOT(iapStateChanged(const QString&, uint))); } else { - qWarning()<<"Manager object not set when trying to connect configurationChanged signal. Your configuration object is not correctly setup, did you remember to call manager.updateConfigurations() before creating session object?"; + qWarning()<<"Manager object not set when trying to connect iapStateChanged signal. Your configuration object is not correctly setup, did you remember to call manager.updateConfigurations() before creating session object?"; state = QNetworkSession::Invalid; lastError = QNetworkSession::UnknownSessionError; return; @@ -464,14 +271,14 @@ 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 @@ -505,7 +312,6 @@ * 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. */ @@ -518,46 +324,44 @@ */ if (publicConfig.type() == QNetworkConfiguration::UserChoice || publicConfig.d->id == state_results.first().params.network_id) { - switch (state_results.first().state) { case ICD_STATE_DISCONNECTED: - state = QNetworkSession::Disconnected; + state = QNetworkSession::Disconnected; if (activeConfig.d.data()) activeConfig.d->isValid = true; break; case ICD_STATE_CONNECTING: - state = QNetworkSession::Connecting; + state = QNetworkSession::Connecting; if (activeConfig.d.data()) activeConfig.d->isValid = true; break; case ICD_STATE_CONNECTED: { - if (!state_results.first().error.isEmpty()) + if (!state_results.first().error.isEmpty()) break; - + const QString id = state_results.first().params.network_id; - QNetworkConfigurationManagerPrivate *mgr = (QNetworkConfigurationManagerPrivate*)activeConfig.d.data()->manager; + QNetworkConfigurationManagerPrivate *mgr = (QNetworkConfigurationManagerPrivate*)publicConfig.d.data()->manager; if (mgr->accessPointConfigurations.contains(id)) { //we don't want the copied data if the config is already known by the manager //just reuse it so that existing references to the old data get the same update - QExplicitlySharedDataPointer priv = mgr->accessPointConfigurations.value(activeConfig.d->id); + QExplicitlySharedDataPointer priv = mgr->accessPointConfigurations.value(id); activeConfig.d = priv; } - state = QNetworkSession::Connected; - activeConfig.d->network_id = state_results.first().params.network_id; - activeConfig.d->id = activeConfig.d->network_id; - activeConfig.d->network_attrs = state_results.first().params.network_attrs; - activeConfig.d->iap_type = state_results.first().params.network_type; - activeConfig.d->service_type = state_results.first().params.service_type; - activeConfig.d->service_id = state_results.first().params.service_id; - activeConfig.d->service_attrs = state_results.first().params.service_attrs; - activeConfig.d->type = QNetworkConfiguration::InternetAccessPoint; - activeConfig.d->state = QNetworkConfiguration::Active; - activeConfig.d->isValid = true; - currentNetworkInterface = get_network_interface(); + activeConfig.d->network_id = state_results.first().params.network_id; + activeConfig.d->id = activeConfig.d->network_id; + activeConfig.d->network_attrs = state_results.first().params.network_attrs; + activeConfig.d->iap_type = state_results.first().params.network_type; + activeConfig.d->service_type = state_results.first().params.service_type; + activeConfig.d->service_id = state_results.first().params.service_id; + activeConfig.d->service_attrs = state_results.first().params.service_attrs; + activeConfig.d->type = QNetworkConfiguration::InternetAccessPoint; + activeConfig.d->state = QNetworkConfiguration::Active; + activeConfig.d->isValid = true; + currentNetworkInterface = get_network_interface(); Maemo::IAPConf iap_name(activeConfig.d->id); QString name_value = iap_name.value("name").toString(); @@ -566,7 +370,6 @@ else activeConfig.d->name = activeConfig.d->id; - // Add the new active configuration to manager or update the old config mgr = (QNetworkConfigurationManagerPrivate*)activeConfig.d.data()->manager; if (!(mgr->accessPointConfigurations.contains(activeConfig.d->id))) { @@ -581,23 +384,17 @@ //qDebug()<<"New configuration"<id<<"added to manager in sync"; #endif - } else { - mgr->configurationChanged((QNetworkConfigurationPrivate*)(activeConfig.d.data())); -#ifdef BEARER_MANAGEMENT_DEBUG - //qDebug()<<"Existing configuration"<id<<"updated in manager in sync"; -#endif - } - + } } break; case ICD_STATE_DISCONNECTING: - state = QNetworkSession::Closing; + state = QNetworkSession::Closing; if (activeConfig.d.data()) activeConfig.d->isValid = true; break; default: - break; + break; } } } else { @@ -686,7 +483,6 @@ state = QNetworkSession::NotAvailable; } else if ((activeConfig.state() & QNetworkConfiguration::Undefined) == QNetworkConfiguration::Undefined) { state = QNetworkSession::NotAvailable; - clearConfiguration(activeConfig); } bool oldActive = isOpen; @@ -701,7 +497,7 @@ if (oldState != state) { emit q->stateChanged(state); - if (state == QNetworkSession::Disconnected) { + if (state == QNetworkSession::Disconnected && oldActive) { #ifdef BEARER_MANAGEMENT_DEBUG //qDebug()<<"session aborted error emitted for"<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); @@ -778,11 +566,18 @@ void QNetworkSessionPrivate::open() { + if (m_stopTimer.isActive()) { + m_stopTimer.stop(); + } + if (!publicConfig.isValid()) { + lastError = QNetworkSession::InvalidConfigurationError; + emit q->error(lastError); + return; + } if (serviceConfig.isValid()) { lastError = QNetworkSession::OperationNotSupportedError; emit q->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 @@ -893,7 +688,7 @@ updateState(QNetworkSession::Disconnected); emit q->error(QNetworkSession::InvalidConfigurationError); if (publicConfig.type() == QNetworkConfiguration::UserChoice) - cleanupAnyConfiguration(); + copyConfig(publicConfig, activeConfig); return; } @@ -969,8 +764,7 @@ } #endif #endif - - QNetworkConfigurationManagerPrivate *mgr = (QNetworkConfigurationManagerPrivate*)config.d.data()->manager; + QNetworkConfigurationManagerPrivate *mgr = (QNetworkConfigurationManagerPrivate*)publicConfig.d.data()->manager; if (!mgr->accessPointConfigurations.contains(result)) { QExplicitlySharedDataPointer ptr = config.d; mgr->accessPointConfigurations.insert(result, ptr); @@ -984,13 +778,13 @@ #endif } else { - QExplicitlySharedDataPointer priv = mgr->accessPointConfigurations.value(result); + QExplicitlySharedDataPointer priv = mgr->accessPointConfigurations.value(result); QNetworkConfiguration reference; reference.d = priv; copyConfig(config, reference, false); + reference.d.data()->id = result; // Note: Id was not copied in copyConfig() function config = reference; activeConfig = reference; - mgr->configurationChanged((QNetworkConfigurationPrivate*)(config.d.data())); #ifdef BEARER_MANAGEMENT_DEBUG //qDebug()<<"Existing configuration"<error(QNetworkSession::UnknownSessionError); } } - -void QNetworkSessionPrivate::cleanupAnyConfiguration() -{ -#ifdef BEARER_MANAGEMENT_DEBUG - qDebug()<<"Removing configuration created for" << activeConfig.d->id; -#endif - activeConfig = publicConfig; -} - - void QNetworkSessionPrivate::close() { if (serviceConfig.isValid()) { @@ -1041,28 +825,29 @@ emit q->error(lastError); } else { if ((activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { - state = QNetworkSession::Closing; - emit q->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 q->stateChanged(state); + + opened = false; + isOpen = false; - /* Note that the state will go disconnected in - * updateStateFromActiveConfig() which gets called after - * configurationChanged is emitted (below). - */ + icd.disconnect(ICD_CONNECTION_FLAG_APPLICATION_EVENT); + startTime = QDateTime(); - activeConfig.d->state = QNetworkConfiguration::Discovered; - QNetworkConfigurationManagerPrivate *mgr = (QNetworkConfigurationManagerPrivate*)activeConfig.d.data()->manager; - mgr->configurationChanged((QNetworkConfigurationPrivate*)activeConfig.d.data()); + /* Note: Session state will change to disconnected + * as soon as QNetworkConfigurationManager sends + * corresponding iapStateChanged signal. + */ - opened = false; - isOpen = false; - + // 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; @@ -1071,6 +856,14 @@ } } +void QNetworkSessionPrivate::finishStopBySendingClosedSignal() +{ + if ((activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) { + state = QNetworkSession::Connected; + emit q->stateChanged(state); + } + emit q->closed(); +} void QNetworkSessionPrivate::migrate() { @@ -1186,7 +979,6 @@ } -#include "qnetworksession_maemo.moc" #include "moc_qnetworksession_maemo_p.cpp" QTM_END_NAMESPACE