721 lines
13 KiB
C
721 lines
13 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
MAIN.C
|
||
|
||
Abstract:
|
||
|
||
This is the main routine for the TCP/IP Services.
|
||
|
||
Author:
|
||
|
||
David Treadwell (davidtr) 7-27-93
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
//
|
||
// INCLUDES
|
||
//
|
||
|
||
#include <nt.h>
|
||
#include <ntrtl.h>
|
||
#include <nturtl.h>
|
||
#include <windows.h>
|
||
#include <winsvc.h> // Service control APIs
|
||
#include <rpc.h>
|
||
|
||
#include "tcpsvcs.h"
|
||
|
||
//
|
||
// Service entry points -- thunks to real service entry points.
|
||
//
|
||
|
||
VOID
|
||
StartDns (
|
||
IN DWORD argc,
|
||
IN LPTSTR argv[]
|
||
);
|
||
|
||
VOID
|
||
StartSimpTcp (
|
||
IN DWORD argc,
|
||
IN LPTSTR argv[]
|
||
);
|
||
|
||
VOID
|
||
StartDhcpServer (
|
||
IN DWORD argc,
|
||
IN LPTSTR argv[]
|
||
);
|
||
|
||
VOID
|
||
StartFtpSvc (
|
||
IN DWORD argc,
|
||
IN LPTSTR argv[]
|
||
);
|
||
|
||
VOID
|
||
StartLpdSvc (
|
||
IN DWORD argc,
|
||
IN LPTSTR argv[]
|
||
);
|
||
|
||
VOID
|
||
StartBinlSvc (
|
||
IN DWORD argc,
|
||
IN LPTSTR argv[]
|
||
);
|
||
|
||
//
|
||
// Local function used by the above to load and invoke a service DLL.
|
||
//
|
||
|
||
VOID
|
||
TcpsvcsStartService (
|
||
IN LPTSTR DllName,
|
||
IN DWORD argc,
|
||
IN LPTSTR argv[]
|
||
);
|
||
|
||
//
|
||
// Used if the services Dll or entry point can't be found
|
||
//
|
||
|
||
VOID
|
||
AbortService(
|
||
LPWSTR ServiceName,
|
||
DWORD Error
|
||
);
|
||
|
||
//
|
||
// Dispatch table for all services. Passed to NetServiceStartCtrlDispatcher.
|
||
//
|
||
// Add new service entries here and in the DLL name list.
|
||
//
|
||
|
||
SERVICE_TABLE_ENTRY TcpServiceDispatchTable[] = {
|
||
{ TEXT("Dns"), StartDns },
|
||
{ TEXT("SimpTcp"), StartSimpTcp },
|
||
{ TEXT("DhcpServer"), StartDhcpServer },
|
||
{ TEXT("FtpSvc"), StartFtpSvc },
|
||
{ TEXT("LpdSvc"), StartLpdSvc },
|
||
{ TEXT("BinlSvc"), StartBinlSvc },
|
||
{ NULL, NULL }
|
||
};
|
||
|
||
//
|
||
// DLL names for all services.
|
||
//
|
||
|
||
#define DNS_DLL TEXT("dnssvc.dll")
|
||
#define SIMPTCP_DLL TEXT("simptcp.dll")
|
||
#define DHCP_SERVER_DLL TEXT("dhcpssvc.dll")
|
||
#define FTPSVC_DLL TEXT("ftpsvc.dll")
|
||
#define LPDSVC_DLL TEXT("lpdsvc.dll")
|
||
#define BINLSVC_DLL TEXT("binlsvc.dll")
|
||
|
||
//
|
||
// Global parameter data passed to each service.
|
||
//
|
||
|
||
TCPSVCS_GLOBAL_DATA TcpsvcsGlobalData;
|
||
|
||
//
|
||
// Global parameters to manage RPC server listen.
|
||
//
|
||
|
||
DWORD TcpSvcsGlobalNumRpcListenCalled = 0;
|
||
CRITICAL_SECTION TcpsvcsGlobalRpcListenCritSect;
|
||
|
||
|
||
DWORD
|
||
TcpsvcStartRpcServerListen(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function starts RpcServerListen for this process. The first
|
||
service that is calling this function will actually start the
|
||
RpcServerListen, subsequent calls are just noted down in num count.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
|
||
RPC_STATUS Status = RPC_S_OK;
|
||
|
||
//
|
||
// LOCK global data.
|
||
//
|
||
|
||
EnterCriticalSection( &TcpsvcsGlobalRpcListenCritSect );
|
||
|
||
//
|
||
// if this is first RPC service, start RPC server listen.
|
||
//
|
||
|
||
if( TcpSvcsGlobalNumRpcListenCalled == 0 ) {
|
||
|
||
Status = RpcServerListen(
|
||
1, // minimum num threads.
|
||
RPC_C_LISTEN_MAX_CALLS_DEFAULT, // max concurrent calls.
|
||
TRUE ); // don't wait
|
||
|
||
}
|
||
|
||
TcpSvcsGlobalNumRpcListenCalled++;
|
||
|
||
//
|
||
// UNLOCK global data.
|
||
//
|
||
|
||
LeaveCriticalSection( &TcpsvcsGlobalRpcListenCritSect );
|
||
|
||
return( Status );
|
||
}
|
||
|
||
|
||
DWORD
|
||
TcpsvcStopRpcServerListen(
|
||
VOID
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
RPC_STATUS Status = RPC_S_OK;
|
||
|
||
//
|
||
// LOCK global data.
|
||
//
|
||
|
||
EnterCriticalSection( &TcpsvcsGlobalRpcListenCritSect );
|
||
|
||
if( TcpSvcsGlobalNumRpcListenCalled != 0 ) {
|
||
|
||
TcpSvcsGlobalNumRpcListenCalled--;
|
||
|
||
//
|
||
// if this is last RPC service shutting down, stop RPC server
|
||
// listen.
|
||
//
|
||
|
||
if( TcpSvcsGlobalNumRpcListenCalled == 0 ) {
|
||
|
||
Status = RpcMgmtStopServerListening(0);
|
||
|
||
//
|
||
// wait for all RPC threads to go away.
|
||
//
|
||
|
||
if( Status == RPC_S_OK) {
|
||
Status = RpcMgmtWaitServerListen();
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// UNLOCK global data.
|
||
//
|
||
|
||
LeaveCriticalSection( &TcpsvcsGlobalRpcListenCritSect );
|
||
|
||
return( Status );
|
||
|
||
}
|
||
|
||
|
||
VOID __cdecl
|
||
main(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the main routine for the LANMan services. It starts up the
|
||
main thread that is going to handle the control requests from the
|
||
service controller.
|
||
|
||
It basically sets up the ControlDispatcher and, on return, exits
|
||
from this main thread. The call to NetServiceStartCtrlDispatcher
|
||
does not return until all services have terminated, and this process
|
||
can go away.
|
||
|
||
The ControlDispatcher thread will start/stop/pause/continue any
|
||
services. If a service is to be started, it will create a thread
|
||
and then call the main routine of that service. The "main routine"
|
||
for each service is actually an intermediate function implemented in
|
||
this module that loads the DLL containing the server being started
|
||
and calls its entry point.
|
||
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
//
|
||
// Disable hard-error popups.
|
||
//
|
||
|
||
SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX );
|
||
|
||
//
|
||
// Initialize Global Data.
|
||
//
|
||
|
||
InitializeCriticalSection( &TcpsvcsGlobalRpcListenCritSect );
|
||
TcpSvcsGlobalNumRpcListenCalled = 0;
|
||
|
||
TcpsvcsGlobalData.StartRpcServerListen = TcpsvcStartRpcServerListen;
|
||
TcpsvcsGlobalData.StopRpcServerListen = TcpsvcStopRpcServerListen;
|
||
|
||
//
|
||
// Call StartServiceCtrlDispatcher to set up the control interface.
|
||
// The API won't return until all services have been terminated. At that
|
||
// point, we just exit.
|
||
//
|
||
|
||
if (! StartServiceCtrlDispatcher (
|
||
TcpServiceDispatchTable
|
||
)) {
|
||
//
|
||
// Log an event for failing to start control dispatcher
|
||
//
|
||
DbgPrint("TCPSVCS: Failed to start control dispatcher %lu\n",
|
||
GetLastError());
|
||
}
|
||
|
||
ExitProcess(0);
|
||
}
|
||
|
||
|
||
VOID
|
||
StartDns (
|
||
IN DWORD argc,
|
||
IN LPTSTR argv[]
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the thunk routine for the DNS service. It loads the DLL
|
||
that contains the service and calls its main routine.
|
||
|
||
Arguments:
|
||
|
||
argc, argv - Passed through to the service
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Call TcpsvcsStartService to load and run the service.
|
||
//
|
||
|
||
TcpsvcsStartService( DNS_DLL, argc, argv );
|
||
|
||
return;
|
||
|
||
} // StartDns
|
||
|
||
|
||
VOID
|
||
StartSimpTcp (
|
||
IN DWORD argc,
|
||
IN LPTSTR argv[]
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the thunk routine for the simple TCP/IP services. It loads
|
||
the DLL that contains the service and calls its main routine.
|
||
|
||
Arguments:
|
||
|
||
argc, argv - Passed through to the service
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Call TcpsvcsStartService to load and run the service.
|
||
//
|
||
|
||
TcpsvcsStartService( SIMPTCP_DLL, argc, argv );
|
||
|
||
return;
|
||
|
||
} // StartSimpTcp
|
||
|
||
|
||
VOID
|
||
StartDhcpServer (
|
||
IN DWORD argc,
|
||
IN LPTSTR argv[]
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the thunk routine to start dhcp server services. It loads
|
||
the DLL that contains the service and calls its main routine.
|
||
|
||
Arguments:
|
||
|
||
argc, argv - Passed through to the service
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Call TcpsvcsStartService to load and run the service.
|
||
//
|
||
|
||
TcpsvcsStartService( DHCP_SERVER_DLL, argc, argv );
|
||
|
||
return;
|
||
|
||
} // StartDhcpServer
|
||
|
||
|
||
|
||
VOID
|
||
StartFtpSvc (
|
||
IN DWORD argc,
|
||
IN LPTSTR argv[]
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the thunk routine for the FTP Server service. It loads
|
||
the DLL that contains the service and calls its main routine.
|
||
|
||
Arguments:
|
||
|
||
argc, argv - Passed through to the service
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Call TcpsvcsStartService to load and run the service.
|
||
//
|
||
|
||
TcpsvcsStartService( FTPSVC_DLL, argc, argv );
|
||
|
||
return;
|
||
|
||
} // StartFtpSvc
|
||
|
||
|
||
VOID
|
||
StartLpdSvc (
|
||
IN DWORD argc,
|
||
IN LPTSTR argv[]
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the thunk routine for the LPD Server service. It loads
|
||
the DLL that contains the service and calls its main routine.
|
||
|
||
Arguments:
|
||
|
||
argc, argv - Passed through to the service
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Call TcpsvcsStartService to load and run the service.
|
||
//
|
||
|
||
TcpsvcsStartService( LPDSVC_DLL, argc, argv );
|
||
|
||
return;
|
||
|
||
} // StartLdpSvc
|
||
|
||
|
||
VOID
|
||
StartBinlSvc (
|
||
IN DWORD argc,
|
||
IN LPTSTR argv[]
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the thunk routine for the LPD Server service. It loads
|
||
the DLL that contains the service and calls its main routine.
|
||
|
||
Arguments:
|
||
|
||
argc, argv - Passed through to the service
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
//
|
||
// Call TcpsvcsStartService to load and run the service.
|
||
//
|
||
|
||
TcpsvcsStartService( BINLSVC_DLL, argc, argv );
|
||
|
||
return;
|
||
|
||
} // StartBinlSvc
|
||
|
||
|
||
VOID
|
||
TcpsvcsStartService (
|
||
IN LPTSTR DllName,
|
||
IN DWORD argc,
|
||
IN LPTSTR argv[]
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine loads the DLL that contains a service and calls its
|
||
main routine.
|
||
|
||
Arguments:
|
||
|
||
DllName - name of the DLL
|
||
|
||
argc, argv - Passed through to the service
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
HMODULE dllHandle;
|
||
PTCPSVCS_SERVICE_DLL_ENTRY serviceEntry;
|
||
BOOL ok;
|
||
DWORD Error;
|
||
TCHAR *FileName;
|
||
TCHAR DllPath[MAX_PATH + 12 + 3];
|
||
|
||
ASSERT(lstrlen(DllName) <= 12);
|
||
|
||
if (GetSystemDirectory(DllPath, MAX_PATH) == 0) {
|
||
Error = GetLastError();
|
||
DbgPrint("TCPSVCS: Failed to get system directory: %ld\n", Error);
|
||
AbortService(argv[0], Error);
|
||
return;
|
||
}
|
||
lstrcat(DllPath, TEXT("\\"));
|
||
|
||
FileName = DllPath + lstrlen(DllPath);
|
||
|
||
lstrcpy( FileName, DllName);
|
||
|
||
//
|
||
// Load the DLL that contains the service.
|
||
//
|
||
|
||
dllHandle = LoadLibrary( DllPath );
|
||
if ( dllHandle == NULL ) {
|
||
Error = GetLastError();
|
||
DbgPrint("TCPSVCS: Failed to load DLL %ws: %ld\n", DllName, Error);
|
||
AbortService(argv[0], Error);
|
||
return;
|
||
}
|
||
|
||
//
|
||
// Get the address of the service's main entry point. This
|
||
// entry point has a well-known name.
|
||
//
|
||
|
||
serviceEntry = (PTCPSVCS_SERVICE_DLL_ENTRY)GetProcAddress(
|
||
dllHandle,
|
||
TCPSVCS_ENTRY_POINT_STRING
|
||
);
|
||
if ( serviceEntry == NULL ) {
|
||
Error = GetLastError();
|
||
DbgPrint("TCPSVCS: Can't find entry %s in DLL %ws: %ld\n",
|
||
TCPSVCS_ENTRY_POINT_STRING, DllName, Error);
|
||
AbortService(argv[0], Error);
|
||
} else {
|
||
|
||
//
|
||
// Call the service's main entry point. This call doesn't return
|
||
// until the service exits.
|
||
//
|
||
|
||
serviceEntry( argc, argv, &TcpsvcsGlobalData );
|
||
|
||
}
|
||
|
||
//
|
||
// Wait for the control dispatcher routine to return. This
|
||
// works around a problem where simptcp was crashing because the
|
||
// FreeLibrary() was happenning before the control routine returned.
|
||
//
|
||
|
||
Sleep( 2000 );
|
||
|
||
//
|
||
// Unload the DLL.
|
||
//
|
||
|
||
ok = FreeLibrary( dllHandle );
|
||
if ( !ok ) {
|
||
DbgPrint("TCPSVCS: Can't unload DLL %ws: %ld\n",
|
||
DllName, GetLastError());
|
||
}
|
||
|
||
return;
|
||
|
||
} // TcpsvcsStartService
|
||
|
||
|
||
VOID
|
||
DummyCtrlHandler(
|
||
DWORD Opcode
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is a dummy control handler which is only used if we can't load
|
||
a services DLL entry point. Then we need this so we can send the
|
||
status back to the service controller saying we are stopped, and why.
|
||
|
||
Arguments:
|
||
|
||
OpCode - Ignored
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
return;
|
||
|
||
} // DummyCtrlHandler
|
||
|
||
|
||
VOID
|
||
AbortService(
|
||
LPWSTR ServiceName,
|
||
DWORD Error)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is called if we can't load the entry point for a service. It
|
||
gets a handle so it can call SetServiceStatus saying we are stopped
|
||
and why.
|
||
|
||
Arguments:
|
||
|
||
ServiceName - the name of the service that couldn't be started
|
||
Error - the reason it couldn't be started
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
SERVICE_STATUS_HANDLE GenericServiceStatusHandle;
|
||
SERVICE_STATUS GenericServiceStatus;
|
||
|
||
GenericServiceStatus.dwServiceType = SERVICE_WIN32;
|
||
GenericServiceStatus.dwCurrentState = SERVICE_STOPPED;
|
||
GenericServiceStatus.dwControlsAccepted = SERVICE_CONTROL_STOP;
|
||
GenericServiceStatus.dwCheckPoint = 0;
|
||
GenericServiceStatus.dwWaitHint = 0;
|
||
GenericServiceStatus.dwWin32ExitCode = Error;
|
||
GenericServiceStatus.dwServiceSpecificExitCode = 0;
|
||
|
||
GenericServiceStatusHandle = RegisterServiceCtrlHandler(
|
||
ServiceName,
|
||
DummyCtrlHandler);
|
||
|
||
if (GenericServiceStatusHandle == (SERVICE_STATUS_HANDLE)0) {
|
||
DbgPrint("[TCPSVCS] RegisterServiceCtrlHandler failed %d\n",
|
||
GetLastError());
|
||
}
|
||
else if (!SetServiceStatus (GenericServiceStatusHandle,
|
||
&GenericServiceStatus)) {
|
||
DbgPrint("[TCPSVCS] SetServiceStatus error %ld\n", GetLastError());
|
||
}
|
||
|
||
return;
|
||
}
|