You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
550 lines
14 KiB
550 lines
14 KiB
/*++
|
|
|
|
Copyright (C) Microsoft Corporation, 1996 - 1999
|
|
|
|
Module Name:
|
|
|
|
ComRspnd
|
|
|
|
Abstract:
|
|
|
|
This module implements the Calais Communication Responder class.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/30/1996
|
|
|
|
Environment:
|
|
|
|
Win32, C++ w/ Exceptions
|
|
|
|
Notes:
|
|
|
|
|
|
|
|
--*/
|
|
|
|
#define __SUBROUTINE__
|
|
#ifndef WIN32_LEAN_AND_MEAN
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#endif
|
|
#include <windows.h>
|
|
#include <WinSCard.h>
|
|
#include <CalMsgs.h>
|
|
#include <CalCom.h>
|
|
#include <stdlib.h>
|
|
|
|
#define CALCOM_PIPE_TIMEOUT 5000
|
|
|
|
|
|
//
|
|
//==============================================================================
|
|
//
|
|
// CComResponder
|
|
//
|
|
|
|
/*++
|
|
|
|
CComResponder:
|
|
|
|
This is the standard constructor and destructor for the Comm Responder
|
|
class. They just call the clean and clear functions, respectively.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Throws:
|
|
|
|
None
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/30/1996
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("CComResponder::CComResponder")
|
|
|
|
CComResponder::CComResponder(
|
|
void)
|
|
: m_bfPipeName(),
|
|
m_aclPipe(),
|
|
m_hComPipe(DBGT("CComResponder's Comm Pipe")),
|
|
m_hAccessMutex(DBGT("CComResponder's Access Mutex")),
|
|
m_hOvrWait(DBGT("CComResponder Overlapped I/O completion event"))
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("CComResponder::~CComResponder")
|
|
CComResponder::~CComResponder()
|
|
{
|
|
Clear();
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Clean:
|
|
|
|
This method sets the object to its default state. It does not perform any
|
|
tear down -- use Clear for that.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Throws:
|
|
|
|
None
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/30/1996
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("CComResponder::Clean")
|
|
|
|
void
|
|
CComResponder::Clean(
|
|
void)
|
|
{
|
|
ZeroMemory(&m_ovrlp, sizeof(m_ovrlp));
|
|
m_bfPipeName.Reset();
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Clear:
|
|
|
|
This method performs object tear-down and returns it to its initial state.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Throws:
|
|
|
|
None
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/30/1996
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("CComResponder::Clear")
|
|
|
|
void
|
|
CComResponder::Clear(
|
|
void)
|
|
{
|
|
if (m_hAccessMutex.IsValid())
|
|
{
|
|
WaitForever(
|
|
m_hAccessMutex,
|
|
CALAIS_LOCK_TIMEOUT,
|
|
DBGT("Waiting for final Service Thread quiescence: %1"),
|
|
(LPCTSTR)NULL);
|
|
m_hAccessMutex.Close();
|
|
}
|
|
|
|
if (m_hComPipe.IsValid())
|
|
{
|
|
if (!DisconnectNamedPipe(m_hComPipe))
|
|
{
|
|
CalaisWarning(
|
|
__SUBROUTINE__,
|
|
DBGT("Comm Responder could not disconnect Comm pipe: %1"),
|
|
GetLastError());
|
|
}
|
|
|
|
m_hComPipe.Close();
|
|
}
|
|
|
|
if (m_hOvrWait.IsValid())
|
|
m_hOvrWait.Close();
|
|
Clean();
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Create:
|
|
|
|
This method Establishes the named target. Close or the destructor takes it
|
|
away.
|
|
|
|
Arguments:
|
|
|
|
szName supplies the name of the communication object to connect to.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
Throws:
|
|
|
|
DWORDs containing the error code, should an error be encountered.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/30/1996
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("CComResponder::Create")
|
|
|
|
void
|
|
CComResponder::Create(
|
|
LPCTSTR szName)
|
|
{
|
|
LPCTSTR szPipeHdr = CalaisString(CALSTR_PIPEDEVICEHEADER);
|
|
static DWORD s_nPipeNo = 0;
|
|
static HKEY s_hCurrentKey = NULL;
|
|
TCHAR szPipeNo[sizeof(s_nPipeNo)*2 + 1]; // Twice as many hex digits + zero
|
|
|
|
try
|
|
{
|
|
DWORD cbPipeHeader = lstrlen(szPipeHdr) * sizeof(TCHAR);
|
|
DWORD dwLen;
|
|
DWORD dwError;
|
|
|
|
dwLen = lstrlen(szName) * sizeof(TCHAR);
|
|
m_bfPipeName.Presize(cbPipeHeader + dwLen + sizeof(szPipeNo));
|
|
|
|
if (s_hCurrentKey == NULL)
|
|
{
|
|
HKEY hKey;
|
|
|
|
//
|
|
// Open the key to the Calais tree.
|
|
//
|
|
dwError = RegOpenKeyEx(
|
|
HKEY_LOCAL_MACHINE,
|
|
CalaisString(CALSTR_CALAISREGISTRYKEY),
|
|
0, // options (ignored)
|
|
KEY_WRITE, // KEY_SET_VALUE | KEY_CREATE_SUB_KEY
|
|
&hKey
|
|
);
|
|
if (ERROR_SUCCESS != dwError)
|
|
{
|
|
CalaisError(__SUBROUTINE__, 104, dwError);
|
|
throw dwError;
|
|
}
|
|
|
|
//
|
|
// Create a new key (or open existing one).
|
|
//
|
|
dwError = RegCreateKeyEx(
|
|
hKey,
|
|
_T("Current"),
|
|
0,
|
|
0,
|
|
REG_OPTION_VOLATILE, // options
|
|
KEY_SET_VALUE, // desired access
|
|
NULL,
|
|
&s_hCurrentKey,
|
|
NULL);
|
|
|
|
RegCloseKey(hKey);
|
|
|
|
if (ERROR_SUCCESS != dwError)
|
|
{
|
|
CalaisError(__SUBROUTINE__, 103, dwError);
|
|
throw dwError;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Build the pipe ACL.
|
|
//
|
|
|
|
ASSERT(!m_hComPipe.IsValid());
|
|
m_aclPipe.InitializeFromProcessToken();
|
|
m_aclPipe.AllowOwner(
|
|
GENERIC_READ | GENERIC_WRITE | GENERIC_ALL);
|
|
m_aclPipe.Allow(
|
|
&m_aclPipe.SID_Interactive,
|
|
(FILE_GENERIC_WRITE | FILE_GENERIC_READ)
|
|
& ~FILE_CREATE_PIPE_INSTANCE);
|
|
m_aclPipe.Allow(
|
|
&m_aclPipe.SID_System,
|
|
(FILE_GENERIC_WRITE | FILE_GENERIC_READ)
|
|
& ~FILE_CREATE_PIPE_INSTANCE);
|
|
|
|
|
|
for (;;)
|
|
{
|
|
//
|
|
// Build the pipe name.
|
|
//
|
|
_itot(s_nPipeNo, szPipeNo, 16);
|
|
|
|
m_bfPipeName.Set((LPCBYTE)szPipeHdr, cbPipeHeader);
|
|
m_bfPipeName.Append((LPCBYTE)szName, dwLen);
|
|
m_bfPipeName.Append((LPCBYTE)szPipeNo, sizeof(szPipeNo));
|
|
|
|
//
|
|
// Build the Pipe (First instance)
|
|
//
|
|
|
|
m_hComPipe = CreateNamedPipe(
|
|
(LPCTSTR)m_bfPipeName.Access(),
|
|
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED | FILE_FLAG_FIRST_PIPE_INSTANCE,
|
|
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
|
|
PIPE_UNLIMITED_INSTANCES,
|
|
CALAIS_COMM_MSGLEN,
|
|
CALAIS_COMM_MSGLEN,
|
|
CALCOM_PIPE_TIMEOUT,
|
|
m_aclPipe);
|
|
if (!m_hComPipe.IsValid())
|
|
{
|
|
dwError = m_hComPipe.GetLastError();
|
|
if (dwError == ERROR_ACCESS_DENIED)
|
|
{
|
|
s_nPipeNo++;
|
|
continue;
|
|
}
|
|
CalaisError(__SUBROUTINE__, 109, dwError);
|
|
throw dwError;
|
|
}
|
|
else
|
|
break;
|
|
}
|
|
|
|
dwError = RegSetValueEx(
|
|
s_hCurrentKey,
|
|
NULL, // Use key's unnamed value
|
|
0,
|
|
REG_DWORD,
|
|
(LPBYTE) &s_nPipeNo,
|
|
sizeof(DWORD));
|
|
if (ERROR_SUCCESS != dwError)
|
|
{
|
|
CalaisError(__SUBROUTINE__, 102, dwError);
|
|
throw dwError;
|
|
}
|
|
|
|
//
|
|
// Prepare the overlapped structure.
|
|
//
|
|
|
|
m_hOvrWait = m_ovrlp.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
if (!m_hOvrWait.IsValid())
|
|
{
|
|
DWORD dwErr = m_hOvrWait.GetLastError();
|
|
CalaisWarning(
|
|
__SUBROUTINE__,
|
|
DBGT("Comm Responder failed to create overlapped event: %1"),
|
|
dwErr);
|
|
throw dwErr;
|
|
}
|
|
}
|
|
|
|
catch (...)
|
|
{
|
|
CalaisError(__SUBROUTINE__, 110);
|
|
Clear();
|
|
throw;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Listen:
|
|
|
|
This method listens on the previously created Communication channel for an
|
|
incoming connection request. When one comes in, it establishes a containing
|
|
CComChannel object for it, and returns it. To disconnect the comm channel,
|
|
just delete the returned CComChannel object.
|
|
|
|
Arguments:
|
|
|
|
None
|
|
|
|
Return Value:
|
|
|
|
The CComChannel established.
|
|
|
|
Throws:
|
|
|
|
DWORDs containing any error codes encountered.
|
|
|
|
Author:
|
|
|
|
Doug Barlow (dbarlow) 10/30/1996
|
|
|
|
--*/
|
|
#undef __SUBROUTINE__
|
|
#define __SUBROUTINE__ DBGT("CComResponder::Listen")
|
|
|
|
CComChannel *
|
|
CComResponder::Listen(
|
|
void)
|
|
{
|
|
CComChannel *pChannel = NULL;
|
|
|
|
for (;;)
|
|
{
|
|
CHandleObject hComPipe(DBGT("Comm Pipe handle from CComResponder::Listen"));
|
|
|
|
try
|
|
{
|
|
BOOL fSts;
|
|
|
|
|
|
//
|
|
// Wait for an incoming connect request.
|
|
//
|
|
|
|
RetryConnect:
|
|
fSts = ConnectNamedPipe(m_hComPipe, &m_ovrlp);
|
|
if (!fSts)
|
|
{
|
|
BOOL fErrorProcessed;
|
|
DWORD dwSts = GetLastError();
|
|
DWORD dwSize;
|
|
DWORD dwWait;
|
|
|
|
do
|
|
{
|
|
fErrorProcessed = TRUE;
|
|
switch (dwSts)
|
|
{
|
|
//
|
|
// Block until something happens.
|
|
case ERROR_IO_PENDING:
|
|
dwWait = WaitForAnyObject(
|
|
INFINITE,
|
|
m_ovrlp.hEvent,
|
|
g_hCalaisShutdown,
|
|
NULL);
|
|
switch (dwWait)
|
|
{
|
|
case 1: // We've got a connect request
|
|
fErrorProcessed = FALSE;
|
|
fSts = GetOverlappedResult(
|
|
m_hComPipe,
|
|
&m_ovrlp,
|
|
&dwSize,
|
|
TRUE);
|
|
dwSts = fSts ? ERROR_SUCCESS : GetLastError();
|
|
break;
|
|
case 2: // Application shutdown
|
|
throw (DWORD)SCARD_P_SHUTDOWN;
|
|
break;
|
|
default:
|
|
CalaisWarning(
|
|
__SUBROUTINE__,
|
|
DBGT("Wait for connect pipe returned invalid value"));
|
|
throw (DWORD)SCARD_F_INTERNAL_ERROR;
|
|
}
|
|
break;
|
|
|
|
//
|
|
// Success after a wait event.
|
|
case ERROR_SUCCESS:
|
|
break;
|
|
|
|
//
|
|
// Non-error. Just ignore it.
|
|
case ERROR_PIPE_CONNECTED:
|
|
break;
|
|
|
|
//
|
|
// The client has closed its end
|
|
case ERROR_NO_DATA:
|
|
CalaisWarning(
|
|
__SUBROUTINE__,
|
|
DBGT("ConnectNamedPipe returned ERROR_NO_DATA, disconnecting and retrying"));
|
|
DisconnectNamedPipe(m_hComPipe);
|
|
goto RetryConnect;
|
|
|
|
//
|
|
// Unexpected error. Report it.
|
|
default:
|
|
CalaisError(__SUBROUTINE__, 108, dwSts);
|
|
throw dwSts;
|
|
}
|
|
} while (!fErrorProcessed);
|
|
}
|
|
|
|
|
|
//
|
|
// Kick off another Pipe instance for the next request.
|
|
//
|
|
|
|
|
|
hComPipe = m_hComPipe.Relinquish();
|
|
// m_hComPipe = INVALID_HANDLE_VALUE;
|
|
m_hComPipe = CreateNamedPipe(
|
|
(LPCTSTR)m_bfPipeName.Access(),
|
|
PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
|
|
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE,
|
|
PIPE_UNLIMITED_INSTANCES,
|
|
CALAIS_COMM_MSGLEN,
|
|
CALAIS_COMM_MSGLEN,
|
|
CALCOM_PIPE_TIMEOUT,
|
|
m_aclPipe);
|
|
if (!m_hComPipe.IsValid())
|
|
{
|
|
DWORD dwErr = m_hComPipe.GetLastError();
|
|
CalaisError(__SUBROUTINE__, 105, dwErr);
|
|
throw dwErr;
|
|
}
|
|
|
|
|
|
//
|
|
// Handle the connect request data.
|
|
//
|
|
|
|
|
|
pChannel = new CComChannel(hComPipe);
|
|
if (NULL == pChannel)
|
|
{
|
|
DWORD dwSts = SCARD_E_NO_MEMORY;
|
|
CalaisWarning(
|
|
__SUBROUTINE__,
|
|
DBGT("Com Responder could not allocate a Comm Channel: %1"),
|
|
dwSts);
|
|
throw dwSts;
|
|
}
|
|
hComPipe.Relinquish();
|
|
break;
|
|
}
|
|
|
|
catch (...)
|
|
{
|
|
if (NULL != pChannel)
|
|
{
|
|
delete pChannel;
|
|
pChannel = NULL;
|
|
}
|
|
if (hComPipe.IsValid())
|
|
hComPipe.Close();
|
|
throw;
|
|
}
|
|
}
|
|
|
|
return pChannel;
|
|
}
|
|
|