windows-nt/Source/XPSP1/NT/base/headless/tcsrv/server/handler.c

297 lines
8.4 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*
* Copyright (c) Microsoft Corporation
*
* Module Name :
* handler.c
*
* Service Handler functions
* Where possible, code has been obtained from BINL server.
*
* Sadagopan Rajaram -- Oct 25, 1999
*
*/
#include "tcsrv.h"
#include "tcsrvc.h"
#include "proto.h"
VOID
ServiceControlHandler(
IN DWORD Opcode
)
/*++
Routine Description:
This is the service control handler of the Terminal Concentrator
Arguments:
Opcode - Supplies a value which specifies the action for the
service to perform.
Return Value:
None.
--*/
{
DWORD Error;
switch (Opcode) {
case SERVICE_CONTROL_STOP:
case SERVICE_CONTROL_SHUTDOWN:
EnterCriticalSection(&GlobalMutex);
// We set the global state to a stop pending while the
// com ports destroy themselves.
// This is triggered by destroying the main socket.
TCGlobalServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
SetServiceStatus(TCGlobalServiceStatusHandle, &TCGlobalServiceStatus);
closesocket(MainSocket);
LeaveCriticalSection(&GlobalMutex);
break;
case SERVICE_CONTROL_PARAMCHANGE:
EnterCriticalSection(&GlobalMutex);
// If we are not currently running, but have been sent too many
// control parameter change requests, we say return.
if(TCGlobalServiceStatus.dwCurrentState != SERVICE_RUNNING){
LeaveCriticalSection(&GlobalMutex);
return;
}
TCGlobalServiceStatus.dwCurrentState = SERVICE_PAUSED;
SetServiceStatus(TCGlobalServiceStatusHandle, &TCGlobalServiceStatus);
LeaveCriticalSection(&GlobalMutex);
// Does the actual work of munging through the registry and
// finding out changes.
UpdateChanges();
break;
}
return;
}
VOID UpdateChanges(
)
/*++
Reads the parameters from the registry and then tries to add or delete com
ports as necessary
--*/
{
PCOM_PORT_INFO pTempInfo;
PCOM_PORT_INFO pTemp;
PCOM_PORT_INFO addedPorts;
LPTSTR device;
LPTSTR name;
BOOLEAN addPort;
HKEY hKey, hParameter;
NTSTATUS Status;
int index;
LONG RetVal;
HANDLE lock;
addedPorts = NULL;
hKey = NULL;
EnterCriticalSection(&GlobalMutex);
pTempInfo = ComPortInfo;
while(pTempInfo != NULL){
// Sets the flag of Deleted to TRUE
// for all COM ports. If they are found
// unchanged in the registry, we can leave
// them. Changing session names are ok.
pTempInfo->Deleted = TRUE;
pTempInfo= pTempInfo->Next;
}
LeaveCriticalSection(&GlobalMutex);
RetVal = TCLock(&lock);
if(RetVal != ERROR_SUCCESS){
TCDebugPrint(("Cannot Lock Registry %d\n", RetVal));
goto end;
}
RetVal = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
HKEY_TCSERV_PARAMETER_KEY,
0,
KEY_ALL_ACCESS,
&hKey
);
if(RetVal != ERROR_SUCCESS){
TCUnlock(lock);
TCDebugPrint(("Cannot open Registry Key %d\n", RetVal));
goto end;
}
// Read the correct parameters from the registry until you get no more.
index= 0;
while(1) {
RetVal = GetNextParameter(hKey,
index,
&hParameter,
&name
);
if (RetVal == ERROR_NO_MORE_ITEMS) {
TCUnlock(lock);
TCDebugPrint(("Done with registry %d\n",index));
break;
}
if(RetVal != ERROR_SUCCESS){
TCUnlock(lock);
TCDebugPrint(("Error reading registry %d\n",RetVal));
goto end;
}
RetVal = GetNameOfDeviceFromRegistry(hParameter,
&device
);
if(RetVal != ERROR_SUCCESS){
TCFree(name);
continue;
}
pTempInfo = GetComPortParameters(hParameter);
RegCloseKey(hParameter);
if(pTempInfo == NULL){
TCFree(name);
TCFree(device);
RegCloseKey(hKey);
TCUnlock(lock);
goto end;
}
pTempInfo->Device.Buffer = device;
pTempInfo->Name.Buffer = name;
pTempInfo->Name.Length = _tcslen(pTempInfo->Name.Buffer)*sizeof(TCHAR);
pTempInfo->Device.Length = _tcslen(pTempInfo->Device.Buffer) * sizeof(TCHAR);
EnterCriticalSection(&GlobalMutex);
if(TCGlobalServiceStatus.dwCurrentState != SERVICE_PAUSED){
// Somehow, the service has been shut down.
RegCloseKey(hKey);
FreeComPortInfo(pTempInfo);
LeaveCriticalSection(&GlobalMutex);
TCUnlock(lock);
goto end;
}
pTemp = ComPortInfo;
addPort = TRUE;
while(pTemp){
RetVal = ComPortInfoCompare(pTemp, pTempInfo);
if(RetVal == SAME_ALL){
pTemp->Deleted = FALSE;
addPort = FALSE;
break;
}
if (RetVal == SAME_DEVICE) {
// User has changed configuration
// settings
addPort = TRUE;
break;
}
if (RetVal == DIFFERENT_SESSION) {
// Only session name has changed. So, we do not
// need to delete the device.
pTemp->Deleted = FALSE;
addPort = FALSE;
TCFree(pTemp->Name.Buffer);
pTemp->Name.Buffer = pTempInfo->Name.Buffer;
pTempInfo->Name.Buffer = NULL;
break;
}
// Different devices, so continue searching
pTemp=pTemp->Next;
}
LeaveCriticalSection(&GlobalMutex);
if (addPort == FALSE) {
FreeComPortInfo(pTempInfo);
}
else{
pTempInfo->Next = addedPorts;
addedPorts= pTempInfo;
}
index++;
}
while(1){
EnterCriticalSection(&GlobalMutex);
if(TCGlobalServiceStatus.dwCurrentState != SERVICE_PAUSED){
LeaveCriticalSection(&GlobalMutex);
goto end;
}
pTempInfo = ComPortInfo;
device = NULL;
while(pTempInfo){
if(pTempInfo->Deleted){
// This is true if the configuration settings are
// changed or if the device has been really deleted.
device = pTempInfo->Device.Buffer;
break;
}
pTempInfo = pTempInfo->Next;
}
LeaveCriticalSection(&GlobalMutex);
if(device){
Status = DeleteComPort(device);
}
else{
break;
}
}
while(addedPorts){
pTempInfo = addedPorts;
addedPorts = addedPorts->Next;
Status = AddComPort(pTempInfo);
if(Status != STATUS_SUCCESS){
FreeComPortInfo(pTempInfo);
TCDebugPrint(("Could not Initialize Com Port %x\n",Status));
}
}
end:
while (addedPorts) {
// We may have come here after an error condition.
pTempInfo = addedPorts;
addedPorts = pTempInfo->Next;
pTempInfo->Next = NULL;
FreeComPortInfo(pTempInfo);
}
EnterCriticalSection(&GlobalMutex);
if(TCGlobalServiceStatus.dwCurrentState != SERVICE_PAUSED){
LeaveCriticalSection(&GlobalMutex);
return ;
}
TCGlobalServiceStatus.dwCurrentState = SERVICE_RUNNING;
SetServiceStatus(TCGlobalServiceStatusHandle, &TCGlobalServiceStatus);
LeaveCriticalSection(&GlobalMutex);
return;
}
int
ComPortInfoCompare(
PCOM_PORT_INFO com1,
PCOM_PORT_INFO com2
)
{
int ret;
if (_tcscmp(com1->Device.Buffer, com2->Device.Buffer)) {
// Different Devices
return DIFFERENT_DEVICES;
}
// Same device
ret = SAME_DEVICE;
if ((com1->Parity != com2->Parity) ||
(com1->StopBits != com2->StopBits) ||
(com1->WordLength != com2->WordLength)||
(com1->BaudRate != com2->BaudRate)){
return ret;
}
if (_tcscmp(com1->Name.Buffer, com2->Name.Buffer)) {
// Different Devices
return DIFFERENT_SESSION;
}
return SAME_ALL;
}