Chipcard-PCSC
view release on metacpan or search on metacpan
void* pvReserved2
PREINIT:
SCARDCONTEXT hContext = 0;
CODE:
ST(0) = sv_newmortal();
gnLastError = hEstablishContext (dwScope, pvReserved1, pvReserved2, &hContext);
/* Then we either return an explicit 'UNDEF' value or the handle */
if (gnLastError != SCARD_S_SUCCESS) {
ST(0) = &PL_sv_undef;
} else {
sv_setiv (ST(0), hContext);
}
#///////////////////////////////////////////////////////////////////////////
#// ReleaseContext ()
#//
#// INPUT :
#// - $hContext -> Connection context to be closed
#//
#// OUTPUT :
#// - ReleaseContext returns a true value on successful operation and a
#// false value otherwise.
bool
_ReleaseContext (hContext)
unsigned long hContext
CODE:
gnLastError = hReleaseContext (hContext);
/* Then returns true or false according to the return code */
if (gnLastError != SCARD_S_SUCCESS) {
RETVAL = FALSE;
} else {
RETVAL = TRUE;
}
OUTPUT:
RETVAL
#///////////////////////////////////////////////////////////////////////////
#// ListReaders ()
#//
#// INPUT :
#// - $hContext -> Connection context to the PC/SC resource manager.
#// - $mszGroups -> List of groups to list readers. (as of this writing,
#// this is not used and should be 0
#//
#// OUTPUT :
#// ListReaders returns the 'undef' value if an error occurs otherwise it
#// returns the list of available readers. Note that this can be an empty
#// list...
#//
SV *
_ListReaders(hContext, svGroups)
unsigned long hContext
SV* svGroups
PREINIT:
DWORD nBufferSize = 0;
char* szBuffer = NULL;
char* szCurrentToken = NULL;
char* mszGroups;
PPCODE:
/* Before doing anything, we check that we have a valid group. */
if (SvPOK(svGroups)) {
/* TODO : see how this works... multistring stuff with time
*svGroups may become a reference to an array of groups... or undef
*/
mszGroups = SvPV (svGroups, PL_na);
} else {
mszGroups = 0;
}
/* The first call to SCardListReaders gives us the size of the
* buffer we must allocate for the list.
*/
gnLastError = hListReaders (hContext, mszGroups, 0, &nBufferSize);
/* In case of any error we immediately return an explicit UNDEF value */
if (gnLastError != SCARD_S_SUCCESS) {
XSRETURN_UNDEF;
}
if (nBufferSize > 0) {
/* At this point, nBufferSize contains the size of the buffer to
* alloate. We use New as recomended by perlguts(3pm). The
* buffer will be freed with Safefree()...
*/
New (2018, szBuffer, nBufferSize, char);
if (szBuffer == NULL) {
gnLastError = SCARD_E_NO_MEMORY;
warn ("Could not allocate buffer at %s line %d\n\t",
__FILE__, __LINE__);
XSRETURN_UNDEF;
}
/* The buffer is ready, so we can now retrieve the whole list. */
gnLastError = hListReaders (hContext, mszGroups, szBuffer, &nBufferSize);
/* Then check for any error */
if (gnLastError != SCARD_S_SUCCESS) {
Safefree (szBuffer);
XSRETURN_UNDEF;
}
/* The string must be NULL terminated
* May be just too much paranoid but...
*/
if (szBuffer[nBufferSize-1] != 0) {
Safefree (szBuffer);
gnLastError = SCARD_F_INTERNAL_ERROR;
warn ("PCSC did not return a NULL terminated multistring at %s line %d\n\t",
__FILE__, __LINE__);
XSRETURN_UNDEF;
}
/* Now we need to push each reader separately on the stack. If
* no readers are found, the stack is left empty...
*/
szCurrentToken = szBuffer;
while (strlen(szCurrentToken)) {
XPUSHs (sv_2mortal(newSVpv(szCurrentToken,0)));
szCurrentToken = strchr (szCurrentToken, 0) + 1;
}
/* Free our buffer...
* DO NOT USE free() or delete() here ! Let Perl deal with this.
*/
Safefree (szBuffer);
} else {
gnLastError = SCARD_F_INTERNAL_ERROR;
warn ("PCSC did not return a valid buffer length at %s line %d\n\t",
__FILE__, __LINE__);
XSRETURN_UNDEF;
}
#///////////////////////////////////////////////////////////////////////////
#// Connect ()
#//
#// INPUT :
#// - $hContext -> Connection context to the PC/SC Resource Manager
#// - $szReader -> ReaderName to connect to
#// - dwShareMode -> Mode of connection : exclusive or shared
#// - dwPreferredProtocols -> Desired protocol use
#//
#// OUTPUT :
#// Connect returns an array with the handle to the connection and the
#// active protocol for this connection ($hCard, $dwActiveProtocol).
#// If a problem occurs, it just return the 'undef' value.
SV*
_Connect (hContext, szReader, dwShareMode, dwPreferredProtocols)
unsigned long hContext
const char* szReader
unsigned long dwShareMode
unsigned long dwPreferredProtocols
PREINIT:
SCARDHANDLE hCard = 0;
DWORD dwActiveProtocol = 0;
PPCODE:
gnLastError = hConnect (hContext, szReader, dwShareMode, dwPreferredProtocols, &hCard, &dwActiveProtocol);
/* We return immediately in case of an error */
if (gnLastError != SCARD_S_SUCCESS)
XSRETURN_UNDEF;
/* If anything was successful, push the two scalar values */
XPUSHs (sv_2mortal(newSViv(hCard)));
XPUSHs (sv_2mortal(newSViv(dwActiveProtocol)));
#///////////////////////////////////////////////////////////////////////////
#// Reconnect ()
#//
#// INPUT :
#// - $hCard -> Handle to a previous call to connect
#// - dwShareMode -> Mode of connection : exclusive or shared
#// - dwPreferredProtocols -> Desired protocol use
#// - $dwInitialization -> Desired action taken on the card/reader
#//
#// OUTPUT :
#// Reconnect returns the new active protocol or the 'undef' value if an
#// error occurs
SV*
_Reconnect (hCard, dwShareMode, dwPreferredProtocols, dwInitialization)
unsigned long hCard
unsigned long dwShareMode
unsigned long dwPreferredProtocols
unsigned long dwInitialization
PREINIT:
DWORD dwActiveProtocol = 0;
CODE:
ST(0) = sv_newmortal();
gnLastError = hReconnect (hCard, dwShareMode, dwPreferredProtocols, dwInitialization, &dwActiveProtocol);
/* Return either an UNDEF value if an error occurs or the current
* active protocol as returned by PCSC
*/
if (gnLastError == SCARD_S_SUCCESS)
sv_setiv (ST(0), dwActiveProtocol);
else
ST(0) = &PL_sv_undef;
#///////////////////////////////////////////////////////////////////////////
#// Disconnect ()
#//
#// INPUT :
#// - $hCard -> Connection made from Connect
#// - $dwDisposition -> Desired action taken on the card/reader
#//
#// OUTPUT :
#// Disconnect returns TRUE upon successful result. Oppositely, it
#// returns FALSE if somthing went bang
bool
_Disconnect (hCard, dwDisposition)
unsigned long hCard;
unsigned long dwDisposition;
CODE:
gnLastError = hDisconnect (hCard, dwDisposition);
/* Then check for an error */
if (gnLastError != SCARD_S_SUCCESS)
RETVAL = FALSE;
else
RETVAL = TRUE;
OUTPUT:
RETVAL
#///////////////////////////////////////////////////////////////////////////
#// Status ()
#//
#// INPUT :
#// - $hCard -> Connection made from Connect
#//
#// OUTPUT :
#// Status returns a list holding different informations about the
#// reader : ($szReaderName, $dwState, $dwProtocol, \@bAttr). If an
#// error pops up, the 'undef' value is returned.
#//
#// Important note:
#// We return the ATR in the form of a reference to an array of bytes.
#// When we build this reference, we start to build an array wich is
#// made mortal, then we fill it with non mortal items usin av_push().
#// These items need to be immortal at this point because av_push does
#// not increase the reference count of the scalar values it pushes into
#// the array. As our array dies when it passes out of scope, perl
#// would free its content and then any attempt to use them would result
#// in an 'Attempt to free unreferenced scalar' error...
SV*
_Status (hCard)
long hCard
PREINIT:
int nCount = 0;
#ifdef WIN32
char tmpReaderName[200];
char* szReaderName = tmpReaderName;
unsigned long cchReaderLen = sizeof(tmpReaderName);
char tmpAtr[MAX_ATR_SIZE];
unsigned char* pbAtr = tmpAtr;
unsigned long cbAtrLen = sizeof(tmpAtr);
#else
char* szReaderName = NULL;
DWORD cchReaderLen = 0;
unsigned char* pbAtr = NULL;
DWORD cbAtrLen = 0;
#endif
DWORD dwState = 0;
DWORD dwProtocol = 0;
AV* aATR = 0;
PPCODE:
/* We call the function with a null cchReaderLen : this should
* gives us the length of the buffer to allocate
*/
gnLastError = hStatus (hCard, szReaderName, &cchReaderLen,
&dwState, &dwProtocol, (BYTE *)pbAtr, &cbAtrLen);
/* Behaviour differs here from PCSC and PCSClite :
* PCSC returns SUCCESS while PCSClite returns an error
*/
if (gnLastError == SCARD_E_INSUFFICIENT_BUFFER || gnLastError == SCARD_S_SUCCESS) {
/* The call was hopefuly successful, so we allocate the
* buffer for the ATR
*/
#ifndef WIN32
/* This hack should be temporary as PCSClite should eventually behave like PCSC */
cbAtrLen = MAX_ATR_SIZE;
#endif
if (cbAtrLen <= 0) {
gnLastError = SCARD_F_INTERNAL_ERROR;
warn ("PCSC did not return a valid buffer length at %s line %d\n\t",
__FILE__, __LINE__);
XSRETURN_UNDEF;
}
New (2018, pbAtr, cbAtrLen, unsigned char);
if (pbAtr == NULL) {
gnLastError = SCARD_E_NO_MEMORY;
warn ("Could not allocate buffer at %s line %d\n\t",
__FILE__, __LINE__);
XSRETURN_UNDEF;
}
/* we then allocate the buffer for the reader name */
if (cbAtrLen <= 0) {
gnLastError = SCARD_F_INTERNAL_ERROR;
warn ("PCSC did not return a valid buffer length at %s line %d\n\t",
__FILE__, __LINE__);
XSRETURN_UNDEF;
}
New (2018, szReaderName, cchReaderLen, char);
if (szReaderName == NULL) {
Safefree (pbAtr);
gnLastError = SCARD_E_NO_MEMORY;
warn ("Could not allocate buffer at %s line %d\n\t",
__FILE__, __LINE__);
XSRETURN_UNDEF;
}
/* Now we perform the real call to SCardStatus */
gnLastError = hStatus (hCard, szReaderName, &cchReaderLen,
&dwState, &dwProtocol, (BYTE *)pbAtr, &cbAtrLen);
if (gnLastError != SCARD_S_SUCCESS) {
Safefree (szReaderName);
Safefree (pbAtr);
XSRETURN_UNDEF;
}
} else {
/* As our first call should trigger the SCARD_E_INSUFFICIENT_BUFFER
* error or no error, we consider any other case as a failure...
*/
XSRETURN_UNDEF;
}
/* Then we fill it with every byte from the ATR
* note that we do not make this data mortal because av_push()
* does not increment the reference count. See the note in the
* function header above
*/
for (nCount=0; nCount < cbAtrLen; nCount++) {
av_push (aATR, newSViv(pbAtr[nCount]));
}
}
/* In the event that no ATR is available, we used to fill aATR
* with '(AV*) &PL_sv_undef' However, pushing a reference to
* this seems is hard to handle I therefore prefer to do
* nothing and leave aATR with the default null value and
* the code below will not push the reference to the ATR array
*/
/* eventually, we end up pushing all the values */
XPUSHs (sv_2mortal(newSVpv(szReaderName,0)));
XPUSHs (sv_2mortal(newSViv(dwState)));
XPUSHs (sv_2mortal(newSViv(dwProtocol)));
/* as well as a reference to the ATR array if available */
if (aATR) {
XPUSHs (sv_2mortal(newRV((SV*)aATR)));
}
/* As a conclusion, we just free what we took */
Safefree (szReaderName);
Safefree (pbAtr);
#///////////////////////////////////////////////////////////////////////////
#// Transmit ()
#//
#// INPUT :
#// - $hCard
#// - @inBuffer = ($Protocol, \@BytesToSend)
#// $Protocol contains the protocol (T0|T1)
#// @BytesToSend contains the bytes to transmit
#// Note: please note that @inBuffer is actually appended to the
#// parameters list, therefore, the following calls are equivalent:
#// @inBuffer ($Protocol, [0x00, 0x12, 0x33]); = ;Transmit ($hCard, @inBuffer);
#// Transmit ($hCard, $Protocol, [0x00, 0x12, 0x33]);
#//
#// OUTPUT :
#// - @outBuffer = ($Protocol, \@BytesRead)
#// - $Protocol may be undef
#// - @BytesRead contains the returned bytes
#// Transmit can return the 'undef' value alone if an error occurs.
SV*
_Transmit (hCard, dwProtocol, psvSendData)
unsigned long hCard;
unsigned long dwProtocol;
SV* psvSendData;
PREINIT:
int nCount = 0;
static char* pbSendBuffer = NULL;
static unsigned char pbRecvBuffer [MAX_BUFFER_SIZE_EXTENDED];
unsigned long cbSendLength = 0;
DWORD cbRecvLength = sizeof (pbRecvBuffer);
SCARD_IO_REQUEST ioSendPci, ioRecvPci;
AV* aRecvBuffer = NULL;
PPCODE:
/* We make sure that the array is sane */
if (psvSendData == NULL) {
gnLastError = SCARD_E_INVALID_PARAMETER;
warn ("psvSendData is a NULL pointer at %s line %d\n\t",
__FILE__, __LINE__);
XSRETURN_UNDEF;
}
/* Should the second parameter not be a reference, we return the
* SCARD_E_INVALID_PARAMETER error code.
*/
if ((!SvROK(psvSendData))||(SvTYPE(SvRV(psvSendData)) != SVt_PVAV)) {
gnLastError = SCARD_E_INVALID_PARAMETER;
warn ("psvSendData is not a RVAV at %s line %d\n\t",
__FILE__, __LINE__);
XSRETURN_UNDEF;
}
/* We have to build up our IO_REQUEST structures according to
* $dwProtocol
*/
switch (dwProtocol) {
case SCARD_PROTOCOL_T0:
case SCARD_PROTOCOL_T1:
case SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1:
case SCARD_PROTOCOL_RAW:
ioSendPci.dwProtocol = dwProtocol;
ioSendPci.cbPciLength = sizeof(ioSendPci);
ioRecvPci.dwProtocol = dwProtocol;
ioRecvPci.cbPciLength = sizeof(ioRecvPci);
break;
default:
/* If $dwProtocol holds an invalid value, we exist reporting
* the error SCARD_E_INVALID_VALUE.
*/
gnLastError = SCARD_E_INVALID_VALUE;
warn ("unknown protocol %ld given at %s line %d\n\t",
dwProtocol, __FILE__, __LINE__);
XSRETURN_UNDEF;
}
/* Let's allocate some space for the send buffer */
cbSendLength = av_len((AV*)SvRV(psvSendData)) + 1;
if (cbSendLength <= 0) {
gnLastError = SCARD_E_INVALID_VALUE;
warn ("empty array given at %s line %d\n\t",
__FILE__, __LINE__);
XSRETURN_UNDEF;
}
New (2018, pbSendBuffer, cbSendLength, char);
if (pbSendBuffer == NULL) {
gnLastError = SCARD_E_NO_MEMORY;
warn ("Could not allocate buffer at %s line %d\n\t",
__FILE__, __LINE__);
XSRETURN_UNDEF;
}
/* We have to extract data from the array referenced by psvSendData */
for (nCount = 0; nCount < cbSendLength ; nCount++)
pbSendBuffer[nCount] = (char)SvIV(*av_fetch((AV*)SvRV(psvSendData), nCount, 0));
/* Everything is ready : call the real function... */
gnLastError = hTransmit (hCard, &ioSendPci, (BYTE *)pbSendBuffer, cbSendLength, &ioRecvPci, pbRecvBuffer, &cbRecvLength);
if (gnLastError != SCARD_S_SUCCESS) {
/* Free the buffer if something went wrong */
Safefree (pbSendBuffer);
XSRETURN_UNDEF;
}
/* At this point, the command was successful. We still need to
* return all the values from our buffer...
* so we build an array for the ATR
*/
aRecvBuffer = (AV*) sv_2mortal((SV*)newAV());
/* we fill this array with every byte from the Response
* note that we do not make this data mortal because av_push()
* does not increment the reference count. See the note in the
* function header above
*/
for (nCount = 0; nCount < cbRecvLength; nCount++)
av_push (aRecvBuffer, newSViv(pbRecvBuffer[nCount]));
XPUSHs (sv_2mortal(newSViv(ioRecvPci.dwProtocol)));
XPUSHs (sv_2mortal(newRV((SV*)aRecvBuffer)));
/* Do not forget to free the dynamically allocated buffer */
Safefree (pbSendBuffer);
#///////////////////////////////////////////////////////////////////////////
#// Control ()
#//
#// INPUT :
#// - $hCard
#// - $dwControlCode
#// - @inBuffer = (\@BytesToSend)
#// @BytesToSend contains the bytes to transmit
#//
#// OUTPUT :
#// - @outBuffer = (\@BytesRead)
#// - @BytesRead contains the returned bytes
#// Control can return the 'undef' value alone if an error occurs.
SV*
_Control (hCard, dwControlCode, psvSendData)
unsigned long hCard;
unsigned long dwControlCode;
SV* psvSendData;
PREINIT:
int nCount = 0;
static char* pbSendBuffer = NULL;
static unsigned char pbRecvBuffer [MAX_BUFFER_SIZE];
unsigned long cbSendLength = 0;
DWORD cbRecvLength = sizeof (pbRecvBuffer);
AV* aRecvBuffer = NULL;
PPCODE:
/* We make sure that the array is sane */
if (psvSendData == NULL) {
gnLastError = SCARD_E_INVALID_PARAMETER;
warn ("psvSendData is a NULL pointer at %s line %d\n\t",
__FILE__, __LINE__);
XSRETURN_UNDEF;
}
/* Should the second parameter not be a reference, we return the
* SCARD_E_INVALID_PARAMETER error code.
*/
if ((!SvROK(psvSendData))||(SvTYPE(SvRV(psvSendData)) != SVt_PVAV)) {
gnLastError = SCARD_E_INVALID_PARAMETER;
warn ("psvSendData is not a RVAV at %s line %d\n\t",
__FILE__, __LINE__);
XSRETURN_UNDEF;
}
/* Let's allocate some space for the send buffer, if needed */
cbSendLength = av_len((AV*)SvRV(psvSendData)) + 1;
if (cbSendLength <= 0) {
gnLastError = SCARD_E_INVALID_VALUE;
warn ("empty array given at %s line %d\n\t",
__FILE__, __LINE__);
XSRETURN_UNDEF;
}
New (2018, pbSendBuffer, cbSendLength, char);
if (pbSendBuffer == NULL) {
gnLastError = SCARD_E_NO_MEMORY;
warn ("Could not allocate buffer at %s line %d\n\t",
__FILE__, __LINE__);
XSRETURN_UNDEF;
}
for (nCount = 0; nCount < cbSendLength ; nCount++)
pbSendBuffer[nCount] = (char)SvIV(*av_fetch((AV*)SvRV(psvSendData), nCount, 0));
/* Everything is ready : call the real function... */
gnLastError = hControl (hCard, dwControlCode,
(cbSendLength > 0 ? (BYTE *)pbSendBuffer : NULL), cbSendLength,
pbRecvBuffer, sizeof(pbRecvBuffer), &cbRecvLength);
if (gnLastError != SCARD_S_SUCCESS) {
/* Free the buffer if something went wrong */
Safefree (pbSendBuffer);
XSRETURN_UNDEF;
}
/* At this point, the command was successful. We still need to
* return all the values from our buffer...
*/
aRecvBuffer = (AV*) sv_2mortal((SV*)newAV());
/* we fill this array with every byte from the Response
* note that we do not make this data mortal because av_push()
* does not increment the reference count. See the note in the
* function header above
*/
for (nCount = 0; nCount < cbRecvLength; nCount++)
av_push (aRecvBuffer, newSViv(pbRecvBuffer[nCount]));
unsigned long hCard;
CODE:
gnLastError = hBeginTransaction (hCard);
/* Then we check for an error */
if (gnLastError != SCARD_S_SUCCESS)
RETVAL = FALSE;
else
RETVAL = TRUE;
OUTPUT:
RETVAL
#///////////////////////////////////////////////////////////////////////////
#// EndTransaction ()
#//
#// INPUT :
#// - $hCard -> connection made from Connect()
#// - $dwDisposition -> Desired action taken on the card/reader
#//
#// OUTPUT :
#// EndTransaction returns true or false depending on its successful
#// completion
unsigned long
_EndTransaction (hCard, dwDisposition)
unsigned long hCard;
unsigned long dwDisposition;
CODE:
gnLastError = hEndTransaction (hCard, dwDisposition);
/* Then we check for an error */
if (gnLastError != SCARD_S_SUCCESS)
RETVAL = FALSE;
else
RETVAL = TRUE;
OUTPUT:
RETVAL
#///////////////////////////////////////////////////////////////////////////
#// GetStatusChange ()
#//
#// This
#//
#// INPUT :
#// - $hContext -> Connection context to the PC/SC resource manager.
#// - $nTimeout -> Time to wait for a change (or SCARD_INFINITE)
#// - \@ReaderStates -> array of reader states
#//
#// OUTPUT :
bool
_GetStatusChange (hContext, dwTimeout, psvReaderStates)
unsigned long hContext;
unsigned long dwTimeout;
SV* psvReaderStates;
PREINIT:
static SCARD_READERSTATE *rgReaderStates_t = NULL;
unsigned int nCount = 0;
unsigned int nATRCount = 0;
unsigned int nReaders = 0;
AV* aRecvBuffer = NULL;
PPCODE:
if (psvReaderStates == NULL) {
gnLastError = SCARD_E_INVALID_PARAMETER;
warn ("psvReaderStates is a NULL pointer at %s line %d\n\t",
__FILE__, __LINE__);
XSRETURN_NO;
}
/* Should the second parameter not be a reference, we return the
* SCARD_E_INVALID_PARAMETER error code.
*/
if ((!SvROK(psvReaderStates))||(SvTYPE(SvRV(psvReaderStates)) != SVt_PVAV)) {
gnLastError = SCARD_E_INVALID_PARAMETER;
warn ("psvReaderStates is not a RVAV at %s line %d\n\t",
__FILE__, __LINE__);
XSRETURN_NO;
}
/* Get the total number of elements in our array */
nReaders = av_len((AV*)SvRV(psvReaderStates)) + 1;
/* free the memory allocated during previous call to GetStatusChange */
if (rgReaderStates_t)
Safefree(rgReaderStates_t);
/* allocate the Reader States table */
Newz(2018, rgReaderStates_t, nReaders, SCARD_READERSTATE);
if (rgReaderStates_t == NULL)
{
warn ("Could not allocate buffer at %s line %d\n\t",
__FILE__, __LINE__);
XSRETURN_NO;
}
for (nCount = 0; nCount < nReaders; nCount++) {
/* As long as psvReaderStates is a reference to a PVAV we
* should be able to use av_fetch() without error
*/
SV *svCurrentToken = (*av_fetch((AV*)SvRV(psvReaderStates), nCount, 0));
/* Now see if the elements in the array are reference to hasharrays */
if ((!SvROK(svCurrentToken)) || (SvTYPE(SvRV(svCurrentToken)) != SVt_PVHV)) {
gnLastError = SCARD_E_INVALID_PARAMETER;
warn ("psvReaderStates[%d] is not a RVHV at %s line %d\n\t", nCount,
__FILE__, __LINE__);
XSRETURN_NO;
}
/* Checkout if the 'name' argument has been passed */
if (hv_exists((HV*)SvRV(svCurrentToken), "reader_name", 11)) {
SV** psvName = NULL;
/* fetch the value of reader_name */
psvName = hv_fetch((HV*)SvRV(svCurrentToken), "reader_name", 11, 0);
/* Link the internal structure and the fetched pointer if appropriate */
if ((psvName != NULL) && (SvTYPE(*psvName) == SVt_PV)) {
// printf ("We got a name\n");
rgReaderStates_t[nCount].szReader = SvPV (*psvName, PL_na);
// printf ("which is : %s\n", rgReaderStates_t[nCount].szReader);
} else {
( run in 0.565 second using v1.01-cache-2.11-cpan-71847e10f99 )