@ -12,7 +12,6 @@
# include <cryptaux.hxx>
# include <cryptaux.hxx>
# include <mrw/shared.hxx>
# include <string>
# include <string>
# ifdef WIN32
# ifdef WIN32
@ -205,7 +204,8 @@ namespace pcsc {
/*! @note Please note that the Reader is required in the
/*! @note Please note that the Reader is required in the
destructor und must therefore live longer than the
destructor und must therefore live longer than the
Transaction instance . */
Transaction instance . */
Transaction ( mrw : : Shared < Reader > r ) : _reader ( r ) , _running ( true ) {
Transaction ( shared_ptr < Reader > : : t r ) :
_reader ( r ) , _running ( true ) {
CRYPTOLOG ( " log " ) ;
CRYPTOLOG ( " log " ) ;
_reader - > beginTransaction ( ) ;
_reader - > beginTransaction ( ) ;
}
}
@ -222,7 +222,7 @@ namespace pcsc {
_running = false ;
_running = false ;
}
}
private :
private :
mrw : : S hared< Reader > _reader ;
s hared_ptr < Reader > : : t _reader ;
bool _running ;
bool _running ;
} ;
} ;
@ -424,7 +424,7 @@ namespace pcsc {
friend class Connection ;
friend class Connection ;
//! Establishes a connection to the given named cardreader
//! Establishes a connection to the given named cardreader
Reader ( const std : : string & nm , const Connection & c ,
Reader ( const std : : string & nm , shared_ptr < Connection > : : t c ,
DWORD mode = SCARD_SHARE_SHARED ,
DWORD mode = SCARD_SHARE_SHARED ,
DWORD protocol = SCARD_PROTOCOL_T1 ) :
DWORD protocol = SCARD_PROTOCOL_T1 ) :
name ( nm ) , _connection ( c ) {
name ( nm ) , _connection ( c ) {
@ -441,7 +441,7 @@ namespace pcsc {
//...........................................................variables
//...........................................................variables
private :
private :
mrw : : S hared< Connection > _connection ;
s hared_ptr < Connection > : : t _connection ;
SCARDHANDLE _id ;
SCARDHANDLE _id ;
DWORD _state ;
DWORD _state ;
DWORD _protocol ;
DWORD _protocol ;
@ -461,64 +461,22 @@ namespace pcsc {
//................................................................methods
//................................................................methods
public :
public :
//! Opens a connection (establishes a smartcard context)
/*! The errorhandling is defined with the @c exceptions flag:
Using exceptions :
@ code
try {
pcsc : : Connection c ; // standard with exceptions
pcsc : : Connection : : Strings r ( c . scan ( ) ) ;
} catch ( std : : exception & x ) {
std : : cout < < " Error with message: " < < x . what ( ) < < std : : endl ;
}
@ endcode
Without exceptions :
@ code
pcsc : : Connection c ( SYSTEM , false ) ;
if ( ! c ) std : : cout < < " Error with message: " < < c . error ( ) < < std : : endl ;
pcsc : : Connection : : Strings r ( c . scan ( ) ) ;
if ( ! c ) std : : cout < < " Error with message: " < < c . error ( ) < < std : : endl ;
@ endcode
Recommendation : Use exceptions !
@ param s defines the scope of the connection
@ param exceptions
- @ c true : class throws exceptions in case of an error
- @ c false : no exceptions , check your instance after each
operation */
Connection ( Scope s = USER , bool exceptions = true ) :
_connectionlifetime ( connectionlifetime ( s , exceptions ) ) {
+ + connectionlifetimecounter ( ) ;
CRYPTOLOG ( " Connection Counter is now: " < < connectionlifetimecounter ( ) ) ;
check ( " establish smartcard context " ) ;
}
Connection ( const Connection & o ) {
+ + connectionlifetimecounter ( ) ;
* this = o ;
}
//! Closes the connection (releases the smartcard context)
//! Closes the connection (releases the smartcard context)
~ Connection ( ) {
~ Connection ( ) {
// connection is closed, when _connectionlifetime is destructed
CRYPTOLOG ( " Close Connection id= " < < _id ) ;
if ( - - connectionlifetimecounter ( ) = = 0 ) {
_state = SCardReleaseContext ( _id ) ;
CRYPTOLOG ( " Delete Connection " ) ;
if ( ! std : : uncaught_exception ( ) ) check ( " smartcard release context " ) ;
delete connectionlifetime ( ) ;
connectionlifetime ( ) = 0 ;
}
CRYPTOLOG ( " Connection Counter is now: " < < connectionlifetimecounter ( ) ) ;
}
}
//! Scans for available readers from a specified list of groups.
//! Scans for available readers from a specified list of groups.
/*! Defaults to all groups. */
/*! Defaults to all groups. */
Strings scan ( const Strings & groups = Strings ( ) ) {
static Strings scan ( const Strings & groups = Strings ( ) ,
Scope s = USER , bool exceptions = true ) {
Connection c ( s , exceptions ) ;
Strings res ;
Strings res ;
std : : string grp ( join ( groups ) ) ;
std : : string grp ( c . join ( groups ) ) ;
DWORD num ( 0 ) ;
DWORD num ( 0 ) ;
if ( ! check ( SCardListReaders ( _connectionlifetime - > id ( ) ,
if ( ! c . check ( SCardListReaders ( c . _id ,
groups . size ( ) ? strconv ( grp ) . data ( ) : 0 , 0 ,
groups . size ( ) ? strconv ( grp ) . data ( ) : 0 , 0 ,
& num ) ,
& num ) ,
" smartcard get size of readers of groups " + grp ) )
" smartcard get size of readers of groups " + grp ) )
@ -526,7 +484,7 @@ namespace pcsc {
CRYPTOLOG ( " size of readers: " < < num ) ;
CRYPTOLOG ( " size of readers: " < < num ) ;
if ( ! num ) return res ;
if ( ! num ) return res ;
std : : auto_ptr < char_t > nm ( new char_t [ num ] ) ;
std : : auto_ptr < char_t > nm ( new char_t [ num ] ) ;
if ( ! check ( SCardListReaders ( _connectionlifetime - > id ( ) ,
if ( ! c . check ( SCardListReaders ( c . _id ,
groups . size ( ) ? strconv ( grp ) . data ( ) : 0 ,
groups . size ( ) ? strconv ( grp ) . data ( ) : 0 ,
nm . get ( ) , & num ) ,
nm . get ( ) , & num ) ,
" smartcard list reader names of groups " + grp ) )
" smartcard list reader names of groups " + grp ) )
@ -535,86 +493,76 @@ namespace pcsc {
if ( ! num ) return res ;
if ( ! num ) return res ;
CRYPTOLOG ( " list of readers: "
CRYPTOLOG ( " list of readers: "
< < crypto : : readable ( std : : string ( nm . get ( ) , num - 1 ) ) ) ;
< < crypto : : readable ( std : : string ( nm . get ( ) , num - 1 ) ) ) ;
return res = split ( strconv ( string ( nm . get ( ) , num - 1 ) ) ) ;
return res = c . split ( strconv ( string ( nm . get ( ) , num - 1 ) ) ) ;
}
//! Get a reader, open a connection if not already open.
/*! First use scan() to get a list of readers, then open a
connection to the reader , then access it . */
mrw : : Shared < Reader > reader ( const std : : string & name ) {
return _connectionlifetime - > reader ( name , this ) ;
}
// //! Close connection of a named reader.
// /*! If you access the same reader through raeder() later, the
// connection will be reestablished. */
// void close(const std::string& s) {
// }
/// Reset and reestablish the connection.
/** @note You must remove all readers that have been returned by
@ ref reader ( ) , if you have assigned them to a variable
and stored them . Otherwise the connections will remain
open and next access should probably fail .
@ begincode
{
mrw : : Shared < Reader > r ( c . reader ( name ) ) ;
// use r
c . reset ( ) ; // now r is invalid
// either reassign r:
r = c . reader ( name ) ;
// or simply reset it
r . reset ( ) ;
}
// or clenaup by leaving the context of r
@ endcode */
void reset ( ) {
_connectionlifetime - > reset ( ) ;
}
}
//! Find all readers with a given ATR.
//! Find all readers with a given ATR.
/*! @param atr full or partial ATR to match to the reader's ATR
/*! @param atr full or partial ATR to match to the reader's ATR
@ returns list of readers that contain @ c atr in their ATR */
@ returns list of readers that contain @ c atr in their ATR */
Strings getReadersWithAtr ( const std : : string & atr ) {
static Strings getReadersWithAtr ( const std : : string & atr ,
Scope s = USER , bool exceptions = true ) {
Connection c ( s , exceptions ) ;
Strings res ;
Strings res ;
pcsc : : Connection : : Strings readers ( scan ( ) ) ;
pcsc : : Connection : : Strings readers ( c . scan ( ) ) ;
for ( pcsc : : Connection : : Strings : : const_iterator it ( readers . begin ( ) ) ;
for ( pcsc : : Connection : : Strings : : const_iterator it ( readers . begin ( ) ) ;
it ! = readers . end ( ) ; + + it )
it ! = readers . end ( ) ; + + it )
if ( crypto : : hex ( reader ( * it ) - > status ( ) . atr ) . find ( atr ) ! = string : : npos )
if ( crypto : : hex ( c . reader ( * it ) - > status ( ) . atr ) . find ( atr ) ! = string : : npos )
res . push_back ( * it ) ;
res . push_back ( * it ) ;
return res ;
return res ;
}
}
//! @c false if last operation was not successful
//! Get a reader, open a connection if not already open.
operator bool ( ) const {
/*! First use scan() to get a list of readers, then open a
return * _connectionlifetime ;
connection to the reader , then access it . */
static shared_ptr < Reader > : : t reader ( const std : : string & name ,
Scope s = USER , bool exceptions = true ) {
CRYPTOLOG ( " get reader: " < < name ) ;
return shared_ptr < Reader > : : t
( new Reader ( name ,
shared_ptr < Connection > : : t
( new Connection ( s , exceptions ) ) ) ) ;
}
}
//................................................................methods
//................................................................methods
private :
private :
mrw : : Shared < Reader > newreader ( const std : : string & name ) {
//! Opens a connection (establishes a smartcard context)
return new Reader ( name , * this ) ;
/*! The errorhandling is defined with the @c exceptions flag:
}
//! Sets state and throws an exception if neccessary.
Using exceptions :
/*! @throw access_error if it is instanciated for exceptions and
@ code
an error occured in the last command . */
try {
bool check ( long state , const std : : string & context = " " ) {
pcsc : : Connection c ; // standard with exceptions
_connectionlifetime - > state ( state ) ;
pcsc : : Connection : : Strings r ( c . scan ( ) ) ;
return check ( context ) ;
} catch ( std : : exception & x ) {
std : : cout < < " Error with message: " < < x . what ( ) < < std : : endl ;
}
}
@ endcode
//! Throws an exception if neccessary.
Without exceptions :
/*! @throw access_error if it is instanciated for exceptions and
@ code
an error occured in the last command . */
pcsc : : Connection c ( SYSTEM , false ) ;
bool check ( const std : : string & context = " " ) {
if ( ! c ) std : : cout < < " Error with message: " < < c . error ( ) < < std : : endl ;
return _connectionlifetime - > check ( context ) ;
pcsc : : Connection : : Strings r ( c . scan ( ) ) ;
if ( ! c ) std : : cout < < " Error with message: " < < c . error ( ) < < std : : endl ;
@ endcode
Recommendation : Use exceptions !
@ param s defines the scope of the connection
@ param exceptions
- @ c true : class throws exceptions in case of an error
- @ c false : no exceptions , check your instance after each
operation */
Connection ( Scope s = USER , bool exceptions = true ) :
_exc ( exceptions ) , _id ( 0 ) , _s ( s ) ,
_state ( SCardEstablishContext ( s , 0 , 0 , & _id ) ) {
CRYPTOLOG ( " Open Connection id= " < < _id ) ;
check ( " establish smartcard context " ) ;
}
}
//! Splits a buffer with 0 separators into a vector of strings.
//! Splits a buffer with 0 separators into a vector of strings.
Strings split ( const std : : string & in ) {
static Strings split ( const std : : string & in ) {
Strings res ;
Strings res ;
for ( std : : string : : size_type pos ( 0 ) ; pos < in . size ( ) & & in [ pos ] ! = 0 ;
for ( std : : string : : size_type pos ( 0 ) ; pos < in . size ( ) & & in [ pos ] ! = 0 ;
pos + = res . rbegin ( ) - > size ( ) + 1 )
pos + = res . rbegin ( ) - > size ( ) + 1 )
@ -623,7 +571,7 @@ namespace pcsc {
}
}
//! Joins a vector of strings into a buffer with 0 separators.
//! Joins a vector of strings into a buffer with 0 separators.
std : : string join ( const Strings & in ) {
static std : : string join ( const Strings & in ) {
std : : string res ;
std : : string res ;
if ( in . size ( ) ) {
if ( in . size ( ) ) {
for ( Strings : : const_iterator it ( in . begin ( ) ) ;
for ( Strings : : const_iterator it ( in . begin ( ) ) ;
@ -634,35 +582,6 @@ namespace pcsc {
return res ;
return res ;
}
}
//! Connection id
SCARDCONTEXT id ( ) {
return _connectionlifetime - > id ( ) ;
}
//! @c true if exceptions are thrown
bool exc ( ) {
return _connectionlifetime - > exc ( ) ;
}
//..............................................................variables
private :
class ConnectionLifetime {
public :
//! opens connection that is closed on destruction
ConnectionLifetime ( Scope s , bool exc ) :
_exc ( exc ) , _id ( 0 ) , _s ( s ) ,
_state ( SCardEstablishContext ( s , 0 , 0 , & _id ) ) {
CRYPTOLOG ( " Open Connection " ) ;
check ( " establish smartcard context " ) ;
}
//! Closes the connection (releases the smartcard context)
~ ConnectionLifetime ( ) {
CRYPTOLOG ( " Close Connection " ) ;
_state = SCardReleaseContext ( _id ) ;
if ( ! std : : uncaught_exception ( ) ) check ( " smartcard release context " ) ;
}
//! @c false if last operation was not successful
operator bool ( ) const {
operator bool ( ) const {
# ifdef WIN32
# ifdef WIN32
return ( _state > > 30 & 3 ) = = 0 ;
return ( _state > > 30 & 3 ) = = 0 ;
@ -670,6 +589,15 @@ namespace pcsc {
return _state = = SCARD_S_SUCCESS ;
return _state = = SCARD_S_SUCCESS ;
# endif
# endif
}
}
//! Throws an exception if neccessary.
/*! @throw access_error if it is instanciated for exceptions and
an error occured in the last command . */
bool check ( long state , const std : : string & context = " " ) {
_state = state ;
check ( context ) ;
}
//! Throws an exception if neccessary.
//! Throws an exception if neccessary.
/*! @throw access_error if it is instanciated for exceptions and
/*! @throw access_error if it is instanciated for exceptions and
an error occured in the last command . */
an error occured in the last command . */
@ -1075,25 +1003,6 @@ namespace pcsc {
return _exc ;
return _exc ;
}
}
//! Get a reader, open a connection if not already open.
/*! First use scan() to get a list of readers, then open a
connection to the reader , then access it . */
mrw : : Shared < Reader > reader ( const std : : string & name , Connection * c ) {
CRYPTOLOG ( " get reader: " < < name < < " from " < < ( void * ) & _readers ) ;
if ( _readers . find ( name ) = = _readers . end ( ) )
_readers . insert ( std : : make_pair ( name , c - > newreader ( name ) ) ) ;
return _readers . find ( name ) - > second ;
}
/// Cleans up the readers, resets the context.
void reset ( ) {
_readers . clear ( ) ;
_state = SCardReleaseContext ( _id ) ;
check ( " smartcard release context " ) ;
_state = SCardEstablishContext ( _s , 0 , 0 , & _id ) ;
check ( " establish smartcard context " ) ;
}
private :
private :
bool _exc ;
bool _exc ;
@ -1101,32 +1010,6 @@ namespace pcsc {
Scope _s ;
Scope _s ;
long _state ;
long _state ;
//! Readers are closed when the last shared object is destructed
std : : map < std : : string , mrw : : Shared < Reader > > _readers ;
} ;
//! Connection is closed when the last shared object is destructed
/*! Handling the connection lifetime in a separate shared object
allows to copy connections and still make sure , that the
lifetime of the connection is as long as all copied opbjects
live . */
static ConnectionLifetime * &
connectionlifetime ( Scope s = USER , bool exc = true ) {
static ConnectionLifetime * instance ( 0 ) ;
if ( instance = = 0 ) {
CRYPTOLOG ( " New Connection " ) ;
instance = new ConnectionLifetime ( s , exc ) ;
}
return instance ;
}
static int & connectionlifetimecounter ( ) {
static int instance ( 0 ) ;
return instance ;
}
ConnectionLifetime * _connectionlifetime ;
} ;
} ;
//@}
//@}