Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

252 lines
7.0 KiB

/*
* 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;
}