examples/SFExamples/RecipeEx/src/MobilityEngine.cpp

00001 // Symbian Foundation Example Code
00002 // 
00003 // This software is in the public domain. No copyright is claimed, and you 
00004 // may use it for any purpose without license from the Symbian Foundation.
00005 // No warranty for any purpose is expressed or implied by the authors or
00006 // the Symbian Foundation. 
00007 
00008 
00009 #include <nifman.h>  // KConnDisableTimers
00010 #include <eikenv.h>
00011 #include <aknglobalnote.h> 
00012 #include <es_enum.h>
00013 #include <TextResolver.h>
00014 #include <aknquerydialog.h> 
00015 #include <txtetext.h>  // CEditableText
00016 #include <cmapplicationsettingsui.h>
00017 
00018 #include "MobilityEngine.h"
00019 #include "LogContainer.h"
00020 
00021 // Constants
00022 _LIT(KInitialText, "Select Options->Connect to start");
00023 _LIT(KStarting, "Starting connection...");
00024 _LIT(KSuccessful, "Successful connection.");
00025 _LIT(KRegisteredWithMobilityExt, "Registered with Mobility Ext");
00026 _LIT(KResolvingUrlFmt,"Resolving URL: %S");
00027 _LIT(KSocketConnecting,"Socket connecting...");
00028 _LIT(KSocketConnected,"Socket connected.");
00029 _LIT(KDisconnected,"Disconnected.");
00030 _LIT(KPreferredCarrierAvailableFmt,"PreferredCarrierAvailable: #%u->#%u, upgrade: %S, seamless: %S");
00031 _LIT(KMigrating, "Migrating...");
00032 _LIT(KNewCarrierActive, "New Carrier Active");
00033 _LIT(KErrorFmt,"Error: %S");
00034 _LIT(KAddressFmt,"Address: %S:%u");
00035 _LIT(KFallBackToPreviousCarrier,"Falling back to previous carrier.");
00036 _LIT(KTrueStr,"true");
00037 _LIT(KFalseStr,"false");
00038 
00039 _LIT(KPanicCategory,"MobilityEngine");
00040 enum TPanicCodes
00041         {
00042         EPanicUnreachable = 0,
00043         EPanicBadAddressFamily = 1
00044         };
00045 
00046 _LIT(KDefaultHost,"www.google.com");
00047 
00048 
00049 // ================= MEMBER FUNCTIONS =======================
00050 
00052 CMobilityEngine::CMobilityEngine(CLogContainer* aLogView) :
00053         CActive(EPriorityStandard),  // Standard priority
00054         iLogView(aLogView)
00055         {
00056         }
00057 
00061 CMobilityEngine* CMobilityEngine::NewLC(CLogContainer* aLogView)
00062         {
00063         CMobilityEngine* self = new (ELeave) CMobilityEngine(aLogView);
00064         CleanupStack::PushL(self);
00065         self->ConstructL();
00066         return self;
00067         }
00068 
00072 CMobilityEngine* CMobilityEngine::NewL(CLogContainer* aLogView)
00073         {
00074         CMobilityEngine* self = CMobilityEngine::NewLC(aLogView);
00075         CleanupStack::Pop(self);
00076         return self;
00077         }
00078 
00080 void CMobilityEngine::ConstructL()
00081         {
00082         User::LeaveIfError(iSocketServ.Connect());
00083         User::LeaveIfError(iConnection.Open(iSocketServ));
00084         
00085         iTextResolver = CTextResolver::NewL();
00086         
00087         CActiveScheduler::Add(this); // Add to scheduler
00088         
00089         iHostAndPort = KDefaultHost().AllocL();
00090 
00091         iLogView->LogEntryL(KInitialText);
00092         }
00093 
00095 CMobilityEngine::~CMobilityEngine()
00096         {
00097         Disconnect();
00098         delete iTextResolver;
00099         iConnection.Close();
00100         iSocketServ.Close();
00101         delete iHostAndPort;
00102         }
00103 
00105 void CMobilityEngine::DoCancel()
00106         {
00107         switch(iState)
00108                 {
00109                 case EStartingConnection:
00110                         iConnection.Stop();
00111                         break;
00112                 case EResolvingAddress:
00113                         iResolver.Cancel();
00114                         break;
00115                 case ESocketConnecting:
00116                         iRoamingSocket.CancelConnect();
00117                         break;
00118                 case EAsyncDisconnect:
00119                         break;
00120                 default:
00121                         User::Panic(KPanicCategory,EPanicUnreachable);
00122                         break;
00123                 }
00124         }
00125 
00127 void CMobilityEngine::RunL()
00128         {
00129         if(iStatus!=KErrNone)
00130                 {
00131                 iLogView->LogEntryL(KErrorFmt,&iTextResolver->ResolveErrorString(iStatus.Int()));
00132                 if(iAcceptOnConnect)
00133                         {
00134                         iAcceptOnConnect = EFalse;
00135                         // failed to connect or resolve - close both socket and resolver
00136                         iRoamingSocket.Close();
00137                         iResolver.Close();
00138                         iMobility->NewCarrierRejected();
00139                         iLogView->LogEntryL(KFallBackToPreviousCarrier);
00140                         ConnectSocketL();
00141                         return;
00142                         }
00143                 Disconnect();
00144                 return;
00145                 }
00146     switch(iState)
00147         {
00148         case EStartingConnection: // Connection started
00149                         {
00150                         iLogView->LogEntryL(KSuccessful);
00151                         // Register for mobility API
00152                         iMobility = CActiveCommsMobilityApiExt::NewL(iConnection, *this);
00153                         iLogView->LogEntryL(KRegisteredWithMobilityExt);
00154                         ConnectSocketL();
00155                         break;
00156                         }
00157         case EResolvingAddress:
00158                 {
00159                 TNameRecord& record = iNameEntry();
00160                 if(record.iFlags&TNameRecord::EAlias)
00161                         {
00162                         iResolver.Next(iNameEntry,iStatus);
00163                         SetActive();
00164                         break;
00165                         }
00166                 iResolver.Close();
00167                         record.iAddr.SetPort(GetPort()); // HTTP
00168                         LogAddressL(record.iAddr);
00169                 iAddrResolved = ETrue;
00170                 ConnectSocketL();
00171                 break;
00172                 }
00173         case ESocketConnecting:
00174                 {
00175                 iState = ESocketConnected;
00176                 if(iAcceptOnConnect)
00177                         {
00178                         iAcceptOnConnect = EFalse;
00179                         iMobility->NewCarrierAccepted();
00180                         }
00181                 // the socket is now connected and available for use
00182                 iLogView->LogEntryL(KSocketConnected);
00183                 break;
00184                 }
00185         case EAsyncDisconnect:
00186                 Disconnect();
00187                 break;
00188                 default:
00189                         {
00190                         User::Panic(KPanicCategory,EPanicUnreachable);
00191                         break;
00192                         }
00193                 }
00194         }
00195 
00196 
00198 TInt CMobilityEngine::RunError(TInt aError)
00199         {
00200         TRAP_IGNORE(iLogView->LogEntryL(KErrorFmt,&iTextResolver->ResolveErrorString(aError)));
00201         Disconnect();
00202         return KErrNone;
00203         }
00204 
00206 void CMobilityEngine::ConnectL()
00207         {
00208         if(iState!=EIdle)
00209                 {
00210                 User::Leave(KErrInUse);
00211                 }
00212     
00213     TCmSettingSelection userSelection;
00214     
00215     CCmApplicationSettingsUi* settings = CCmApplicationSettingsUi::NewL();
00216     CleanupStack::PushL(settings);
00217     
00218     TUint listedItems = CMManager::EShowAlwaysAsk |
00219                         CMManager::EShowDefaultConnection |
00220                         CMManager::EShowDestinations |
00221                         CMManager::EShowConnectionMethods;
00222     
00223     TBearerFilterArray filter;
00224     
00225     TBool selected = settings->RunApplicationSettingsL(userSelection,
00226                                                        listedItems,
00227                                                        filter);
00228 
00229     CleanupStack::PopAndDestroy(settings);
00230 
00231     if (selected) {
00232         switch (userSelection.iResult)
00233             {
00234             case CMManager::EDestination:
00235                 {
00236                 TConnSnapPref prefs;
00237                 prefs.SetSnap(userSelection.iId);
00238         
00239                 iConnection.Start(prefs, iStatus);
00240                 break;
00241                 }
00242             case CMManager::EConnectionMethod:
00243                 {
00244                 TCommDbConnPref prefs;
00245                 prefs.SetIapId(userSelection.iId);
00246                 prefs.SetDialogPreference(ECommDbDialogPrefDoNotPrompt);
00247         
00248                 iConnection.Start(prefs, iStatus);
00249                 break;
00250                 }
00251             case CMManager::EDefaultConnection:
00252                 {
00253                 iConnection.Start(iStatus);
00254                 break;
00255                 }
00256             default: // EAlwaysAsk
00257                 {
00258                 TCommDbConnPref prefs;
00259                 prefs.SetDialogPreference(ECommDbDialogPrefPrompt);
00260         
00261                 iConnection.Start(prefs, iStatus);
00262                 }
00263             }
00264 
00265         iState = EStartingConnection;
00266         SetActive();
00267         iLogView->LogEntryL(KStarting);
00268         }
00269         }
00270 
00272 void CMobilityEngine::Disconnect()
00273         {
00274         Cancel();
00275         // see comments about RSocket::Close() in PreferredCarrierAvailable(...)
00276         iRoamingSocket.Close();
00277         iAddrResolved = EFalse;
00278         iResolver.Close();
00279         delete iMobility;
00280         iMobility = NULL;
00281         iConnection.Stop();
00282         iState = EIdle;
00283         TRAP_IGNORE(iLogView->LogEntryL(KDisconnected));
00284         }
00285 
00287 TBool CMobilityEngine::IsIdle()
00288         {
00289         return iState==EIdle;
00290         }
00291 
00300 void CMobilityEngine::PreferredCarrierAvailable(TAccessPointInfo aOldAPInfo,
00301                                TAccessPointInfo aNewAPInfo,
00302                                TBool aIsUpgrade,
00303                                TBool aIsSeamless)
00304         {
00305     TRAP_IGNORE(iLogView->LogEntryL(KPreferredCarrierAvailableFmt,
00306                 aOldAPInfo.AccessPoint(),aNewAPInfo.AccessPoint(),
00307                 &(aIsUpgrade ? KTrueStr() : KFalseStr()),&(aIsSeamless ? KTrueStr() : KFalseStr())));
00308 
00309         if (aIsSeamless)
00310         {
00311         // ...
00312         }
00313     else
00314         {
00315         Cancel();
00316 
00317         // RSocket::Close() will Shutdown(ENormal,.) and, under some conditions,
00318         // that may take a long time and make the UI non-responsive. It may be
00319         // a good idea to Shutdown(EImmediate,.) and resend the data after
00320         // reconnecting if the higher-level protocol allows, say, by requiring
00321         // message acknowledgement and allowing duplicates.
00322         iRoamingSocket.Close();
00323         iResolver.Close();
00324         iMobility->MigrateToPreferredCarrier();
00325         iState = EChangingCarrier;
00326         TRAP_IGNORE(iLogView->LogEntryL(KMigrating));
00327         }       
00328         }
00329 
00333 void CMobilityEngine::NewCarrierActive(TAccessPointInfo /*aNewAPInfo*/, TBool /*aIsSeamless*/)
00334         {
00335         TRAPD(err,HandleNewCarrierActiveL());
00336         if(err!=KErrNone)
00337                 {
00338                 iMobility->NewCarrierRejected();
00339                 TRAP_IGNORE(iLogView->LogEntryL(KErrorFmt,&iTextResolver->ResolveErrorString(err)));
00340                 // we can't disconnect immediatelly in a callback from *iMobility 
00341                 AsyncDisconnect();
00342                 }
00343         }
00344 
00348 void CMobilityEngine::Error(TInt aError)        
00349         {
00350         // KErrCancel is received from "delete iMobility;" i.e. from Disconnect()
00351         if(aError!=KErrCancel)
00352                 {
00353                 TRAP_IGNORE(iLogView->LogEntryL(KErrorFmt,&iTextResolver->ResolveErrorString(aError)));
00354                 // we can't disconnect immediatelly in a callback from *iMobility 
00355                 AsyncDisconnect();
00356                 }
00357         }
00358 
00362 void CMobilityEngine::HandleNewCarrierActiveL()
00363         {
00364     iLogView->LogEntryL(KNewCarrierActive);
00365     ConnectSocketL();
00366     iAcceptOnConnect = ETrue;
00367     }
00368 
00372 void CMobilityEngine::ConnectSocketL()
00373         {
00374         if(!iAddrResolved)
00375                 {
00376                 User::LeaveIfError(iResolver.Open(iSocketServ,KAfInet,KProtocolInetTcp,iConnection));
00377                 iResolver.GetByName(GetHost(),iNameEntry,iStatus);
00378                 iState = EResolvingAddress;
00379                 SetActive();
00380                 iLogView->LogEntryL(KResolvingUrlFmt,iHostAndPort);
00381                 return;
00382                 }
00383         User::LeaveIfError(iRoamingSocket.Open(iSocketServ,KAfInet,KSockStream,KProtocolInetTcp,iConnection));
00384         iRoamingSocket.Connect(iNameEntry().iAddr,iStatus);
00385         iState = ESocketConnecting;
00386         SetActive();
00387         iLogView->LogEntryL(KSocketConnecting);
00388         }
00389 
00393 void CMobilityEngine::AsyncDisconnect()
00394         {
00395         iState = EAsyncDisconnect;
00396         iStatus = KRequestPending;
00397         SetActive();
00398         TRequestStatus* status = &iStatus;
00399         User::RequestComplete(status,KErrNone);
00400         }
00401 
00405 void CMobilityEngine::LogAddressL(const TSockAddr& aAddr)
00406         {
00407         __ASSERT_DEBUG(aAddr.Family()==KAfInet,User::Panic(KPanicCategory,EPanicBadAddressFamily));
00408         TBuf<16> buf;
00409         static_cast<const TInetAddr&>(aAddr).Output(buf);
00410         iLogView->LogEntryL(KAddressFmt,&buf,aAddr.Port());
00411         }
00412 
00416 TPtrC CMobilityEngine::GetHost() const
00417         {
00418         TInt pos = iHostAndPort->Locate(':');
00419         if(pos==KErrNotFound)
00420                 {
00421                 return *iHostAndPort;
00422                 }
00423         return (pos==KErrNotFound) ? *iHostAndPort : iHostAndPort->Left(pos);
00424         }
00425 
00429 TUint CMobilityEngine::GetPort() const
00430         {
00431         TInt pos = iHostAndPort->Locate(':');
00432         if(pos==KErrNotFound)
00433                 {
00434                 return 80u; // default to HTTP
00435                 }
00436         TPtrC portStr = iHostAndPort->Right(pos+1);
00437         TLex lex(portStr);
00438         TUint port;
00439         if(lex.Val(port)!=KErrNone || port==0u)
00440                 {
00441                 port = 80u;
00442                 }
00443         return port;
00444         }
00445 
00446 // End of file

Generated by  doxygen 1.6.2