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