/****************************************************************************
**
** 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 "qnetworksession_impl.h"
#include "qicdengine.h"
#include <QHash>
#include <maemo_icd.h>
#include <iapconf.h>
#include <proxyconf.h>
#include <ifaddrs.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#ifndef QT_NO_BEARERMANAGEMENT
QT_BEGIN_NAMESPACE
QDBusArgument &operator<<(QDBusArgument &argument,
const ICd2DetailsDBusStruct &icd2)
{
argument.beginStructure();
argument << icd2.serviceType;
argument << icd2.serviceAttributes;
argument << icd2.setviceId;
argument << icd2.networkType;
argument << icd2.networkAttributes;
argument << icd2.networkId;
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
ICd2DetailsDBusStruct &icd2)
{
argument.beginStructure();
argument >> icd2.serviceType;
argument >> icd2.serviceAttributes;
argument >> icd2.setviceId;
argument >> icd2.networkType;
argument >> icd2.networkAttributes;
argument >> icd2.networkId;
argument.endStructure();
return argument;
}
const QDBusArgument &operator>>(const QDBusArgument &argument,
ICd2DetailsList &detailsList)
{
argument.beginArray();
detailsList.clear();
while (!argument.atEnd()) {
ICd2DetailsDBusStruct element;
argument >> element;
detailsList.append(element);
}
argument.endArray();
return argument;
}
QDBusArgument &operator<<(QDBusArgument &argument,
const ICd2DetailsList &detailsList)
{
argument.beginArray(qMetaTypeId<ICd2DetailsDBusStruct>());
for (int i = 0; i < detailsList.count(); ++i)
argument << detailsList[i];
argument.endArray();
return argument;
}
static QHash<QString, QVariant> properties;
static QString get_network_interface();
void QNetworkSessionPrivateImpl::iapStateChanged(const QString& iapid, uint icd_connection_state)
{
if ((publicConfig.type() == QNetworkConfiguration::UserChoice) && opened) {
updateIdentifier(iapid);
}
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)
{
QObject::disconnect(q, SIGNAL(stateChanged(QNetworkSession::State)), this, SLOT(updateProxies(QNetworkSession::State)));
}
void QNetworkSessionPrivateImpl::updateState(QNetworkSession::State newState)
{
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));
icdConfig->mutex.lock();
icdConfig->state = QNetworkConfiguration::Active;
icdConfig->type = QNetworkConfiguration::InternetAccessPoint;
icdConfig->mutex.unlock();
}
IcdNetworkConfigurationPrivate *icdConfig =
toIcdConfig(privateConfiguration(publicConfig));
icdConfig->mutex.lock();
icdConfig->state = QNetworkConfiguration::Active;
icdConfig->mutex.unlock();
}
if (newState != state) {
state = newState;
emit stateChanged(newState);
}
}
}
void QNetworkSessionPrivateImpl::updateIdentifier(const QString &newId)
{
if (publicConfig.type() == QNetworkConfiguration::UserChoice) {
IcdNetworkConfigurationPrivate *icdConfig =
toIcdConfig(privateConfiguration(activeConfig));
icdConfig->mutex.lock();
icdConfig->network_attrs |= ICD_NW_ATTR_IAPNAME;
icdConfig->id = newId;
icdConfig->mutex.unlock();
} else {
IcdNetworkConfigurationPrivate *icdConfig =
toIcdConfig(privateConfiguration(publicConfig));
icdConfig->mutex.lock();
icdConfig->network_attrs |= ICD_NW_ATTR_IAPNAME;
if (icdConfig->id != newId)
icdConfig->id = newId;
icdConfig->mutex.unlock();
}
}
QNetworkSessionPrivateImpl::Statistics QNetworkSessionPrivateImpl::getStatistics() const
{
/* This could be also implemented by using the Maemo::Icd::statistics()
* that gets the statistics data for a specific IAP. Change if
* necessary.
*/
Maemo::Icd icd;
QList<Maemo::IcdStatisticsResult> stats_results;
Statistics stats = { 0, 0, 0};
if (!icd.statistics(stats_results))
return stats;
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()) {
stats.txData = res.bytes_sent;
stats.rxData = res.bytes_received;
stats.activeTime = res.time_active;
}
} else {
/* We probably will never get to this branch */
IcdNetworkConfigurationPrivate *icdConfig =
toIcdConfig(privateConfiguration(activeConfig));
icdConfig->mutex.lock();
if (res.params.network_id == icdConfig->network_id) {
stats.txData = res.bytes_sent;
stats.rxData = res.bytes_received;
stats.activeTime = res.time_active;
}
icdConfig->mutex.unlock();
}
}
return stats;
}
quint64 QNetworkSessionPrivateImpl::bytesWritten() const
{
return getStatistics().txData;
}
quint64 QNetworkSessionPrivateImpl::bytesReceived() const
{
return getStatistics().rxData;
}
quint64 QNetworkSessionPrivateImpl::activeTime() const
{
return getStatistics().activeTime;
}
QNetworkConfiguration& QNetworkSessionPrivateImpl::copyConfig(QNetworkConfiguration &fromConfig,
QNetworkConfiguration &toConfig,
bool deepCopy)
{
IcdNetworkConfigurationPrivate *cpPriv;
if (deepCopy) {
cpPriv = new IcdNetworkConfigurationPrivate;
setPrivateConfiguration(toConfig, QNetworkConfigurationPrivatePointer(cpPriv));
} else {
cpPriv = toIcdConfig(privateConfiguration(toConfig));
}
IcdNetworkConfigurationPrivate *fromPriv = toIcdConfig(privateConfiguration(fromConfig));
QMutexLocker toLocker(&cpPriv->mutex);
QMutexLocker fromLocker(&fromPriv->mutex);
cpPriv->name = fromPriv->name;
cpPriv->isValid = fromPriv->isValid;
// Note that we do not copy id field here as the publicConfig does
// not contain a valid IAP id.
cpPriv->state = fromPriv->state;
cpPriv->type = fromPriv->type;
cpPriv->roamingSupported = fromPriv->roamingSupported;
cpPriv->purpose = fromPriv->purpose;
cpPriv->network_id = fromPriv->network_id;
cpPriv->iap_type = fromPriv->iap_type;
cpPriv->bearerType = fromPriv->bearerType;
cpPriv->network_attrs = fromPriv->network_attrs;
cpPriv->service_type = fromPriv->service_type;
cpPriv->service_id = fromPriv->service_id;
cpPriv->service_attrs = fromPriv->service_attrs;
return toConfig;
}
/* This is called by QNetworkSession constructor and it updates the current
* state of the configuration.
*/
void QNetworkSessionPrivateImpl::syncStateWithInterface()
{
/* Initially we are not active although the configuration might be in
* connected state.
*/
isOpen = false;
opened = false;
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)));
state = QNetworkSession::Invalid;
lastError = QNetworkSession::UnknownSessionError;
switch (publicConfig.type()) {
case QNetworkConfiguration::InternetAccessPoint:
activeConfig = publicConfig;
break;
case QNetworkConfiguration::ServiceNetwork:
serviceConfig = publicConfig;
break;
case QNetworkConfiguration::UserChoice:
// active config will contain correct data after open() has succeeded
copyConfig(publicConfig, activeConfig);
/* We create new configuration that holds the actual configuration
* returned by icd. This way publicConfig still contains the
* original user specified configuration.
*
* Note that the new activeConfig configuration is not inserted
* to configurationManager as manager class will get the newly
* connected configuration from gconf when the IAP is saved.
* This configuration manager update is done by IapMonitor class.
* If the ANY connection fails in open(), then the configuration
* data is not saved to gconf and will not be added to
* configuration manager IAP list.
*/
#ifdef BEARER_MANAGEMENT_DEBUG
qDebug()<<"New configuration created for" << publicConfig.identifier();
#endif
break;
default:
/* Invalid configuration, no point continuing */
return;
}
if (!activeConfig.isValid())
return;
/* Get the initial state from icd */
Maemo::Icd icd;
QList<Maemo::IcdStateResult> state_results;
/* Update the active config from first connection, this is ok as icd
* 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.
*/
if (!(state_results.first().params.network_attrs == 0 &&
state_results.first().params.network_id.isEmpty())) {
/* If we try to connect to specific IAP and we get results back
* that tell the icd is actually connected to another IAP,
* then do not update current state etc.
*/
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;
if (QNetworkConfigurationPrivatePointer ptr = privateConfiguration(activeConfig)) {
ptr->mutex.lock();
ptr->isValid = true;
ptr->mutex.unlock();
}
break;
case ICD_STATE_CONNECTING:
state = QNetworkSession::Connecting;
if (QNetworkConfigurationPrivatePointer ptr = privateConfiguration(activeConfig)) {
ptr->mutex.lock();
ptr->isValid = true;
ptr->mutex.unlock();
}
break;
case ICD_STATE_CONNECTED:
{
if (!state_results.first().error.isEmpty())
break;
const QString id = state_results.first().params.network_id;
QNetworkConfiguration config = manager.configurationFromIdentifier(id);
if (config.isValid()) {
//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
setPrivateConfiguration(activeConfig, privateConfiguration(config));
}
QNetworkConfigurationPrivatePointer ptr = privateConfiguration(activeConfig);
QMutexLocker configLocker(&ptr->mutex);
state = QNetworkSession::Connected;
toIcdConfig(ptr)->network_id = state_results.first().params.network_id;
ptr->id = toIcdConfig(ptr)->network_id;
toIcdConfig(ptr)->network_attrs = state_results.first().params.network_attrs;
toIcdConfig(ptr)->iap_type = state_results.first().params.network_type;
ptr->bearerType = bearerTypeFromIapType(toIcdConfig(ptr)->iap_type);
toIcdConfig(ptr)->service_type = state_results.first().params.service_type;
toIcdConfig(ptr)->service_id = state_results.first().params.service_id;
toIcdConfig(ptr)->service_attrs = state_results.first().params.service_attrs;
ptr->type = QNetworkConfiguration::InternetAccessPoint;
ptr->state = QNetworkConfiguration::Active;
ptr->isValid = true;
currentNetworkInterface = get_network_interface();
Maemo::IAPConf iap_name(ptr->id);
QString name_value = iap_name.value("name").toString();
if (!name_value.isEmpty())
ptr->name = name_value;
else
ptr->name = ptr->id;
const QString identifier = ptr->id;
configLocker.unlock();
// Add the new active configuration to manager or update the old config
if (!engine->hasIdentifier(identifier))
engine->addSessionConfiguration(ptr);
else
engine->changedSessionConfiguration(ptr);
}
break;
case ICD_STATE_DISCONNECTING:
state = QNetworkSession::Closing;
if (QNetworkConfigurationPrivatePointer ptr = privateConfiguration(activeConfig)) {
ptr->mutex.lock();
ptr->isValid = true;
ptr->mutex.unlock();
}
break;
default:
break;
}
}
} else {
#ifdef BEARER_MANAGEMENT_DEBUG
qDebug() << "status_req tells icd is not connected";
#endif
}
} else {
#ifdef BEARER_MANAGEMENT_DEBUG
qDebug() << "status_req did not return any results from icd";
#endif
}
networkConfigurationsChanged();
}
void QNetworkSessionPrivateImpl::networkConfigurationsChanged()
{
if (serviceConfig.isValid())
updateStateFromServiceNetwork();
else
updateStateFromActiveConfig();
}
void QNetworkSessionPrivateImpl::updateStateFromServiceNetwork()
{
QNetworkSession::State oldState = state;
foreach (const QNetworkConfiguration &config, serviceConfig.children()) {
if ((config.state() & QNetworkConfiguration::Active) != QNetworkConfiguration::Active)
continue;
if (activeConfig != config) {
activeConfig = config;
emit newConfigurationActivated();
}
state = QNetworkSession::Connected;
if (state != oldState)
emit stateChanged(state);
return;
}
if (serviceConfig.children().isEmpty())
state = QNetworkSession::NotAvailable;
else
state = QNetworkSession::Disconnected;
if (state != oldState)
emit stateChanged(state);
}
void QNetworkSessionPrivateImpl::clearConfiguration(QNetworkConfiguration &config)
{
IcdNetworkConfigurationPrivate *icdConfig = toIcdConfig(privateConfiguration(config));
QMutexLocker locker(&icdConfig->mutex);
icdConfig->network_id.clear();
icdConfig->iap_type.clear();
icdConfig->network_attrs = 0;
icdConfig->service_type.clear();
icdConfig->service_id.clear();
icdConfig->service_attrs = 0;
}
void QNetworkSessionPrivateImpl::updateStateFromActiveConfig()
{
QNetworkSession::State oldState = state;
bool newActive = false;
if (!activeConfig.isValid())
return;
if (!activeConfig.isValid()) {
state = QNetworkSession::Invalid;
clearConfiguration(activeConfig);
} else if ((activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
state = QNetworkSession::Connected;
newActive = opened;
} else if ((activeConfig.state() & QNetworkConfiguration::Discovered) == QNetworkConfiguration::Discovered) {
state = QNetworkSession::Disconnected;
} else if ((activeConfig.state() & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined) {
state = QNetworkSession::NotAvailable;
} else if ((activeConfig.state() & QNetworkConfiguration::Undefined) == QNetworkConfiguration::Undefined) {
state = QNetworkSession::NotAvailable;
}
bool oldActive = isOpen;
isOpen = newActive;
if (!oldActive && isOpen)
emit quitPendingWaitsForOpened();
if (oldActive && !isOpen)
emit closed();
if (oldState != state) {
emit stateChanged(state);
if (state == QNetworkSession::Disconnected && oldActive) {
#ifdef BEARER_MANAGEMENT_DEBUG
//qDebug()<<"session aborted error emitted for"<<activeConfig.identifier();
#endif
lastError = QNetworkSession::SessionAbortedError;
emit QNetworkSessionPrivate::error(lastError);
}
}
#ifdef BEARER_MANAGEMENT_DEBUG
//qDebug()<<"oldState ="<<oldState<<" state ="<<state<<" oldActive ="<<oldActive<<" newActive ="<<newActive<<" opened ="<<opened;
#endif
}
static QString get_network_interface()
{
Maemo::Icd icd;
QList<Maemo::IcdAddressInfoResult> addr_results;
uint ret;
QString iface;
ret = icd.addrinfo(addr_results);
if (ret == 0) {
/* No results */
#ifdef BEARER_MANAGEMENT_DEBUG
qDebug() << "Cannot get addrinfo from icd, are you connected or is icd running?";
#endif
return iface;
}
if (addr_results.first().ip_info.isEmpty())
return QString();
const char *address = addr_results.first().ip_info.first().address.toAscii().constData();
struct in_addr addr;
if (inet_aton(address, &addr) == 0) {
#ifdef BEARER_MANAGEMENT_DEBUG
qDebug() << "address" << address << "invalid";
#endif
return iface;
}
struct ifaddrs *ifaddr, *ifa;
int family;
if (getifaddrs(&ifaddr) == -1) {
#ifdef BEARER_MANAGEMENT_DEBUG
qDebug() << "getifaddrs() failed";
#endif
return iface;
}
for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
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);
return iface;
}
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
* connect and update the active config when the IAP is
* connected.
*/
opened = true;
state = QNetworkSession::Connecting;
emit stateChanged(state);
QTimer::singleShot(0, this, SLOT(do_open()));
return;
}
/* User is connecting to one specific IAP. If that IAP is not
* in discovered state we cannot continue.
*/
if ((activeConfig.state() & QNetworkConfiguration::Discovered) !=
QNetworkConfiguration::Discovered) {
lastError =QNetworkSession::InvalidConfigurationError;
emit QNetworkSessionPrivate::error(lastError);
return;
}
opened = true;
if ((activeConfig.state() & QNetworkConfiguration::Active) != QNetworkConfiguration::Active) {
state = QNetworkSession::Connecting;
emit stateChanged(state);
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();
}
}
void QNetworkSessionPrivateImpl::do_open()
{
icd_connection_flags flags = connectFlags;
QString iap = publicConfig.identifier();
if (state == QNetworkSession::Connected) {
#ifdef BEARER_MANAGEMENT_DEBUG
qDebug() << "Already connected to" << activeConfig.identifier();
#endif
emit stateChanged(QNetworkSession::Connected);
emit quitPendingWaitsForOpened();
return;
}
if (publicConfig.type() == QNetworkConfiguration::UserChoice)
config = activeConfig;
else
config = publicConfig;
if (iap == OSSO_IAP_ANY) {
#ifdef BEARER_MANAGEMENT_DEBUG
qDebug() << "connecting to default IAP" << iap;
#endif
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));
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",
icd2.networkId.data(),
icd2.networkType.toAscii().constData(),
icd2.networkAttributes,
icd2.serviceType.toAscii().constData(),
icd2.serviceAttributes,
icd2.setviceId.toAscii().constData());
#endif
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;
}
}
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"<< publicConfig.identifier() << "failed, result is empty";
#endif
updateState(QNetworkSession::Disconnected);
emit QNetworkSessionPrivate::error(QNetworkSession::InvalidConfigurationError);
if (publicConfig.type() == QNetworkConfiguration::UserChoice)
copyConfig(publicConfig, activeConfig);
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;
}
/* 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;
icdConfig->iap_type = rep.arguments().at(3).toString(); // connect_result.connect.network_type;
icdConfig->bearerType = bearerTypeFromIapType(icdConfig->iap_type);
icdConfig->isValid = true;
icdConfig->state = QNetworkConfiguration::Active;
icdConfig->type = QNetworkConfiguration::InternetAccessPoint;
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;
#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);
privateConfiguration(reference)->id = result; // Note: Id was not copied in copyConfig() function
config = reference;
activeConfig = reference;
engine->changedSessionConfiguration(privateConfiguration(config));
#ifdef BEARER_MANAGEMENT_DEBUG
qDebug()<<"Existing configuration"<<result<<"updated in manager in open";
#endif
}
}
emit quitPendingWaitsForOpened();
}
}
void QNetworkSessionPrivateImpl::connectTimeout()
{
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);
} else if (isOpen) {
if ((activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
// We will not wait any disconnect from icd as it might never come
Maemo::Icd icd;
#ifdef BEARER_MANAGEMENT_DEBUG
qDebug() << "closing session" << publicConfig.identifier();
#endif
state = QNetworkSession::Closing;
emit stateChanged(state);
// we fake a disconnection, session error is sent
updateState(QNetworkSession::Disconnected);
opened = false;
isOpen = false;
icd.disconnect(ICD_CONNECTION_FLAG_APPLICATION_EVENT);
startTime = QDateTime();
} else {
opened = false;
isOpen = false;
emit closed();
}
}
}
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) {
Maemo::Icd icd;
#ifdef BEARER_MANAGEMENT_DEBUG
qDebug() << "stopping session" << publicConfig.identifier();
#endif
state = QNetworkSession::Closing;
emit stateChanged(state);
// we fake a disconnection, a session error is sent also
updateState(QNetworkSession::Disconnected);
opened = false;
isOpen = false;
icd.disconnect(ICD_CONNECTION_FLAG_APPLICATION_EVENT);
startTime = QDateTime();
} else {
opened = false;
isOpen = false;
emit closed();
}
}
}
void QNetworkSessionPrivateImpl::finishStopBySendingClosedSignal()
{
if ((activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
state = QNetworkSession::Connected;
emit stateChanged(state);
}
emit closed();
}
void QNetworkSessionPrivateImpl::migrate()
{
}
void QNetworkSessionPrivateImpl::accept()
{
}
void QNetworkSessionPrivateImpl::ignore()
{
}
void QNetworkSessionPrivateImpl::reject()
{
}
#ifndef QT_NO_NETWORKINTERFACE
QNetworkInterface QNetworkSessionPrivateImpl::currentInterface() const
{
if (!publicConfig.isValid() || state != QNetworkSession::Connected)
return QNetworkInterface();
if (currentNetworkInterface.isEmpty())
return QNetworkInterface();
return QNetworkInterface::interfaceFromName(currentNetworkInterface);
}
#endif
void QNetworkSessionPrivateImpl::setSessionProperty(const QString& key, const QVariant& value)
{
if (value.isValid()) {
properties.insert(key, value);
if (key == "ConnectInBackground") {
bool v = value.toBool();
if (v)
connectFlags = ICD_CONNECTION_FLAG_APPLICATION_EVENT;
else
connectFlags = ICD_CONNECTION_FLAG_USER_EVENT;
}
} else {
properties.remove(key);
/* Set default value when property is removed */
if (key == "ConnectInBackground")
connectFlags = ICD_CONNECTION_FLAG_USER_EVENT;
}
}
QVariant QNetworkSessionPrivateImpl::sessionProperty(const QString& key) const
{
return properties.value(key);
}
QString QNetworkSessionPrivateImpl::errorString() const
{
QString errorStr;
switch(q->error()) {
case QNetworkSession::RoamingError:
errorStr = QNetworkSessionPrivateImpl::tr("Roaming error");
break;
case QNetworkSession::SessionAbortedError:
errorStr = QNetworkSessionPrivateImpl::tr("Session aborted by user or system");
break;
default:
case QNetworkSession::UnknownSessionError:
errorStr = QNetworkSessionPrivateImpl::tr("Unidentified Error");
break;
}
return errorStr;
}
QNetworkSession::SessionError QNetworkSessionPrivateImpl::error() const
{
return QNetworkSession::UnknownSessionError;
}
void QNetworkSessionPrivateImpl::updateProxies(QNetworkSession::State newState)
{
if ((newState == QNetworkSession::Connected) &&
(newState != currentState))
updateProxyInformation();
else if ((newState == QNetworkSession::Disconnected) &&
(currentState == QNetworkSession::Closing))
clearProxyInformation();
currentState = newState;
}
void QNetworkSessionPrivateImpl::updateProxyInformation()
{
Maemo::ProxyConf::update();
}
void QNetworkSessionPrivateImpl::clearProxyInformation()
{
Maemo::ProxyConf::clear();
}
QT_END_NAMESPACE
#endif // QT_NO_BEARERMANAGEMENT