📄 pcscreader.cpp
字号:
/* ============================================================================ Project Name : jayaCard Module Name : inkit - PCSCReader.cpp Version : $Id: PCSCReader.cpp,v 1.9 2003/11/13 18:11:32 pfremy Exp $ Description: The Original Code is inKit code, the contactless library of the jayacard project (http://www.jayacard.org). The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Initial Developer of the Original Code is inSeal SAS and the authors Gilles Dumortier and Philippe Fremy. Portions created by the Initial Developer are Copyright (C) 1996-2003 the Initial Developer. All Rights Reserved. Alternatively, the contents of this file may be used under the terms of either the GNU General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the LGPL are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of either the GPL or the LGPL, and not to allow others to use your version of this file under the terms of the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the GPL or the LGPL. If you do not delete the provisions above, a recipient may use your version of this file under the terms of any one of the MPL, the GPL or the LGPL. inKit is also available under commercial license. For pricing and ordering information, send an email to sales@inseal.com History Rev Description 060803 phf wrote it from scratch ============================================================================*//* ========================================================================= */#include <string>#include <sstream>#include "inkit/jaya_reader/PCSCReader/PCSCReader.h"#include <winscard.h>#ifndef WIN32#include <pcsclite.h>#endifnamespace Jayacard {void * PCSCReader::operator new( size_t tSize ){ return malloc( tSize );}void PCSCReader::operator delete( void *p ){ free(p);}/* ========================================================================= PCSCReader - constructor On construction, the class connects to the reader and retrieves the serial number, to validate the reader's presence. ========================================================================= */PCSCReader::PCSCReader( string type, string configString, jresult * result ) : JayaReader( type, configString, result ){ LONG rv; // *** need to handle / parse configString // establish a connection context to the PC/SC ressource manager rv = SCardEstablishContext( SCARD_SCOPE_SYSTEM, NULL, NULL, &_hContext ); if ( rv != SCARD_S_SUCCESS ) { *result = convertPCSCError( rv ); jlog( "PCSCReader", "Error when establishing PC/SC context" ); return; } // test the availability of the reader SCARD_READERSTATE rgReaderState; rgReaderState.szReader = (LPCSTR)strdup( _type.c_str() ); rgReaderState.dwCurrentState = SCARD_STATE_UNAWARE; rv = SCardGetStatusChange( _hContext, 0, &rgReaderState, 1 ); if ( rv != SCARD_S_SUCCESS ) { *result = convertPCSCError( rv ); jlog( "PCSCReader", "Error when checking for status of reader '%s'", _type.c_str() ); } else if ( rgReaderState.dwEventState & SCARD_STATE_IGNORE || rgReaderState.dwEventState & SCARD_STATE_UNKNOWN || rgReaderState.dwEventState & SCARD_STATE_UNAVAILABLE ) { *result = convertPCSCError( rv ); jlog( "PCSCReader", "Error - reader '%s' is unavailable", _type.c_str() ); } // various initializations _hCard = NULL; _dwActiveProtocol = SCARD_PROTOCOL_UNDEFINED;}/* ========================================================================= ~PCSCReader - destructor ========================================================================= */PCSCReader::~PCSCReader(){ LONG rv; // release the connection context rv = SCardReleaseContext( _hContext ); if ( rv != SCARD_S_SUCCESS ) jlog( "PCSCReader", "Error when releasing PC/SC context" );}/* ========================================================================= powerOn Powers on the card. Most readers automatically power on the card but some do not [powerOn should always succeed (when a card is in)]. ========================================================================= */jresult PCSCReader::powerOn( Apdu & atr ){ LONG rv; _lastResult = JY_OK; if ( _isPowered == false ) { // connect to the reader (and power up the card) // *** pass the reader name elsewhere than in _type? rv = SCardConnect( _hContext, (LPCSTR)_type.c_str(), SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &_hCard, &_dwActiveProtocol ); if ( rv != SCARD_S_SUCCESS ) { _isPowered = false; _lastResult = convertPCSCError( rv ); jlog( "PCSCReader", "Error when connecting to the reader '%s'", _type.c_str() ); return _lastResult; } // the card is now powered on _isPowered = true; } else { // card already connected, we do a warm reset rv = SCardReconnect( _hCard, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, SCARD_RESET_CARD, &_dwActiveProtocol ); // *** or cold reset if ( rv != SCARD_S_SUCCESS ) { _isPowered = false; _lastResult = convertPCSCError( rv ); jlog( "PCSCReader", "Error when reconnecting the reader '%s'", _type.c_str() ); return _lastResult; } } // get the ATR of the card DWORD dwReaderLen; DWORD dwState; DWORD dwProtocol; BYTE pbAtr[33]; // *** check if size is ok DWORD dwAtrLen; rv = SCardStatus( _hCard, NULL, &dwReaderLen, &dwState, &dwProtocol, pbAtr, &dwAtrLen ); if ( rv != SCARD_S_SUCCESS ) { _isPowered = false; _lastResult = convertPCSCError( rv ); jlog( "PCSCReader", "Error when retrieving the card ATR" ); } else if ( dwState == SCARD_ABSENT || dwState == SCARD_SWALLOWED || dwState == SCARD_POWERED ) // see winsmcrd.h, not OR'ed values { _isPowered = false; _lastResult = JY_NOT_POWERED; jlog( "PCSCReader", "Error when retrieving the card ATR" ); } atr.set( (jbyte*)pbAtr, dwAtrLen ); // *** efficient enough? return _lastResult;}/* ========================================================================= powerOff Powers off the card. ========================================================================= */jresult PCSCReader::_powerOff(){ LONG rv; _lastResult = JY_OK; if (_hCard != NULL) { // disconnect from the reader rv = SCardDisconnect( _hCard, SCARD_UNPOWER_CARD ); // *** or eject? if ( rv != SCARD_S_SUCCESS ) { _lastResult = convertPCSCError( rv ); jlog( "PCSCReader", "Error when disconnecting from the reader '%s'", _type.c_str() ); } } _hCard = NULL; _isPowered = false; return _lastResult;}/* ========================================================================= isCardPresent Test if card is present. ========================================================================= */jresult PCSCReader::isCardPresent( bool & cardPresent ){ LONG rv; cardPresent = false; _lastResult = JY_OK; // test if the card is present in the reader SCARD_READERSTATE rgReaderState; rgReaderState.szReader = (LPCSTR)strdup( _type.c_str() ); rgReaderState.dwCurrentState = SCARD_STATE_UNAWARE; rv = SCardGetStatusChange( _hContext, 0, &rgReaderState, 1 ); if ( rv != SCARD_S_SUCCESS ) { _lastResult = convertPCSCError( rv ); jlog( "PCSCReader", "Error when checking for card presence in reader '%s'", _type.c_str() ); } else if ( rgReaderState.dwEventState & SCARD_STATE_PRESENT ) cardPresent = true; return _lastResult;}/* ========================================================================= internalExchangeApdu [internal] Exchange Apdu with the card. ========================================================================= */jresult PCSCReader::internalExchangeApdu( jbyte * command, int commandLen, jbyte * response, int * responseLen ){ LONG rv; LPCSCARD_IO_REQUEST pioSendPci; _lastResult = JY_OK; // point the right i/o request structure depending on the protocol if ( _dwActiveProtocol == SCARD_PROTOCOL_T0 ) pioSendPci = SCARD_PCI_T0; else if ( _dwActiveProtocol == SCARD_PROTOCOL_T1 ) pioSendPci = SCARD_PCI_T1; else return _lastResult = JY_UNSUPPORTED_MODE; // exchange the Apdu with the card rv = SCardTransmit( _hCard, pioSendPci, (LPCBYTE)command, (DWORD)commandLen, NULL, (LPBYTE)response, (LPDWORD)responseLen ); // need to try a reconnect? (or shared mode, card reset only) if ( rv != SCARD_S_SUCCESS ) { _lastResult = convertPCSCError( rv ); jlog( "PCSCReader", "Error exchanging APDU on reader '%s'", _type.c_str() ); } return _lastResult;}/* ========================================================================= getSerialNumber Serial number or identifier of the reader. In case of error, a null string is returned and lastResult is set. ========================================================================= */jresult PCSCReader::getSerialNumber( string & serialNumber ){#ifdef WIN32 LONG rv; BYTE * pbAttr; DWORD dwAttrLen; _lastResult = JY_OK; // we need a hCard to call SCardGetAttrib, but we're not necessarily // connected, and if we try to connect without a card inserted, // SCardConnect won't return a valid hCard anyway. // // SO, for the moment, we only try to return the serial if connected // to a reader and card if ( _hCard != NULL ) { // ask for the buffer size needed for the serial rv = SCardGetAttrib( _hCard, // SCARD_ATTR_VENDOR_IFD_VERSION SCARD_ATTR_VENDOR_IFD_SERIAL_NO, NULL, &dwAttrLen ); if ( rv != SCARD_S_SUCCESS ) { _lastResult = convertPCSCError( rv ); jlog( "PCSCReader", "Error getting the serial number of reader '%s'", _type.c_str() ); return _lastResult; } // allocate the buffer pbAttr = (BYTE *) malloc( dwAttrLen*sizeof(BYTE) ); if ( pbAttr == NULL ) { _lastResult = JY_ALLOCATION_FAILURE; jlog( "PCSCReader", "Error when allocation memory for " "the serial number of reader '%s'", _type.c_str() ); return _lastResult; } // ask for the serial number rv = SCardGetAttrib( _hCard, SCARD_ATTR_VENDOR_IFD_SERIAL_NO, pbAttr, &dwAttrLen ); if ( rv != SCARD_S_SUCCESS ) { _lastResult = convertPCSCError( rv ); jlog( "PCSCReader", "Error getting the serial number of reader '%s'", _type.c_str() ); return _lastResult; } // convert the serial into a string ostringstream buf; for (int i=0 ; i<dwAttrLen ; i++ ) buf << pbAttr[i]; serialNumber = buf.str(); } else { serialNumber = "NoSerial"; _lastResult = JY_OK; } return _lastResult;#else // unix // *** Need to be implemented, return "NoSerial" for the moment serialNumber = "NoSerial"; _lastResult = JY_OK; return _lastResult;#endif // WIN32}/* ========================================================================= _extraCommand [internal] Allow to pass custom commands to reader. ========================================================================= */string PCSCReader::_extraCommand( string cmd, string arg ){ return "";}/* ========================================================================= convertPCSCError [internal] Allow to pass custom commands to reader. ========================================================================= */jresult PCSCReader::convertPCSCError( LONG rv ){ switch ( rv ) { case SCARD_S_SUCCESS: return JY_SUCCESS; // invalid scope, hContext, hCard or disposition // (SCardEstablishContext, SCardConnect, SCardReconnect, SCardDisconnect, // SCardTransmit, SCardStatus, SCardGetStatusChange) case SCARD_E_INVALID_VALUE: case SCARD_E_INVALID_HANDLE: return JY_BAD_ARGUMENT; // no card inserted when connecting // (SCardConnect) case SCARD_E_NO_SMARTCARD: return JY_FAILED; // *** create a new jaya_error // could not power up the reader or card // (SCardConnect, SCardReconnect) case SCARD_E_READER_UNAVAILABLE: case SCARD_E_NOT_READY: // *** not sure about this one return JY_NOT_POWERED; // *** create a new jaya_error? // protocol not supported // (SCardConnect, SCardReconnect)// case SCARD_E_UNSUPPORTED_FEATURE: // return JY_UNSUPPORTED_MODE; // *** or JY_PROTOCOL_ERROR ? // APDU exchange not successful // (SCardTransmit) case SCARD_E_NOT_TRANSACTED: return JY_FAILED; // *** create a new jaya_error // connect protocol is different than desired // (SCardTransmit) case SCARD_E_PROTO_MISMATCH: return JY_PROTOCOL_ERROR; case SCARD_E_INSUFFICIENT_BUFFER: // should not happen return JY_BUFFER_TOO_SMALL; case SCARD_F_UNKNOWN_ERROR: case SCARD_F_INTERNAL_ERROR: case SCARD_E_SHARING_VIOLATION: // should not happen case SCARD_W_RESET_CARD: // return JY_UNEXPECTED; default: return JY_FAILED; }}/* ========================================================================= */} /* namespace Jayacard */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -