|
|
|
@ -143,6 +143,13 @@ namespace pcsc { |
|
|
|
|
runtime_error(const std::string& reason, const std::string& data) throw(): |
|
|
|
|
exception("runtime error,\n"+reason+":\n"+crypto::hex(data)) {} |
|
|
|
|
}; |
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
class neesting_error: public exception { |
|
|
|
|
public: |
|
|
|
|
neesting_error() throw(): |
|
|
|
|
exception("neesting error: more endTransaction than beginTransaction") |
|
|
|
|
{} |
|
|
|
|
}; |
|
|
|
|
//@}
|
|
|
|
|
|
|
|
|
|
//! @addtogroup pcsclib
|
|
|
|
@ -165,25 +172,26 @@ namespace pcsc { |
|
|
|
|
friend class Transaction; |
|
|
|
|
//! Scoped transaction.
|
|
|
|
|
/*! This is a scoped transaction. That means, the
|
|
|
|
|
transaction is started in the constructor and cancelled |
|
|
|
|
in the destructor, unless it is committed before. That |
|
|
|
|
means: If you commit the transaction, it is executed. If |
|
|
|
|
you leave the code block unexpectedly, i.e. through an |
|
|
|
|
exception, the transaction is cancelled. |
|
|
|
|
transaction is started in the constructor and ended in |
|
|
|
|
the destructor, unless it is already ended before. In |
|
|
|
|
case of an exception or leaving the block, the |
|
|
|
|
transaction is always cleaned up. |
|
|
|
|
|
|
|
|
|
There's a neesting counter to make sure, transaction is |
|
|
|
|
started only once and ended only once, even though the |
|
|
|
|
locking can be neested. |
|
|
|
|
|
|
|
|
|
@code |
|
|
|
|
pcsc::Connection c; |
|
|
|
|
{ |
|
|
|
|
Transaction t(c.reader("name")); |
|
|
|
|
[...] // do some stuff, possible exceptions thrown
|
|
|
|
|
if (problem) return; // automatically cancelled
|
|
|
|
|
if (problem) return; // automatically ended
|
|
|
|
|
[...] |
|
|
|
|
t.commit(); // commit if we reach this line
|
|
|
|
|
} // cancelled, unless commit reaced
|
|
|
|
|
@endcode |
|
|
|
|
|
|
|
|
|
@note Micro$oft QinSCard does not know cancel, therefore |
|
|
|
|
on Windoze cancel is replaced by commit. */ |
|
|
|
|
t.end(); // ended if we reach this line
|
|
|
|
|
[...] |
|
|
|
|
} // also ended, unless commit reaced
|
|
|
|
|
@endcode */ |
|
|
|
|
class Transaction { |
|
|
|
|
public: |
|
|
|
|
//! Begins a transaction.
|
|
|
|
@ -195,18 +203,13 @@ namespace pcsc { |
|
|
|
|
} |
|
|
|
|
//! Cancels the transaction if not yet finished.
|
|
|
|
|
~Transaction() try { |
|
|
|
|
cancel(); |
|
|
|
|
end(); |
|
|
|
|
} catch (...) { |
|
|
|
|
if (!std::uncaught_exception()) throw; |
|
|
|
|
} |
|
|
|
|
//! Ends (commits) the running transaction.
|
|
|
|
|
void commit() { |
|
|
|
|
if (_running) _reader.commitTransaction(); |
|
|
|
|
_running = false; |
|
|
|
|
} |
|
|
|
|
//! Cancels the running transaction.
|
|
|
|
|
void cancel() { |
|
|
|
|
if (_running) _reader.cancelTransaction(); |
|
|
|
|
//! Ends the running transaction.
|
|
|
|
|
void end() { |
|
|
|
|
if (_running) _reader.endTransaction(); |
|
|
|
|
_running = false; |
|
|
|
|
} |
|
|
|
|
private: |
|
|
|
@ -348,25 +351,26 @@ namespace pcsc { |
|
|
|
|
private: |
|
|
|
|
|
|
|
|
|
//! Use scoped transactions with @ref Transaction
|
|
|
|
|
/*! Calls @c SCardBeginTransaction unless it's already inside
|
|
|
|
|
a transaction. */ |
|
|
|
|
void beginTransaction() { |
|
|
|
|
if (++_neesting==1) |
|
|
|
|
check(SCardBeginTransaction(_id), "smartcard begin transaction"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
//! Use scoped transactions with @ref Transaction
|
|
|
|
|
void commitTransaction() { |
|
|
|
|
check(SCardEndTransaction(_id, SCARD_LEAVE_CARD), |
|
|
|
|
"smartcard end transaction"); |
|
|
|
|
} |
|
|
|
|
/*! Calls @c SCardEndTransaction if it's inside a transaction.
|
|
|
|
|
|
|
|
|
|
//! Use scoped transactions with @ref Transaction
|
|
|
|
|
/*! @note Micro$oft QinSCard does not know cancel, therefore
|
|
|
|
|
on Windoze cancel is replaced by commit. */ |
|
|
|
|
void cancelTransaction() { |
|
|
|
|
#ifndef WIN32 |
|
|
|
|
check(SCardCancelTransaction(_id), "smartcard cancel transaction"); |
|
|
|
|
#endif |
|
|
|
|
@throws neesting_error if there are more calls to @c |
|
|
|
|
endTransaction than to @c beginTransaction. */ |
|
|
|
|
void endTransaction() { |
|
|
|
|
if (--_neesting==0) |
|
|
|
|
check(SCardEndTransaction(_id, SCARD_LEAVE_CARD), |
|
|
|
|
"smartcard end transaction"); |
|
|
|
|
else if (_neesting<0) { |
|
|
|
|
_neesting = 0; |
|
|
|
|
throw neesting_error(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/*! @throw not_implemented if _protocol is unknown. */ |
|
|
|
@ -414,6 +418,7 @@ namespace pcsc { |
|
|
|
|
SCARDHANDLE _id; |
|
|
|
|
DWORD _state; |
|
|
|
|
DWORD _protocol; |
|
|
|
|
static int _neesting; |
|
|
|
|
|
|
|
|
|
}; |
|
|
|
|
//------------------------------------------------------------------Reader
|
|
|
|
|