channels/smartcard: refactor usage of lists and get rid of workarounds
This commit is contained in:
parent
f78efde09a
commit
1dbf279212
@ -38,7 +38,7 @@
|
||||
|
||||
#include "devman.h"
|
||||
|
||||
static void devman_device_free(DEVICE* device)
|
||||
void devman_device_free(DEVICE* device)
|
||||
{
|
||||
IFCALL(device->Free, device);
|
||||
}
|
||||
|
@ -35,6 +35,9 @@
|
||||
|
||||
static void irp_free(IRP* irp)
|
||||
{
|
||||
if (!irp)
|
||||
return;
|
||||
|
||||
Stream_Free(irp->input, TRUE);
|
||||
Stream_Free(irp->output, TRUE);
|
||||
|
||||
@ -66,9 +69,7 @@ IRP* irp_new(DEVMAN* devman, wStream* s)
|
||||
device = devman_get_device_by_id(devman, DeviceId);
|
||||
|
||||
if (!device)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
irp = (IRP*) _aligned_malloc(sizeof(IRP), MEMORY_ALLOCATION_ALIGNMENT);
|
||||
ZeroMemory(irp, sizeof(IRP));
|
||||
|
@ -36,36 +36,20 @@
|
||||
|
||||
#include "smartcard_main.h"
|
||||
|
||||
static void smartcard_free(DEVICE* dev)
|
||||
static void smartcard_free(DEVICE* device)
|
||||
{
|
||||
IRP* irp;
|
||||
COMPLETIONIDINFO* CompletionIdInfo;
|
||||
SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) dev;
|
||||
SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) device;
|
||||
|
||||
SetEvent(smartcard->stopEvent);
|
||||
printf("smartcard_free\n");
|
||||
|
||||
MessageQueue_PostQuit(smartcard->IrpQueue, 0);
|
||||
WaitForSingleObject(smartcard->thread, INFINITE);
|
||||
|
||||
while ((irp = (IRP*) InterlockedPopEntrySList(smartcard->pIrpList)) != NULL)
|
||||
irp->Discard(irp);
|
||||
|
||||
_aligned_free(smartcard->pIrpList);
|
||||
|
||||
/* Begin TS Client defect workaround. */
|
||||
|
||||
while ((CompletionIdInfo = (COMPLETIONIDINFO*) list_dequeue(smartcard->CompletionIds)) != NULL)
|
||||
free(CompletionIdInfo);
|
||||
|
||||
CloseHandle(smartcard->thread);
|
||||
CloseHandle(smartcard->irpEvent);
|
||||
CloseHandle(smartcard->stopEvent);
|
||||
CloseHandle(smartcard->CompletionIdsMutex);
|
||||
|
||||
Stream_Free(smartcard->device.data, TRUE);
|
||||
list_free(smartcard->CompletionIds);
|
||||
|
||||
/* End TS Client defect workaround. */
|
||||
|
||||
free(dev);
|
||||
free(device);
|
||||
}
|
||||
|
||||
static void smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp)
|
||||
@ -85,224 +69,37 @@ static void smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp)
|
||||
}
|
||||
}
|
||||
|
||||
static void smartcard_process_irp_list(SMARTCARD_DEVICE* smartcard)
|
||||
static void* smartcard_thread_func(void* arg)
|
||||
{
|
||||
IRP* irp;
|
||||
wMessage message;
|
||||
SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) arg;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (WaitForSingleObject(smartcard->stopEvent, 0) == WAIT_OBJECT_0)
|
||||
if (!MessageQueue_Wait(smartcard->IrpQueue))
|
||||
break;
|
||||
|
||||
irp = (IRP*) InterlockedPopEntrySList(smartcard->pIrpList);
|
||||
|
||||
if (irp == NULL)
|
||||
if (!MessageQueue_Peek(smartcard->IrpQueue, &message, TRUE))
|
||||
break;
|
||||
|
||||
smartcard_process_irp(smartcard, irp);
|
||||
if (message.id == WMQ_QUIT)
|
||||
break;
|
||||
|
||||
irp = (IRP*) message.wParam;
|
||||
|
||||
if (irp)
|
||||
smartcard_process_irp(smartcard, irp);
|
||||
}
|
||||
}
|
||||
|
||||
struct _SMARTCARD_IRP_WORKER
|
||||
{
|
||||
SMARTCARD_DEVICE* smartcard;
|
||||
IRP* irp;
|
||||
HANDLE thread;
|
||||
};
|
||||
typedef struct _SMARTCARD_IRP_WORKER SMARTCARD_IRP_WORKER;
|
||||
|
||||
static void *smartcard_process_irp_thread_func(SMARTCARD_IRP_WORKER* irpWorker)
|
||||
{
|
||||
smartcard_process_irp(irpWorker->smartcard, irpWorker->irp);
|
||||
|
||||
CloseHandle(irpWorker->thread);
|
||||
|
||||
free(irpWorker);
|
||||
|
||||
ExitThread(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void* smartcard_thread_func(void* arg)
|
||||
{
|
||||
SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) arg;
|
||||
HANDLE ev[] = {smartcard->irpEvent, smartcard->stopEvent};
|
||||
|
||||
while (1)
|
||||
{
|
||||
DWORD status = WaitForMultipleObjects(2, ev, FALSE, INFINITE);
|
||||
|
||||
if (status == WAIT_OBJECT_0 + 1)
|
||||
break;
|
||||
else if(status != WAIT_OBJECT_0)
|
||||
continue;
|
||||
|
||||
ResetEvent(smartcard->irpEvent);
|
||||
smartcard_process_irp_list(smartcard);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Begin TS Client defect workaround. */
|
||||
static COMPLETIONIDINFO* smartcard_mark_duplicate_id(SMARTCARD_DEVICE* smartcard, UINT32 CompletionId)
|
||||
{
|
||||
LIST_ITEM* item;
|
||||
COMPLETIONIDINFO* CompletionIdInfo;
|
||||
|
||||
/*
|
||||
* Search from the beginning of the LIST for one outstanding "CompletionID"
|
||||
* that matches the one passed in. If there is one, mark it as a duplicate
|
||||
* if it is not already marked.
|
||||
*/
|
||||
|
||||
for (item = smartcard->CompletionIds->head; item; item = item->next)
|
||||
{
|
||||
CompletionIdInfo = (COMPLETIONIDINFO*) item->data;
|
||||
|
||||
if (CompletionIdInfo->ID == CompletionId)
|
||||
{
|
||||
if (!CompletionIdInfo->duplicate)
|
||||
{
|
||||
CompletionIdInfo->duplicate = TRUE;
|
||||
DEBUG_WARN("CompletionID number %u is now marked as a duplicate.", CompletionId);
|
||||
}
|
||||
|
||||
return CompletionIdInfo;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL; /* Either no items in the list or no match. */
|
||||
}
|
||||
|
||||
static BOOL smartcard_check_for_duplicate_id(SMARTCARD_DEVICE* smartcard, UINT32 CompletionId)
|
||||
{
|
||||
BOOL duplicate;
|
||||
LIST_ITEM* item;
|
||||
COMPLETIONIDINFO* CompletionIdInfo;
|
||||
|
||||
/*
|
||||
* Search from the end of the LIST for one outstanding "CompletionID"
|
||||
* that matches the one passed in. Remove it from the list and free the
|
||||
* memory associated with it. Return whether or not it was marked
|
||||
* as a duplicate.
|
||||
*/
|
||||
|
||||
for (item = smartcard->CompletionIds->tail; item; item = item->prev)
|
||||
{
|
||||
CompletionIdInfo = (COMPLETIONIDINFO*) item->data;
|
||||
|
||||
if (CompletionIdInfo->ID == CompletionId)
|
||||
{
|
||||
duplicate = CompletionIdInfo->duplicate;
|
||||
|
||||
if (duplicate)
|
||||
{
|
||||
DEBUG_WARN("CompletionID number %u was previously marked as a duplicate.", CompletionId);
|
||||
}
|
||||
|
||||
list_remove(smartcard->CompletionIds, CompletionIdInfo);
|
||||
free(CompletionIdInfo);
|
||||
|
||||
return duplicate;
|
||||
}
|
||||
}
|
||||
|
||||
/* This function should only be called when there is
|
||||
* at least one outstanding CompletionID item in the list.
|
||||
*/
|
||||
DEBUG_WARN("Error!!! No CompletionIDs (or no matching IDs) in the list!");
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void smartcard_irp_complete(IRP* irp)
|
||||
{
|
||||
int pos;
|
||||
BOOL duplicate;
|
||||
SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) irp->device;
|
||||
|
||||
/* This function is (mostly) a copy of the statically-declared "irp_complete()"
|
||||
* function except that this function adds extra operations for the
|
||||
* smart card's handling of duplicate "CompletionID"s. This function needs
|
||||
* to be in this file so that "smartcard_irp_request()" can reference it.
|
||||
*/
|
||||
|
||||
DEBUG_SCARD("DeviceId %d FileId %d CompletionId %d", irp->device->id, irp->FileId, irp->CompletionId);
|
||||
|
||||
pos = Stream_GetPosition(irp->output);
|
||||
Stream_SetPosition(irp->output, 12);
|
||||
Stream_Write_UINT32(irp->output, irp->IoStatus);
|
||||
Stream_SetPosition(irp->output, pos);
|
||||
|
||||
/* Begin TS Client defect workaround. */
|
||||
WaitForSingleObject(smartcard->CompletionIdsMutex, INFINITE);
|
||||
/* Remove from the list the item identified by the CompletionID.
|
||||
* The function returns whether or not it was a duplicate CompletionID.
|
||||
*/
|
||||
duplicate = smartcard_check_for_duplicate_id(smartcard, irp->CompletionId);
|
||||
ReleaseMutex(smartcard->CompletionIdsMutex);
|
||||
|
||||
if (!duplicate)
|
||||
{
|
||||
irp->Complete(irp);
|
||||
}
|
||||
|
||||
/* End TS Client defect workaround. */
|
||||
|
||||
/* irp_free(irp); The "irp_free()" function is statically-declared
|
||||
* and so is not available to be called
|
||||
* here. Instead, call it indirectly by calling
|
||||
* the IRP's "Discard()" function,
|
||||
* which has already been assigned
|
||||
* to point to "irp_free()" in "irp_new()".
|
||||
*/
|
||||
irp->Discard(irp);
|
||||
}
|
||||
/* End TS Client defect workaround. */
|
||||
|
||||
static void smartcard_irp_request(DEVICE* device, IRP* irp)
|
||||
{
|
||||
COMPLETIONIDINFO* CompletionIdInfo;
|
||||
SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) device;
|
||||
|
||||
/* Begin TS Client defect workaround. */
|
||||
|
||||
CompletionIdInfo = (COMPLETIONIDINFO*) malloc(sizeof(COMPLETIONIDINFO));
|
||||
ZeroMemory(CompletionIdInfo, sizeof(COMPLETIONIDINFO));
|
||||
|
||||
CompletionIdInfo->ID = irp->CompletionId;
|
||||
|
||||
WaitForSingleObject(smartcard->CompletionIdsMutex, INFINITE);
|
||||
smartcard_mark_duplicate_id(smartcard, irp->CompletionId);
|
||||
list_enqueue(smartcard->CompletionIds, CompletionIdInfo);
|
||||
ReleaseMutex(smartcard->CompletionIdsMutex);
|
||||
|
||||
/* Overwrite the previous assignment made in irp_new() */
|
||||
irp->Complete = smartcard_irp_complete;
|
||||
|
||||
/* End TS Client defect workaround. */
|
||||
|
||||
if ((irp->MajorFunction == IRP_MJ_DEVICE_CONTROL) && smartcard_async_op(irp))
|
||||
{
|
||||
/* certain potentially long running operations get their own thread */
|
||||
SMARTCARD_IRP_WORKER* irpWorker = malloc(sizeof(SMARTCARD_IRP_WORKER));
|
||||
|
||||
irpWorker->thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) smartcard_process_irp_thread_func,
|
||||
irpWorker, CREATE_SUSPENDED, NULL);
|
||||
|
||||
irpWorker->smartcard = smartcard;
|
||||
irpWorker->irp = irp;
|
||||
|
||||
ResumeThread(irpWorker->thread);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
InterlockedPushEntrySList(smartcard->pIrpList, &(irp->ItemEntry));
|
||||
|
||||
SetEvent(smartcard->irpEvent);
|
||||
MessageQueue_Post(smartcard->IrpQueue, NULL, 0, (void*) irp, NULL);
|
||||
}
|
||||
|
||||
#ifdef STATIC_CHANNELS
|
||||
@ -351,17 +148,10 @@ int DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
||||
smartcard->name = name;
|
||||
}
|
||||
|
||||
smartcard->pIrpList = (PSLIST_HEADER) _aligned_malloc(sizeof(SLIST_HEADER), MEMORY_ALLOCATION_ALIGNMENT);
|
||||
InitializeSListHead(smartcard->pIrpList);
|
||||
|
||||
smartcard->irpEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
smartcard->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
smartcard->IrpQueue = MessageQueue_New();
|
||||
smartcard->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) smartcard_thread_func,
|
||||
smartcard, CREATE_SUSPENDED, NULL);
|
||||
|
||||
smartcard->CompletionIds = list_new();
|
||||
smartcard->CompletionIdsMutex = CreateMutex(NULL, FALSE, NULL);
|
||||
|
||||
pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*) smartcard);
|
||||
|
||||
ResumeThread(smartcard->thread);
|
||||
|
@ -29,6 +29,7 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
#define BOOL PCSC_BOOL
|
||||
#include <PCSC/pcsclite.h>
|
||||
@ -106,14 +107,8 @@ struct _SMARTCARD_DEVICE
|
||||
char* name;
|
||||
char* path;
|
||||
|
||||
PSLIST_HEADER pIrpList;
|
||||
|
||||
HANDLE thread;
|
||||
HANDLE irpEvent;
|
||||
HANDLE stopEvent;
|
||||
|
||||
LIST* CompletionIds;
|
||||
HANDLE CompletionIdsMutex;
|
||||
wMessageQueue* IrpQueue;
|
||||
|
||||
SCARDCONTEXT hContext;
|
||||
SCARDHANDLE hCard;
|
||||
@ -126,7 +121,7 @@ typedef struct _SMARTCARD_DEVICE SMARTCARD_DEVICE;
|
||||
#define DEBUG_SCARD(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
BOOL smartcard_async_op(IRP*);
|
||||
void smartcard_device_control(SMARTCARD_DEVICE*, IRP*);
|
||||
BOOL smartcard_async_op(IRP* irp);
|
||||
void smartcard_device_control(SMARTCARD_DEVICE* smartcard, IRP* irp);
|
||||
|
||||
#endif /* FREERDP_CHANNEL_SMARTCARD_CLIENT_MAIN_H */
|
||||
|
@ -415,9 +415,10 @@ wListDictionary* ListDictionary_New(BOOL synchronized)
|
||||
listDictionary->head = NULL;
|
||||
|
||||
InitializeCriticalSectionAndSpinCount(&listDictionary->lock, 4000);
|
||||
|
||||
ZeroMemory(&(listDictionary->object), sizeof(wObject));
|
||||
}
|
||||
|
||||
ZeroMemory(&listDictionary->object, sizeof(wObject));
|
||||
return listDictionary;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user