--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/wim/Scard/src/ScardSession.cpp Tue Jan 26 15:20:08 2010 +0200
@@ -0,0 +1,1126 @@
+/*
+* 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: Session for the Scard server, to a single client-side session
+*
+*/
+
+
+
+// INCLUDE FILES
+#include "ScardBase.h"
+#include "ScardReader.h"
+#include "ScardClsv.h"
+#include "ScardNotifyRegistry.h"
+#include "ScardSession.h"
+#include "ScardServer.h"
+#include "ScardAccessControl.h"
+#include "WimTrace.h"
+
+#ifdef _DEBUG // for logging
+#include "ScardLogs.h"
+#include <flogger.h>
+#endif
+
+// LOCAL CONSTANTS AND MACROS
+const TInt KResponseLengthCloseChannel = 0;
+const TInt KResponseLengthOpenChannel = 1;
+const TInt KCommandLengthCloseChannel = 4;
+const TInt KCommandLengthOpenChannel = 6;
+
+// Assert that the channel has been opened for this session, and if not, leave
+#define __ASSERT_CHANNEL_OPEN( a ) TRAPD( channelClosed,\
+ iAccessCtrl->ValidateChannelL( ( a ), iSessionID ) );\
+ if ( channelClosed )\
+ {\
+ aMessage.Complete( KScServerErrIllegalChannel );\
+ return;\
+ }
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CScardSession::CScardSession
+// C++ default constructor can NOT contain any code, that
+// might leave.
+// -----------------------------------------------------------------------------
+//
+CScardSession::CScardSession()
+ : CSession2()
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::CScardSession|Begin"));
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::ConstructL
+// Symbian 2nd phase constructor can leave.
+// -----------------------------------------------------------------------------
+//
+void CScardSession::ConstructL( CScardServer* aServer )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::ConstructL|Begin"));
+ iServer = aServer;
+ iNotifyRegistry = iServer->NotifyRegistry();
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::NewL
+// Two-phased constructor.
+// -----------------------------------------------------------------------------
+//
+CScardSession* CScardSession::NewL( CScardServer* aServer )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::NewL|Begin"));
+ CScardSession* self = new( ELeave ) CScardSession;
+
+ CleanupStack::PushL( self );
+ self->ConstructL( aServer );
+ CleanupStack::Pop( self );
+
+ return self;
+ }
+
+// Destructor
+CScardSession::~CScardSession()
+ {
+ DeleteBuffers();
+ }
+
+
+// -----------------------------------------------------------------------------
+// CScardSession::ServiceL
+// Handle the client message
+// -----------------------------------------------------------------------------
+//
+void CScardSession::ServiceL( const TMessageHandle& aMessageHandle )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::ServiceL|Begin"));
+ ServiceL( aMessageHandle.iMessage );
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::CloseSession
+// Clean up the reader event listeners
+// -----------------------------------------------------------------------------
+//
+void CScardSession::CloseSession( const RMessage2& aMessage )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::CloseSession|Begin"));
+ if ( iAccessCtrl && iAccessCtrl->IsAttached( this ) )
+ {
+ iAccessCtrl->DetachSessionFromReader( iSessionID );
+ }
+
+ RThread client;
+ aMessage.Client( client );
+ iNotifyRegistry->RemoveReaderEventListeners( client );
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::AsynchronousServiceComplete
+// An asynchronous service has been completed by the reader.
+// -----------------------------------------------------------------------------
+//
+void CScardSession::AsynchronousServiceComplete(
+ const TMessageHandle& aMessageHandle,
+ const TInt aErrorCode )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::AsynchronousServiceComplete|Begin"));
+ const RMessage2& aMessage = aMessageHandle.iMessage;
+ // In all cases, if the operation has encountered a problem, ignore
+ // results and just complain to the client that something went wrong.
+ if ( aErrorCode != KErrNone )
+ {
+#ifdef _DEBUG
+ RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName,
+ EFileLoggingModeAppend,
+ _L( "CScardSession::AsynchronousServiceComplete ERROR: %d.\n" ),
+ aErrorCode );
+#endif
+
+ DeleteBuffers();
+ aMessage.Complete( aErrorCode );
+ return;
+ }
+
+ // Now, see what got serviced
+ _WIMTRACE2(_L("WIM|Scard|CScardSession::AsynchronousServiceComplete|Event=%d"), aMessage.Function());
+ switch ( aMessage.Function() )
+ {
+ case EScardServerTransmitToCard:
+ {
+#ifdef _DEBUG
+ RFileLogger::Write( KScardLogDir, KScardLogFileName,
+ EFileLoggingModeAppend,
+ _L( "Transmit to card completed.\n" ) );
+#endif
+ // Write response to client and cleanup
+ WriteToClient( aMessage, *iResponse, 1 );
+ DeleteBuffers();
+ aMessage.Complete( KErrNone );
+ break;
+ }
+
+ case EScardServerGetCapabilities:
+ {
+#ifdef _DEBUG
+ RFileLogger::Write( KScardLogDir, KScardLogFileName,
+ EFileLoggingModeAppend,
+ _L( "Get capabilities completed.\n" ) );
+#endif
+ // Write response to client and cleanup
+ WriteToClient( aMessage, *iResponse, 2 );
+ DeleteBuffers();
+ aMessage.Complete( KErrNone );
+ break;
+ }
+
+ case EScardServerManageChannel:
+ {
+#ifdef _DEBUG
+ RFileLogger::Write( KScardLogDir, KScardLogFileName,
+ EFileLoggingModeAppend,
+ _L( "Manage channel completed.\n" ) );
+#endif
+
+ // Which type of channel management got serviced?
+ switch ( aMessage.Int0() )
+ {
+ case EOpenAnyChannel:
+ {
+ // Was there a proper response
+ // (aka. the command was successful)
+ if ( iResponse->Length() == KOpenChannelResponseLength )
+ {
+ // Add this session to the newly opened channel
+ TBool ok( EFalse );
+ TRAPD( mem, ok = iAccessCtrl->AddSessionToChannelL(
+ (*iResponse)[0], iSessionID ) );
+ __ASSERT_MEMORY( mem );
+ if ( !ok )
+ {
+ aMessage.Complete( KScErrNotSupported );
+ return;
+ }
+ }
+ // Then write the card's response back to the client
+ // and cleanup
+ WriteToClient( aMessage, *iResponse, 1 );
+ DeleteBuffers();
+ aMessage.Complete( KErrNone );
+ break;
+ }
+ case ECloseChannel:
+ {
+ // Channel closed, OK
+ aMessage.Complete( KErrNone );
+ DeleteBuffers();
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ return;
+ }
+
+ default:
+ {
+ User::Panic( _L( "Message Stack Corrupted" ),
+ KScServerPanicInternalError );
+ break;
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::ServiceL
+// Message handler for the session.
+// Dispatches requests to the appropriate handler
+// Trap harness for dispatcher
+// -----------------------------------------------------------------------------
+//
+void CScardSession::ServiceL( const RMessage2& aMessage )
+ {
+ _WIMTRACE2(_L("WIM|Scard|CScardSession::ServiceL|Begin|Event=%d"), aMessage.Function());
+ // Divide the operation to the handler functions
+ switch ( aMessage.Function() )
+ {
+ // These functions are synchronous, and don't use message stack,
+ // so we can complete the messages here.
+ case EScardServerNotifyChange:
+ {
+ iNotifyRegistry->AddReaderEventListenerL( aMessage );
+ // Does not complete message because it is completed when card
+ // event occurs
+ break;
+ }
+ case EScardServerCancelNotifyChange:
+ {
+ iNotifyRegistry->RemoveReaderEventListener( aMessage );
+ aMessage.Complete( KErrNone );
+ break;
+ }
+ case EScardServerCloseSession:
+ {
+ CloseSession( aMessage );
+ aMessage.Complete( KErrNone );
+ break;
+ }
+ case EScardServerDisconnectFromReader:
+ {
+ DisconnectFromReader();
+ aMessage.Complete( KErrNone );
+ break;
+ }
+ case EScardServerCancelTransmit:
+ {
+ CancelTransmitL();
+ aMessage.Complete( KErrNone );
+ break;
+ }
+ // These functions are asynchronous, and (may) put their messages
+ // in the message stack, so they do completion internally.
+ case EScardServerConnectToReader:
+ {
+ TInt desLen = aMessage.GetDesMaxLength( 1 );
+ _WIMTRACE2(_L( "WIM|Scard|EScardServerConnectToReader desLen %d" ), desLen );
+ if ( desLen <= 0 )
+ {
+ _WIMTRACE(_L(" WIM|Scard|EScardServerConnectToReader Descriptor is bad"));
+ aMessage.Panic( _L( "ScardServer" ), KErrBadDescriptor );
+ break;
+ }
+ ConnectToReaderL( aMessage );
+ break;
+ }
+ case EScardServerGetATR:
+ {
+ aMessage.Complete( KErrNotSupported );
+ break;
+ }
+ case EScardServerTransmitToCard:
+ {
+ TransmitToCard( aMessage );
+ break;
+ }
+ case EScardServerGetCapabilities:
+ {
+ GetCapabilities( aMessage );
+ break;
+ }
+ case EScardServerManageChannel:
+ {
+ ManageChannel( aMessage );
+ break;
+ }
+
+ // A corrupt request
+ default:
+ aMessage.Panic( _L( "ScardServer" ), KScServerPanicBadRequest );
+ break;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::ConnectToReaderL
+// Ask Access Control to add this session to registry, and update session ID
+// -----------------------------------------------------------------------------
+//
+void CScardSession::ConnectToReaderL( const RMessage2& aMessage )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::ConnectToReaderL|Begin"));
+#ifdef _DEBUG
+ RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName,
+ EFileLoggingModeAppend,
+ _L( "CScardSession::ConnectToReaderL entered.\n" ) );
+#endif
+ // If already connected, what more could the client want??
+ if ( iConnectedToReader )
+ {
+#ifdef _DEBUG
+ RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName,
+ EFileLoggingModeAppend,
+ _L( "CScardSession::ConnectToReaderL FAILED: already connected.\n" ) );
+#endif
+ aMessage.Complete( KScErrAlreadyExists );
+ return;
+ }
+ // Store client thread from message to member to be used in PanicClient().
+ aMessage.Client( iClient );
+ // If not, get on with it...
+ iServer->ConnectToReaderL( this, aMessage );
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::DisconnectFromReader
+// Ask Access Control to detach this session from the reader.
+// -----------------------------------------------------------------------------
+//
+void CScardSession::DisconnectFromReader()
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::DisconnectFromReader|Begin"));
+ // If connected at all, disconnect
+ if ( iConnectedToReader )
+ {
+ iAccessCtrl->DetachSessionFromReader( iSessionID );
+ iConnectedToReader = EFalse;
+ iAccessCtrl = NULL;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::GetCapabilities
+// Get capabilities of the card
+// -----------------------------------------------------------------------------
+//
+void CScardSession::GetCapabilities( const RMessage2& aMessage )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::GetCapabilities|Begin"));
+ if ( !iConnectedToReader )
+ {
+ aMessage.Panic( _L( "Reader not contacted" ),
+ KScPanicNoResourceConnection );
+ return;
+ }
+ const TInt8 channel( 0 );
+
+ if ( iAccessCtrl->ReaderIsReady( iSessionID, channel ) )
+ {
+ TRequestStatus& status =
+ iAccessCtrl->InitiateCommunication( iSessionID, aMessage,
+ reinterpret_cast< TInt32>( aMessage.Ptr3() ), channel );
+ __ASSERT_MEMORY( status.Int() );
+ TInt32 commandCode( 0 );
+ commandCode = aMessage.Int1();
+ commandCode |= ( aMessage.Int0() << 8 ) & 0xff00;
+
+ // Get the response buffer
+ TInt error = AllocateResponse( aMessage, 2 );
+ if ( error )
+ {
+ aMessage.Complete( error );
+ return;
+ }
+
+ TInt32 timeout = reinterpret_cast< TInt32>( aMessage.Ptr3() );
+ // ...do the control command
+ iReader->GetCapabilities( status, commandCode, *iResponse, timeout );
+ }
+ // The reader was busy, queue
+ else
+ {
+#ifdef _DEBUG
+ RFileLogger::Write( KScardLogDir, KScardLogFileName,
+ EFileLoggingModeAppend,
+ _L("CScardSession::GetCapabilities()-reader busy, message queued.\n") );
+#endif
+
+ iAccessCtrl->QueueExecution( aMessage, iSessionID,
+ reinterpret_cast< TInt32 >( aMessage.Ptr3() ), channel );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::TransmitToCard
+// Transmit data to the card
+// -----------------------------------------------------------------------------
+//
+void CScardSession::TransmitToCard( const RMessage2& aMessage )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::TransmitToCard|Begin"));
+ if ( !iConnectedToReader )
+ {
+ aMessage.Panic( _L( "Reader not contacted" ),
+ KScPanicNoResourceConnection );
+ return;
+ }
+
+ // check if this client has the access rights for the reader
+ // and reader is ready
+ const TInt8 channel( static_cast< TInt8>( aMessage.Int3() ) );
+ __ASSERT_CHANNEL_OPEN( channel );
+
+ if ( iAccessCtrl->ReaderIsReady( iSessionID, channel ) )
+ {
+ // Read the command APDU from the client
+ TInt error = ReadFromClient( aMessage, iCommandBuffer, iCommand, 0 );
+ if ( error )
+ {
+#ifdef _DEBUG
+ RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName,
+ EFileLoggingModeAppend,
+ _L("CScardSession::TransmitToCard()-Cmd APDU couldn't be read from\
+ client. Error: %d.\n"), error );
+#endif
+ return;
+ }
+
+ // If the channel number is not the same one as asked for
+ // in the parameter 3 of the message, adjust the command...
+ if ( ( (*iCommand)[KCLA] & 0x0f) != channel )
+ {
+#ifdef _DEBUG
+ RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName,
+ EFileLoggingModeAppend,
+ _L("CScardSession::TransmitToCard() -- Channel changed from %d\
+ to: %d.\n"), (*iCommand)[KCLA] & 0x0f, channel & 0x0f );
+#endif
+ (*iCommand)[KCLA] &= 0xf0;
+ (*iCommand)[KCLA] |= channel;
+ }
+
+ // No manage channel apdu's are allowed.
+ // Use CScardComm::ManageChannel() instead.
+ if ( (*iCommand)[KINS] == KManageChannel )
+ {
+#ifdef _DEBUG
+ RFileLogger::Write( KScardLogDir, KScardLogFileName,
+ EFileLoggingModeAppend,
+ _L( "CScardSession::TransmitToCard() -- Error! Manage channel\
+ APDU.\n" ) );
+#endif
+ delete iCommand;
+ iCommand = NULL;
+ aMessage.Complete( KScServerErrIllegalOperation );
+ return;
+ }
+
+ // Alloc response
+ error = AllocateResponse( aMessage, 1 );
+ if ( error )
+ {
+#ifdef _DEBUG
+ RFileLogger::Write( KScardLogDir, KScardLogFileName,
+ EFileLoggingModeAppend,
+ _L( "CScardSession::TransmitToCard() -- Could not allocate\
+ response.\n" ) );
+#endif
+ return;
+ }
+
+ // Transfer APDU
+ TRequestStatus& sr =
+ iAccessCtrl->InitiateCommunication( iSessionID, aMessage,
+ reinterpret_cast< TInt32>( aMessage.Ptr2() ), channel );
+ __ASSERT_MEMORY( sr.Int() );
+ const TInt32 timeout = static_cast< TInt32>( aMessage.Int2() );
+#ifdef _DEBUG
+ RFileLogger::HexDump( KScardLogDir, KScardLogFileName,
+ EFileLoggingModeAppend,
+ _S( "CScardSession::TransmitToCard() command APDU:\n" ), 0,
+ iCommand->Ptr(), iCommand->Length() );
+#endif
+ iReader->TransmitToCard( sr, *iCommand, *iResponse, timeout );
+ }
+ // The reader was busy, queue
+ else
+ {
+#ifdef _DEBUG
+ RFileLogger::Write( KScardLogDir, KScardLogFileName,
+ EFileLoggingModeAppend,
+ _L( "CScardSession::TransmitToCard() -- reader busy. message\
+ queued.\n" ) );
+#endif
+ iAccessCtrl->QueueExecution( aMessage, iSessionID,
+ static_cast< TInt32>( aMessage.Int2() ), channel );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::CancelTransmit
+// Cancel all transmissions belonging to this session
+// -----------------------------------------------------------------------------
+//
+void CScardSession::CancelTransmitL()
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::CancelTransmit|Begin"));
+ // It is not clear if this session is attempting to connect, so cancel any
+ // connection attempts as well... If this session is not connecting at the
+ // moment, this does nothing.
+ iServer->ConnectionRegistry()->CancelConnection( this );
+
+ if ( iAccessCtrl )
+ {
+ // Cancel from the reader
+ iAccessCtrl->CancelTransmissionsL( iSessionID );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::ManageChannel
+// Manage logical channel
+// -----------------------------------------------------------------------------
+//
+void CScardSession::ManageChannel( const RMessage2& aMessage )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::ManageChannel|Begin"));
+ if ( !iConnectedToReader )
+ {
+ aMessage.Panic( _L( "Reader not contacted" ),
+ KScPanicNoResourceConnection );
+ return;
+ }
+
+ const TUint8 maxChannels( 4 );
+
+ // What exactly does the client want to do?
+ const TInt operationCode = aMessage.Int0();
+ _WIMTRACE2(_L("WIM|Scard|CScardSession::ManageChannel|operationCode=%d"), operationCode);
+ switch ( operationCode )
+ {
+ // Open a channel and the card will assign the channel number
+ case EOpenAnyChannel:
+ {
+ // If we're already on all the channels, return error indicating
+ // that no more channels are available
+ TBool allOpen( ETrue );
+ TInt8 i( 0 );
+ for ( i = 1; i < maxChannels; i++ )
+ {
+ TRAPD( closed, iAccessCtrl->ValidateChannelL( i, iSessionID ) );
+ if ( closed )
+ {
+ allOpen = EFalse;
+ break;
+ }
+ }
+ if ( allOpen )
+ {
+#ifdef _DEBUG
+ RFileLogger::Write( KScardLogDir, KScardLogFileName,
+ EFileLoggingModeAppend,
+ _L( "CScardSession::ManageChannel() -- Open any channel:\
+ all channels open.\n" ) );
+#endif
+ _WIMTRACE(_L("WIM|Scard|CScardSession::ManageChannel|no more channels available"));
+ aMessage.Complete( KScErrFull );
+ return;
+ }
+
+ // Check if all channels have already been opened.
+ // (Of course this session is not yet on all of them)
+ allOpen = ETrue;
+ for ( i = 1 ; i < maxChannels ; i++ )
+ {
+ if ( !( iAccessCtrl->ChannelOpenedYet( i ) ) )
+ {
+ allOpen = EFalse;
+ break;
+ }
+ }
+
+ // If all channels have been opened, get the first unreserved
+ // one and assign the session to it. If no unreserved channels
+ // are found, put the message on hold for the next available channel.
+ if ( allOpen )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::ManageChannel|all channels open"));
+ const TInt8 channel = iAccessCtrl->UnreservedLogicalChannel();
+ if ( channel > 0 )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::ManageChannel|unreserved channels found"));
+ TRAPD( err, iAccessCtrl->AddSessionToChannelL(
+ channel, iSessionID ) );
+ __ASSERT_MEMORY( err );
+ _WIMTRACE(_L("WIM|Scard|CScardSession::ManageChannel|session added to channel"));
+ aMessage.Complete( KErrNone );
+ return;
+ }
+ else
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::ManageChannel|no unreserved channels found"));
+ iAccessCtrl->QueueChannelOperation( aMessage, iSessionID,
+ reinterpret_cast< TInt32>( aMessage.Ptr2() ),
+ KAllChannels );
+ return;
+ }
+ }
+ _WIMTRACE(_L("WIM|Scard|CScardSession::ManageChannel|some channels not open"));
+ // The card has logical channels available that have not been
+ // yet opened. Make the command and send it to the SC
+ if ( iAccessCtrl->ReaderIsReady( iSessionID, KChannel0 ) )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::ManageChannel|reader ready"));
+ DoCommandAndTransmit(
+ aMessage,
+ KOpenChannel,
+ 0,
+ KCommandLengthOpenChannel,
+ KResponseLengthOpenChannel,
+ reinterpret_cast< TInt32 >( aMessage.Ptr2() ),
+ KChannel0 );
+ return;
+ }
+ // The reader was busy, queue
+ else
+ {
+#ifdef _DEBUG
+ RFileLogger::Write( KScardLogDir, KScardLogFileName,
+ EFileLoggingModeAppend,
+ _L( "CScardSession::ManageChannel() -- reader busy.\
+ message queued.\n" ) );
+#endif
+ _WIMTRACE(_L("WIM|Scard|CScardSession::ManageChannel|reader busy"));
+ iAccessCtrl->QueueExecution( aMessage, iSessionID,
+ reinterpret_cast< TInt32>( aMessage.Ptr2() ), KChannel0 );
+ return;
+ }
+ //break; //unreachable
+ }
+
+ // Close a channel
+ case ECloseChannel:
+ {
+ const TUint8 channel( static_cast< TUint8>( aMessage.Int1() ) );
+ TBool stillOpen( EFalse );
+ // Remove this session from the channel
+ TRAPD( err, stillOpen = iAccessCtrl->RemoveSessionFromChannelL(
+ channel, iSessionID ) );
+ if ( err != KErrNone )
+ {
+#ifdef _DEBUG
+ RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName,
+ EFileLoggingModeAppend,
+ _L( "CScardSession::ManageChannel() -- Close channel:\
+ Error %d in removing session.\n" ), err );
+#endif
+ aMessage.Complete( err );
+ return;
+ }
+
+ // If no one else is using the channel send CloseChannel to card
+ if ( !stillOpen )
+ {
+ if ( iAccessCtrl->ReaderIsReady( iSessionID, KChannel0 ) )
+ {
+ // If possible send the close channel APDU
+ DoCommandAndTransmit(
+ aMessage,
+ KCloseChannel,
+ channel,
+ KCommandLengthCloseChannel,
+ KResponseLengthCloseChannel,
+ reinterpret_cast< TInt32>( aMessage.Ptr2() ),
+ KChannel0 );
+ return;
+ }
+
+ // The reader is busy, queue
+ else
+ {
+#ifdef _DEBUG
+ RFileLogger::Write( KScardLogDir, KScardLogFileName,
+ EFileLoggingModeAppend,
+ _L( "CScardSession::ManageChannel() -- reader busy.\
+ message queued.\n" ) );
+#endif
+ iAccessCtrl->QueueExecution( aMessage, iSessionID, 0,
+ KChannel0 );
+ return;
+ }
+ }
+ // Some one else is still on the channel, so we can't physically
+ // close it from the SC
+ else
+ {
+ aMessage.Complete( KErrNone );
+ return;
+ }
+ //break; //unreachable
+ }
+
+ // Check channel status
+ case EChannelStatus:
+ {
+ // Get status
+ TUint16 status = iAccessCtrl->ChannelStatus();
+ TBuf8<2> buf(2);
+ // Split the 16 bit integer to two 8-bit bytes
+ buf[0] = static_cast< TInt8 >( status & 0x00ff );
+ buf[1] = static_cast< TInt8 >( ( status & 0xff00 ) >> 8 );
+
+ // Inform client
+ WriteToClient( aMessage, buf, 1 );
+ aMessage.Complete( KErrNone );
+ break;
+ }
+ // Something's gotten warped
+ default:
+ aMessage.Complete( KScErrBadArgument );
+ break;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::DoCommandAndTransmit
+// Create a command APDU for ManageChannel operations, and send it
+// -----------------------------------------------------------------------------
+//
+void CScardSession::DoCommandAndTransmit(
+ const RMessage2& aMessage,
+ const TUint8 aCommand,
+ const TUint8 aP2,
+ const TInt8 aCommandLength,
+ const TUint8 aResponseLength,
+ const TInt32 aTimeOut,
+ const TUint8 aChannel )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::DoCommandAndTransmit|Begin"));
+
+ TRAPD( memFail, DoCommandAndTransmitL( aMessage,
+ aCommand,
+ aP2,
+ aCommandLength,
+ aResponseLength,
+ aTimeOut,
+ aChannel ) );
+ __ASSERT_MEMORY( memFail );
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::DoCommandAndTransmitL
+// Create a command APDU for ManageChannel operations, and send it
+// -----------------------------------------------------------------------------
+//
+void CScardSession::DoCommandAndTransmitL(
+ const RMessage2& aMessage,
+ const TUint8 aCommand,
+ const TUint8 aP2,
+ const TInt8 aCommandLength,
+ const TUint8 aResponseLength,
+ const TInt32 aTimeOut,
+ const TUint8 aChannel )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::DoCommandAndTransmitL|Begin"));
+ TRequestStatus& status = iAccessCtrl->InitiateCommunication( iSessionID,
+ aMessage, aTimeOut, static_cast< TInt8 >( aChannel ) );
+ __ASSERT_MEMORY( status.Int() );
+
+ // allocate and assert the command
+ iCommandBuffer = HBufC8::NewL( aCommandLength );
+ iCommand = new( ELeave ) TPtr8( iCommandBuffer->Des() );
+
+ // Allocate and assert the response
+
+ // response + 2 status bytes
+ iResponseBuffer = HBufC8::NewL( aResponseLength + 2 );
+ iResponse = new( ELeave ) TPtr8( iResponseBuffer->Des() );
+
+ // Make the command APDU
+ iCommand->SetLength( 4 );
+ (*iCommand)[KCLA] = aChannel;
+ (*iCommand)[KINS] = KManageChannel;
+ (*iCommand)[KP1] = aCommand;
+ (*iCommand)[KP2] = aP2;
+
+ if ( aResponseLength )
+ {
+ // one byte length
+ iCommand->SetLength( 5 );
+ (*iCommand)[KLcHigh] = aResponseLength;
+ }
+
+ // Transmit the APDU to the SC
+#ifdef _DEBUG
+ RFileLogger::HexDump( KScardLogDir, KScardLogFileName,
+ EFileLoggingModeAppend,
+ _S( "CScardSession::DoCommandAndTransmit() command APDU:\n" ), 0,
+ iCommand->Ptr(), iCommand->Length() );
+#endif
+
+ iReader->TransmitToCard( status, *iCommand, *iResponse, aTimeOut );
+ _WIMTRACE(_L("WIM|Scard|CScardSession::DoCommandAndTransmitL|End"));
+ return;
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::WriteToClient
+// Write the provided descriptor to the client thread, 8 bit version.
+// -----------------------------------------------------------------------------
+//
+void CScardSession::WriteToClient(
+ const RMessage2& aMessage,
+ const TDesC8& aResponseBuffer,
+ const TInt aPtrIndex )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::WriteToClient|Begin"));
+
+ TInt desLen = DesLength( aMessage, aPtrIndex, ETrue ); //Len of descriptor;
+
+ // Make sure there is always enough space for the response
+ __ASSERT_ALWAYS( desLen >= aResponseBuffer.Length(),
+ aMessage.Panic( _L( "Response space too short" ),
+ KScServerPanicBadDescriptor ) );
+
+ // Write
+ TRAPD( desError, aMessage.WriteL( aPtrIndex, aResponseBuffer ) );
+
+ if ( desError )
+ {
+ aMessage.Panic( _L( "ScardServer" ), KScServerPanicBadDescriptor );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::WriteToClient
+// Write the provided descriptor to the client thread, 16 bit version.
+// -----------------------------------------------------------------------------
+//
+void CScardSession::WriteToClient(
+ const RMessage2& aMessage,
+ const TDesC16& aResponseBuffer,
+ const TInt aPtrIndex )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::|Begin"));
+ TInt desLen = DesLength( aMessage, aPtrIndex, ETrue ); //Len of descriptor
+ _WIMTRACE2(_L("WIM|Scard|CScardSession:: %d "), desLen );
+ _WIMTRACE2(_L("WIM|Scard|CScardSession:: %d "), aResponseBuffer.Length() );
+
+ // Make sure there is always enough space for the response
+ __ASSERT_ALWAYS( desLen >= aResponseBuffer.Length(),
+ aMessage.Panic( _L( "Response space too short" ),
+ KScServerPanicBadDescriptor ) );
+
+ // Write
+ TRAPD( desError, aMessage.WriteL( aPtrIndex, aResponseBuffer ) );
+
+ if ( desError )
+ {
+ aMessage.Panic( _L( "ScardServer" ), KScServerPanicBadDescriptor );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::ReadFromClient
+// 8 bit version
+// -----------------------------------------------------------------------------
+//
+TInt CScardSession::ReadFromClient(
+ const RMessage2& aMessage,
+ HBufC8*& aBuffer,
+ TPtr8*& aPointer,
+ const TInt aPtrIndex )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::ReadFromClient|Begin"));
+ TInt desLen = DesLength( aMessage, aPtrIndex, EFalse );
+
+ // Allocate the buffer and pointer to it
+ TRAPD( memFail, aBuffer = HBufC8::NewL( desLen ) );
+ __ASSERT_MEMORY( memFail );
+
+ aPointer = new TPtr8( aBuffer->Des() );
+ __ASSERT_MEMORY( !aPointer );
+
+ // Read the descriptor and that's it
+ TRAPD( desError, aMessage.ReadL( aPtrIndex, *aPointer ) );
+ if ( desError )
+ {
+ aMessage.Panic( _L( "ScardServer" ), KScServerPanicBadDescriptor );
+ return KScErrGeneral;
+ }
+ return KErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::AllocateResponse
+// Allocate space for the internal response buffer. The lenght of the
+// necessary space is deduced from the message.
+// -----------------------------------------------------------------------------
+//
+TInt CScardSession::AllocateResponse( const RMessage2& aMessage,
+ const TInt aPtrIndex )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::AllocateResponse|Begin"));
+ TInt desLen = DesLength( aMessage, aPtrIndex, ETrue ); //Len of descriptor;
+
+ // If no space is needed, why bother
+ if ( desLen <= 0 )
+ {
+ return -1;
+ }
+
+ // Allocate and assert the response buffer
+ TRAPD( memFail, AllocateResponseL( desLen ) );
+ __ASSERT_MEMORY( memFail );
+
+ return KErrNone;
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::AllocateResponse
+// Allocate space for the internal response buffer. The lenght of the
+// necessary space is deduced from the message.
+// -----------------------------------------------------------------------------
+//
+void CScardSession::AllocateResponseL( TInt aDesLen )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::AllocateResponseL|Begin"));
+
+ // Allocate the response buffer
+ iResponseBuffer = HBufC8::NewL( aDesLen );
+ iResponse = new( ELeave ) TPtr8( iResponseBuffer->Des() );
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::DeleteBuffers
+// Delete all reserved buffers
+// -----------------------------------------------------------------------------
+//
+void CScardSession::DeleteBuffers()
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::DeleteBuffers|Begin"));
+ delete iCommand;
+ delete iResponse;
+ iCommand = NULL;
+ iResponse = NULL;
+ delete iCommandBuffer;
+ delete iResponseBuffer;
+ iCommandBuffer = NULL;
+ iResponseBuffer = NULL;
+ _WIMTRACE(_L("WIM|Scard|CScardSession::DeleteBuffers|End"));
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::ConnectionDone
+// Connection has established (maybe with error)
+// -----------------------------------------------------------------------------
+//
+void CScardSession::ConnectionDone(
+ const TReaderID& aReaderID,
+ const RMessage2& aMessage,
+ const TInt aErrorCode )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::ConnectionDone|Begin"));
+ // Connection successfully completed, attach to the reader and write the
+ // reader's name to the client thread
+ if ( aErrorCode == KErrNone )
+ {
+ iAccessCtrl = iServer->FindAccessControl( aReaderID );
+ __ASSERT_MEMORY( !iAccessCtrl );
+ TRAPD( readerError, iReader = iAccessCtrl->AttachSessionToReaderL(
+ this, iSessionID ) );
+ if ( readerError == KErrNone )
+ {
+ iConnectedToReader = ETrue;
+ TScardReaderName name( iServer->FriendlyName( aReaderID ) );
+ WriteToClient( aMessage, name, 1 );
+ }
+ else
+ {
+#ifdef _DEBUG
+ RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName,
+ EFileLoggingModeAppend,
+ _L( "CScardSession::ConnectionDone() -- Error %d when attaching\
+ session to reader: \n" ), readerError );
+#endif
+ iConnectedToReader = EFalse;
+ }
+ }
+ // No connection could be established
+ else
+ {
+#ifdef _DEBUG
+ RFileLogger::WriteFormat( KScardLogDir, KScardLogFileName,
+ EFileLoggingModeAppend,
+ _L( "CScardSession::ConnectionDone() -- ERROR: %d.\n" ),
+ aErrorCode );
+#endif
+ iConnectedToReader = EFalse;
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::DesLength
+// Return length of descriptor in client message
+// -----------------------------------------------------------------------------
+//
+TInt CScardSession::DesLength(
+ const RMessage2& aMessage,
+ const TInt aPtrIndex,
+ const TBool aMaxLength )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::DesLength|Begin"));
+ TInt desLen( 0 );
+
+ if ( aMaxLength ) //Get max length
+ {
+ desLen = aMessage.GetDesMaxLength( aPtrIndex );
+ }
+ else
+ {
+ desLen = aMessage.GetDesLength( aPtrIndex );
+ }
+
+ return desLen;
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::MessagePointer
+// Return pointer to wanted block of client message
+// -----------------------------------------------------------------------------
+//
+TAny* CScardSession::MessagePointer(
+ const RMessage2& aMessage,
+ const TInt aPtrIndex )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::MessagePointer|Begin"));
+ TAny* messagePointer = NULL;
+
+ // See from which pointer we are reading and set parameters accordingly
+ switch ( aPtrIndex )
+ {
+ case 0:
+ {
+ messagePointer = ( TAny* )aMessage.Ptr0();
+ break;
+ }
+ case 1:
+ {
+ messagePointer = ( TAny* )aMessage.Ptr1();
+ break;
+ }
+ case 2:
+ {
+ messagePointer = ( TAny* )aMessage.Ptr2();
+ break;
+ }
+ case 3:
+ {
+ messagePointer = ( TAny* )aMessage.Ptr3();
+ break;
+ }
+ default:
+ {
+ User::Panic( _L( "Bad index" ), KScServerPanicInternalError );
+ }
+ }
+ return messagePointer;
+ }
+
+// -----------------------------------------------------------------------------
+// CScardSession::CardEvent
+// This is here only for derivative class CScardConnector
+// It implements and needs this function
+// -----------------------------------------------------------------------------
+//
+void CScardSession::CardEvent(
+ const TScardServiceStatus,
+ const TScardATR&,
+ const TReaderID& )
+ {
+ _WIMTRACE(_L("WIM|Scard|CScardSession::CardEvent|Begin"));
+ }
+
+// End of File