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.

720 lines
13 KiB

  1. /*++
  2. Copyright (c) 1991 Microsoft Corporation
  3. Module Name:
  4. MAIN.C
  5. Abstract:
  6. This is the main routine for the TCP/IP Services.
  7. Author:
  8. David Treadwell (davidtr) 7-27-93
  9. Revision History:
  10. --*/
  11. //
  12. // INCLUDES
  13. //
  14. #include <nt.h>
  15. #include <ntrtl.h>
  16. #include <nturtl.h>
  17. #include <windows.h>
  18. #include <winsvc.h> // Service control APIs
  19. #include <rpc.h>
  20. #include "tcpsvcs.h"
  21. //
  22. // Service entry points -- thunks to real service entry points.
  23. //
  24. VOID
  25. StartDns (
  26. IN DWORD argc,
  27. IN LPTSTR argv[]
  28. );
  29. VOID
  30. StartSimpTcp (
  31. IN DWORD argc,
  32. IN LPTSTR argv[]
  33. );
  34. VOID
  35. StartDhcpServer (
  36. IN DWORD argc,
  37. IN LPTSTR argv[]
  38. );
  39. VOID
  40. StartFtpSvc (
  41. IN DWORD argc,
  42. IN LPTSTR argv[]
  43. );
  44. VOID
  45. StartLpdSvc (
  46. IN DWORD argc,
  47. IN LPTSTR argv[]
  48. );
  49. VOID
  50. StartBinlSvc (
  51. IN DWORD argc,
  52. IN LPTSTR argv[]
  53. );
  54. //
  55. // Local function used by the above to load and invoke a service DLL.
  56. //
  57. VOID
  58. TcpsvcsStartService (
  59. IN LPTSTR DllName,
  60. IN DWORD argc,
  61. IN LPTSTR argv[]
  62. );
  63. //
  64. // Used if the services Dll or entry point can't be found
  65. //
  66. VOID
  67. AbortService(
  68. LPWSTR ServiceName,
  69. DWORD Error
  70. );
  71. //
  72. // Dispatch table for all services. Passed to NetServiceStartCtrlDispatcher.
  73. //
  74. // Add new service entries here and in the DLL name list.
  75. //
  76. SERVICE_TABLE_ENTRY TcpServiceDispatchTable[] = {
  77. { TEXT("Dns"), StartDns },
  78. { TEXT("SimpTcp"), StartSimpTcp },
  79. { TEXT("DhcpServer"), StartDhcpServer },
  80. { TEXT("FtpSvc"), StartFtpSvc },
  81. { TEXT("LpdSvc"), StartLpdSvc },
  82. { TEXT("BinlSvc"), StartBinlSvc },
  83. { NULL, NULL }
  84. };
  85. //
  86. // DLL names for all services.
  87. //
  88. #define DNS_DLL TEXT("dnssvc.dll")
  89. #define SIMPTCP_DLL TEXT("simptcp.dll")
  90. #define DHCP_SERVER_DLL TEXT("dhcpssvc.dll")
  91. #define FTPSVC_DLL TEXT("ftpsvc.dll")
  92. #define LPDSVC_DLL TEXT("lpdsvc.dll")
  93. #define BINLSVC_DLL TEXT("binlsvc.dll")
  94. //
  95. // Global parameter data passed to each service.
  96. //
  97. TCPSVCS_GLOBAL_DATA TcpsvcsGlobalData;
  98. //
  99. // Global parameters to manage RPC server listen.
  100. //
  101. DWORD TcpSvcsGlobalNumRpcListenCalled = 0;
  102. CRITICAL_SECTION TcpsvcsGlobalRpcListenCritSect;
  103. DWORD
  104. TcpsvcStartRpcServerListen(
  105. VOID
  106. )
  107. /*++
  108. Routine Description:
  109. This function starts RpcServerListen for this process. The first
  110. service that is calling this function will actually start the
  111. RpcServerListen, subsequent calls are just noted down in num count.
  112. Arguments:
  113. None.
  114. Return Value:
  115. None.
  116. --*/
  117. {
  118. RPC_STATUS Status = RPC_S_OK;
  119. //
  120. // LOCK global data.
  121. //
  122. EnterCriticalSection( &TcpsvcsGlobalRpcListenCritSect );
  123. //
  124. // if this is first RPC service, start RPC server listen.
  125. //
  126. if( TcpSvcsGlobalNumRpcListenCalled == 0 ) {
  127. Status = RpcServerListen(
  128. 1, // minimum num threads.
  129. RPC_C_LISTEN_MAX_CALLS_DEFAULT, // max concurrent calls.
  130. TRUE ); // don't wait
  131. }
  132. TcpSvcsGlobalNumRpcListenCalled++;
  133. //
  134. // UNLOCK global data.
  135. //
  136. LeaveCriticalSection( &TcpsvcsGlobalRpcListenCritSect );
  137. return( Status );
  138. }
  139. DWORD
  140. TcpsvcStopRpcServerListen(
  141. VOID
  142. )
  143. /*++
  144. Routine Description:
  145. Arguments:
  146. None.
  147. Return Value:
  148. None.
  149. --*/
  150. {
  151. RPC_STATUS Status = RPC_S_OK;
  152. //
  153. // LOCK global data.
  154. //
  155. EnterCriticalSection( &TcpsvcsGlobalRpcListenCritSect );
  156. if( TcpSvcsGlobalNumRpcListenCalled != 0 ) {
  157. TcpSvcsGlobalNumRpcListenCalled--;
  158. //
  159. // if this is last RPC service shutting down, stop RPC server
  160. // listen.
  161. //
  162. if( TcpSvcsGlobalNumRpcListenCalled == 0 ) {
  163. Status = RpcMgmtStopServerListening(0);
  164. //
  165. // wait for all RPC threads to go away.
  166. //
  167. if( Status == RPC_S_OK) {
  168. Status = RpcMgmtWaitServerListen();
  169. }
  170. }
  171. }
  172. //
  173. // UNLOCK global data.
  174. //
  175. LeaveCriticalSection( &TcpsvcsGlobalRpcListenCritSect );
  176. return( Status );
  177. }
  178. VOID __cdecl
  179. main(
  180. VOID
  181. )
  182. /*++
  183. Routine Description:
  184. This is the main routine for the LANMan services. It starts up the
  185. main thread that is going to handle the control requests from the
  186. service controller.
  187. It basically sets up the ControlDispatcher and, on return, exits
  188. from this main thread. The call to NetServiceStartCtrlDispatcher
  189. does not return until all services have terminated, and this process
  190. can go away.
  191. The ControlDispatcher thread will start/stop/pause/continue any
  192. services. If a service is to be started, it will create a thread
  193. and then call the main routine of that service. The "main routine"
  194. for each service is actually an intermediate function implemented in
  195. this module that loads the DLL containing the server being started
  196. and calls its entry point.
  197. Arguments:
  198. None.
  199. Return Value:
  200. None.
  201. --*/
  202. {
  203. //
  204. // Disable hard-error popups.
  205. //
  206. SetErrorMode( SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX );
  207. //
  208. // Initialize Global Data.
  209. //
  210. InitializeCriticalSection( &TcpsvcsGlobalRpcListenCritSect );
  211. TcpSvcsGlobalNumRpcListenCalled = 0;
  212. TcpsvcsGlobalData.StartRpcServerListen = TcpsvcStartRpcServerListen;
  213. TcpsvcsGlobalData.StopRpcServerListen = TcpsvcStopRpcServerListen;
  214. //
  215. // Call StartServiceCtrlDispatcher to set up the control interface.
  216. // The API won't return until all services have been terminated. At that
  217. // point, we just exit.
  218. //
  219. if (! StartServiceCtrlDispatcher (
  220. TcpServiceDispatchTable
  221. )) {
  222. //
  223. // Log an event for failing to start control dispatcher
  224. //
  225. DbgPrint("TCPSVCS: Failed to start control dispatcher %lu\n",
  226. GetLastError());
  227. }
  228. ExitProcess(0);
  229. }
  230. VOID
  231. StartDns (
  232. IN DWORD argc,
  233. IN LPTSTR argv[]
  234. )
  235. /*++
  236. Routine Description:
  237. This is the thunk routine for the DNS service. It loads the DLL
  238. that contains the service and calls its main routine.
  239. Arguments:
  240. argc, argv - Passed through to the service
  241. Return Value:
  242. None.
  243. --*/
  244. {
  245. //
  246. // Call TcpsvcsStartService to load and run the service.
  247. //
  248. TcpsvcsStartService( DNS_DLL, argc, argv );
  249. return;
  250. } // StartDns
  251. VOID
  252. StartSimpTcp (
  253. IN DWORD argc,
  254. IN LPTSTR argv[]
  255. )
  256. /*++
  257. Routine Description:
  258. This is the thunk routine for the simple TCP/IP services. It loads
  259. the DLL that contains the service and calls its main routine.
  260. Arguments:
  261. argc, argv - Passed through to the service
  262. Return Value:
  263. None.
  264. --*/
  265. {
  266. //
  267. // Call TcpsvcsStartService to load and run the service.
  268. //
  269. TcpsvcsStartService( SIMPTCP_DLL, argc, argv );
  270. return;
  271. } // StartSimpTcp
  272. VOID
  273. StartDhcpServer (
  274. IN DWORD argc,
  275. IN LPTSTR argv[]
  276. )
  277. /*++
  278. Routine Description:
  279. This is the thunk routine to start dhcp server services. It loads
  280. the DLL that contains the service and calls its main routine.
  281. Arguments:
  282. argc, argv - Passed through to the service
  283. Return Value:
  284. None.
  285. --*/
  286. {
  287. //
  288. // Call TcpsvcsStartService to load and run the service.
  289. //
  290. TcpsvcsStartService( DHCP_SERVER_DLL, argc, argv );
  291. return;
  292. } // StartDhcpServer
  293. VOID
  294. StartFtpSvc (
  295. IN DWORD argc,
  296. IN LPTSTR argv[]
  297. )
  298. /*++
  299. Routine Description:
  300. This is the thunk routine for the FTP Server service. It loads
  301. the DLL that contains the service and calls its main routine.
  302. Arguments:
  303. argc, argv - Passed through to the service
  304. Return Value:
  305. None.
  306. --*/
  307. {
  308. //
  309. // Call TcpsvcsStartService to load and run the service.
  310. //
  311. TcpsvcsStartService( FTPSVC_DLL, argc, argv );
  312. return;
  313. } // StartFtpSvc
  314. VOID
  315. StartLpdSvc (
  316. IN DWORD argc,
  317. IN LPTSTR argv[]
  318. )
  319. /*++
  320. Routine Description:
  321. This is the thunk routine for the LPD Server service. It loads
  322. the DLL that contains the service and calls its main routine.
  323. Arguments:
  324. argc, argv - Passed through to the service
  325. Return Value:
  326. None.
  327. --*/
  328. {
  329. //
  330. // Call TcpsvcsStartService to load and run the service.
  331. //
  332. TcpsvcsStartService( LPDSVC_DLL, argc, argv );
  333. return;
  334. } // StartLdpSvc
  335. VOID
  336. StartBinlSvc (
  337. IN DWORD argc,
  338. IN LPTSTR argv[]
  339. )
  340. /*++
  341. Routine Description:
  342. This is the thunk routine for the LPD Server service. It loads
  343. the DLL that contains the service and calls its main routine.
  344. Arguments:
  345. argc, argv - Passed through to the service
  346. Return Value:
  347. None.
  348. --*/
  349. {
  350. //
  351. // Call TcpsvcsStartService to load and run the service.
  352. //
  353. TcpsvcsStartService( BINLSVC_DLL, argc, argv );
  354. return;
  355. } // StartBinlSvc
  356. VOID
  357. TcpsvcsStartService (
  358. IN LPTSTR DllName,
  359. IN DWORD argc,
  360. IN LPTSTR argv[]
  361. )
  362. /*++
  363. Routine Description:
  364. This routine loads the DLL that contains a service and calls its
  365. main routine.
  366. Arguments:
  367. DllName - name of the DLL
  368. argc, argv - Passed through to the service
  369. Return Value:
  370. None.
  371. --*/
  372. {
  373. HMODULE dllHandle;
  374. PTCPSVCS_SERVICE_DLL_ENTRY serviceEntry;
  375. BOOL ok;
  376. DWORD Error;
  377. TCHAR *FileName;
  378. TCHAR DllPath[MAX_PATH + 12 + 3];
  379. ASSERT(lstrlen(DllName) <= 12);
  380. if (GetSystemDirectory(DllPath, MAX_PATH) == 0) {
  381. Error = GetLastError();
  382. DbgPrint("TCPSVCS: Failed to get system directory: %ld\n", Error);
  383. AbortService(argv[0], Error);
  384. return;
  385. }
  386. lstrcat(DllPath, TEXT("\\"));
  387. FileName = DllPath + lstrlen(DllPath);
  388. lstrcpy( FileName, DllName);
  389. //
  390. // Load the DLL that contains the service.
  391. //
  392. dllHandle = LoadLibrary( DllPath );
  393. if ( dllHandle == NULL ) {
  394. Error = GetLastError();
  395. DbgPrint("TCPSVCS: Failed to load DLL %ws: %ld\n", DllName, Error);
  396. AbortService(argv[0], Error);
  397. return;
  398. }
  399. //
  400. // Get the address of the service's main entry point. This
  401. // entry point has a well-known name.
  402. //
  403. serviceEntry = (PTCPSVCS_SERVICE_DLL_ENTRY)GetProcAddress(
  404. dllHandle,
  405. TCPSVCS_ENTRY_POINT_STRING
  406. );
  407. if ( serviceEntry == NULL ) {
  408. Error = GetLastError();
  409. DbgPrint("TCPSVCS: Can't find entry %s in DLL %ws: %ld\n",
  410. TCPSVCS_ENTRY_POINT_STRING, DllName, Error);
  411. AbortService(argv[0], Error);
  412. } else {
  413. //
  414. // Call the service's main entry point. This call doesn't return
  415. // until the service exits.
  416. //
  417. serviceEntry( argc, argv, &TcpsvcsGlobalData );
  418. }
  419. //
  420. // Wait for the control dispatcher routine to return. This
  421. // works around a problem where simptcp was crashing because the
  422. // FreeLibrary() was happenning before the control routine returned.
  423. //
  424. Sleep( 2000 );
  425. //
  426. // Unload the DLL.
  427. //
  428. ok = FreeLibrary( dllHandle );
  429. if ( !ok ) {
  430. DbgPrint("TCPSVCS: Can't unload DLL %ws: %ld\n",
  431. DllName, GetLastError());
  432. }
  433. return;
  434. } // TcpsvcsStartService
  435. VOID
  436. DummyCtrlHandler(
  437. DWORD Opcode
  438. )
  439. /*++
  440. Routine Description:
  441. This is a dummy control handler which is only used if we can't load
  442. a services DLL entry point. Then we need this so we can send the
  443. status back to the service controller saying we are stopped, and why.
  444. Arguments:
  445. OpCode - Ignored
  446. Return Value:
  447. None.
  448. --*/
  449. {
  450. return;
  451. } // DummyCtrlHandler
  452. VOID
  453. AbortService(
  454. LPWSTR ServiceName,
  455. DWORD Error)
  456. /*++
  457. Routine Description:
  458. This is called if we can't load the entry point for a service. It
  459. gets a handle so it can call SetServiceStatus saying we are stopped
  460. and why.
  461. Arguments:
  462. ServiceName - the name of the service that couldn't be started
  463. Error - the reason it couldn't be started
  464. Return Value:
  465. None.
  466. --*/
  467. {
  468. SERVICE_STATUS_HANDLE GenericServiceStatusHandle;
  469. SERVICE_STATUS GenericServiceStatus;
  470. GenericServiceStatus.dwServiceType = SERVICE_WIN32;
  471. GenericServiceStatus.dwCurrentState = SERVICE_STOPPED;
  472. GenericServiceStatus.dwControlsAccepted = SERVICE_CONTROL_STOP;
  473. GenericServiceStatus.dwCheckPoint = 0;
  474. GenericServiceStatus.dwWaitHint = 0;
  475. GenericServiceStatus.dwWin32ExitCode = Error;
  476. GenericServiceStatus.dwServiceSpecificExitCode = 0;
  477. GenericServiceStatusHandle = RegisterServiceCtrlHandler(
  478. ServiceName,
  479. DummyCtrlHandler);
  480. if (GenericServiceStatusHandle == (SERVICE_STATUS_HANDLE)0) {
  481. DbgPrint("[TCPSVCS] RegisterServiceCtrlHandler failed %d\n",
  482. GetLastError());
  483. }
  484. else if (!SetServiceStatus (GenericServiceStatusHandle,
  485. &GenericServiceStatus)) {
  486. DbgPrint("[TCPSVCS] SetServiceStatus error %ld\n", GetLastError());
  487. }
  488. return;
  489. }