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 "symbianengine.h"
44 
45 #include <es_enum.h>
46 #include <es_sock.h>
47 #include <in_sock.h>
48 #include <private/qcore_symbian_p.h>
49 
50 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
51 #include <cmmanager.h>
52 #endif
53 
54 #if defined(OCC_FUNCTIONALITY_AVAILABLE) && defined(SNAP_FUNCTIONALITY_AVAILABLE)
55 #include <extendedconnpref.h>
56 #endif
57 
58 #ifndef QT_NO_BEARERMANAGEMENT
59 
60 QT_BEGIN_NAMESPACE
61 
QNetworkSessionPrivateImpl(SymbianEngine * engine)62 QNetworkSessionPrivateImpl::QNetworkSessionPrivateImpl(SymbianEngine *engine)
63 :   engine(engine), iSocketServ(qt_symbianGetSocketServer()),
64     ipConnectionNotifier(0), ipConnectionStarter(0),
65     iHandleStateNotificationsFromManager(false), iFirstSync(true), iStoppedByUser(false),
66     iClosedByUser(false), iError(QNetworkSession::UnknownSessionError), iALREnabled(0),
67     iConnectInBackground(false), iCurrentIap(0), isOpening(false)
68 {
69 
70 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
71     iMobility = NULL;
72 #endif
73 
74     TRAP_IGNORE(iConnectionMonitor.ConnectL());
75 }
76 
closeHandles()77 void QNetworkSessionPrivateImpl::closeHandles()
78 {
79     QMutexLocker lock(&mutex);
80     updateCurrentIap(0);
81     // Cancel Connection Progress Notifications first.
82     // Note: ConnectionNotifier must be destroyed before RConnection::Close()
83     //       => deleting ipConnectionNotifier results RConnection::CancelProgressNotification()
84     delete ipConnectionNotifier;
85     ipConnectionNotifier = NULL;
86 
87 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
88     // mobility monitor must be deleted before RConnection is closed
89     delete iMobility;
90     iMobility = NULL;
91 #endif
92 
93     // Cancel possible RConnection::Start() - may call RConnection::Close if Start was in progress
94     delete ipConnectionStarter;
95     ipConnectionStarter = 0;
96     //close any open connection (note Close twice is safe in case Cancel did it above)
97     iConnection.Close();
98 
99     QSymbianSocketManager::instance().setDefaultConnection(0);
100 
101 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
102     qDebug() << "QNS this : " << QString::number((uint)this)
103              << " - handles closed";
104 #endif
105 
106 }
107 
~QNetworkSessionPrivateImpl()108 QNetworkSessionPrivateImpl::~QNetworkSessionPrivateImpl()
109 {
110     isOpen = false;
111     isOpening = false;
112 
113     closeHandles();
114     iConnectionMonitor.Close();
115 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
116     qDebug() << "QNS this : " << QString::number((uint)this)
117              << " - destroyed";
118 #endif
119 }
120 
configurationStateChanged(quint32 accessPointId,quint32 connMonId,QNetworkSession::State newState)121 void QNetworkSessionPrivateImpl::configurationStateChanged(quint32 accessPointId, quint32 connMonId, QNetworkSession::State newState)
122 {
123     if (iHandleStateNotificationsFromManager) {
124 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
125         qDebug() << "QNS this : " << QString::number((uint)this) << " - "
126                  << "configurationStateChanged from manager for IAP : " << QString::number(accessPointId)
127                  << "connMon ID : " << QString::number(connMonId) << " : to a state: " << newState
128                  << "whereas my current state is: " << state;
129 #else
130       Q_UNUSED(connMonId);
131 #endif
132         this->newState(newState, accessPointId);
133     }
134 }
135 
configurationRemoved(QNetworkConfigurationPrivatePointer config)136 void QNetworkSessionPrivateImpl::configurationRemoved(QNetworkConfigurationPrivatePointer config)
137 {
138     if (!publicConfig.isValid())
139         return;
140 
141     TUint32 publicNumericId =
142         toSymbianConfig(privateConfiguration(publicConfig))->numericIdentifier();
143 
144     if (toSymbianConfig(config)->numericIdentifier() == publicNumericId) {
145 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
146         qDebug() << "QNS this : " << QString::number((uint)this) << " - "
147                  << "configurationRemoved IAP: " << QString::number(publicNumericId) << " : going to State: Invalid";
148 #endif
149         this->newState(QNetworkSession::Invalid, publicNumericId);
150     }
151 }
152 
configurationAdded(QNetworkConfigurationPrivatePointer config)153 void QNetworkSessionPrivateImpl::configurationAdded(QNetworkConfigurationPrivatePointer config)
154 {
155     Q_UNUSED(config);
156     // If session is based on service network, some other app may create new access points
157     // to the SNAP --> synchronize session's state with that of interface's.
158     if (!publicConfig.isValid() || publicConfig.type() != QNetworkConfiguration::ServiceNetwork)
159         return;
160 
161 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
162         qDebug() << "QNS this : " << QString::number((uint)this) << " - "
163                  << "configurationAdded IAP: "
164                  << toSymbianConfig(config)->numericIdentifier();
165 #endif
166 
167         syncStateWithInterface();
168 }
169 
170 // Function sets the state of the session to match the state
171 // of the underlying interface (the configuration this session is based on)
syncStateWithInterface()172 void QNetworkSessionPrivateImpl::syncStateWithInterface()
173 {
174     if (!publicConfig.isValid())
175         return;
176 
177     if (iFirstSync) {
178         QObject::connect(engine,
179                          SIGNAL(configurationStateChanged(quint32,quint32,QNetworkSession::State)),
180                          this,
181                          SLOT(configurationStateChanged(quint32,quint32,QNetworkSession::State)));
182         // Listen to configuration removals, so that in case the configuration
183         // this session is based on is removed, session knows to enter Invalid -state.
184         QObject::connect(engine, SIGNAL(configurationRemoved(QNetworkConfigurationPrivatePointer)),
185                          this, SLOT(configurationRemoved(QNetworkConfigurationPrivatePointer)));
186         // Connect to configuration additions, so that in case a configuration is added
187         // in a SNAP this session is based on, the session knows to synch its state with its
188         // interface.
189         QObject::connect(engine, SIGNAL(configurationAdded(QNetworkConfigurationPrivatePointer)),
190                          this, SLOT(configurationAdded(QNetworkConfigurationPrivatePointer)));
191     }
192     // Start listening IAP state changes from QNetworkConfigurationManagerPrivate
193     iHandleStateNotificationsFromManager = true;
194 
195     // Check what is the state of the configuration this session is based on
196     // and set the session in appropriate state.
197 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
198     qDebug() << "QNS this : " << QString::number((uint)this) << " - "
199              << "syncStateWithInterface() state of publicConfig is: " << publicConfig.state();
200 #endif
201     switch (publicConfig.state()) {
202     case QNetworkConfiguration::Active:
203         newState(QNetworkSession::Connected);
204         break;
205     case QNetworkConfiguration::Discovered:
206         newState(QNetworkSession::Disconnected);
207         break;
208     case QNetworkConfiguration::Defined:
209         newState(QNetworkSession::NotAvailable);
210         break;
211     case QNetworkConfiguration::Undefined:
212     default:
213         newState(QNetworkSession::Invalid);
214     }
215 }
216 
217 #ifndef QT_NO_NETWORKINTERFACE
interface(TUint iapId) const218 QNetworkInterface QNetworkSessionPrivateImpl::interface(TUint iapId) const
219 {
220     QString interfaceName;
221 
222     TSoInetInterfaceInfo ifinfo;
223     TPckg<TSoInetInterfaceInfo> ifinfopkg(ifinfo);
224     TSoInetIfQuery ifquery;
225     TPckg<TSoInetIfQuery> ifquerypkg(ifquery);
226 
227     // Open dummy socket for interface queries
228     RSocket socket;
229     TInt retVal = socket.Open(iSocketServ, _L("udp"));
230     if (retVal != KErrNone) {
231         return QNetworkInterface();
232     }
233 
234     // Start enumerating interfaces
235     socket.SetOpt(KSoInetEnumInterfaces, KSolInetIfCtrl);
236     while(socket.GetOpt(KSoInetNextInterface, KSolInetIfCtrl, ifinfopkg) == KErrNone) {
237         ifquery.iName = ifinfo.iName;
238         TInt err = socket.GetOpt(KSoInetIfQueryByName, KSolInetIfQuery, ifquerypkg);
239         if(err == KErrNone && ifquery.iZone[1] == iapId) { // IAP ID is index 1 of iZone
240             if(ifinfo.iAddress.Address() > 0) {
241                 interfaceName = QString::fromUtf16(ifinfo.iName.Ptr(),ifinfo.iName.Length());
242                 break;
243             }
244         }
245     }
246 
247     socket.Close();
248 
249     if (interfaceName.isEmpty()) {
250         return QNetworkInterface();
251     }
252 
253     return QNetworkInterface::interfaceFromName(interfaceName);
254 }
255 #endif
256 
257 #ifndef QT_NO_NETWORKINTERFACE
currentInterface() const258 QNetworkInterface QNetworkSessionPrivateImpl::currentInterface() const
259 {
260 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
261     qDebug() << "QNS this : " << QString::number((uint)this) << " - "
262              << "currentInterface() requested, state: " << state
263              << "publicConfig validity: " << publicConfig.isValid();
264     if (activeInterface.isValid())
265         qDebug() << "QNS this : " << QString::number((uint)this) << " - "
266                  << "interface is: " << activeInterface.humanReadableName();
267 #endif
268 
269     if (!publicConfig.isValid() || state != QNetworkSession::Connected) {
270         return QNetworkInterface();
271     }
272 
273     return activeInterface;
274 }
275 #endif
276 
sessionProperty(const QString & key) const277 QVariant QNetworkSessionPrivateImpl::sessionProperty(const QString& key) const
278 {
279     if (key == "ConnectInBackground") {
280         return QVariant(iConnectInBackground);
281     }
282     return QVariant();
283 }
284 
setSessionProperty(const QString & key,const QVariant & value)285 void QNetworkSessionPrivateImpl::setSessionProperty(const QString& key, const QVariant& value)
286 {
287     // Valid value means adding property, invalid means removing it.
288     if (key == "ConnectInBackground") {
289         if (value.isValid()) {
290             iConnectInBackground = value.toBool();
291         } else {
292             iConnectInBackground = EFalse;
293         }
294     }
295 }
296 
errorString() const297 QString QNetworkSessionPrivateImpl::errorString() const
298 {
299     switch (iError) {
300     case QNetworkSession::UnknownSessionError:
301         return tr("Unknown session error.");
302     case QNetworkSession::SessionAbortedError:
303         return tr("The session was aborted by the user or system.");
304     case QNetworkSession::OperationNotSupportedError:
305         return tr("The requested operation is not supported by the system.");
306     case QNetworkSession::InvalidConfigurationError:
307         return tr("The specified configuration cannot be used.");
308     case QNetworkSession::RoamingError:
309         return tr("Roaming was aborted or is not possible.");
310     }
311 
312     return QString();
313 }
314 
error() const315 QNetworkSession::SessionError QNetworkSessionPrivateImpl::error() const
316 {
317     return iError;
318 }
319 
open()320 void QNetworkSessionPrivateImpl::open()
321 {
322     QMutexLocker lock(&mutex);
323 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
324         qDebug() << "QNS this : " << QString::number((uint)this) << " - "
325                 << "open() called, session state is: " << state << " and isOpen is: "
326                 << isOpen << isOpening;
327 #endif
328 
329     if (isOpen || isOpening)
330         return;
331 
332     isOpening = true;
333 
334     // Stop handling IAP state change signals from QNetworkConfigurationManagerPrivate
335     // => RConnection::ProgressNotification will be used for IAP/SNAP monitoring
336     iHandleStateNotificationsFromManager = false;
337 
338     // Configuration may have been invalidated after session creation by platform
339     // (e.g. configuration has been deleted).
340     if (!publicConfig.isValid()) {
341         newState(QNetworkSession::Invalid);
342         iError = QNetworkSession::InvalidConfigurationError;
343         emit QNetworkSessionPrivate::error(iError);
344         return;
345     }
346     // If opening a undefined configuration, session emits error and enters
347     // NotAvailable -state. Note that we will try ones in 'defined' state to avoid excessive
348     // need for WLAN scans (via updateConfigurations()), because user may have walked
349     // into a WLAN range, but periodic background scan has not occurred yet -->
350     // we don't want to force application to make frequent updateConfigurations() calls
351     // to be able to try if e.g. home WLAN is available.
352     if (publicConfig.state() == QNetworkConfiguration::Undefined) {
353         newState(QNetworkSession::NotAvailable);
354         iError = QNetworkSession::InvalidConfigurationError;
355         emit QNetworkSessionPrivate::error(iError);
356         return;
357     }
358     // Clear possible previous states
359     iStoppedByUser = false;
360     iClosedByUser = false;
361 
362     Q_ASSERT(!iConnection.SubSessionHandle());
363     TInt error = iConnection.Open(iSocketServ);
364     if (error != KErrNone) {
365         // Could not open RConnection
366         newState(QNetworkSession::Invalid);
367         iError = QNetworkSession::UnknownSessionError;
368         emit QNetworkSessionPrivate::error(iError);
369         syncStateWithInterface();
370         return;
371     }
372 
373     // Use RConnection::ProgressNotification for IAP/SNAP monitoring
374     // (<=> ConnectionProgressNotifier uses RConnection::ProgressNotification)
375     if (!ipConnectionNotifier) {
376         ipConnectionNotifier = new ConnectionProgressNotifier(*this,iConnection);
377     }
378     if (ipConnectionNotifier) {
379         ipConnectionNotifier->StartNotifications();
380     }
381 
382     if (publicConfig.type() == QNetworkConfiguration::InternetAccessPoint) {
383             SymbianNetworkConfigurationPrivate *symbianConfig =
384                 toSymbianConfig(privateConfiguration(publicConfig));
385 
386 #if defined(OCC_FUNCTIONALITY_AVAILABLE) && defined(SNAP_FUNCTIONALITY_AVAILABLE)
387             // With One Click Connectivity (Symbian^3 onwards) it is possible
388             // to connect silently, without any popups.
389             TConnPrefList pref;
390             TExtendedConnPref prefs;
391 
392             prefs.SetIapId(symbianConfig->numericIdentifier());
393             if (iConnectInBackground) {
394                 prefs.SetNoteBehaviour( TExtendedConnPref::ENoteBehaviourConnSilent );
395             }
396             pref.AppendL(&prefs);
397 #else
398             TCommDbConnPref pref;
399             pref.SetDialogPreference(ECommDbDialogPrefDoNotPrompt);
400 
401             pref.SetIapId(symbianConfig->numericIdentifier());
402 #endif
403             if (!ipConnectionStarter) {
404                 ipConnectionStarter = new ConnectionStarter(*this, iConnection);
405                 ipConnectionStarter->Start(pref);
406             }
407             // Avoid flip flop of states if the configuration is already
408             // active. IsOpen/opened() will indicate when ready.
409             if (state != QNetworkSession::Connected) {
410                 newState(QNetworkSession::Connecting);
411             }
412     } else if (publicConfig.type() == QNetworkConfiguration::ServiceNetwork) {
413         SymbianNetworkConfigurationPrivate *symbianConfig =
414             toSymbianConfig(privateConfiguration(publicConfig));
415 
416 #if defined(OCC_FUNCTIONALITY_AVAILABLE) && defined(SNAP_FUNCTIONALITY_AVAILABLE)
417         // On Symbian^3 if service network is not reachable, it triggers a UI (aka EasyWLAN) where
418         // user can create new IAPs. To detect this, we need to store the number of IAPs
419         // there was before connection was started.
420         iKnownConfigsBeforeConnectionStart = engine->accessPointConfigurationIdentifiers();
421         TConnPrefList snapPref;
422         TExtendedConnPref prefs;
423         prefs.SetSnapId(symbianConfig->numericIdentifier());
424         if (iConnectInBackground) {
425             prefs.SetNoteBehaviour( TExtendedConnPref::ENoteBehaviourConnSilent );
426         }
427         snapPref.AppendL(&prefs);
428 #else
429         TConnSnapPref snapPref(symbianConfig->numericIdentifier());
430 #endif
431         if (!ipConnectionStarter) {
432             ipConnectionStarter = new ConnectionStarter(*this, iConnection);
433             ipConnectionStarter->Start(snapPref);
434         }
435         // Avoid flip flop of states if the configuration is already
436         // active. IsOpen/opened() will indicate when ready.
437         if (state != QNetworkSession::Connected) {
438             newState(QNetworkSession::Connecting);
439         }
440     } else if (publicConfig.type() == QNetworkConfiguration::UserChoice) {
441         iKnownConfigsBeforeConnectionStart = engine->accessPointConfigurationIdentifiers();
442         if (!ipConnectionStarter) {
443             ipConnectionStarter = new ConnectionStarter(*this, iConnection);
444             ipConnectionStarter->Start();
445         }
446         newState(QNetworkSession::Connecting);
447     }
448 
449     if (error != KErrNone) {
450         isOpen = false;
451         isOpening = false;
452         iError = QNetworkSession::UnknownSessionError;
453         closeHandles();
454         emit QNetworkSessionPrivate::error(iError);
455         syncStateWithInterface();
456     }
457 }
458 
iapClientCount(TUint aIAPId) const459 TUint QNetworkSessionPrivateImpl::iapClientCount(TUint aIAPId) const
460 {
461     TRequestStatus status;
462     TUint connectionCount;
463     if (!iConnectionMonitor.Handle())
464         return 0;
465     iConnectionMonitor.GetConnectionCount(connectionCount, status);
466     User::WaitForRequest(status);
467     if (status.Int() == KErrNone) {
468         for (TUint i = 1; i <= connectionCount; i++) {
469             TUint connectionId;
470             TUint subConnectionCount;
471             iConnectionMonitor.GetConnectionInfo(i, connectionId, subConnectionCount);
472             TUint apId;
473             iConnectionMonitor.GetUintAttribute(connectionId, subConnectionCount, KIAPId, apId, status);
474             User::WaitForRequest(status);
475             if (apId == aIAPId) {
476                 TConnMonClientEnumBuf buf;
477                 iConnectionMonitor.GetPckgAttribute(connectionId, 0, KClientInfo, buf, status);
478                 User::WaitForRequest(status);
479                 if (status.Int() == KErrNone) {
480                     return buf().iCount;
481                 }
482             }
483         }
484     }
485     return 0;
486 }
487 
close(bool allowSignals)488 void QNetworkSessionPrivateImpl::close(bool allowSignals)
489 {
490 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
491     qDebug() << "QNS this : " << QString::number((uint)this) << " - "
492             << "close() called, session state is: " << state << " and isOpen is : "
493             << isOpen;
494 #endif
495 
496     if (!isOpen && state != QNetworkSession::Connecting) {
497         return;
498     }
499     // Mark this session as closed-by-user so that we are able to report
500     // distinguish between stop() and close() state transitions
501     // when reporting.
502     iClosedByUser = true;
503     isOpen = false;
504     isOpening = false;
505 
506     serviceConfig = QNetworkConfiguration();
507 
508     closeHandles();
509 
510     // Start handling IAP state change signals from QNetworkConfigurationManagerPrivate
511     iHandleStateNotificationsFromManager = true;
512 
513     // If UserChoice, go down immediately. If some other configuration,
514     // go down immediately if there is no reports expected from the platform;
515     // in practice Connection Monitor is aware of connections only after
516     // KFinishedSelection event, and hence reports only after that event, but
517     // that does not seem to be trusted on all Symbian versions --> safest
518     // to go down.
519     if (publicConfig.type() == QNetworkConfiguration::UserChoice || state == QNetworkSession::Connecting) {
520 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
521         qDebug() << "QNS this : " << QString::number((uint)this) << " - "
522                  << "going disconnected right away, since either UserChoice or Connecting";
523 #endif
524         newState(QNetworkSession::Closing);
525         newState(QNetworkSession::Disconnected);
526     }
527     if (allowSignals) {
528         emit closed();
529     }
530 }
531 
stop()532 void QNetworkSessionPrivateImpl::stop()
533 {
534     QMutexLocker lock(&mutex);
535 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
536     qDebug() << "QNS this : " << QString::number((uint)this) << " - "
537             << "stop() called, session state is: " << state << " and isOpen is : "
538             << isOpen;
539 #endif
540     if (!isOpen &&
541         publicConfig.isValid() &&
542         publicConfig.type() == QNetworkConfiguration::InternetAccessPoint &&
543         iConnectionMonitor.Handle()) {
544 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
545     qDebug() << "QNS this : " << QString::number((uint)this) << " - "
546             << "since session is not open, using RConnectionMonitor to stop() the interface";
547 #endif
548         iStoppedByUser = true;
549         // If the publicConfig is type of IAP, enumerate through connections at
550         // connection monitor. If publicConfig is active in that list, stop it.
551         // Otherwise there is nothing to stop. Note: because this QNetworkSession is not open,
552         // activeConfig is not usable.
553         TUint count;
554         TRequestStatus status;
555         iConnectionMonitor.GetConnectionCount(count, status);
556         User::WaitForRequest(status);
557         if (status.Int() != KErrNone) {
558             return;
559         }
560         TUint numSubConnections; // Not used but needed by GetConnectionInfo i/f
561         TUint connectionId;
562         for (TUint i = 1; i <= count; ++i) {
563             // Get (connection monitor's assigned) connection ID
564             TInt ret = iConnectionMonitor.GetConnectionInfo(i, connectionId, numSubConnections);
565             if (ret == KErrNone) {
566                 SymbianNetworkConfigurationPrivate *symbianConfig =
567                     toSymbianConfig(privateConfiguration(publicConfig));
568 
569                 // See if connection Id matches with our Id. If so, stop() it.
570                 if (symbianConfig->connectionIdentifier() == connectionId) {
571                     ret = iConnectionMonitor.SetBoolAttribute(connectionId,
572                                                               0, // subConnectionId don't care
573                                                               KConnectionStop,
574                                                               ETrue);
575                 }
576             }
577             // Enter disconnected state right away since the session is not even open.
578             // Symbian^3 connection monitor does not emit KLinkLayerClosed when
579             // connection is stopped via connection monitor.
580             newState(QNetworkSession::Disconnected);
581         }
582     } else if (isOpen) {
583 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
584     qDebug() << "QNS this : " << QString::number((uint)this) << " - "
585             << "since session is open, using RConnection to stop() the interface";
586 #endif
587         // Since we are open, use RConnection to stop the interface
588         isOpen = false;
589         isOpening = false;
590         iStoppedByUser = true;
591         newState(QNetworkSession::Closing);
592         if (ipConnectionNotifier) {
593             ipConnectionNotifier->StopNotifications();
594             // Start handling IAP state change signals from QNetworkConfigurationManagerPrivate
595             iHandleStateNotificationsFromManager = true;
596         }
597         iConnection.Stop(RConnection::EStopAuthoritative);
598         isOpen = true;
599         isOpening = false;
600         close(false);
601         emit closed();
602     }
603 }
604 
migrate()605 void QNetworkSessionPrivateImpl::migrate()
606 {
607 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
608     if (iMobility) {
609         QSymbianSocketManager::instance().setDefaultConnection(0);
610         // Start migrating to new IAP
611         iMobility->MigrateToPreferredCarrier();
612     }
613 #endif
614 }
615 
ignore()616 void QNetworkSessionPrivateImpl::ignore()
617 {
618 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
619     if (iMobility) {
620         iMobility->IgnorePreferredCarrier();
621 
622         if (!iALRUpgradingConnection) {
623             newState(QNetworkSession::Disconnected);
624         } else {
625             newState(QNetworkSession::Connected,iOldRoamingIap);
626         }
627     }
628 #endif
629 }
630 
accept()631 void QNetworkSessionPrivateImpl::accept()
632 {
633 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
634     if (iMobility) {
635         iMobility->NewCarrierAccepted();
636 
637         QNetworkConfiguration newActiveConfig = activeConfiguration(iNewRoamingIap);
638 
639         QSymbianSocketManager::instance().setDefaultConnection(&iConnection);
640 
641         updateCurrentIap(iNewRoamingIap);
642 
643         newState(QNetworkSession::Connected, iNewRoamingIap);
644     }
645 #endif
646 }
647 
reject()648 void QNetworkSessionPrivateImpl::reject()
649 {
650 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
651     if (iMobility) {
652         iMobility->NewCarrierRejected();
653 
654         if (!iALRUpgradingConnection) {
655             newState(QNetworkSession::Disconnected);
656         } else {
657             QNetworkConfiguration newActiveConfig = activeConfiguration(iOldRoamingIap);
658 
659             QSymbianSocketManager::instance().setDefaultConnection(&iConnection);
660 
661             newState(QNetworkSession::Connected, iOldRoamingIap);
662         }
663     }
664 #endif
665 }
666 
667 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
PreferredCarrierAvailable(TAccessPointInfo aOldAPInfo,TAccessPointInfo aNewAPInfo,TBool aIsUpgrade,TBool aIsSeamless)668 void QNetworkSessionPrivateImpl::PreferredCarrierAvailable(TAccessPointInfo aOldAPInfo,
669                                                        TAccessPointInfo aNewAPInfo,
670                                                        TBool aIsUpgrade,
671                                                        TBool aIsSeamless)
672 {
673     iOldRoamingIap = aOldAPInfo.AccessPoint();
674     iNewRoamingIap = aNewAPInfo.AccessPoint();
675     newState(QNetworkSession::Roaming);
676     if (iALREnabled > 0) {
677         iALRUpgradingConnection = aIsUpgrade;
678         QList<QNetworkConfiguration> configs = publicConfig.children();
679         for (int i=0; i < configs.count(); i++) {
680             SymbianNetworkConfigurationPrivate *symbianConfig =
681                 toSymbianConfig(privateConfiguration(configs[i]));
682 
683             if (symbianConfig->numericIdentifier() == aNewAPInfo.AccessPoint()) {
684                 // Any slot connected to the signal might throw an std::exception,
685                 // which must not propagate into Symbian code (this function is a callback
686                 // from platform). We could convert exception to a symbian Leave, but since the
687                 // prototype of this function bans this (no trailing 'L'), we just catch
688                 // and drop.
689                 QT_TRY {
690                     emit preferredConfigurationChanged(configs[i], aIsSeamless);
691                 }
692                 QT_CATCH (std::exception&) {}
693             }
694         }
695     } else {
696         migrate();
697     }
698 }
699 
NewCarrierActive(TAccessPointInfo,TBool)700 void QNetworkSessionPrivateImpl::NewCarrierActive(TAccessPointInfo /*aNewAPInfo*/, TBool /*aIsSeamless*/)
701 {
702     if (iALREnabled > 0) {
703         QT_TRY {
704             emit newConfigurationActivated();
705         }
706         QT_CATCH (std::exception&) {}
707     } else {
708         accept();
709     }
710 }
711 
Error(TInt aError)712 void QNetworkSessionPrivateImpl::Error(TInt aError)
713 {
714 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
715     qDebug() << "QNS this : " << QString::number((uint)this) << " - "
716             << "roaming Error() occurred" << aError << ", isOpen is: " << isOpen;
717 #endif
718     if (aError == KErrCancel)
719         return; //avoid recursive deletion
720     if (isOpen) {
721         isOpen = false;
722         isOpening = false;
723         activeConfig = QNetworkConfiguration();
724         serviceConfig = QNetworkConfiguration();
725         iError = QNetworkSession::RoamingError;
726         closeHandles();
727         emit QNetworkSessionPrivate::error(iError);
728         QT_TRY {
729             syncStateWithInterface();
730             // In some cases IAP is still in Connected state when
731             // syncStateWithInterface(); is called
732             // => Following call makes sure that Session state
733             //    changes immediately to Disconnected.
734             newState(QNetworkSession::Disconnected);
735             emit closed();
736         }
737         QT_CATCH (std::exception&) {}
738     } else if (iStoppedByUser) {
739         // If the user of this session has called the stop() and
740         // configuration is based on internet SNAP, this needs to be
741         // done here because platform might roam.
742         QT_TRY {
743             newState(QNetworkSession::Disconnected);
744         }
745         QT_CATCH (std::exception&) {}
746     }
747 }
748 #endif
749 
setALREnabled(bool enabled)750 void QNetworkSessionPrivateImpl::setALREnabled(bool enabled)
751 {
752     if (enabled) {
753         iALREnabled++;
754     } else {
755         iALREnabled--;
756     }
757 }
758 
bestConfigFromSNAP(const QNetworkConfiguration & snapConfig) const759 QNetworkConfiguration QNetworkSessionPrivateImpl::bestConfigFromSNAP(const QNetworkConfiguration& snapConfig) const
760 {
761     QNetworkConfiguration config;
762     QList<QNetworkConfiguration> subConfigurations = snapConfig.children();
763     for (int i = 0; i < subConfigurations.count(); i++ ) {
764         if (subConfigurations[i].state() == QNetworkConfiguration::Active) {
765             config = subConfigurations[i];
766             break;
767         } else if (!config.isValid() && subConfigurations[i].state() == QNetworkConfiguration::Discovered) {
768             config = subConfigurations[i];
769         }
770     }
771     if (!config.isValid() && subConfigurations.count() > 0) {
772         config = subConfigurations[0];
773     }
774     return config;
775 }
776 
bytesWritten() const777 quint64 QNetworkSessionPrivateImpl::bytesWritten() const
778 {
779     return transferredData(KUplinkData);
780 }
781 
bytesReceived() const782 quint64 QNetworkSessionPrivateImpl::bytesReceived() const
783 {
784     return transferredData(KDownlinkData);
785 }
786 
transferredData(TUint dataType) const787 quint64 QNetworkSessionPrivateImpl::transferredData(TUint dataType) const
788 {
789     if (!publicConfig.isValid()) {
790         return 0;
791     }
792 
793     QNetworkConfiguration config;
794     if (publicConfig.type() == QNetworkConfiguration::UserChoice) {
795         if (serviceConfig.isValid()) {
796             config = serviceConfig;
797         } else {
798             if (activeConfig.isValid()) {
799                 config = activeConfig;
800             }
801         }
802     } else {
803         config = publicConfig;
804     }
805 
806     if (!config.isValid()) {
807         return 0;
808     }
809 
810     if (!iConnectionMonitor.Handle())
811         return 0;
812     TUint count;
813     TRequestStatus status;
814     iConnectionMonitor.GetConnectionCount(count, status);
815     User::WaitForRequest(status);
816     if (status.Int() != KErrNone) {
817         return 0;
818     }
819 
820     TUint transferredData = 0;
821     TUint numSubConnections;
822     TUint connectionId;
823     bool configFound;
824     for (TUint i = 1; i <= count; i++) {
825         TInt ret = iConnectionMonitor.GetConnectionInfo(i, connectionId, numSubConnections);
826         if (ret == KErrNone) {
827             TUint apId;
828             iConnectionMonitor.GetUintAttribute(connectionId, 0, KIAPId, apId, status);
829             User::WaitForRequest(status);
830             if (status.Int() == KErrNone) {
831                 configFound = false;
832                 if (config.type() == QNetworkConfiguration::ServiceNetwork) {
833                     QList<QNetworkConfiguration> configs = config.children();
834                     for (int i=0; i < configs.count(); i++) {
835                         SymbianNetworkConfigurationPrivate *symbianConfig =
836                             toSymbianConfig(privateConfiguration(configs[i]));
837 
838                         if (symbianConfig->numericIdentifier() == apId) {
839                             configFound = true;
840                             break;
841                         }
842                     }
843                 } else {
844                     SymbianNetworkConfigurationPrivate *symbianConfig =
845                         toSymbianConfig(privateConfiguration(config));
846 
847                     if (symbianConfig->numericIdentifier() == apId)
848                         configFound = true;
849                 }
850                 if (configFound) {
851                     TUint tData;
852                     iConnectionMonitor.GetUintAttribute(connectionId, 0, dataType, tData, status );
853                     User::WaitForRequest(status);
854                     if (status.Int() == KErrNone) {
855                     transferredData += tData;
856                     }
857                 }
858             }
859         }
860     }
861 
862     return transferredData;
863 }
864 
activeTime() const865 quint64 QNetworkSessionPrivateImpl::activeTime() const
866 {
867     if (!isOpen || startTime.isNull()) {
868         return 0;
869     }
870     return startTime.secsTo(QDateTime::currentDateTime());
871 }
872 
activeIapId(TUint32 & iapId) const873 bool QNetworkSessionPrivateImpl::activeIapId(TUint32& iapId) const
874 {
875     if (!iConnection.SubSessionHandle())
876         return false;
877     _LIT(KSetting, "IAP\\Id");
878     TInt err = iConnection.GetIntSetting(KSetting, iapId);
879     if (err != KErrNone)
880         return false;
881 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
882     // Check if this is an Easy WLAN configuration. On Symbian^3 RConnection may report
883     // the used configuration as 'EasyWLAN' IAP ID if someone has just opened the configuration
884     // from WLAN Scan dialog, _and_ that connection is still up. We need to find the
885     // real matching configuration. Function alters the Easy WLAN ID to real IAP ID (only if
886     // easy WLAN):
887     easyWlanTrueIapId(iapId);
888 #endif
889     return true;
890 }
891 
activeConfiguration(TUint32 iapId) const892 QNetworkConfiguration QNetworkSessionPrivateImpl::activeConfiguration(TUint32 iapId) const
893 {
894     if (iapId == 0) {
895         bool ok = activeIapId(iapId);
896         if (!ok)
897             return QNetworkConfiguration();
898     }
899 
900 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
901     if (publicConfig.type() == QNetworkConfiguration::ServiceNetwork) {
902         // Try to search IAP from the used SNAP using IAP Id
903         QList<QNetworkConfiguration> children = publicConfig.children();
904         for (int i=0; i < children.count(); i++) {
905             SymbianNetworkConfigurationPrivate *childConfig =
906                 toSymbianConfig(privateConfiguration(children[i]));
907 
908             if (childConfig->numericIdentifier() == iapId)
909                 return children[i];
910         }
911 
912         // Given IAP Id was not found from the used SNAP
913         // => Try to search matching IAP using mappingName
914         //    mappingName contains:
915         //      1. "Access point name" for "Packet data" Bearer
916         //      2. "WLAN network name" (= SSID) for "Wireless LAN" Bearer
917         //      3. "Dial-up number" for "Data call Bearer" or "High Speed (GSM)" Bearer
918         //    <=> Note: It's possible that in this case reported IAP is
919         //              clone of the one of the IAPs of the used SNAP
920         //              => If mappingName matches, clone has been found
921         QNetworkConfiguration pt = QNetworkConfigurationManager().configurationFromIdentifier(
922                 QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(iapId)));
923 
924         SymbianNetworkConfigurationPrivate *symbianConfig =
925             toSymbianConfig(privateConfiguration(pt));
926         if (symbianConfig) {
927             for (int i=0; i < children.count(); i++) {
928                 SymbianNetworkConfigurationPrivate *childConfig =
929                     toSymbianConfig(privateConfiguration(children[i]));
930 
931                 if (childConfig->configMappingName() == symbianConfig->configMappingName()) {
932                     return children[i];
933                 }
934             }
935         } else {
936 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
937             // On Symbian^3 (only, not earlier or Symbian^4) if the SNAP was not reachable, it
938             // triggers user choice type of activity (EasyWLAN). As a result, a new IAP may be
939             // created, and hence if was not found yet. Therefore update configurations and see if
940             // there is something new.
941 
942             // 1. Update knowledge from the databases.
943             if (thread() != engine->thread())
944                 QMetaObject::invokeMethod(engine, "requestUpdate", Qt::BlockingQueuedConnection);
945             else
946                 engine->requestUpdate();
947 
948             // 2. Check if new configuration was created during connection creation
949             QList<QString> knownConfigs = engine->accessPointConfigurationIdentifiers();
950 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
951             qDebug() << "QNS this : " << QString::number((uint)this) << " - "
952                     << "opened configuration was not known beforehand, looking for new.";
953 #endif
954             if (knownConfigs.count() > iKnownConfigsBeforeConnectionStart.count()) {
955                 // Configuration count increased => new configuration was created
956                 // => Search new, created configuration
957                 QString newIapId;
958                 for (int i=0; i < iKnownConfigsBeforeConnectionStart.count(); i++) {
959                     if (knownConfigs[i] != iKnownConfigsBeforeConnectionStart[i]) {
960                         newIapId = knownConfigs[i];
961                         break;
962                     }
963                 }
964                 if (newIapId.isEmpty()) {
965                     newIapId = knownConfigs[knownConfigs.count()-1];
966                 }
967                 pt = QNetworkConfigurationManager().configurationFromIdentifier(newIapId);
968                 if (pt.isValid()) {
969 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
970                     qDebug() << "QNS this : " << QString::number((uint)this) << " - "
971                             << "new configuration was found, name, IAP id: " << pt.name() << pt.identifier();
972 #endif
973                     return pt;
974                 }
975             }
976 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
977             qDebug() << "QNS this : " << QString::number((uint)this) << " - "
978                     << "configuration was not found, returning invalid.";
979 #endif
980 #endif
981             // Given IAP Id was not found from known IAPs array
982             return QNetworkConfiguration();
983         }
984         // Matching IAP was not found from used SNAP
985         // => IAP from another SNAP is returned
986         //    (Note: Returned IAP matches to given IAP Id)
987         return pt;
988     }
989 #endif
990     if (publicConfig.type() == QNetworkConfiguration::UserChoice) {
991         if (engine) {
992             QNetworkConfiguration pt = QNetworkConfigurationManager().configurationFromIdentifier(
993                     QT_BEARERMGMT_CONFIGURATION_IAP_PREFIX+QString::number(qHash(iapId)));
994             // Try to found User Selected IAP from known IAPs (accessPointConfigurations)
995             if (pt.isValid()) {
996                 return pt;
997             } else {
998                 // Check if new (WLAN) IAP was created in IAP/SNAP dialog
999                 // 1. Sync internal configurations array to commsdb first
1000                 if (thread() != engine->thread()) {
1001                     QMetaObject::invokeMethod(engine, "requestUpdate",
1002                                               Qt::BlockingQueuedConnection);
1003                 } else {
1004                     engine->requestUpdate();
1005                 }
1006                 // 2. Check if new configuration was created during connection creation
1007                 QStringList knownConfigs = engine->accessPointConfigurationIdentifiers();
1008                 if (knownConfigs.count() > iKnownConfigsBeforeConnectionStart.count()) {
1009                     // Configuration count increased => new configuration was created
1010                     // => Search new, created configuration
1011                     QString newIapId;
1012                     for (int i=0; i < iKnownConfigsBeforeConnectionStart.count(); i++) {
1013                         if (knownConfigs[i] != iKnownConfigsBeforeConnectionStart[i]) {
1014                             newIapId = knownConfigs[i];
1015                             break;
1016                         }
1017                     }
1018                     if (newIapId.isEmpty()) {
1019                         newIapId = knownConfigs[knownConfigs.count()-1];
1020                     }
1021                     pt = QNetworkConfigurationManager().configurationFromIdentifier(newIapId);
1022                     if (pt.isValid())
1023                         return pt;
1024                 }
1025             }
1026         }
1027         return QNetworkConfiguration();
1028     }
1029 
1030     return publicConfig;
1031 }
1032 
updateCurrentIap(TUint32 iapId)1033 void QNetworkSessionPrivateImpl::updateCurrentIap(TUint32 iapId)
1034 {
1035     if (iCurrentIap == iapId)
1036         return;
1037 
1038     if (iCurrentIap != 0)
1039         QSymbianSocketManager::instance().removeActiveConnection(iCurrentIap);
1040 
1041     iCurrentIap = iapId;
1042 
1043     if (iCurrentIap != 0)
1044         QSymbianSocketManager::instance().addActiveConnection(iCurrentIap);
1045 }
1046 
ConnectionStartComplete(TInt statusCode)1047 void QNetworkSessionPrivateImpl::ConnectionStartComplete(TInt statusCode)
1048 {
1049 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1050     qDebug() << "QNS this : " << QString::number((uint)this) << " - "
1051             << "RConnection::Start completed with status code: " << statusCode;
1052 #endif
1053     // ConnectionStarter *ipConnectionStarter will delete itself at the end of RunL
1054     ipConnectionStarter = 0;
1055 
1056     switch (statusCode) {
1057         case KErrNone: // Connection created successfully
1058             {
1059             TInt error = KErrNone;
1060             TUint32 iapId;
1061             QNetworkConfiguration newActiveConfig;
1062             if (activeIapId(iapId))
1063                 newActiveConfig = activeConfiguration(iapId);
1064             if (!newActiveConfig.isValid()) {
1065                 // RConnection startup was successful but no configuration
1066                 // was found. That indicates that user has chosen to create a
1067                 // new WLAN configuration (from scan results), but that new
1068                 // configuration does not have access to Internet (Internet
1069                 // Connectivity Test, ICT, failed).
1070                 error = KErrGeneral;
1071             } else {
1072                 QSymbianSocketManager::instance().setDefaultConnection(&iConnection);
1073                 updateCurrentIap(iapId);
1074             }
1075             if (error != KErrNone) {
1076                 isOpen = false;
1077                 isOpening = false;
1078                 iError = QNetworkSession::UnknownSessionError;
1079                 closeHandles();
1080                 QT_TRYCATCH_LEAVING(emit QNetworkSessionPrivate::error(iError));
1081                 if (!newActiveConfig.isValid()) {
1082                     // No valid configuration, bail out.
1083                     // Status updates from QNCM won't be received correctly
1084                     // because there is no configuration to associate them with so transit here.
1085                     newState(QNetworkSession::Closing);
1086                     newState(QNetworkSession::Disconnected);
1087                 }
1088                 QT_TRYCATCH_LEAVING(syncStateWithInterface());
1089                 return;
1090             }
1091 
1092 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
1093             if (publicConfig.type() == QNetworkConfiguration::ServiceNetwork) {
1094                 // Activate ALR monitoring
1095                 iMobility = CActiveCommsMobilityApiExt::NewL(iConnection, *this);
1096             }
1097 #endif
1098 
1099             isOpen = true;
1100             isOpening = false;
1101             activeConfig = newActiveConfig;
1102 
1103             SymbianNetworkConfigurationPrivate *symbianConfig =
1104                 toSymbianConfig(privateConfiguration(activeConfig));
1105 
1106 #ifndef QT_NO_NETWORKINTERFACE
1107             activeInterface = interface(symbianConfig->numericIdentifier());
1108 #endif
1109             if (publicConfig.type() == QNetworkConfiguration::UserChoice) {
1110                 serviceConfig = QNetworkConfigurationManager()
1111                     .configurationFromIdentifier(activeConfig.identifier());
1112             }
1113 
1114             startTime = QDateTime::currentDateTime();
1115 
1116             QT_TRYCATCH_LEAVING({
1117                     newState(QNetworkSession::Connected);
1118                     emit quitPendingWaitsForOpened();
1119                 });
1120             }
1121             break;
1122         case KErrNotFound: // Connection failed
1123             isOpen = false;
1124             isOpening = false;
1125             activeConfig = QNetworkConfiguration();
1126             serviceConfig = QNetworkConfiguration();
1127             iError = QNetworkSession::InvalidConfigurationError;
1128             closeHandles();
1129             QT_TRYCATCH_LEAVING(emit QNetworkSessionPrivate::error(iError));
1130             QT_TRYCATCH_LEAVING(syncStateWithInterface());
1131             break;
1132         case KErrCancel: // Connection attempt cancelled
1133         case KErrAlreadyExists: // Connection already exists
1134         default:
1135             isOpen = false;
1136             isOpening = false;
1137             activeConfig = QNetworkConfiguration();
1138             serviceConfig = QNetworkConfiguration();
1139             if (statusCode == KErrCancel) {
1140                 iError = QNetworkSession::SessionAbortedError;
1141             } else if (publicConfig.state() == QNetworkConfiguration::Undefined ||
1142                 publicConfig.state() == QNetworkConfiguration::Defined) {
1143                 iError = QNetworkSession::InvalidConfigurationError;
1144             } else {
1145                 iError = QNetworkSession::UnknownSessionError;
1146             }
1147             closeHandles();
1148             QT_TRYCATCH_LEAVING(emit QNetworkSessionPrivate::error(iError));
1149             QT_TRYCATCH_LEAVING(syncStateWithInterface());
1150             break;
1151     }
1152 }
1153 
1154 // Enters newState if feasible according to current state.
1155 // AccessPointId may be given as parameter. If it is zero, state-change is assumed to
1156 // concern this session's configuration. If non-zero, the configuration is looked up
1157 // and checked if it matches the configuration this session is based on.
newState(QNetworkSession::State newState,TUint accessPointId)1158 bool QNetworkSessionPrivateImpl::newState(QNetworkSession::State newState, TUint accessPointId)
1159 {
1160 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1161     qDebug() << "QNS this : " << QString::number((uint)this) << " - "
1162              << "NEW STATE, IAP ID : " << QString::number(accessPointId) << " , newState : " << QString::number(newState);
1163 #endif
1164     // Make sure that activeConfig is always updated when SNAP is signaled to be
1165     // connected.
1166     if (isOpen && publicConfig.type() == QNetworkConfiguration::ServiceNetwork &&
1167         newState == QNetworkSession::Connected) {
1168         activeConfig = activeConfiguration(accessPointId);
1169 
1170 #ifndef QT_NO_NETWORKINTERFACE
1171         SymbianNetworkConfigurationPrivate *symbianConfig =
1172             toSymbianConfig(privateConfiguration(activeConfig));
1173 
1174         activeInterface = interface(symbianConfig->numericIdentifier());
1175 #endif
1176 
1177 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
1178         QSymbianSocketManager::instance().setDefaultConnection(&iConnection);
1179 #endif
1180     }
1181 
1182     // Make sure that same state is not signaled twice in a row.
1183     if (state == newState) {
1184         return true;
1185     }
1186 
1187     // Make sure that Connecting state does not overwrite Roaming state
1188     if (state == QNetworkSession::Roaming && newState == QNetworkSession::Connecting) {
1189         return false;
1190     }
1191 
1192     // Make sure that Connected state is not reported when Connection is
1193     // already Closing.
1194     // Note: Stopping connection results sometimes KLinkLayerOpen
1195     //       to be reported first (just before KLinkLayerClosed).
1196     if (state == QNetworkSession::Closing && newState == QNetworkSession::Connected) {
1197         return false;
1198     }
1199 
1200     // Make sure that some lagging 'closing' state-changes do not overwrite
1201     // if we are already disconnected or closed.
1202     if (state == QNetworkSession::Disconnected && newState == QNetworkSession::Closing) {
1203         return false;
1204     }
1205 
1206     // Make sure that some lagging 'connecting' state-changes do not overwrite
1207     // if we are already connected (may righfully still happen with roaming though).
1208     if (state == QNetworkSession::Connected && newState == QNetworkSession::Connecting) {
1209         return false;
1210     }
1211 
1212     bool emitSessionClosed = false;
1213 
1214     // If we abruptly go down and user hasn't closed the session, we've been aborted.
1215     // Note that session may be in 'closing' state and not in 'connected' state, because
1216     // depending on platform the platform may report KConfigDaemonStartingDeregistration
1217     // event before KLinkLayerClosed
1218     if ((isOpen && state == QNetworkSession::Connected && newState == QNetworkSession::Disconnected) ||
1219         (isOpen && !iClosedByUser && newState == QNetworkSession::Disconnected)) {
1220         // Active & Connected state should change directly to Disconnected state
1221         // only when something forces connection to close (eg. when another
1222         // application or session stops connection or when network drops
1223         // unexpectedly).
1224         isOpen = false;
1225         isOpening = false;
1226         activeConfig = QNetworkConfiguration();
1227         serviceConfig = QNetworkConfiguration();
1228         iError = QNetworkSession::SessionAbortedError;
1229         closeHandles();
1230         emit QNetworkSessionPrivate::error(iError);
1231         // Start handling IAP state change signals from QNetworkConfigurationManagerPrivate
1232         iHandleStateNotificationsFromManager = true;
1233         emitSessionClosed = true; // Emit SessionClosed after state change has been reported
1234     }
1235 
1236     bool retVal = false;
1237     if (accessPointId == 0) {
1238         state = newState;
1239 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1240         qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed A to: " << state;
1241 #endif
1242         emit stateChanged(state);
1243         retVal = true;
1244     } else {
1245         if (publicConfig.type() == QNetworkConfiguration::InternetAccessPoint) {
1246             SymbianNetworkConfigurationPrivate *symbianConfig =
1247                 toSymbianConfig(privateConfiguration(publicConfig));
1248 
1249             if (symbianConfig->numericIdentifier() == accessPointId) {
1250                 state = newState;
1251 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1252                 qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed B to: " << state;
1253 #endif
1254                 emit stateChanged(state);
1255                 retVal = true;
1256             }
1257         } else if (publicConfig.type() == QNetworkConfiguration::UserChoice && isOpen) {
1258             SymbianNetworkConfigurationPrivate *symbianConfig =
1259                 toSymbianConfig(privateConfiguration(activeConfig));
1260 
1261             if (symbianConfig->numericIdentifier() == accessPointId) {
1262                 state = newState;
1263 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1264                 qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed C to: " << state;
1265 #endif
1266                 emit stateChanged(state);
1267                 retVal = true;
1268             }
1269         } else if (publicConfig.type() == QNetworkConfiguration::ServiceNetwork) {
1270             QList<QNetworkConfiguration> subConfigurations = publicConfig.children();
1271             for (int i = 0; i < subConfigurations.count(); i++) {
1272                 SymbianNetworkConfigurationPrivate *symbianConfig =
1273                     toSymbianConfig(privateConfiguration(subConfigurations[i]));
1274 
1275                 if (symbianConfig->numericIdentifier() == accessPointId) {
1276                     if (newState != QNetworkSession::Disconnected) {
1277                         state = newState;
1278 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1279                         qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed D  to: " << state;
1280 #endif
1281                         emit stateChanged(state);
1282                         retVal = true;
1283                     } else {
1284                         QNetworkConfiguration config = bestConfigFromSNAP(publicConfig);
1285                         if ((config.state() == QNetworkConfiguration::Defined) ||
1286                             (config.state() == QNetworkConfiguration::Discovered)) {
1287                             activeConfig = QNetworkConfiguration();
1288                             state = newState;
1289 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1290                             qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed E  to: " << state;
1291 #endif
1292                             emit stateChanged(state);
1293                             retVal = true;
1294                         } else if (config.state() == QNetworkConfiguration::Active) {
1295                             // Connection to used IAP was closed, but there is another
1296                             // IAP that's active in used SNAP
1297                             // => Change state back to Connected
1298                             state =  QNetworkSession::Connected;
1299                             emit stateChanged(state);
1300                             retVal = true;
1301 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1302                             qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed F  to: " << state;
1303 #endif
1304                         }
1305                     }
1306                 }
1307             }
1308 #ifdef SNAP_FUNCTIONALITY_AVAILABLE
1309             // If the retVal is not true here, it means that the status update may apply to an IAP outside of
1310             // SNAP (session is based on SNAP but follows IAP outside of it), which may occur on Symbian^3 EasyWlan.
1311             if (retVal == false && activeConfig.isValid() &&
1312                 toSymbianConfig(privateConfiguration(activeConfig))->numericIdentifier() == accessPointId) {
1313 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1314                 qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "===> EMIT State changed G  to: " << state;
1315 #endif
1316                 if (newState == QNetworkSession::Disconnected) {
1317                     activeConfig = QNetworkConfiguration();
1318                 }
1319                 state = newState;
1320                 emit stateChanged(state);
1321                 retVal = true;
1322             }
1323 #endif
1324         }
1325     }
1326     if (emitSessionClosed) {
1327         emit closed();
1328     }
1329     if (state == QNetworkSession::Disconnected) {
1330         // Just in case clear activeConfiguration.
1331         activeConfig = QNetworkConfiguration();
1332     }
1333     return retVal;
1334 }
1335 
handleSymbianConnectionStatusChange(TInt aConnectionStatus,TInt aError,TUint accessPointId)1336 void QNetworkSessionPrivateImpl::handleSymbianConnectionStatusChange(TInt aConnectionStatus,
1337                                                                  TInt aError,
1338                                                                  TUint accessPointId)
1339 {
1340 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1341     qDebug() << "QNS this : " << QString::number((uint)this) << " - " << QString::number(accessPointId) << " , status : " << QString::number(aConnectionStatus);
1342 #endif
1343     switch (aConnectionStatus)
1344         {
1345         // Connection unitialised
1346         case KConnectionUninitialised:
1347             break;
1348 
1349         // Starting connetion selection
1350         case KStartingSelection:
1351             break;
1352 
1353         // Selection finished
1354         case KFinishedSelection:
1355             if (aError == KErrNone)
1356                 {
1357                 break;
1358                 }
1359             else
1360                 {
1361                 // The user pressed e.g. "Cancel" and did not select an IAP
1362                 newState(QNetworkSession::Disconnected,accessPointId);
1363                 }
1364             break;
1365 
1366         // Connection failure
1367         case KConnectionFailure:
1368             newState(QNetworkSession::NotAvailable);
1369             break;
1370 
1371         // Prepearing connection (e.g. dialing)
1372         case KPsdStartingConfiguration:
1373         case KPsdFinishedConfiguration:
1374         case KCsdFinishedDialling:
1375         case KCsdScanningScript:
1376         case KCsdGettingLoginInfo:
1377         case KCsdGotLoginInfo:
1378             break;
1379 
1380         case KConfigDaemonStartingRegistration:
1381         // Creating connection (e.g. GPRS activation)
1382         case KCsdStartingConnect:
1383         case KCsdFinishedConnect:
1384             newState(QNetworkSession::Connecting,accessPointId);
1385             break;
1386 
1387         // Starting log in
1388         case KCsdStartingLogIn:
1389             break;
1390 
1391         // Finished login
1392         case KCsdFinishedLogIn:
1393             break;
1394 
1395         // Connection open
1396         case KConnectionOpen:
1397             break;
1398 
1399         case KLinkLayerOpen:
1400             newState(QNetworkSession::Connected,accessPointId);
1401             break;
1402 
1403         // Connection blocked or suspended
1404         case KDataTransferTemporarilyBlocked:
1405             break;
1406 
1407         case KConfigDaemonStartingDeregistration:
1408         // Hangup or GRPS deactivation
1409         case KConnectionStartingClose:
1410             newState(QNetworkSession::Closing,accessPointId);
1411             break;
1412 
1413         // Connection stopped
1414         case KConfigDaemonFinishedDeregistrationStop: //this comes if this is the last session, instead of KLinkLayerClosed
1415         case KConfigDaemonFinishedDeregistrationPreserve:
1416         // Connection closed
1417         case KConnectionClosed:
1418         case KLinkLayerClosed:
1419             newState(QNetworkSession::Disconnected,accessPointId);
1420             // Report manager about this to make sure this event
1421             // is received by all interseted parties (mediated by
1422             // manager because it does always receive all events from
1423             // connection monitor).
1424 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1425             qDebug() << "QNS this : " << QString::number((uint)this) << " - " << "reporting disconnection to manager.";
1426 #endif
1427             if (publicConfig.isValid()) {
1428                 SymbianNetworkConfigurationPrivate *symbianConfig =
1429                     toSymbianConfig(privateConfiguration(publicConfig));
1430 
1431                 engine->configurationStateChangeReport(symbianConfig->numericIdentifier(),
1432                                                        QNetworkSession::Disconnected);
1433             }
1434             break;
1435         // Unhandled state
1436         default:
1437             break;
1438         }
1439 }
1440 
1441 #if defined(SNAP_FUNCTIONALITY_AVAILABLE)
easyWlanTrueIapId(TUint32 & trueIapId) const1442 bool QNetworkSessionPrivateImpl::easyWlanTrueIapId(TUint32 &trueIapId) const
1443 {
1444     RCmManager iCmManager;
1445     TRAPD(err, iCmManager.OpenL());
1446     if (err != KErrNone)
1447         return false;
1448 
1449     // Check if this is easy wlan id in the first place
1450     if (trueIapId != iCmManager.EasyWlanIdL()) {
1451         iCmManager.Close();
1452         return false;
1453     }
1454 
1455     iCmManager.Close();
1456 
1457     // Loop through all connections that connection monitor is aware
1458     // and check for IAPs based on easy WLAN
1459     if (!iConnectionMonitor.Handle())
1460         return false;
1461     TRequestStatus status;
1462     TUint connectionCount;
1463     iConnectionMonitor.GetConnectionCount(connectionCount, status);
1464     User::WaitForRequest(status);
1465     TUint connectionId;
1466     TUint subConnectionCount;
1467     TUint apId;
1468     if (status.Int() == KErrNone) {
1469         for (TUint i = 1; i <= connectionCount; i++) {
1470             iConnectionMonitor.GetConnectionInfo(i, connectionId, subConnectionCount);
1471             iConnectionMonitor.GetUintAttribute(connectionId, subConnectionCount,
1472                                                 KIAPId, apId, status);
1473             User::WaitForRequest(status);
1474             if (apId == trueIapId) {
1475                 TBuf<50>easyWlanNetworkName;
1476                 iConnectionMonitor.GetStringAttribute(connectionId, 0, KNetworkName,
1477                                                       easyWlanNetworkName, status);
1478                 User::WaitForRequest(status);
1479                 if (status.Int() != KErrNone)
1480                     continue;
1481 
1482                 const QString ssid = QString::fromUtf16(easyWlanNetworkName.Ptr(),
1483                                                             easyWlanNetworkName.Length());
1484 
1485                 QNetworkConfigurationPrivatePointer ptr = engine->configurationFromSsid(ssid);
1486                 if (ptr) {
1487 #ifdef QT_BEARERMGMT_SYMBIAN_DEBUG
1488                     qDebug() << "QNCM easyWlanTrueIapId(), found true IAP ID: "
1489                              << toSymbianConfig(ptr)->numericIdentifier();
1490 #endif
1491                     trueIapId = toSymbianConfig(ptr)->numericIdentifier();
1492                     return true;
1493                 }
1494             }
1495         }
1496     }
1497     return false;
1498 }
1499 #endif
1500 
nativeSession()1501 RConnection* QNetworkSessionPrivateImpl::nativeSession()
1502 {
1503     return &iConnection;
1504 }
1505 
ConnectionProgressNotifier(QNetworkSessionPrivateImpl & owner,RConnection & connection)1506 ConnectionProgressNotifier::ConnectionProgressNotifier(QNetworkSessionPrivateImpl& owner, RConnection& connection)
1507     : CActive(CActive::EPriorityUserInput), iOwner(owner), iConnection(connection)
1508 {
1509     CActiveScheduler::Add(this);
1510 }
1511 
~ConnectionProgressNotifier()1512 ConnectionProgressNotifier::~ConnectionProgressNotifier()
1513 {
1514     Cancel();
1515 }
1516 
StartNotifications()1517 void ConnectionProgressNotifier::StartNotifications()
1518 {
1519     if (!IsActive()) {
1520         SetActive();
1521         iConnection.ProgressNotification(iProgress, iStatus);
1522     }
1523 }
1524 
StopNotifications()1525 void ConnectionProgressNotifier::StopNotifications()
1526 {
1527     Cancel();
1528 }
1529 
DoCancel()1530 void ConnectionProgressNotifier::DoCancel()
1531 {
1532     iConnection.CancelProgressNotification();
1533 }
1534 
RunL()1535 void ConnectionProgressNotifier::RunL()
1536 {
1537     if (iStatus == KErrNone) {
1538         SetActive();
1539         iConnection.ProgressNotification(iProgress, iStatus);
1540         // warning, this object may be deleted in the callback - do nothing after handleSymbianConnectionStatusChange
1541         QT_TRYCATCH_LEAVING(iOwner.handleSymbianConnectionStatusChange(iProgress().iStage, iProgress().iError));
1542     }
1543 }
1544 
ConnectionStarter(QNetworkSessionPrivateImpl & owner,RConnection & connection)1545 ConnectionStarter::ConnectionStarter(QNetworkSessionPrivateImpl &owner, RConnection &connection)
1546     : CActive(CActive::EPriorityUserInput), iOwner(owner), iConnection(connection)
1547 {
1548     CActiveScheduler::Add(this);
1549 }
1550 
~ConnectionStarter()1551 ConnectionStarter::~ConnectionStarter()
1552 {
1553     Cancel();
1554 }
1555 
Start()1556 void ConnectionStarter::Start()
1557 {
1558     if (!IsActive()) {
1559         iConnection.Start(iStatus);
1560         SetActive();
1561     }
1562 }
1563 
Start(TConnPref & pref)1564 void ConnectionStarter::Start(TConnPref &pref)
1565 {
1566     if (!IsActive()) {
1567         iConnection.Start(pref, iStatus);
1568         SetActive();
1569     }
1570 }
1571 
RunL()1572 void ConnectionStarter::RunL()
1573 {
1574     iOwner.ConnectionStartComplete(iStatus.Int());
1575     delete this;
1576 }
1577 
RunError(TInt err)1578 TInt ConnectionStarter::RunError(TInt err)
1579 {
1580     qWarning() << "ConnectionStarter::RunError" << err;
1581     // there must have been a leave from iOwner.ConnectionStartComplete, in which case "delete this" in RunL was missed.
1582     delete this;
1583     return KErrNone;
1584 }
1585 
DoCancel()1586 void ConnectionStarter::DoCancel()
1587 {
1588     iConnection.Close();
1589 }
1590 
1591 QT_END_NAMESPACE
1592 
1593 #endif //QT_NO_BEARERMANAGEMENT
1594 
1595