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