Leaked source code of windows server 2003
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.
 
 
 
 
 
 

551 lines
12 KiB

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
conn.cpp
Abstract:
Code to maintain list of process connections for an active device
Author:
Vlad Sadovsky (VladS) 11-Feb-1997
History:
--*/
//
// Include Headers
//
#include "precomp.h"
#include "stiexe.h"
#include "conn.h"
//
// Static variables
//
//
LONG g_lGlobalConnectionId = 0;
LIST_ENTRY g_ConnectionListHead; //
LONG g_lTotalOpenedConnections = 0; //
CRIT_SECT g_ConnectionListSync; // Global sync object for linked list syncronization
//
// Static functions
//
STI_CONN *
LocateConnectionByHandle(
HANDLE hConnection
);
//
// Methods
//
STI_CONN::STI_CONN(
IN LPCTSTR pszDeviceName,
IN DWORD dwMode,
IN DWORD dwProcessId
)
{
BOOL fRet;
//
// Initialize fields
//
m_dwSignature = CONN_SIGNATURE;
m_dwProcessId = dwProcessId;
m_pOpenedDevice = NULL;
m_dwOpenMode = dwMode;
strDeviceName.CopyString(pszDeviceName);
m_dwNotificationMessage = 0L;
m_hwndProcessWindow = NULL;
m_hevProcessEvent = INVALID_HANDLE_VALUE;
m_GlocalListEntry.Flink = m_GlocalListEntry.Blink = NULL;
m_DeviceListEntry.Flink = m_DeviceListEntry.Blink = NULL;
InitializeListHead( &m_NotificationListHead );
m_hUniqueId = LongToPtr(InterlockedIncrement(&g_lGlobalConnectionId));
__try {
// Critical section for protecting interthread access to the device
if(!InitializeCriticalSectionAndSpinCount(&m_CritSec, MINLONG)) {
m_fValid = FALSE;
return;
}
}
__except (EXCEPTION_EXECUTE_HANDLER) {
// This is really bad - mark this connection as invalid
m_fValid = FALSE;
return;
}
SetFlags(0);
//
// Locate device incrementing it's ref count
//
m_pOpenedDevice = g_pDevMan->IsInList(DEV_MAN_IN_LIST_DEV_ID, pszDeviceName);
if (!m_pOpenedDevice) {
// Failed to connect to the device
DBG_WRN(("Refused connection to non-existing device (%S)", pszDeviceName));
return;
}
//
// Establish link to the device object
//
fRet = m_pOpenedDevice->AddConnection(this);
m_pOpenedDevice->Release();
if (!fRet) {
//
// Failed to connect to the device, find out reason
//
DBG_WRN(("Refused connection to device (%S)", pszDeviceName));
ReportError(::GetLastError());
return;
}
m_fValid = TRUE;
DBG_TRC(("Successfully created connection to device (%S) handle:(%x)",
pszDeviceName,this));
}
STI_CONN::~STI_CONN()
{
SetFlags(CONN_FLAG_SHUTDOWN);
DBG_TRC(("Destroying connection(%X)",this));
DumpObject();
#if 0
DebugDumpScheduleList(TEXT("Conn DTOR enter"));
#endif
EnterCrit();
//
// If there are items in notification queue - remove them
//
if (!IsListEmpty(&m_NotificationListHead )) {
}
LeaveCrit();
//
// Disconnect from the device
//
if (m_pOpenedDevice) {
m_pOpenedDevice->RemoveConnection(this);
}
//
// Remove from global list if still there
//
if (m_GlocalListEntry.Flink &&!IsListEmpty(&m_GlocalListEntry)) {
RemoveEntryList(&m_GlocalListEntry);
}
//
// We know we tried to initialize it, so it is safe to delete it.
//
DeleteCriticalSection(&m_CritSec);
m_fValid = FALSE;
}
/*
* Reference counting methods. It is simpler to use COM ref counting , to looks the same
* as COM objects, in spite of the fact we are not really supporting COM, because QI method is
* not functional
*/
STDMETHODIMP
STI_CONN::QueryInterface( REFIID riid, LPVOID * ppvObj)
{
return E_FAIL;
}
STDMETHODIMP_(ULONG)
STI_CONN::AddRef( void)
{
return ::InterlockedIncrement(&m_cRef);
}
STDMETHODIMP_(ULONG)
STI_CONN::Release( void)
{
LONG cNew;
if(!(cNew = ::InterlockedDecrement(&m_cRef))) {
delete this;
}
return cNew;
}
BOOL
STI_CONN::
SetSubscribeInfo(
PLOCAL_SUBSCRIBE_CONTAINER pSubscribe
)
{
BOOL fRet = FALSE;
DBG_TRC(("Subscribing to device on connection (%X)",this));
ReportError(NOERROR);
//
// NULL means resetting subscribe info block
//
if (!pSubscribe) {
m_dwSubscribeFlags = 0L;
m_hwndProcessWindow = NULL;
m_hevProcessEvent = INVALID_HANDLE_VALUE;
fRet = TRUE;
}
else {
//
// Save information needed to notify process
//
m_dwSubscribeFlags = pSubscribe->dwFlags;
if (pSubscribe->dwFlags & STI_SUBSCRIBE_FLAG_WINDOW) {
if (IsWindow((HWND)pSubscribe->upLocalWindowHandle)) {
m_hwndProcessWindow = (HWND)pSubscribe->upLocalWindowHandle;
m_uiNotificationMessage = pSubscribe->uiNotificationMessage;
fRet = TRUE;
}
else {
ASSERT(("Invalid window handle passed", 0));
}
}
else if (pSubscribe->dwFlags & STI_SUBSCRIBE_FLAG_EVENT) {
HANDLE hProcessMe = GetCurrentProcess();
HANDLE hProcessClient = NULL;
hProcessClient = ::OpenProcess(PROCESS_DUP_HANDLE,
FALSE,
m_dwProcessId
);
if (IS_VALID_HANDLE(hProcessClient)) {
if (::DuplicateHandle(hProcessClient,
(HANDLE)pSubscribe->upLocalEventHandle,
hProcessMe,
&m_hevProcessEvent,
EVENT_MODIFY_STATE,
0,
0)
) {
fRet = TRUE;
ReportError(NOERROR);
}
else {
DBG_WRN(("Subscribe handler failed to recognize client process on connection (%X)",this));
ReportError(::GetLastError());
}
::CloseHandle(hProcessClient);
}
else {
ReportError(::GetLastError());
}
}
}
return fRet;
}
BOOL
STI_CONN::
QueueNotificationToProcess(
LPSTINOTIFY pStiNotification
)
{
BOOL fRet;
//
// Validate notification block
//
//
// Add to the tail of the list
//
STI_NOTIFICATION * pNotification = NULL;
pNotification = new STI_NOTIFICATION(pStiNotification);
if (pNotification && pNotification->IsValid()) {
EnterCrit();
InsertTailList(&m_NotificationListHead,&pNotification->m_ListEntry);
LeaveCrit();
}
//
// Notify process
//
if (m_dwSubscribeFlags & STI_SUBSCRIBE_FLAG_WINDOW) {
::PostMessage(m_hwndProcessWindow,m_uiNotificationMessage ,0,0L);
}
else if (m_dwSubscribeFlags & STI_SUBSCRIBE_FLAG_EVENT) {
::SetEvent(m_hevProcessEvent);
}
fRet = TRUE;
return fRet;
}
DWORD
STI_CONN::
GetNotification(
PVOID pBuffer,
DWORD *pdwSize
)
{
STI_NOTIFICATION * pNotification = NULL;
TAKE_STI_CONN t(this);
LIST_ENTRY *pentry;
if (IsListEmpty(&m_NotificationListHead)) {
return ERROR_NO_DATA;
}
DBG_TRC(("Request to get last notification on connection (%X) ",this));
//
// Get size of the head
//
pentry = m_NotificationListHead.Flink;
pNotification = CONTAINING_RECORD( pentry, STI_NOTIFICATION,m_ListEntry );
if (*pdwSize < pNotification->QueryAllocSize() ) {
*pdwSize = pNotification->QueryAllocSize();
return ERROR_MORE_DATA;
}
//
// Get head of the list ( and remove) and copy into user buffer
//
pentry = RemoveHeadList(&m_NotificationListHead);
pNotification = CONTAINING_RECORD( pentry, STI_NOTIFICATION,m_ListEntry );
memcpy(pBuffer,pNotification->QueryNotifyData(),pNotification->QueryAllocSize());
delete pNotification;
return NOERROR;
}
//
// Create and initialize connection object
//
BOOL
CreateDeviceConnection(
LPCTSTR pszDeviceName,
DWORD dwMode,
DWORD dwProcessId,
HANDLE *phConnection
)
{
STI_CONN *pConn = NULL;
BOOL fRet = FALSE;
DWORD dwErr = NOERROR;
DBG_TRC(("Request to add connection to device (%S) from process(%x) with mode (%x)",
pszDeviceName, dwProcessId, dwMode));
//
// Create connection object
//
pConn = new STI_CONN(pszDeviceName,
dwMode,
dwProcessId);
if (pConn) {
if(pConn->IsValid()) {
*phConnection = (HANDLE)(pConn->QueryID());
fRet = TRUE;
}
else {
// Did not initialize properly
dwErr = pConn->QueryError();
delete pConn;
}
}
else {
// Could not allocate connectionobject
dwErr = ERROR_NOT_ENOUGH_MEMORY;
}
//
// If succeeded - add created object to linked list head
//
if (fRet)
// BEGIN PROTECTED CODE
{
TAKE_CRIT_SECT t(g_ConnectionListSync);
InsertTailList(&g_ConnectionListHead,&pConn->m_GlocalListEntry);
}
// END PROTECTED CODE
::SetLastError(dwErr);
return fRet;
}
//
//
// Remove connection object from the list
//
BOOL
DestroyDeviceConnection(
HANDLE hConnection,
BOOL fForce
)
{
//
// Find connection by id
//
DBG_TRC(("Request to remove connection (%X) ",hConnection));
STI_CONN *pConnection = NULL;
// BEGIN PROTECTED CODE
{
TAKE_CRIT_SECT t(g_ConnectionListSync);
pConnection = LocateConnectionByHandle(hConnection);
if (pConnection) {
if (!fForce) {
pConnection->Release();
}
else {
delete pConnection;
}
}
}
// END PROTECTED CODE
#if 0
DebugDumpScheduleList(TEXT("DestroyConnection"));
#endif
return (!(pConnection == NULL));
}
//
// Find connection object by given handle by walking all devices and all connections
// for each device
//
BOOL
LookupConnectionByHandle(
HANDLE hConnection,
STI_CONN **ppConnectionObject
)
{
STI_CONN *pConnection = NULL;
*ppConnectionObject = NULL;
// BEGIN PROTECTED CODE
{
TAKE_CRIT_SECT t(g_ConnectionListSync);
pConnection = LocateConnectionByHandle(hConnection);
if (pConnection) {
*ppConnectionObject = pConnection;
pConnection->AddRef();
}
}
// END PROTECTED CODE
return (!(*ppConnectionObject == NULL));
}
//
// Requires caller to synchronize access
//
STI_CONN *
LocateConnectionByHandle(
HANDLE hConnection
)
{
LIST_ENTRY *pentry;
LIST_ENTRY *pentryNext;
STI_CONN *pConnection = NULL;
ULONG ulInternalHandle = HandleToUlong(hConnection);
for ( pentry = g_ConnectionListHead.Flink;
pentry != &g_ConnectionListHead;
pentry = pentryNext ) {
pentryNext = pentry->Flink;
pConnection = CONTAINING_RECORD( pentry, STI_CONN,m_GlocalListEntry );
if ( !pConnection->IsValid()) {
ASSERT(("Invalid connection signature", 0));
break;
}
if ((ulInternalHandle == PtrToUlong(pConnection->QueryID())) &&
!(pConnection->QueryFlags() & CONN_FLAG_SHUTDOWN)
) {
return pConnection;
}
}
return NULL;
}