253 lines
7 KiB
C
253 lines
7 KiB
C
/*
|
|
* Copyright (c) Microsoft Corporation
|
|
*
|
|
* Module Name :
|
|
* main.c
|
|
*
|
|
* This is the main file containing the service entry and shutdown routines.
|
|
* Where possible, code has been obtained from BINL server.
|
|
*
|
|
* Sadagopan Rajaram -- Oct 14, 1999
|
|
*
|
|
*/
|
|
|
|
|
|
#include "tcsrv.h"
|
|
#include "tcsrvc.h"
|
|
#include "proto.h"
|
|
|
|
SERVICE_STATUS_HANDLE TCGlobalServiceStatusHandle;
|
|
SERVICE_STATUS TCGlobalServiceStatus;
|
|
|
|
VOID
|
|
ServiceEntry(
|
|
DWORD NumArgs,
|
|
LPTSTR *ArgsArray
|
|
)
|
|
/*++
|
|
|
|
Routine Description
|
|
This is the main routine for the terminal concentrator service. After
|
|
initialization, the service processes requests on the main socket until
|
|
a terminate service has been signalled.
|
|
|
|
Arguments:
|
|
NumArgs - Number of strings in the ArgsArray
|
|
ArgsArray - String arguments
|
|
pGlobalData - Contains the necessary global information needed to start
|
|
the service
|
|
|
|
Return Value:
|
|
None
|
|
|
|
++*/
|
|
{
|
|
// Initialize Status fields
|
|
|
|
NTSTATUS status;
|
|
|
|
TCGlobalServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
|
|
TCGlobalServiceStatus.dwCurrentState = SERVICE_START_PENDING;
|
|
TCGlobalServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN
|
|
|SERVICE_ACCEPT_STOP
|
|
|SERVICE_ACCEPT_PARAMCHANGE ;
|
|
TCGlobalServiceStatus.dwCheckPoint = 1;
|
|
TCGlobalServiceStatus.dwWaitHint = 60000; // 60 secs.
|
|
TCGlobalServiceStatus.dwWin32ExitCode = ERROR_SUCCESS;
|
|
TCGlobalServiceStatus.dwServiceSpecificExitCode = 0;
|
|
|
|
|
|
TCGlobalServiceStatusHandle= RegisterServiceCtrlHandler(TCSERV_NAME,
|
|
ServiceControlHandler
|
|
);
|
|
if(TCGlobalServiceStatusHandle == INVALID_HANDLE_VALUE){
|
|
return;
|
|
}
|
|
if(!SetServiceStatus(TCGlobalServiceStatusHandle, &TCGlobalServiceStatus)){
|
|
return;
|
|
}
|
|
|
|
// Open a well known socket for the client to connect.
|
|
|
|
INITIALIZE_TRACE_MEMORY
|
|
MainSocket = ServerSocket();
|
|
if(MainSocket == INVALID_SOCKET){
|
|
// gone case . Terminate Service
|
|
TCDebugPrint(("Cannot open Socket\n"));
|
|
return;
|
|
}
|
|
|
|
|
|
// Initialize by getting control of the COM ports and starting threads
|
|
// for each of them.
|
|
status = Initialize();
|
|
|
|
if(status != STATUS_SUCCESS){
|
|
TCDebugPrint(("Cannot Initialize\n"));
|
|
Shutdown(status);
|
|
return;
|
|
}
|
|
|
|
// Blindly loops around waiting for a request from the control socket and
|
|
// processes their requests.
|
|
|
|
status = ProcessRequests(MainSocket);
|
|
|
|
if (status != STATUS_SUCCESS){
|
|
TCDebugPrint(("Ended with Error"));
|
|
}
|
|
|
|
Shutdown(status);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
DWORD
|
|
ProcessRequests(
|
|
SOCKET socket
|
|
)
|
|
/*++
|
|
Here we sit around waiting for connections.
|
|
Once we get a connection, we start a thread to get the required parameters
|
|
and send the information to the thread processing that COM port.
|
|
--*/
|
|
{
|
|
|
|
int status;
|
|
SOCKET cli_sock;
|
|
CLIENT_INFO ClientInfo;
|
|
struct sockaddr_in cli_addr;
|
|
int addr_len;
|
|
ULONG argp;
|
|
NTSTATUS Status;
|
|
HANDLE ThreadHandle;
|
|
PHANDLE NewThreads;
|
|
ULONG ThreadID;
|
|
|
|
status = listen(socket, SOMAXCONN);
|
|
|
|
if (status == SOCKET_ERROR) {
|
|
TCDebugPrint(("Cannot listen to socket %x\n",WSAGetLastError()));
|
|
closesocket(socket);
|
|
return (WSAGetLastError());
|
|
}
|
|
EnterCriticalSection(&GlobalMutex);
|
|
if(TCGlobalServiceStatus.dwCurrentState != SERVICE_START_PENDING){
|
|
LeaveCriticalSection(&GlobalMutex);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
TCGlobalServiceStatus.dwCurrentState = SERVICE_RUNNING;
|
|
SetServiceStatus(TCGlobalServiceStatusHandle, &TCGlobalServiceStatus);
|
|
LeaveCriticalSection(&GlobalMutex);
|
|
|
|
while(1){
|
|
cli_sock = accept(socket,NULL,NULL);
|
|
if (cli_sock == INVALID_SOCKET){
|
|
// got to shutdown - no Error here
|
|
TCDebugPrint(("Main Socket No more %d\n",GetLastError()));
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
// receive the com port that the client wants to connect to.
|
|
|
|
ThreadHandle=CreateThread(NULL,
|
|
THREAD_ALL_ACCESS,
|
|
(LPTHREAD_START_ROUTINE) InitializeComPortConnection,
|
|
(LPVOID) cli_sock,
|
|
0,
|
|
&ThreadID
|
|
);
|
|
if(ThreadHandle == NULL){
|
|
closesocket(cli_sock);
|
|
TCDebugPrint(("Create connection Thread Failure %lx\n",GetLastError()));
|
|
}
|
|
else{
|
|
NtClose(ThreadHandle);
|
|
}
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
DWORD
|
|
InitializeComPortConnection(
|
|
SOCKET cli_sock
|
|
)
|
|
{
|
|
PCOM_PORT_INFO pTempInfo;
|
|
PCONNECTION_INFO pConn;
|
|
int i;
|
|
BOOL ret;
|
|
ULONG par;
|
|
DWORD status;
|
|
CLIENT_INFO ClientInfo;
|
|
|
|
status = recv(cli_sock,
|
|
(PCHAR) &ClientInfo,
|
|
sizeof(CLIENT_INFO),
|
|
0
|
|
);
|
|
if((status == SOCKET_ERROR) ||( status == 0)){
|
|
//something wrong
|
|
TCDebugPrint(("Receive Problem %x\n",WSAGetLastError()));
|
|
closesocket(cli_sock);
|
|
return 0;
|
|
}
|
|
ClientInfo.device[MAX_BUFFER_SIZE -1] = 0;
|
|
EnterCriticalSection(&GlobalMutex);
|
|
if(TCGlobalServiceStatus.dwCurrentState == SERVICE_STOP_PENDING){
|
|
// Entire Service is shutting down.
|
|
closesocket(cli_sock);
|
|
LeaveCriticalSection(&GlobalMutex);
|
|
return 1;
|
|
}
|
|
pTempInfo = FindDevice(ClientInfo.device, &i);
|
|
if(!pTempInfo){
|
|
closesocket(cli_sock);
|
|
TCDebugPrint(("No Such Device\n"));
|
|
LeaveCriticalSection(&GlobalMutex);
|
|
return -1;
|
|
}
|
|
|
|
MutexLock(pTempInfo);
|
|
if(pTempInfo->ShuttingDown){
|
|
// The Com Port alone is shutting down, so
|
|
// make sure the socket goes away.
|
|
closesocket(cli_sock);
|
|
MutexRelease(pTempInfo);
|
|
LeaveCriticalSection(&GlobalMutex);
|
|
return -1;
|
|
}
|
|
pConn = TCAllocate(sizeof(CONNECTION_INFO),"New Connection");
|
|
if(pConn == NULL){
|
|
closesocket(cli_sock);
|
|
MutexRelease(pTempInfo);
|
|
LeaveCriticalSection(&GlobalMutex);
|
|
return -1;
|
|
}
|
|
pConn->Socket = cli_sock;
|
|
// Make the socket non-blocking so that receive
|
|
// does not wait.
|
|
i = ioctlsocket(cli_sock,
|
|
FIONBIO,
|
|
&par
|
|
);
|
|
if(i == SOCKET_ERROR){
|
|
TCDebugPrint(("Error in setting socket parameters %d\n",GetLastError()));
|
|
}
|
|
pConn->pComPortInfo = pTempInfo;
|
|
pConn->Next = pTempInfo->Sockets;
|
|
pTempInfo->Sockets=pConn;
|
|
pConn->Flags = ClientInfo.len;
|
|
(pConn->Buffer).buf = pConn->buffer;
|
|
(pConn->Buffer).len = MAX_BUFFER_SIZE;
|
|
(pConn->Overlapped).hEvent = (WSAEVENT) pConn;
|
|
ret = SetEvent(pTempInfo->Events[1]);
|
|
if(ret == FALSE){
|
|
TCDebugPrint(("Cannot signal object %d\n",GetLastError()));
|
|
}
|
|
MutexRelease(pTempInfo);
|
|
LeaveCriticalSection(&GlobalMutex);
|
|
return 0;
|
|
}
|