diff --git a/src/makefile.am b/src/makefile.am index 91d4ead..c56831a 100644 --- a/src/makefile.am +++ b/src/makefile.am @@ -7,9 +7,13 @@ include_HEADERS = pcsc.hxx cryptoki.hxx openssl.hxx cryptaux.hxx +if !MINGW32 if MAC AM_CPPFLAGS += -I/opt/local/include -I/Library/OpenSC/include AM_LDFLAGS = -F/System/Library/Frameworks/PCSC.framework -L/opt/local/lib +else +AM_CPPFLAGS += -I/usr/include/PCSC +endif endif pkcs11dir = ${includedir}/pkcs11 @@ -24,7 +28,7 @@ EXTRA_DIST = $(pkgconfig_DATA).in $(shell ls -1 *.doc) lib_LTLIBRARIES = libcryptoki++.la -libcryptoki___la_SOURCES = cryptoki.cxx cryptoki.hxx version.cxx +libcryptoki___la_SOURCES = cryptoki.cxx cryptoki.hxx pcsc.cxx version.cxx libcryptoki___la_LIBADD = -lssl if !MINGW32 if !MAC diff --git a/src/pcsc.cxx b/src/pcsc.cxx new file mode 100644 index 0000000..8664fd3 --- /dev/null +++ b/src/pcsc.cxx @@ -0,0 +1,10 @@ +/*! @file + + @id $Id$ +*/ +// 1 2 3 4 5 6 7 8 +// 45678901234567890123456789012345678901234567890123456789012345678901234567890 + +#include + +int pcsc::Connection::Reader::_neesting(0); diff --git a/src/pcsc.hxx b/src/pcsc.hxx index 589ed08..503fb39 100644 --- a/src/pcsc.hxx +++ b/src/pcsc.hxx @@ -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() { - check(SCardBeginTransaction(_id), "smartcard begin transaction"); - } - - //! Use scoped transactions with @ref Transaction - void commitTransaction() { - check(SCardEndTransaction(_id, SCARD_LEAVE_CARD), - "smartcard end transaction"); + if (++_neesting==1) + check(SCardBeginTransaction(_id), "smartcard begin 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 - check(SCardEndTransaction(_id, SCARD_LEAVE_CARD), - "smartcard end transaction"); + /*! Calls @c SCardEndTransaction if it's inside a transaction. + + @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