diff -r 000000000000 -r 164170e6151a wim/Scard/src/ScardConnector.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wim/Scard/src/ScardConnector.cpp Tue Jan 26 15:20:08 2010 +0200 @@ -0,0 +1,796 @@ +/* +* Copyright (c) 2003 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: A connection to a smart card +* +*/ + + + +// INCLUDE FILES +#include "ScardConnector.h" +#include "ScardConnectionRegistry.h" +#include "ScardAccessControl.h" +#include "ScardAccessControlRegistry.h" +#include "ScardConnectionTimer.h" +#include "ScardServer.h" +#include "ScardServerBase.h" +#include "WimTrace.h" + +#ifdef _DEBUG // for logging +#include "ScardLogs.h" +#include +#endif + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// TConnectionParameter::TConnectionParameter +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +TConnectionParameter::TConnectionParameter() + : iReaderName( NULL ), + iExcluded( NULL ), + iATRBytes( NULL ), + iAIDBytes( NULL ), + iNewCardOnly( EFalse ), + iNewReaderOnly( EFalse ) + { + _WIMTRACE(_L("WIM|Scard|TConnectionParameter::TConnectionParameter|Begin")); + } + +// ----------------------------------------------------------------------------- +// TConnection::TConnection +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +TConnection::TConnection() + : iCtrl( NULL ), + iReader( NULL ), + iReaderID( 0 ), + iSessionID( ENoSession ) + { + } + +// ----------------------------------------------------------------------------- +// Compare two connections +// ----------------------------------------------------------------------------- +// +TBool operator==( + const TConnection& aConnection1, + const TConnection& aConnection2 ) + { + if ( aConnection1.iReader == aConnection2.iReader && + aConnection1.iCtrl == aConnection2.iCtrl && + aConnection1.iSessionID == aConnection2.iSessionID && + aConnection1.iReaderID == aConnection2.iReaderID ) + { + return ETrue; + } + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CScardConnector::CScardConnector +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CScardConnector::CScardConnector( + CScardConnectionRegistry* aConnRegistry, + RThread& /*aClient*/ ) + : CScardSession(), + iConnectionRegistry( aConnRegistry ), + iState( EActive ) + { + _WIMTRACE(_L("WIM|Scard|CScardConnector::CScardConnector|Begin")); + } + + +// ----------------------------------------------------------------------------- +// CScardConnector::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CScardConnector::ConstructL( const RMessage2& aMessage ) + { + _WIMTRACE(_L("WIM|Scard|CScardConnector::ConstructL|Begin")); + iConnections = new( ELeave ) CArrayFixFlat( 1 ); + iStack = CScardEventStack::NewL( this ); + iClientMessage = new( ELeave ) RMessage2( aMessage ); + iState = EActive; + } + +// ----------------------------------------------------------------------------- +// CScardConnector::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CScardConnector* CScardConnector::NewL( + CScardConnectionRegistry* aConnRegistry, + RThread& aClient, + const RMessage2& aMessage ) + { + _WIMTRACE(_L("WIM|Scard|CScardConnector::NewL|Begin")); + CScardConnector* self = new( ELeave ) CScardConnector( aConnRegistry, + aClient ); + + CleanupStack::PushL( self ); + self->ConstructL( aMessage ); + CleanupStack::Pop( self ); + + return self; + } + + +// Destructor +CScardConnector::~CScardConnector() + { + _WIMTRACE(_L("WIM|Scard|CScardConnector::~CScardConnector|Begin")); + delete iTimer; + + // Delete members of the parameter block + delete iParameters.iReaderName; + delete iParameters.iExcluded; + delete iParameters.iATRBytes; + delete iParameters.iAIDBytes; + + // Detach from all connections + if ( iConnections->Count() ) + { + TConnection& connection = iConnections->At( 0 ); + // Detach and delete all connections + while ( iConnections->Count() ) + { + connection = iConnections->At( 0 ); + TInt err = KErrNone; + TRAP( err, connection.iCtrl->CancelTransmissionsL( + connection.iSessionID ) ); + connection.iCtrl->DetachSessionFromReader( connection.iSessionID ); + iConnections->Delete( 0 ); + } + } + + iConnections->Reset(); + delete iConnections; + delete iClientMessage; + delete iStack; + } + + +// ----------------------------------------------------------------------------- +// CScardConnector::ConnectToReaderL +// The connection is attempted and if it is successful +// the session requesting the connection is notified. If the connection +// can not yet be made, this object will remain waiting until all the +// required parameters are matched or a timeout occurs. +// ----------------------------------------------------------------------------- +// +void CScardConnector::ConnectToReaderL() + { + _WIMTRACE(_L("WIM|Scard|CScardConnector::ConnectToReaderL|Begin")); + // Get the limit factors + TRAPD( messageError, ReadLimitsL() ); + if ( messageError == KScErrBadArgument || + messageError == KScErrNotSupported ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardConnector::ConnectToReader: ReadLimits failed: %d \n" ), + messageError ); +#endif + iConnectionRegistry->ConnectDone( this, 0, messageError ); + iConnectionRegistry->RemoveConnector( this ); + delete this; + return; + } + else if ( messageError != KErrNone ) + { + User::Panic( _L( "Not enough free memory" ), KScPanicNoMemory ); + } + + // Now go to all the ACs you need and attach to them. If the reader + // is spesific, only one entry is required. Otherwise all are. + if ( iParameters.iReaderName ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardConnector::ConnectToReader Connecting to specific\ + reader: %S\n" ), + iParameters.iReaderName); +#endif + iOneReaderMode = ETrue; + // Is the chosen one supported ?? + if ( !( iConnectionRegistry->Server()->ReaderSupported( + *iParameters.iReaderName ) ) ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardConnector::ConnectToReader ReaderSupported\ + failed: \n" ) ); +#endif + iConnectionRegistry->ConnectDone( this, 0, KScErrUnknownReader ); + iConnectionRegistry->RemoveConnector( this ); + delete this; + return; + } + + // Grab the reader id (this shouldn't fail if the previous step + // went ok) + const TReaderID readerID = + iConnectionRegistry->Server()->ReaderID( *iParameters.iReaderName ); + + // If the reader can't be open when connecting, check it + if ( iParameters.iNewReaderOnly ) + { + if ( iConnectionRegistry->Server()->AccessRegistry()-> + ReaderHandlerLoaded( readerID ) ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardConnector::ConnectToReader Failed! Only new\ + readers allowed!\n" ) ); +#endif + iConnectionRegistry->ConnectDone( this, 0, + KScErrAlreadyExists ); + iConnectionRegistry->RemoveConnector( this ); + delete this; + return; + } + } + // Create the access controller and the reader + TBool opened( EFalse ); + TRAPD( readerError, opened = NewConnectionL( (*iClientMessage), + readerID ) ); + + // If the reader object could not be created, look no further, + // we're in trouble + if ( readerError != KErrNone ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardConnector::ConnectToReader NewConnectionL failed:\ + %d \n" ), readerError ); +#endif + iConnectionRegistry->ConnectDone( this, 0, readerError ); + iConnectionRegistry->RemoveConnector( this ); + delete this; + return; + } + + // The reader was created successfully. + + // 1. If the reader is open and if old cards are acceptable, + // check conditions + + if ( opened && !iParameters.iNewCardOnly ) + { + TScardATR atr; + iConnections->At( 0 ).iReader->GetATR( atr ); + const TBool ok( CheckConditions( iConnections->At( 0 ), &atr ) ); + if ( ok ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardConnector::ConnectToReader: Connection\ + succesfully established.\n" ) ); +#endif + ConnectionDone( iConnections->At( 0 ).iReaderID, KErrNone ); + return; + } +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardConnector::ConnectToReader CheckConditions\ + failed! \n" ) ); +#endif + } + + // 2. In other cases, just stay waiting for either the OpenReader + // or condition checking to go through or for a card event to occur. + return; + } + else + { + // Contact (almost) all readers, dead or alive... +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L("CScardConnector::ConnectToReader Connecting to all readers.\n") ); +#endif + CScardReaderRegistry* rr = + iConnectionRegistry->Server()->ReaderRegistry(); + + // First list the ones not yet opened + CArrayFixFlat* closelist = NULL; + closelist = new( ELeave ) CArrayFixFlat( 1 ); + CleanupStack::PushL( closelist ); + rr->ListClosedReadersL( closelist ); + + // then list the ones that are currently open (if necessary) + CArrayPtrFlat* openlist = NULL; + if ( !iParameters.iNewReaderOnly ) + { + openlist = new( ELeave ) CArrayPtrFlat( 1 ); + CleanupStack::PushL( openlist ); + rr->ListOpenReadersL( openlist ); + } + + TReaderID excludeID( -1 ); + if ( iParameters.iExcluded ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardConnector::ConnectToReader Get ID of excluded\ + reader.\n" ) ); +#endif + excludeID = iConnectionRegistry->Server()->ReaderID( + *iParameters.iExcluded ); + } + + // Attach to open readers + if ( !iParameters.iNewReaderOnly ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardConnector::ConnectToReader Attach to open readers" ) ); +#endif + for ( TInt i( 0 ); i < openlist->Count(); i++ ) + { + TReaderID next = openlist->At( i )->ReaderID(); + if ( next != excludeID ) + { + TBool open( EFalse ); + // Create the connection + TRAPD( readerError, + open = NewConnectionL( *iClientMessage, next ) ); + + // If the reader is already open and old cards are + // acceptable, check SC for the parameters. + + if ( !readerError && open && !iParameters.iNewCardOnly ) + { + const TInt index = iConnections->Count() - 1; + TScardATR atr; + iConnections->At( index ).iReader->GetATR( atr ); + TBool ok = CheckConditions( iConnections->At( + iConnections->Count() - 1 ), &atr ); + if ( ok ) + { + //delete openlist & closelist + CleanupStack::PopAndDestroy( 2 ); + ConnectionDone( next, KErrNone ); + return; + } + } + else if ( open && iParameters.iNewCardOnly ) + { + //delete openlist & closelist + CleanupStack::PopAndDestroy( 2 ); + // old cards are not acceptable, return error + ConnectionDone( next, KScErrNotFound ); + return; + } + } + } + CleanupStack::PopAndDestroy( openlist ); // delete openlist + } + + // attach to new readers + for ( TInt i( 0 ); i < closelist->Count(); i++ ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardConnector::ConnectToReader Attach to new readers" ) ); +#endif + TReaderID next = closelist->At( i ); + if ( next != excludeID ) + { + TInt err = KErrNone; + TRAP( err, NewConnectionL( (*iClientMessage), next ) ); + } + } + + CleanupStack::PopAndDestroy( closelist ); // delete closelist + } + + // If no readers could be contacted at all ( == the handlers could not be + // created) why continue? + if ( !iConnections->Count() ) + { + iState = EConnectionComplete; + ConnectionDone( 0, KScErrNotFound ); + return; + } + + if ( iConnections->Count() == 1 ) + { + iOneReaderMode = ETrue; + } + } + +// ----------------------------------------------------------------------------- +// CScardConnector::CardEvent +// Handle card event +// ----------------------------------------------------------------------------- +// +void CScardConnector::CardEvent( + const TScardServiceStatus aEvent, + const TScardATR& aATR, + const TReaderID& aReaderID ) + { + _WIMTRACE(_L("WIM|Scard|CScardConnector::CardEvent|Begin")); + // Card event handling is postponed if waiting for confirmation on + // a connection attempt + if ( iState == EWaitingForConfirm ) + { + iStack->QueueEvent( aReaderID, aEvent ); + return; + } + + // Find the connection handling the reader and see if it meets the + // criteria + TConnection* conn = NULL; + TRAPD( err, conn = &( FindReaderConnectionL( aReaderID ) ) ); + + // The connection must be found... + __ASSERT_ALWAYS( !err, User::Panic( _L( "Connector stack failure" ), + KScServerPanicInternalError ) ); + + // Now see what kind of event has occurred + switch ( aEvent ) + { + case EScardRemoved: // Flow through + case EReaderRemoved: + { + break; + } + case EScardInserted: + { + // A new card has been inserted, match it against the parameters + const TBool ok = CheckConditions( *conn, &aATR ); + if ( ok ) + { + ConnectionDone( conn->iReaderID, KErrNone ); + } + break; + } + default: + { + break; + } + } + } + +// ----------------------------------------------------------------------------- +// CScardConnector::ReadLimitsL +// Extract the limit parameters for this connection attempt +// ----------------------------------------------------------------------------- +// +void CScardConnector::ReadLimitsL() + { + _WIMTRACE(_L("WIM|Scard|CScardConnector::ReadLimitsL|Begin")); + TInt limiters = (*iClientMessage).Int0(); + + // Check out the limiting factors + + // The name of the reader is specified + if ( limiters & KExplicitReader ) + { + TInt desLen = (*iClientMessage).GetDesLength( 1 ); + HBufC* name = HBufC::NewL( desLen ); + CleanupStack::PushL( name ); + iParameters.iReaderName = new( ELeave ) TPtr( name->Des() ); + TRAPD( err, (*iClientMessage).ReadL( 1, *iParameters.iReaderName ) ); + if ( err != KErrNone ) + { + (*iClientMessage).Panic( _L( "SCardServer" ), + KScServerPanicBadDescriptor ); + User::Leave( KScErrBadArgument ); + } + CleanupStack::Pop( name ); + } + + // The specified must not be contacted + else if ( limiters & KExcludedReader ) + { + TInt desLen = (*iClientMessage).GetDesLength( 1 ); + HBufC* bytes = HBufC::NewL( desLen ); + CleanupStack::PushL( bytes ); + iParameters.iExcluded = new( ELeave ) TScardReaderName( bytes->Des() ); + TRAPD( err, (*iClientMessage).ReadL( 1, *iParameters.iExcluded ) ); + if ( err != KErrNone ) + { + (*iClientMessage).Panic( _L( "SCardServer" ), + KScServerPanicBadDescriptor ); + User::Leave( KScErrBadArgument ); + } + CleanupStack::Pop( bytes ); + } + + // Only newly inserted cards are acceptable + if ( limiters & KNewReadersOnly ) + { + iParameters.iNewReaderOnly = ETrue; + } + + // The ATR bytes of the card are spesified + if ( limiters & KATRSpesified ) + { + User::Leave( KScErrNotSupported ); + } + + // The spesified application must be located within the SC + else if ( limiters & KApplicationSpesified ) + { + User::Leave( KScErrNotSupported ); + } + + // Only newly inserted cards are acceptable + if ( limiters & KNewCardsOnly ) + { + iParameters.iNewCardOnly = ETrue; + } + + // Is there a time limit as well ? + TInt32 timeOut = reinterpret_cast< TInt32 >( iClientMessage->Ptr3() ); + + if ( timeOut ) + { + iTimer = CScardConnectionTimer::NewL( this, timeOut ); + } + } + +// ----------------------------------------------------------------------------- +// CScardConnector::CheckConditions +// Check if connection conditions are met. +// ----------------------------------------------------------------------------- +// +TBool CScardConnector::CheckConditions( + TConnection& /*aConnection*/, + const TScardATR* aATR ) + { + _WIMTRACE(_L("WIM|Scard|CScardConnector::CheckConditions|Begin")); + // If no parameters are spesified, announce a match + if ( !(iParameters.iATRBytes || iParameters.iAIDBytes ) ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardConnector::CheckConditions: no parameters\ + specified.\n" ) ); +#endif + + iState = EConnectionComplete; + return ETrue; + } + + // Now check the parameters one by one + + // ATR match ? + if ( iParameters.iATRBytes ) + { + if ( aATR ) + { + if ( *iParameters.iATRBytes == *aATR ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardConnector::CheckConditions: ATR match." ) ); +#endif + + iState = EConnectionComplete; + return ETrue; + } + } +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardConnector::CheckConditions: ATR mismatch!\n" ) ); +#endif + + return EFalse; + } + + // The card has the requiered application ? + else if ( iParameters.iAIDBytes ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardConnector::CheckConditions: AIDBytes not supported!\n" ) ); +#endif + return EFalse; + } + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CScardConnector::NewConnectionL +// Create new connection to the reader. +// ----------------------------------------------------------------------------- +// +TBool CScardConnector::NewConnectionL( + const RMessage2 aMessage, + const TReaderID aReaderID ) + { + _WIMTRACE(_L("WIM|Scard|CScardConnector::NewConnectionL|Begin")); + TConnection conn; + + conn.iReaderID = aReaderID; + + // Assign an access controller to this connection + conn.iCtrl = iConnectionRegistry->Server()->AccessRegistry()-> + AccessController( aReaderID ); + + // Make sure there was enough memory for the access controller + __ASSERT_MEMORY( !(conn.iCtrl) ); + + // attempt to create the connection's reader + TRAPD( readerError, conn.iReader = conn.iCtrl->AttachSessionToReaderL( + this, conn.iSessionID ) ); + + // If creating the reader succeeds, attempt to initialise the reader + if ( readerError == KErrNone ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardConnector::NewConnectionL: Reader (ID: %d)\ + succesfully created.\n" ), aReaderID ); +#endif + const TBool ok( conn.iCtrl->InitialiseReader( conn.iSessionID, + aMessage ) ); + iConnections->AppendL( conn ); + return ok; + } + +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardConnector::NewConnectionL: FAILED! error: %d\n" ), + readerError ); +#endif + + conn.iCtrl->DetachSessionFromReader( conn.iSessionID ); + User::Leave( readerError ); + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CScardConnector::FindReaderConnectionL +// Find connection for given reader. +// ----------------------------------------------------------------------------- +// +TConnection& CScardConnector::FindReaderConnectionL( + const TReaderID& aReaderID ) + { + _WIMTRACE(_L("WIM|Scard|CScardConnector::FindReaderConnectionL|Begin")); + TInt count = iConnections->Count(); + for ( TInt i( 0 ); i < count; i++ ) + { + if ( iConnections->At( i ).iReaderID == aReaderID ) + { + return iConnections->At( i ); + } + } + User::Leave( KScErrNotFound ); + return iConnections->At( 0 ); //just to satisfy compiler + } + +// ----------------------------------------------------------------------------- +// CScardConnector::ConnectionDone +// Connection has been established. Remove connector. +// ----------------------------------------------------------------------------- +// +void CScardConnector::ConnectionDone( + const TReaderID aReaderID, + const TInt& aErrorCode ) + { + _WIMTRACE(_L("WIM|Scard|CScardConnector::ConnectionDone|Begin")); +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, _L( "CScardConnector::ConnectionDone \ + status: %d \n" ), aErrorCode ); +#endif + if ( aErrorCode != KErrNone ) + { + iState = EConnectionComplete; + } + if ( iTimer ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, _L( "CScardConnector::ConnectionDone Cancel\ + timer. \n" ) ); +#endif + iTimer->Cancel(); + } + + if ( aErrorCode == KScErrTimeOut ) + { + iConnectionRegistry->Server()-> + FindAccessControl( aReaderID )->Cancel(); + + } + + iConnectionRegistry->ConnectDone( this, aReaderID, aErrorCode ); + if ( iState == EConnectionComplete ) + { + iConnectionRegistry->RemoveConnector( this ); + delete this; + } + } + +// ----------------------------------------------------------------------------- +// CScardConnector::Cancel +// Cancel connection. Call ConnectionDone with error code KScErrCancelled. +// ----------------------------------------------------------------------------- +// +void CScardConnector::Cancel() + { + _WIMTRACE(_L("WIM|Scard|CScardConnector::Cancel|Begin")); + iState = EConnectionComplete; + ConnectionDone( 0, KScErrCancelled ); + } + +// ----------------------------------------------------------------------------- +// CScardConnector::Message +// Return client message. +// ----------------------------------------------------------------------------- +// +RMessage2& CScardConnector::Message() + { + _WIMTRACE(_L("WIM|Scard|CScardConnector::Message|Begin")); + return *iClientMessage; + } + +// ----------------------------------------------------------------------------- +// CScardConnector::ConnectionTimedOut +// Timeout has occurred. Connectin done with KScErrTimeOut. +// ----------------------------------------------------------------------------- +// +void CScardConnector::ConnectionTimedOut() + { + _WIMTRACE(_L("WIM|Scard|CScardConnector::ConnectionTimedOut|Begin")); +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardConnector::ConnectionTimedOut state=%d\n" ), iState ); +#endif + if ( iState == EWaitingForConfirm ) + { + iState = ETimedOut; + return; + } + else + { + iState = EConnectionComplete; + ConnectionDone( iConnections->At( 0 ).iReaderID, KScErrTimeOut ); + } + } + +// End of File