qtmobility/src/bearer/qnetworksession_maemo.cpp
branchRCL_3
changeset 9 5d007b20cfd0
parent 8 885c2596c964
child 10 cd2778e5acfe
equal deleted inserted replaced
8:885c2596c964 9:5d007b20cfd0
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the Qt Mobility Components.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 #include <QHash>
       
    43 
       
    44 #include "qnetworksession_maemo_p.h"
       
    45 
       
    46 #include <maemo_icd.h>
       
    47 #include <iapconf.h>
       
    48 #include <proxyconf.h>
       
    49 
       
    50 #include <ifaddrs.h>
       
    51 #include <netinet/in.h>
       
    52 #include <arpa/inet.h>
       
    53 
       
    54 
       
    55 QDBusArgument &operator<<(QDBusArgument &argument,
       
    56                           const QtMobility::ICd2DetailsDBusStruct &icd2)
       
    57 {
       
    58     argument.beginStructure();
       
    59     argument << icd2.serviceType;
       
    60     argument << icd2.serviceAttributes;
       
    61     argument << icd2.setviceId;
       
    62     argument << icd2.networkType;
       
    63     argument << icd2.networkAttributes;
       
    64     argument << icd2.networkId;
       
    65     argument.endStructure();
       
    66     return argument;
       
    67 }
       
    68 
       
    69 const QDBusArgument &operator>>(const QDBusArgument &argument,
       
    70                                 QtMobility::ICd2DetailsDBusStruct &icd2)
       
    71 {
       
    72     argument.beginStructure();
       
    73     argument >> icd2.serviceType;
       
    74     argument >> icd2.serviceAttributes;
       
    75     argument >> icd2.setviceId;
       
    76     argument >> icd2.networkType;
       
    77     argument >> icd2.networkAttributes;
       
    78     argument >> icd2.networkId;
       
    79     argument.endStructure();
       
    80     return argument;
       
    81 }
       
    82 
       
    83 const QDBusArgument &operator>>(const QDBusArgument &argument,
       
    84                                 QtMobility::ICd2DetailsList &detailsList)
       
    85 {
       
    86      argument.beginArray();
       
    87      detailsList.clear();
       
    88 
       
    89      while (!argument.atEnd()) {
       
    90          QtMobility::ICd2DetailsDBusStruct element;
       
    91          argument >> element;
       
    92          detailsList.append(element);
       
    93      }
       
    94 
       
    95      argument.endArray();
       
    96      return argument;
       
    97 }
       
    98 
       
    99 QDBusArgument &operator<<(QDBusArgument &argument,
       
   100                           const QtMobility::ICd2DetailsList &detailsList)
       
   101 {
       
   102      argument.beginArray(qMetaTypeId<QtMobility::ICd2DetailsDBusStruct>());
       
   103      for (int i = 0; i < detailsList.count(); ++i)
       
   104          argument << detailsList[i];
       
   105      argument.endArray();
       
   106      return argument;
       
   107 }
       
   108 
       
   109 QTM_BEGIN_NAMESPACE
       
   110 
       
   111 static QHash<QString, QVariant> properties;
       
   112 
       
   113 static QString get_network_interface();
       
   114 
       
   115 void QNetworkSessionPrivate::iapStateChanged(const QString& iapid, uint icd_connection_state)
       
   116 {
       
   117     if ((publicConfig.type() == QNetworkConfiguration::UserChoice) && opened) {
       
   118         updateIdentifier(iapid);
       
   119     }
       
   120 
       
   121     if (((publicConfig.type() == QNetworkConfiguration::UserChoice) && (activeConfig.d->id == iapid)) ||
       
   122         (publicConfig.d->id == iapid)) {
       
   123         switch (icd_connection_state) {
       
   124         case ICD_STATE_CONNECTING:
       
   125             updateState(QNetworkSession::Connecting);
       
   126             break;
       
   127         case ICD_STATE_CONNECTED:
       
   128             updateState(QNetworkSession::Connected);
       
   129             break;
       
   130         case ICD_STATE_DISCONNECTING:
       
   131             updateState(QNetworkSession::Closing);
       
   132             break;
       
   133         case ICD_STATE_DISCONNECTED:
       
   134             updateState(QNetworkSession::Disconnected);
       
   135             break;
       
   136         default:
       
   137             break;
       
   138         }
       
   139     }
       
   140 }
       
   141 
       
   142 void QNetworkSessionPrivate::cleanupSession(void)
       
   143 {
       
   144     QObject::disconnect(q, SIGNAL(stateChanged(QNetworkSession::State)), this, SLOT(updateProxies(QNetworkSession::State)));
       
   145 }
       
   146 
       
   147 
       
   148 void QNetworkSessionPrivate::updateState(QNetworkSession::State newState)
       
   149 {
       
   150     if (newState != state) {
       
   151         if (newState == QNetworkSession::Disconnected) {
       
   152             if (isOpen) {
       
   153                 // The Session was aborted by the user or system
       
   154                 lastError = QNetworkSession::SessionAbortedError;
       
   155                 emit q->error(lastError);
       
   156                 emit q->closed();
       
   157             }
       
   158             if (m_stopTimer.isActive()) {
       
   159                 // Session was closed by calling stop()
       
   160                 m_stopTimer.stop();
       
   161             }
       
   162             isOpen = false;
       
   163             opened = false;
       
   164 	    currentNetworkInterface.clear();
       
   165             if (publicConfig.type() == QNetworkConfiguration::UserChoice) {
       
   166                 copyConfig(publicConfig, activeConfig);
       
   167                 activeConfig.d->state = QNetworkConfiguration::Defined;
       
   168             } else {
       
   169                 if (!activeConfig.isValid()) {
       
   170                     // Active configuration (IAP) was removed from system
       
   171                     // => Connection was disconnected and configuration became
       
   172                     //    invalid
       
   173                     // => Also Session state must be changed to invalid
       
   174                     newState = QNetworkSession::Invalid;
       
   175                 }
       
   176             }
       
   177         } else if (newState == QNetworkSession::Connected) {
       
   178             if (opened) {
       
   179                 isOpen = true;
       
   180             }
       
   181 	    if (publicConfig.type() == QNetworkConfiguration::UserChoice) {
       
   182 		activeConfig.d->state = QNetworkConfiguration::Active;
       
   183 		activeConfig.d->type = QNetworkConfiguration::InternetAccessPoint;
       
   184 	    }
       
   185 	    publicConfig.d->state = QNetworkConfiguration::Active;
       
   186 	}
       
   187 
       
   188         if (newState != state) {
       
   189             state = newState;
       
   190             emit q->stateChanged(newState);
       
   191         }
       
   192     }
       
   193 }
       
   194 
       
   195 
       
   196 void QNetworkSessionPrivate::updateIdentifier(const QString &newId)
       
   197 {
       
   198     if (publicConfig.type() == QNetworkConfiguration::UserChoice) {
       
   199 	activeConfig.d->network_attrs |= ICD_NW_ATTR_IAPNAME;
       
   200 	activeConfig.d->id = newId;
       
   201     } else {
       
   202 	publicConfig.d->network_attrs |= ICD_NW_ATTR_IAPNAME;
       
   203 	if (publicConfig.d->id != newId) {
       
   204 	    qWarning() << "Your config id changed from" << publicConfig.d->id << "to" << newId;
       
   205 	    publicConfig.d->id = newId;
       
   206 	}
       
   207     }
       
   208 }
       
   209 
       
   210 
       
   211 QNetworkSessionPrivate::Statistics QNetworkSessionPrivate::getStatistics() const
       
   212 {
       
   213     /* This could be also implemented by using the Maemo::Icd::statistics()
       
   214      * that gets the statistics data for a specific IAP. Change if
       
   215      * necessary.
       
   216      */
       
   217     Maemo::Icd icd;
       
   218     QList<Maemo::IcdStatisticsResult> stats_results;
       
   219     Statistics stats = { 0, 0, 0};
       
   220 
       
   221     if (!icd.statistics(stats_results))
       
   222         return stats;
       
   223 
       
   224     foreach (const Maemo::IcdStatisticsResult &res, stats_results) {
       
   225         if (res.params.network_attrs & ICD_NW_ATTR_IAPNAME) {
       
   226             /* network_id is the IAP UUID */
       
   227             if (QString(res.params.network_id.data()) == activeConfig.identifier()) {
       
   228                 stats.txData = res.bytes_sent;
       
   229                 stats.rxData = res.bytes_received;
       
   230                 stats.activeTime = res.time_active;
       
   231             }
       
   232         } else {
       
   233             /* We probably will never get to this branch */
       
   234             QNetworkConfigurationPrivate *d = activeConfig.d.data();
       
   235             if (res.params.network_id == d->network_id) {
       
   236                 stats.txData = res.bytes_sent;
       
   237                 stats.rxData = res.bytes_received;
       
   238                 stats.activeTime = res.time_active;
       
   239             }
       
   240         }
       
   241     }
       
   242 
       
   243     return stats;
       
   244 }
       
   245 
       
   246 
       
   247 quint64 QNetworkSessionPrivate::bytesWritten() const
       
   248 {
       
   249     return getStatistics().txData;
       
   250 }
       
   251 
       
   252 quint64 QNetworkSessionPrivate::bytesReceived() const
       
   253 {
       
   254     return getStatistics().rxData;
       
   255 }
       
   256 
       
   257 quint64 QNetworkSessionPrivate::activeTime() const
       
   258 {
       
   259     return getStatistics().activeTime;
       
   260 }
       
   261 
       
   262 
       
   263 QNetworkConfiguration& QNetworkSessionPrivate::copyConfig(QNetworkConfiguration &fromConfig, QNetworkConfiguration &toConfig, bool deepCopy)
       
   264 {
       
   265     if (deepCopy) {
       
   266         QNetworkConfigurationPrivate* cpPriv = new QNetworkConfigurationPrivate();
       
   267         QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> ptr(cpPriv);
       
   268         toConfig.d = ptr;
       
   269     }
       
   270 
       
   271     toConfig.d->name = fromConfig.d->name;
       
   272     toConfig.d->isValid = fromConfig.d->isValid;
       
   273     // Note that we do not copy id field here as the publicConfig does
       
   274     // not contain a valid IAP id.
       
   275     toConfig.d->state = fromConfig.d->state;
       
   276     toConfig.d->type = fromConfig.d->type;
       
   277     toConfig.d->roamingSupported = fromConfig.d->roamingSupported;
       
   278     toConfig.d->purpose = fromConfig.d->purpose;
       
   279     toConfig.d->network_id = fromConfig.d->network_id;
       
   280     toConfig.d->iap_type = fromConfig.d->iap_type;
       
   281     toConfig.d->network_attrs = fromConfig.d->network_attrs;
       
   282     toConfig.d->service_type = fromConfig.d->service_type;
       
   283     toConfig.d->service_id = fromConfig.d->service_id;
       
   284     toConfig.d->service_attrs = fromConfig.d->service_attrs;
       
   285     toConfig.d->manager = fromConfig.d->manager;
       
   286 
       
   287     return toConfig;
       
   288 }
       
   289 
       
   290 
       
   291 /* This is called by QNetworkSession constructor and it updates the current
       
   292  * state of the configuration.
       
   293  */
       
   294 void QNetworkSessionPrivate::syncStateWithInterface()
       
   295 {
       
   296     /* Initially we are not active although the configuration might be in
       
   297      * connected state.
       
   298      */
       
   299     isOpen = false;
       
   300     opened = false;
       
   301 
       
   302     QObject::connect(&manager, SIGNAL(updateCompleted()), this, SLOT(networkConfigurationsChanged()));
       
   303 
       
   304     if (publicConfig.d.data()) {
       
   305 	QNetworkConfigurationManagerPrivate* mgr = (QNetworkConfigurationManagerPrivate*)publicConfig.d.data()->manager;
       
   306 	if (mgr) {
       
   307             connect(mgr, SIGNAL(iapStateChanged(const QString&, uint)),
       
   308                     this, SLOT(iapStateChanged(const QString&, uint)));
       
   309 	} else {
       
   310             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?";
       
   311 	    state = QNetworkSession::Invalid;
       
   312 	    lastError = QNetworkSession::UnknownSessionError;
       
   313 	    return;
       
   314 	}
       
   315     }
       
   316 
       
   317     QObject::connect(q, SIGNAL(stateChanged(QNetworkSession::State)), this, SLOT(updateProxies(QNetworkSession::State)));
       
   318 
       
   319     state = QNetworkSession::Invalid;
       
   320     lastError = QNetworkSession::UnknownSessionError;
       
   321 
       
   322     switch (publicConfig.type()) {
       
   323     case QNetworkConfiguration::InternetAccessPoint:
       
   324         activeConfig = publicConfig;
       
   325         break;
       
   326     case QNetworkConfiguration::ServiceNetwork:
       
   327         serviceConfig = publicConfig;
       
   328 	break;
       
   329     case QNetworkConfiguration::UserChoice:
       
   330 	// active config will contain correct data after open() has succeeded
       
   331         copyConfig(publicConfig, activeConfig);
       
   332 
       
   333 	/* We create new configuration that holds the actual configuration
       
   334 	 * returned by icd. This way publicConfig still contains the
       
   335 	 * original user specified configuration.
       
   336 	 *
       
   337 	 * Note that the new activeConfig configuration is not inserted
       
   338 	 * to configurationManager as manager class will get the newly
       
   339 	 * connected configuration from gconf when the IAP is saved.
       
   340 	 * This configuration manager update is done by IapMonitor class.
       
   341 	 * If the ANY connection fails in open(), then the configuration
       
   342 	 * data is not saved to gconf and will not be added to
       
   343 	 * configuration manager IAP list.
       
   344 	 */
       
   345 #ifdef BEARER_MANAGEMENT_DEBUG
       
   346 	qDebug()<<"New configuration created for" << publicConfig.identifier();
       
   347 #endif
       
   348 	break;
       
   349     default:
       
   350 	/* Invalid configuration, no point continuing */
       
   351 	return;
       
   352     }
       
   353 
       
   354     if (!activeConfig.isValid())
       
   355 	return;
       
   356 
       
   357     /* Get the initial state from icd */
       
   358     Maemo::Icd icd;
       
   359     QList<Maemo::IcdStateResult> state_results;
       
   360 
       
   361     /* Update the active config from first connection, this is ok as icd
       
   362      * supports only one connection anyway.
       
   363      */
       
   364     if (icd.state(state_results) && !state_results.isEmpty()) {
       
   365 	/* If we did not get full state back, then we are not
       
   366 	 * connected and can skip the next part.
       
   367 	 */
       
   368 	if (!(state_results.first().params.network_attrs == 0 &&
       
   369 		state_results.first().params.network_id.isEmpty())) {
       
   370 
       
   371 	    /* If we try to connect to specific IAP and we get results back
       
   372 	     * that tell the icd is actually connected to another IAP,
       
   373 	     * then do not update current state etc.
       
   374 	     */
       
   375 	    if (publicConfig.type() == QNetworkConfiguration::UserChoice ||
       
   376 		    publicConfig.d->id == state_results.first().params.network_id) {
       
   377 		switch (state_results.first().state) {
       
   378 		case ICD_STATE_DISCONNECTED:
       
   379                     state = QNetworkSession::Disconnected;
       
   380 		    if (activeConfig.d.data())
       
   381 			activeConfig.d->isValid = true;
       
   382 		    break;
       
   383 		case ICD_STATE_CONNECTING:
       
   384                     state = QNetworkSession::Connecting;
       
   385 		    if (activeConfig.d.data())
       
   386 			activeConfig.d->isValid = true;
       
   387 		    break;
       
   388 		case ICD_STATE_CONNECTED:
       
   389 		    {
       
   390                         if (!state_results.first().error.isEmpty())
       
   391 			    break;
       
   392 
       
   393                         const QString id = state_results.first().params.network_id;
       
   394 
       
   395                         QNetworkConfigurationManagerPrivate *mgr = (QNetworkConfigurationManagerPrivate*)publicConfig.d.data()->manager;
       
   396 			if (mgr->accessPointConfigurations.contains(id)) {
       
   397                             //we don't want the copied data if the config is already known by the manager
       
   398                             //just reuse it so that existing references to the old data get the same update
       
   399                             QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = mgr->accessPointConfigurations.value(id);
       
   400                             activeConfig.d = priv;
       
   401                         }
       
   402 
       
   403 			state = QNetworkSession::Connected;
       
   404                         activeConfig.d->network_id = state_results.first().params.network_id;
       
   405                         activeConfig.d->id = activeConfig.d->network_id;
       
   406                         activeConfig.d->network_attrs = state_results.first().params.network_attrs;
       
   407                         activeConfig.d->iap_type = state_results.first().params.network_type;
       
   408                         activeConfig.d->service_type = state_results.first().params.service_type;
       
   409                         activeConfig.d->service_id = state_results.first().params.service_id;
       
   410                         activeConfig.d->service_attrs = state_results.first().params.service_attrs;
       
   411                         activeConfig.d->type = QNetworkConfiguration::InternetAccessPoint;
       
   412                         activeConfig.d->state = QNetworkConfiguration::Active;
       
   413                         activeConfig.d->isValid = true;
       
   414                         currentNetworkInterface = get_network_interface();
       
   415 
       
   416 			Maemo::IAPConf iap_name(activeConfig.d->id);
       
   417 			QString name_value = iap_name.value("name").toString();
       
   418 			if (!name_value.isEmpty())
       
   419 			    activeConfig.d->name = name_value;
       
   420 			else
       
   421 			    activeConfig.d->name = activeConfig.d->id;
       
   422 
       
   423 			// Add the new active configuration to manager or update the old config
       
   424 			mgr = (QNetworkConfigurationManagerPrivate*)activeConfig.d.data()->manager;
       
   425 			if (!(mgr->accessPointConfigurations.contains(activeConfig.d->id))) {
       
   426 			    QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> ptr = activeConfig.d;
       
   427 			    mgr->accessPointConfigurations.insert(activeConfig.d->id, ptr);
       
   428 
       
   429 			    QNetworkConfiguration item;
       
   430 			    item.d = ptr;
       
   431 			    emit mgr->configurationAdded(item);
       
   432 
       
   433 #ifdef BEARER_MANAGEMENT_DEBUG
       
   434 			    //qDebug()<<"New configuration"<<activeConfig.d->id<<"added to manager in sync";
       
   435 #endif
       
   436 
       
   437                         }
       
   438 		    }
       
   439 		    break;
       
   440 
       
   441 		case ICD_STATE_DISCONNECTING:
       
   442                     state = QNetworkSession::Closing;
       
   443 		    if (activeConfig.d.data())
       
   444 			activeConfig.d->isValid = true;
       
   445 		    break;
       
   446 		default:
       
   447                     break;
       
   448 		}
       
   449 	    }
       
   450 	} else {
       
   451 #ifdef BEARER_MANAGEMENT_DEBUG
       
   452 	    qDebug() << "status_req tells icd is not connected";
       
   453 #endif
       
   454 	}
       
   455     } else {
       
   456 #ifdef BEARER_MANAGEMENT_DEBUG
       
   457 	qDebug() << "status_req did not return any results from icd";
       
   458 #endif
       
   459     }
       
   460 
       
   461     networkConfigurationsChanged();
       
   462 }
       
   463 
       
   464 
       
   465 void QNetworkSessionPrivate::networkConfigurationsChanged()
       
   466 {
       
   467     if (serviceConfig.isValid())
       
   468         updateStateFromServiceNetwork();
       
   469     else
       
   470         updateStateFromActiveConfig();
       
   471 }
       
   472 
       
   473 
       
   474 void QNetworkSessionPrivate::updateStateFromServiceNetwork()
       
   475 {
       
   476     QNetworkSession::State oldState = state;
       
   477 
       
   478     foreach (const QNetworkConfiguration &config, serviceConfig.children()) {
       
   479         if ((config.state() & QNetworkConfiguration::Active) != QNetworkConfiguration::Active)
       
   480             continue;
       
   481 
       
   482         if (activeConfig != config) {
       
   483             activeConfig = config;
       
   484             emit q->newConfigurationActivated();
       
   485         }
       
   486 
       
   487         state = QNetworkSession::Connected;
       
   488         if (state != oldState)
       
   489             emit q->stateChanged(state);
       
   490 
       
   491         return;
       
   492     }
       
   493 
       
   494     if (serviceConfig.children().isEmpty())
       
   495         state = QNetworkSession::NotAvailable;
       
   496     else
       
   497         state = QNetworkSession::Disconnected;
       
   498 
       
   499     if (state != oldState)
       
   500         emit q->stateChanged(state);
       
   501 }
       
   502 
       
   503 
       
   504 void QNetworkSessionPrivate::clearConfiguration(QNetworkConfiguration &config)
       
   505 {
       
   506     config.d->network_id.clear();
       
   507     config.d->iap_type.clear();
       
   508     config.d->network_attrs = 0;
       
   509     config.d->service_type.clear();
       
   510     config.d->service_id.clear();
       
   511     config.d->service_attrs = 0;
       
   512 }
       
   513 
       
   514 
       
   515 void QNetworkSessionPrivate::updateStateFromActiveConfig()
       
   516 {
       
   517     QNetworkSession::State oldState = state;
       
   518 
       
   519     bool newActive = false;
       
   520 
       
   521     if (!activeConfig.d.data())
       
   522 	return;
       
   523 
       
   524     if (!activeConfig.isValid()) {
       
   525         state = QNetworkSession::Invalid;
       
   526 	clearConfiguration(activeConfig);
       
   527     } else if ((activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
       
   528         state = QNetworkSession::Connected;
       
   529         newActive = opened;
       
   530     } else if ((activeConfig.state() & QNetworkConfiguration::Discovered) == QNetworkConfiguration::Discovered) {
       
   531         state = QNetworkSession::Disconnected;
       
   532     } else if ((activeConfig.state() & QNetworkConfiguration::Defined) == QNetworkConfiguration::Defined) {
       
   533         state = QNetworkSession::NotAvailable;
       
   534     } else if ((activeConfig.state() & QNetworkConfiguration::Undefined) == QNetworkConfiguration::Undefined) {
       
   535         state = QNetworkSession::NotAvailable;
       
   536     }
       
   537 
       
   538     bool oldActive = isOpen;
       
   539     isOpen = newActive;
       
   540 
       
   541     if (!oldActive && isOpen)
       
   542         emit quitPendingWaitsForOpened();
       
   543 
       
   544     if (oldActive && !isOpen)
       
   545         emit q->closed();
       
   546 
       
   547     if (oldState != state) {
       
   548         emit q->stateChanged(state);
       
   549 
       
   550         if (state == QNetworkSession::Disconnected && oldActive) {
       
   551 #ifdef BEARER_MANAGEMENT_DEBUG
       
   552 	    //qDebug()<<"session aborted error emitted for"<<activeConfig.identifier();
       
   553 #endif
       
   554 	    lastError = QNetworkSession::SessionAbortedError;
       
   555 	    emit q->error(lastError);
       
   556 	}
       
   557     }
       
   558 
       
   559 #ifdef BEARER_MANAGEMENT_DEBUG
       
   560     //qDebug()<<"oldState ="<<oldState<<" state ="<<state<<" oldActive ="<<oldActive<<" newActive ="<<newActive<<" opened ="<<opened;
       
   561 #endif
       
   562 }
       
   563 
       
   564 static QString get_network_interface()
       
   565 {
       
   566     Maemo::Icd icd;
       
   567     QList<Maemo::IcdAddressInfoResult> addr_results;
       
   568     uint ret;
       
   569     QString iface;
       
   570 
       
   571     ret = icd.addrinfo(addr_results);
       
   572     if (ret == 0) {
       
   573 	/* No results */
       
   574 #ifdef BEARER_MANAGEMENT_DEBUG
       
   575 	qDebug() << "Cannot get addrinfo from icd, are you connected or is icd running?";
       
   576 #endif
       
   577 	return iface;
       
   578     }
       
   579 
       
   580     const char *address = addr_results.first().ip_info.first().address.toAscii().constData();
       
   581     struct in_addr addr;
       
   582     if (inet_aton(address, &addr) == 0) {
       
   583 #ifdef BEARER_MANAGEMENT_DEBUG
       
   584 	qDebug() << "address" << address << "invalid";
       
   585 #endif
       
   586 	return iface;
       
   587     }
       
   588 
       
   589     struct ifaddrs *ifaddr, *ifa;
       
   590     int family;
       
   591 
       
   592     if (getifaddrs(&ifaddr) == -1) {
       
   593 #ifdef BEARER_MANAGEMENT_DEBUG
       
   594 	qDebug() << "getifaddrs() failed";
       
   595 #endif
       
   596 	return iface;
       
   597     }
       
   598 
       
   599     for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) {
       
   600         if (ifa->ifa_addr) {
       
   601             family = ifa->ifa_addr->sa_family;
       
   602             if (family != AF_INET) {
       
   603                 continue; /* Currently only IPv4 is supported by icd dbus interface */
       
   604             }
       
   605             if (((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr == addr.s_addr) {
       
   606                 iface = QString(ifa->ifa_name);
       
   607                 break;
       
   608             }
       
   609         }
       
   610     }
       
   611 
       
   612     freeifaddrs(ifaddr);
       
   613     return iface;
       
   614 }
       
   615 
       
   616 
       
   617 void QNetworkSessionPrivate::open()
       
   618 {
       
   619     if (m_stopTimer.isActive()) {
       
   620         m_stopTimer.stop();
       
   621     }
       
   622     if (!publicConfig.isValid()) {
       
   623         lastError = QNetworkSession::InvalidConfigurationError;
       
   624         emit q->error(lastError);
       
   625         return;
       
   626     }
       
   627     if (serviceConfig.isValid()) {
       
   628         lastError = QNetworkSession::OperationNotSupportedError;
       
   629         emit q->error(lastError);
       
   630     } else if (!isOpen) {
       
   631 	if (publicConfig.type() == QNetworkConfiguration::UserChoice) {
       
   632 	    /* Caller is trying to connect to default IAP.
       
   633 	     * At this time we will not know the IAP details so we just
       
   634 	     * connect and update the active config when the IAP is
       
   635 	     * connected.
       
   636 	     */
       
   637 	    opened = true;
       
   638             state = QNetworkSession::Connecting;
       
   639             emit q->stateChanged(state);
       
   640 	    QTimer::singleShot(0, this, SLOT(do_open()));
       
   641 	    return;
       
   642 	}
       
   643 
       
   644 	/* User is connecting to one specific IAP. If that IAP is not
       
   645 	 * in discovered state we cannot continue.
       
   646 	 */
       
   647         if ((activeConfig.state() & QNetworkConfiguration::Discovered) !=
       
   648             QNetworkConfiguration::Discovered) {
       
   649             lastError =QNetworkSession::InvalidConfigurationError;
       
   650             emit q->error(lastError);
       
   651             return;
       
   652         }
       
   653         opened = true;
       
   654 
       
   655         if ((activeConfig.state() & QNetworkConfiguration::Active) != QNetworkConfiguration::Active) {
       
   656             state = QNetworkSession::Connecting;
       
   657             emit q->stateChanged(state);
       
   658             QTimer::singleShot(0, this, SLOT(do_open()));
       
   659             return;
       
   660         }
       
   661         isOpen = (activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active;
       
   662         if (isOpen)
       
   663             emit quitPendingWaitsForOpened();
       
   664     } else {
       
   665         /* We seem to be active so inform caller */
       
   666         emit quitPendingWaitsForOpened();
       
   667     }
       
   668 }
       
   669 
       
   670 void QNetworkSessionPrivate::do_open()
       
   671 {
       
   672     icd_connection_flags flags = connectFlags;
       
   673     QString iap = publicConfig.identifier();
       
   674 
       
   675     if (state == QNetworkSession::Connected) {
       
   676 #ifdef BEARER_MANAGEMENT_DEBUG
       
   677         qDebug() << "Already connected to" << activeConfig.identifier();
       
   678 #endif
       
   679         emit q->stateChanged(QNetworkSession::Connected);
       
   680         emit quitPendingWaitsForOpened();
       
   681 	return;
       
   682     }
       
   683 
       
   684     if (publicConfig.type() == QNetworkConfiguration::UserChoice)
       
   685         config = activeConfig;
       
   686     else
       
   687         config = publicConfig;
       
   688 
       
   689     if (iap == OSSO_IAP_ANY) {
       
   690 #ifdef BEARER_MANAGEMENT_DEBUG
       
   691         qDebug() << "connecting to default IAP" << iap;
       
   692 #endif
       
   693         m_connectRequestTimer.start(ICD_LONG_CONNECT_TIMEOUT);
       
   694         m_dbusInterface->asyncCall(ICD_DBUS_API_CONNECT_REQ, (uint)flags); // Return value ignored
       
   695         m_asynchCallActive = true;
       
   696     } else {
       
   697         ICd2DetailsDBusStruct icd2;
       
   698         icd2.serviceType = config.d->service_type;
       
   699         icd2.serviceAttributes = config.d->service_attrs;
       
   700         icd2.setviceId = config.d->service_id;
       
   701         icd2.networkType = config.d->iap_type;
       
   702         icd2.networkAttributes = config.d->network_attrs;
       
   703         if (config.d->network_attrs & ICD_NW_ATTR_IAPNAME) {
       
   704             icd2.networkId  = QByteArray(iap.toLatin1());
       
   705         } else {
       
   706             icd2.networkId  = config.d->network_id;
       
   707         }
       
   708 
       
   709 #ifdef BEARER_MANAGEMENT_DEBUG
       
   710     qDebug("connecting to %s/%s/0x%x/%s/0x%x/%s",
       
   711         icd2.networkId.data(),
       
   712         icd2.networkType.toAscii().constData(),
       
   713         icd2.networkAttributes,
       
   714         icd2.serviceType.toAscii().constData(),
       
   715         icd2.serviceAttributes,
       
   716         icd2.setviceId.toAscii().constData());
       
   717 #endif
       
   718 
       
   719         ICd2DetailsList paramArray;
       
   720         paramArray.append(icd2);
       
   721         m_connectRequestTimer.start(ICD_LONG_CONNECT_TIMEOUT);
       
   722         m_dbusInterface->asyncCall(ICD_DBUS_API_CONNECT_REQ, (uint)flags, QVariant::fromValue(paramArray)); // Return value ignored
       
   723         m_asynchCallActive = true;
       
   724     }
       
   725 }
       
   726 
       
   727  void QNetworkSessionPrivate::stateChange(const QDBusMessage& rep)
       
   728 {
       
   729      if (m_asynchCallActive == true) {
       
   730         if (m_connectRequestTimer.isActive())
       
   731             m_connectRequestTimer.stop();
       
   732         m_asynchCallActive = false;
       
   733 
       
   734         QString result = rep.arguments().at(5).toString(); // network id or empty string
       
   735         QString connected_iap = result;
       
   736         if (connected_iap.isEmpty()) {
       
   737 #ifdef BEARER_MANAGEMENT_DEBUG
       
   738             qDebug() << "connect to"<< publicConfig.identifier() << "failed, result is empty";
       
   739 #endif
       
   740             updateState(QNetworkSession::Disconnected);
       
   741             emit q->error(QNetworkSession::InvalidConfigurationError);
       
   742             if (publicConfig.type() == QNetworkConfiguration::UserChoice)
       
   743                     copyConfig(publicConfig, activeConfig);
       
   744             return;
       
   745         }
       
   746 
       
   747          /* If the user tried to connect to some specific connection (foo)
       
   748          * and we were already connected to some other connection (bar),
       
   749          * then we cannot activate this session although icd has a valid
       
   750          * connection to somewhere.
       
   751          */
       
   752         if ((publicConfig.type() != QNetworkConfiguration::UserChoice) &&
       
   753             (connected_iap != config.identifier())) {
       
   754             updateState(QNetworkSession::Disconnected);
       
   755             emit q->error(QNetworkSession::InvalidConfigurationError);
       
   756             return;
       
   757         }
       
   758 
       
   759         /* Did we connect to non saved IAP? */
       
   760         if (!(config.d->network_attrs & ICD_NW_ATTR_IAPNAME)) {
       
   761             /* Because the connection succeeded, the IAP is now known.
       
   762              */
       
   763             config.d->network_attrs |= ICD_NW_ATTR_IAPNAME;
       
   764             config.d->id = connected_iap;
       
   765         }
       
   766 
       
   767         /* User might have changed the IAP name when a new IAP was saved */
       
   768         Maemo::IAPConf iap_name(config.d->id);
       
   769         QString name = iap_name.value("name").toString();
       
   770         if (!name.isEmpty())
       
   771             config.d->name = name;
       
   772 
       
   773         config.d->iap_type = rep.arguments().at(3).toString(); // connect_result.connect.network_type;
       
   774         config.d->isValid = true;
       
   775         config.d->state = QNetworkConfiguration::Active;
       
   776         config.d->type = QNetworkConfiguration::InternetAccessPoint;
       
   777 
       
   778         startTime = QDateTime::currentDateTime();
       
   779         updateState(QNetworkSession::Connected);
       
   780         //currentNetworkInterface = get_network_interface();
       
   781 #ifdef BEARER_MANAGEMENT_DEBUG
       
   782         //qDebug() << "connected to" << result << config.d->name << "at" << currentNetworkInterface;
       
   783 #endif
       
   784 
       
   785         /* We first check if the configuration already exists in the manager
       
   786          * and if it is not found there, we then insert it. Note that this
       
   787          * is only done for user choice config only because it can be missing
       
   788          * from config manager list.
       
   789          */
       
   790         if (publicConfig.d->type == QNetworkConfiguration::UserChoice) {
       
   791 #ifdef BEARER_MANAGEMENT_DEBUG
       
   792 #if 0
       
   793             QList<QNetworkConfiguration> configs;
       
   794             QNetworkConfigurationManagerPrivate *conPriv = (QNetworkConfigurationManagerPrivate*)config.d.data()->manager;
       
   795             QList<QString> cpsIdents = conPriv->accessPointConfigurations.keys();
       
   796             foreach( QString ii, cpsIdents) {
       
   797                 QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> p =
       
   798                         conPriv->accessPointConfigurations.value(ii);
       
   799                 QNetworkConfiguration pt;
       
   800                 pt.d = conPriv->accessPointConfigurations.value(ii);
       
   801                 configs << pt;
       
   802             }
       
   803 
       
   804             int all = configs.count();
       
   805             qDebug() << "All configurations:" << all;
       
   806             foreach(QNetworkConfiguration p, configs) {
       
   807                 qDebug() << p.name() <<":  isvalid->" <<p.isValid() << " type->"<< p.type() <<
       
   808                         " roaming->" << p.isRoamingAvailable() << "identifier->" << p.identifier() <<
       
   809                         " purpose->" << p.purpose() << " state->" << p.state();
       
   810             }
       
   811 #endif
       
   812 #endif
       
   813             QNetworkConfigurationManagerPrivate *mgr = (QNetworkConfigurationManagerPrivate*)publicConfig.d.data()->manager;
       
   814             if (!mgr->accessPointConfigurations.contains(result)) {
       
   815                 QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> ptr = config.d;
       
   816                 mgr->accessPointConfigurations.insert(result, ptr);
       
   817 
       
   818                 QNetworkConfiguration item;
       
   819                 item.d = ptr;
       
   820                 emit mgr->configurationAdded(item);
       
   821 
       
   822 #ifdef BEARER_MANAGEMENT_DEBUG
       
   823             qDebug()<<"New configuration"<<result<<"added to manager in open";
       
   824 #endif
       
   825 
       
   826             } else {
       
   827                 QExplicitlySharedDataPointer<QNetworkConfigurationPrivate> priv = mgr->accessPointConfigurations.value(result);
       
   828                 QNetworkConfiguration reference;
       
   829                 reference.d = priv;
       
   830                 copyConfig(config, reference, false);
       
   831                 reference.d.data()->id = result; // Note: Id was not copied in copyConfig() function
       
   832                 config = reference;
       
   833                 activeConfig = reference;
       
   834 
       
   835 #ifdef BEARER_MANAGEMENT_DEBUG
       
   836                 qDebug()<<"Existing configuration"<<result<<"updated in manager in open";
       
   837 #endif
       
   838             }
       
   839         }
       
   840 
       
   841         emit quitPendingWaitsForOpened();
       
   842     }
       
   843 }
       
   844 
       
   845 void QNetworkSessionPrivate::connectTimeout()
       
   846 {
       
   847     updateState(QNetworkSession::Disconnected);
       
   848     if (publicConfig.type() == QNetworkConfiguration::UserChoice)
       
   849             copyConfig(publicConfig, activeConfig);
       
   850         emit q->error(QNetworkSession::UnknownSessionError);
       
   851 }
       
   852 
       
   853 void QNetworkSessionPrivate::close()
       
   854 {
       
   855     if (m_connectRequestTimer.isActive())
       
   856         m_connectRequestTimer.stop();
       
   857 
       
   858     if (serviceConfig.isValid()) {
       
   859         lastError = QNetworkSession::OperationNotSupportedError;
       
   860         emit q->error(lastError);
       
   861     } else if (isOpen) {
       
   862         opened = false;
       
   863         isOpen = false;
       
   864         emit q->closed();
       
   865     }
       
   866 }
       
   867 
       
   868 
       
   869 void QNetworkSessionPrivate::stop()
       
   870 {
       
   871     if (m_connectRequestTimer.isActive())
       
   872         m_connectRequestTimer.stop();
       
   873 
       
   874     if (serviceConfig.isValid()) {
       
   875         lastError = QNetworkSession::OperationNotSupportedError;
       
   876         emit q->error(lastError);
       
   877     } else {
       
   878         if ((activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
       
   879             if (!m_stopTimer.isActive()) {
       
   880                 Maemo::Icd icd;
       
   881 #ifdef BEARER_MANAGEMENT_DEBUG
       
   882                 qDebug() << "stopping session" << publicConfig.identifier();
       
   883 #endif
       
   884                 state = QNetworkSession::Closing;
       
   885                 emit q->stateChanged(state);
       
   886 
       
   887                 opened = false;
       
   888                 isOpen = false;
       
   889 
       
   890                 icd.disconnect(ICD_CONNECTION_FLAG_APPLICATION_EVENT);
       
   891                 startTime = QDateTime();
       
   892 
       
   893                 /* Note: Session state will change to disconnected
       
   894                  *       as soon as QNetworkConfigurationManager sends
       
   895                  *       corresponding iapStateChanged signal.
       
   896                  */
       
   897 
       
   898                 // Make sure that this Session will send closed signal
       
   899                 // even though ICD connection will not ever get closed
       
   900                 m_stopTimer.start(ICD_SHORT_CONNECT_TIMEOUT); // 10 seconds wait
       
   901             }
       
   902         } else {
       
   903 	    opened = false;
       
   904 	    isOpen = false;
       
   905 	    emit q->closed();
       
   906 	}
       
   907     }
       
   908 }
       
   909 
       
   910 void QNetworkSessionPrivate::finishStopBySendingClosedSignal()
       
   911 {
       
   912     if ((activeConfig.state() & QNetworkConfiguration::Active) == QNetworkConfiguration::Active) {
       
   913         state = QNetworkSession::Connected;
       
   914         emit q->stateChanged(state);
       
   915     }
       
   916     emit q->closed();
       
   917 }
       
   918 
       
   919 void QNetworkSessionPrivate::migrate()
       
   920 {
       
   921     qWarning("This platform does not support roaming (%s).", __FUNCTION__);
       
   922 }
       
   923 
       
   924 
       
   925 void QNetworkSessionPrivate::accept()
       
   926 {
       
   927     qWarning("This platform does not support roaming (%s).", __FUNCTION__);
       
   928 }
       
   929 
       
   930 
       
   931 void QNetworkSessionPrivate::ignore()
       
   932 {
       
   933     qWarning("This platform does not support roaming (%s).", __FUNCTION__);
       
   934 }
       
   935 
       
   936 
       
   937 void QNetworkSessionPrivate::reject()
       
   938 {
       
   939     qWarning("This platform does not support roaming (%s).", __FUNCTION__);
       
   940 }
       
   941 
       
   942 
       
   943 QNetworkInterface QNetworkSessionPrivate::currentInterface() const
       
   944 {
       
   945     if (!publicConfig.isValid() || state != QNetworkSession::Connected)
       
   946         return QNetworkInterface();
       
   947 
       
   948     if (currentNetworkInterface.isEmpty())
       
   949         return QNetworkInterface();
       
   950 
       
   951     return QNetworkInterface::interfaceFromName(currentNetworkInterface);
       
   952 }
       
   953 
       
   954 
       
   955 void QNetworkSessionPrivate::setSessionProperty(const QString& key, const QVariant& value)
       
   956 {
       
   957     if (value.isValid()) {
       
   958 	properties.insert(key, value);
       
   959 
       
   960 	if (key == "ConnectInBackground") {
       
   961 	    bool v = value.toBool();
       
   962 	    if (v)
       
   963 		connectFlags = ICD_CONNECTION_FLAG_APPLICATION_EVENT;
       
   964 	    else
       
   965 		connectFlags = ICD_CONNECTION_FLAG_USER_EVENT;
       
   966 	}
       
   967     } else {
       
   968 	properties.remove(key);
       
   969 
       
   970 	/* Set default value when property is removed */
       
   971 	if (key == "ConnectInBackground")
       
   972 	    connectFlags = ICD_CONNECTION_FLAG_USER_EVENT;
       
   973     }
       
   974 }
       
   975 
       
   976 
       
   977 QVariant QNetworkSessionPrivate::sessionProperty(const QString& key) const
       
   978 {
       
   979     return properties.value(key);
       
   980 }
       
   981 
       
   982 
       
   983 QString QNetworkSessionPrivate::errorString() const
       
   984 {
       
   985     QString errorStr;
       
   986     switch(q->error()) {
       
   987     case QNetworkSession::RoamingError:
       
   988         errorStr = QObject::tr("Roaming error");
       
   989         break;
       
   990     case QNetworkSession::SessionAbortedError:
       
   991         errorStr = QObject::tr("Session aborted by user or system");
       
   992         break;
       
   993     default:
       
   994     case QNetworkSession::UnknownSessionError:
       
   995         errorStr = QObject::tr("Unidentified Error");
       
   996         break;
       
   997     }
       
   998     return errorStr;
       
   999 }
       
  1000 
       
  1001 
       
  1002 QNetworkSession::SessionError QNetworkSessionPrivate::error() const
       
  1003 {
       
  1004     return QNetworkSession::UnknownSessionError;
       
  1005 }
       
  1006 
       
  1007 
       
  1008 void QNetworkSessionPrivate::updateProxies(QNetworkSession::State newState)
       
  1009 {
       
  1010     if ((newState == QNetworkSession::Connected) &&
       
  1011 	(newState != currentState))
       
  1012 	updateProxyInformation();
       
  1013     else if ((newState == QNetworkSession::Disconnected) &&
       
  1014 	    (currentState == QNetworkSession::Closing))
       
  1015 	clearProxyInformation();
       
  1016 
       
  1017     currentState = newState;
       
  1018 }
       
  1019 
       
  1020 
       
  1021 void QNetworkSessionPrivate::updateProxyInformation()
       
  1022 {
       
  1023     Maemo::ProxyConf::update();
       
  1024 }
       
  1025 
       
  1026 
       
  1027 void QNetworkSessionPrivate::clearProxyInformation()
       
  1028 {
       
  1029     Maemo::ProxyConf::clear();
       
  1030 }
       
  1031 
       
  1032 
       
  1033 #include "moc_qnetworksession_maemo_p.cpp"
       
  1034 
       
  1035 QTM_END_NAMESPACE