wim/Scard/src/ScardAccessControl.cpp
changeset 0 164170e6151a
child 5 3b17fc5c9564
--- /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    <c32comm.h>         // Needed for RCommServ in WINS
+#include    "WimTrace.h"
+
+#ifdef _DEBUG // for logging
+#include    "ScardLogs.h"
+#include    <flogger.h> 
+#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<TReaderSession>( 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