diff -r 000000000000 -r 164170e6151a wim/Scard/src/ScardAccessControl.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/wim/Scard/src/ScardAccessControl.cpp Tue Jan 26 15:20:08 2010 +0200 @@ -0,0 +1,775 @@ +/* +* 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: This object is the one responsible for trafficing between +* the Smart Card reader and the sessions. +* +*/ + + + +// INCLUDE FILES +#include "ScardServer.h" +#include "ScardReaderRegistry.h" +#include "ScardAccessControl.h" +#include "ScardAccessControlRegistry.h" +#include "ScardCommandTimer.h" +#include "ScardConnector.h" +#include // Needed for RCommServ in WINS +#include "WimTrace.h" + +#ifdef _DEBUG // for logging +#include "ScardLogs.h" +#include +#endif + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// TMessageHandle::TMessageHandle +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +TMessageHandle::TMessageHandle( + const RMessage2& aMessage, + const TInt aSessionID, + const TReaderID aReaderID, + const TInt8 aChannel, + const TInt8 aAddition) + : iMessage( aMessage ), + iSessionID( aSessionID ), + iReaderID( aReaderID ), + iCancelled( EFalse ), + iChannel( aChannel ), + iTimer( NULL ), + iAdditionalParameter( aAddition ) + { + } + +// ----------------------------------------------------------------------------- +// TMessageHandle::TMessageHandle +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +TMessageHandle::TMessageHandle() + : iMessage(), + iSessionID( ENoSession ), + iReaderID( 0 ), + iCancelled( EFalse ), + iChannel( 0 ), + iTimer( NULL ), + iAdditionalParameter( 0 ) + { + } + +// ----------------------------------------------------------------------------- +// CScardAccessControl::CScardAccessControl +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CScardAccessControl::CScardAccessControl( + const TReaderID aReaderID, + CScardAccessControlRegistry* aControlRegistry ) + : CActive( EPriorityNormal ), + iSessionRegistry( NULL ), + iReaderActive( EFalse ), + iIsCreated( EFalse ), + iIsOpen( EFalse ), + iNextSessionID( 1 ), + iReader( NULL ), + iReaderID( aReaderID ), + iControlRegistry( aControlRegistry ), + iManager( NULL ), + iLifeMode( ECanBeDeleted ) + { + _WIMTRACE(_L("WIM|Scard|CScardAccessControl::CScardAccessControl|Begin")); + CActiveScheduler::Add( this ); + } + +// ----------------------------------------------------------------------------- +// CScardAccessControl::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CScardAccessControl::ConstructL() + { + _WIMTRACE(_L("WIM|Scard|CScardAccessControl::ConstructL|Begin")); + iSessionRegistry = new( ELeave ) CArrayFixFlat( 1 ); + iManager = CScardChannelManager::NewL(); + } + +// ----------------------------------------------------------------------------- +// CScardAccessControl::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +CScardAccessControl* CScardAccessControl::NewL( + const TReaderID aReaderID, + CScardAccessControlRegistry* aControl ) + { + _WIMTRACE(_L("WIM|Scard|CScardAccessControl::NewL|Begin")); + CScardAccessControl* self = new( ELeave ) CScardAccessControl( aReaderID, + aControl ); + + CleanupStack::PushL( self ); + self->ConstructL(); + CleanupStack::Pop( self ); + +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "Access controller created.\n" ) ); +#endif + return self; + } + + +// Destructor +CScardAccessControl::~CScardAccessControl() + { + _WIMTRACE(_L("WIM|Scard|CScardAccessControl::~CScardAccessControl|Begin")); + Cancel(); + + if ( iIsCreated ) + { + DetachSessionFromReader( EAccessMasterID ); + } + if ( iControlRegistry ) + { + iControlRegistry->ControllerRetired( this ); + } + delete iSessionRegistry; + delete iManager; +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "Access controller destroyed.\n" ) ); +#endif + } + +// ----------------------------------------------------------------------------- +// CScardAccessControl::InitiateCommunication +// Set the reader as active. Prevents polling and other sessions +// from using the reader. Returns the request status of this object. +// ----------------------------------------------------------------------------- +// +TRequestStatus& CScardAccessControl::InitiateCommunication( + const TInt aSessionID, + const RMessage2& aMessage, + const TInt32 aTimeOut, + const TInt8 aChannel, + const TUint8 aAdditionalParameter ) + { + _WIMTRACE(_L("WIM|Scard|CScardAccessControl::InitiateCommunication|Begin")); +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardAccessControl::InitiateCommunication session: %d, channel:\ + %d, reader: %d\n" ), aSessionID, aChannel, iReaderID ); +#endif + iReaderActive = ETrue; + + TMessageHandle handle( aMessage, aSessionID, iReaderID, aChannel, + aAdditionalParameter ); + if ( aTimeOut ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardAccessControl::InitiateCommunication create command\ + timer\n" ) ); +#endif + TRAPD( err, + handle.iTimer = CScardCommandTimer::NewL( aTimeOut, this ) ); + if ( err ) + { + return iStatus; + } + handle.iTimer->StartTiming(); + } + + TRAPD( err, iManager->PushMessageToTopL( handle ) ); + if ( !err ) + { + SetActive(); + } + iStatus = err; + _WIMTRACE2(_L("WIM|Scard|CScardAccessControl::InitiateCommunication|End|iStatus=%d"), err); + return iStatus; + } + +// ----------------------------------------------------------------------------- +// CScardAccessControl::ReaderIsReady +// Ask if the reader is available to use for aSessionID. +// ----------------------------------------------------------------------------- +// +TBool CScardAccessControl::ReaderIsReady( + const TInt aSessionID, + const TInt8 aChannel ) const + { + _WIMTRACE(_L("WIM|Scard|CScardAccessControl::ReaderIsReady|Begin")); + TInt res( 0 ); + + TRAPD( err, res = iManager->ChannelReservedL( aChannel ) ); + if ( err ) + { + return EFalse; + } + if ( res ) + { + if ( res != aSessionID && aSessionID != EAccessMasterID ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardAccessControl::ReaderIsReady: Channel reserved by\ + another session.\n" ) ); +#endif + return EFalse; + } + } + + if ( iReaderActive ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardAccessControl::ReaderIsReady: Reader active.\n" ) ); +#endif + return EFalse; + } + else + { + return ETrue; + } + } + +// ----------------------------------------------------------------------------- +// CScardAccessControl::FreeChannelL +// Free current reservation (if this session has a reservation) +// If there are messages in the stack, service them. +// ----------------------------------------------------------------------------- +// +void CScardAccessControl::FreeChannelL( + const TInt aSessionID, + const TInt8 aChannel ) + { + _WIMTRACE(_L("WIM|Scard|CScardAccessControl::FreeChannelL|Begin")); + if ( aChannel == KAllChannels ) + { + iManager->FreeChannels( aSessionID ); + } + else + { + iManager->FreeChannelL( aChannel, aSessionID ); + } + + if ( !iReaderActive ) + { + HandleNextMessageL( iManager->NextMessageFromFree( aChannel ) ); + } + } + +// ----------------------------------------------------------------------------- +// CScardAccessControl::RunL +// Handle completed reader messages by finding the caller, and calling +// the complete function. Also take the next message from the stack (if +// present) and start handling it. +// ----------------------------------------------------------------------------- +// +void CScardAccessControl::RunL() + { + _WIMTRACE(_L("WIM|Scard|CScardAccessControl::RunL|Begin")); +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardAccessControl::RunL\n" ) ); +#endif + iLifeMode = ECanNotDelete; + + // reader has finished, mark it as inactive + iReaderActive = EFalse; + + // Get the message that was serviced, and the session that made the + // request + TMessageHandle msgHandle = iManager->MessageFromTop(); + + // Controller needs to know if a connection has been successful + if ( msgHandle.iAdditionalParameter == KOpenReader ) + { + // If connection was succesful, ConnectionDone() is called from + // notifier. Otherwise, call it from here. + if ( iStatus == KErrNone ) + { + iIsOpen = ETrue; + } + else + { + iControlRegistry->Server()->ConnectionRegistry()-> + Connection( 0 ).iConnector->ConnectionDone( + msgHandle.iReaderID, iStatus.Int() ); + } + } + + // Handle result in appropriate session + // In case the operation was cancelled, continue from the next operation + // w/o completing the last one. + // In case of connecting to reader, ConnectionDone() takes care of + // completing the message. + if ( !msgHandle.iCancelled && + msgHandle.iAdditionalParameter != KOpenReader ) + { + CScardSession* session = SessionBase( msgHandle.iSessionID ); + if ( !session ) + { + User::Panic( _L( "Message stack fault" ), + KScServerPanicInternalError ); + } +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardAccessControl::RunL: Message %x completed with status\ + %d.\n" ), msgHandle.iAdditionalParameter, iStatus.Int() ); +#endif + session->AsynchronousServiceComplete( msgHandle, iStatus.Int() ); + } + + // The session may have indicated that it's about time for this + // object to destroy itself + if ( iLifeMode == EDestroyASAP ) + { + delete this; + return; + } + + iLifeMode = ECanBeDeleted; + + // Check for queued messages. + HandleNextMessageL( iManager->NextMessageL() ); + } + +// ----------------------------------------------------------------------------- +// CScardAccessControl::DoCancel +// Instruct the reader to cancel +// ----------------------------------------------------------------------------- +// +void CScardAccessControl::DoCancel() + { + _WIMTRACE(_L("WIM|Scard|CScardAccessControl::DoCancel|Begin")); + if ( iReader ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardAccessControl::DoCancel: Canceling transmissions.\n" ) ); +#endif + TRAPD( err, CancelTransmissionsL( EAccessMasterID ) ); + + if ( err != KErrNone ) + { + // Do nothing + } + } + } + +// ----------------------------------------------------------------------------- +// CScardAccessControl::QueueExecution +// Queue the execution of a command until it can be serviced +// ----------------------------------------------------------------------------- +// +void CScardAccessControl::QueueExecution( + const RMessage2& aMessage, + const TInt aSessionID, + const TInt32 aTimeOut, + const TInt8 aChannel, + const TInt8 aParameter ) + { + _WIMTRACE(_L("WIM|Scard|CScardAccessControl::QueueExecution|Begin")); + TMessageHandle tmp( aMessage, aSessionID, iReaderID, aChannel, aParameter ); + TInt err; + if ( aTimeOut ) + { + TRAP( err, tmp.iTimer = CScardCommandTimer::NewL( aTimeOut, this ) ); + if ( err ) + { + tmp.iMessage.Complete( err ); + } + tmp.iTimer->StartTiming(); + } + + TRAP( err, iManager->PushMessageToBottomL( tmp ) ); + if ( err ) + { + tmp.iMessage.Complete( err ); + } + } + +// ----------------------------------------------------------------------------- +// CScardAccessControl::QueueChannelOperation +// Queue channel operation +// ----------------------------------------------------------------------------- +// +void CScardAccessControl::QueueChannelOperation( + const RMessage2& aMessage, + const TInt aSessionID, + const TInt32 aTimeOut, + const TInt8 aChannel ) + { + _WIMTRACE(_L("WIM|Scard|CScardAccessControl::QueueChannelOperation|Begin")); + TMessageHandle tmp( aMessage, aSessionID, iReaderID, aChannel, + KReservation ); + if ( aTimeOut ) + { + TRAPD( err, tmp.iTimer = CScardCommandTimer::NewL( aTimeOut, this ) ); + if ( err ) + { + tmp.iMessage.Complete( err ); + } + tmp.iTimer->StartTiming(); + } + + TRAPD( err, iManager->PushMessageToBottomL( tmp ) ); + if ( err ) + { + tmp.iMessage.Complete( err ); + } + } + +// ----------------------------------------------------------------------------- +// CScardAccessControl::IsAttached +// Is this session attached to the reader yet? +// ----------------------------------------------------------------------------- +// +TBool CScardAccessControl::IsAttached( CScardSession* aSession ) const + { + _WIMTRACE(_L("WIM|Scard|CScardAccessControl::IsAttached|Begin")); + TInt sessionCount = iSessionRegistry->Count(); + for ( TInt i( 0 ); i < sessionCount; i++ ) + { + if ( (*iSessionRegistry)[i].SessionBase == aSession ) + { + return ETrue; + } + } + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CScardAccessControl::SessionBase +// Returns CScardSession* belonging to this session id +// ----------------------------------------------------------------------------- +// +CScardSession* CScardAccessControl::SessionBase( const TInt aSessionID ) + { + _WIMTRACE(_L("WIM|Scard|CScardAccessControl::SessionBase|Begin")); + TInt sessionCount = iSessionRegistry->Count(); + for ( TInt i( 0 ); i < sessionCount; i++ ) + { + if ( (*iSessionRegistry)[i].SessionID == aSessionID ) + { + return (*iSessionRegistry)[i].SessionBase; + } + } + return NULL; + } + +// ----------------------------------------------------------------------------- +// CScardAccessControl::CardEvent +// Handle card event +// ----------------------------------------------------------------------------- +// +void CScardAccessControl::CardEvent( + const TScardServiceStatus aEvent, + const TScardATR& aATR ) + { + _WIMTRACE(_L("WIM|Scard|CScardAccessControl::CardEvent|Begin")); + + if ( aATR.Length() ) + { + iATR = aATR; + } + + if ( aEvent == EScardRemoved ) + { + iManager->CardRemoved(); + } + + TInt sessionCount = iSessionRegistry->Count(); + + for ( TInt index( 0 ); index < sessionCount ; index++ ) + { + iSessionRegistry->At( index ).SessionBase->CardEvent( aEvent, aATR, + iReaderID ); + } + } + +// ----------------------------------------------------------------------------- +// CScardAccessControl::CancelTransmissionsL +// Cancel Transmissions +// ----------------------------------------------------------------------------- +// +void CScardAccessControl::CancelTransmissionsL( const TInt aSessionID ) + { + _WIMTRACE(_L("WIM|Scard|CScardAccessControl::CancelTransmissions|Begin")); +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardAccessControl::CancelTransmissions: Purge messages from \ + stack.\n" ) ); +#endif + // First purge the messages from the stack + iManager->CancelAll( aSessionID ); + + // If the message currently served is for the calling session, cancel it + // from the reader also and put it back + TMessageHandle tmp = iManager->MessageFromTop(); + if ( tmp.iSessionID == aSessionID || aSessionID == EAccessMasterID ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardAccessControl::CancelTransmissions: Cancel message from\ + reader.\n" ) ); +#endif + + iReader->CancelTransmit(); + + if ( aSessionID == EAccessMasterID ) + { + // reader not active anymore + iReaderActive = EFalse; + } + } + + if ( tmp.iSessionID != ENoSession && aSessionID != EAccessMasterID ) + { + iManager->PushMessageToTopL( tmp ); + } + + // Finish by clearing any reservations the cancelling session has done +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardAccessControl::CancelTransmissions: Free reserved\ + channels.\n" ) ); +#endif + iManager->FreeChannels( aSessionID ); + } + +// ----------------------------------------------------------------------------- +// CScardAccessControl::DetachSessionFromReader +// Detach session from reader +// ----------------------------------------------------------------------------- +// +void CScardAccessControl::DetachSessionFromReader( const TInt aSessionID ) + { + _WIMTRACE(_L("WIM|Scard|CScardAccessControl::DetachSessionFromReader|Begin")); + if ( aSessionID == EAccessMasterID ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardAccessControl::DetachSessionFromReader: Detach all\ + sessions...\n" ) ); +#endif + + // detach all sessions and delete all their messages + DequeueOperations( EAccessMasterID ); + while ( iSessionRegistry->Count() ) + { + iSessionRegistry->Delete( 0 ); + } + + // all sessions have been detached, so kill the reader (if it's around) + if ( iReader ) + { + iReader->Close(); + } + iControlRegistry->Server()->FactoryRegistry()->CloseReader( + iReaderID ); + iReader = NULL; + iIsOpen = EFalse; + iIsCreated = EFalse; + } + + else + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardAccessControl::DetachSessionFromReader: Detach session\ + %d...\n" ), aSessionID ); +#endif + TInt i( 0 ); + if ( !IsAttached( SessionBase( aSessionID ) ) ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardAccessControl::DetachSessionFromReader: Session not\ + attached!!!\n" ), aSessionID ); +#endif + return; + } + + // locate the session to be detached + for ( ; (*iSessionRegistry)[i].SessionID != aSessionID; i++ ) + {;} + + iSessionRegistry->Delete( i ); + + // pop out all messages queued to it + DequeueOperations( aSessionID ); + + // Free any possible transactions with the smart card + TRAPD( error, FreeChannelL( aSessionID, KAllChannels ) ); + + if ( error != KErrNone ) + { + // Do nothing + } + } + } + +// ----------------------------------------------------------------------------- +// CScardAccessControl::DequeueOperations +// Cancel all pending messages +// ----------------------------------------------------------------------------- +// +void CScardAccessControl::DequeueOperations( const TInt aSessionID ) + { + _WIMTRACE(_L("WIM|Scard|CScardAccessControl::DequeueOperations|Begin")); + iManager->CancelAll( aSessionID ); + } + +// ----------------------------------------------------------------------------- +// CScardAccessControl::InitialiseReader +// Initialise reader handler +// ----------------------------------------------------------------------------- +// +TBool CScardAccessControl::InitialiseReader( + const TInt aSessionID, + const RMessage2& aMessage ) + { + _WIMTRACE(_L("WIM|Scard|CScardAccessControl::InitialiseReader|Begin")); + if ( iIsOpen ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardAccessControl::InitialiseReader: Reader already\ + open.\n" ) ); +#endif + return ETrue; + } + + if ( ReaderIsReady( EAccessMasterID, 0 ) ) + { + InitiateCommunication( aSessionID, aMessage, static_cast< TInt32>( 0 ), + 0, KOpenReader ); +#if defined (__WINS__) + RCommServ commServer; + TInt error = commServer.Connect(); + if ( error == KErrNone) + { + commServer.Close(); + } +#endif +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardAccessControl::InitialiseReader: Opening Reader\n" ) ); +#endif + iReader->Open( iStatus ); + } +#ifdef _DEBUG + else + { + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardAccessControl::InitialiseReader: Reader not ready!.\n" ) ); + } +#endif + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CScardAccessControl::AttachSessionToReaderL +// Attach session to reader +// ----------------------------------------------------------------------------- +// +MScardReader* CScardAccessControl::AttachSessionToReaderL( + CScardSession* aSession, + TInt &aSessionID ) + { + _WIMTRACE(_L("WIM|Scard|CScardAccessControl::AttachSessionToReaderL|Begin")); + TReaderSession newSession; + newSession.SessionID = iNextSessionID; + newSession.SessionBase = aSession; + + TInt readerCreationError( 0 ); + + // If no other session has connected yet or the reader launcher has been + // unable to create the reader object, go here... + if ( !iIsCreated ) + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardAccessControl::AttachSessionToReader: reader not\ + created!\n" ) ); +#endif + // ... and ask the launcher to create the reader object + CScardReaderRegistry* reg = + iControlRegistry->Server()->FactoryRegistry(); + TRAP( readerCreationError, iReader = reg->LoadReaderL( iReaderID ) ); + } + +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardAccessControl::AttachSessionToReader: session ID %d\n" ), + newSession.SessionID ); +#endif + + iSessionRegistry->AppendL( newSession ); + + // Place session ID and increment the next ID + aSessionID = iNextSessionID++; + + // All sessions are immediately on channel 0 + iManager->AddSessionToChannelL( KChannel0, aSessionID ); + + if ( !readerCreationError && iReader ) + { + iIsCreated = ETrue; + return iReader; + } + else + { +#ifdef _DEBUG + RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName, + EFileLoggingModeAppend, + _L( "CScardAccessControl::AttachSessionToReader: reader creation\ + failed!!!\n" ) ); +#endif + iIsCreated = EFalse; + User::Leave( readerCreationError ); + return NULL; + } + } + +// End of File