Leaked source code of windows server 2003
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.

2401 lines
57 KiB

  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. Simpsvc.c
  5. Abstract:
  6. Supports several simple TCP/IP services in a single thread: TCP Echo,
  7. UDP Echo, Daytime, Null, Chargen.
  8. Author:
  9. David Treadwell (davidtr) 3-Mar-1993
  10. Revision History:
  11. --*/
  12. #include "simptcp.h"
  13. #define MAX_UDP_CHARGEN_RESPONSE 7030
  14. #define MAX_DATE_BUFFER_SIZE 2000
  15. // Number of services, counting tcp and udp versions as separate
  16. #define NUM_SERVICES 10
  17. typedef struct _FAMILY {
  18. short family;
  19. SOCKET tcpEcho;
  20. SOCKET udpEcho;
  21. SOCKET tcpDaytime;
  22. SOCKET udpDaytime;
  23. SOCKET tcpDiscard;
  24. SOCKET udpDiscard;
  25. SOCKET tcpChargen;
  26. SOCKET udpChargen;
  27. SOCKET tcpQotd;
  28. SOCKET udpQotd;
  29. } FAMILY;
  30. FAMILY family[] = {
  31. { AF_INET, INVALID_SOCKET,INVALID_SOCKET,INVALID_SOCKET,INVALID_SOCKET,
  32. INVALID_SOCKET,INVALID_SOCKET,INVALID_SOCKET,INVALID_SOCKET,
  33. INVALID_SOCKET,INVALID_SOCKET },
  34. { AF_INET6, INVALID_SOCKET,INVALID_SOCKET,INVALID_SOCKET,INVALID_SOCKET,
  35. INVALID_SOCKET,INVALID_SOCKET,INVALID_SOCKET,INVALID_SOCKET,
  36. INVALID_SOCKET,INVALID_SOCKET },
  37. };
  38. #define NUM_FAMILIES (sizeof(family) / sizeof(FAMILY))
  39. DWORD IoBufferSize = 4096;
  40. PCHAR IoBuffer = NULL;
  41. WSADATA WsaData;
  42. RTL_CRITICAL_SECTION CriticalSection;
  43. BOOL InitializedCriticalSection = FALSE;
  44. typedef struct _TCP_CLIENT_INFO {
  45. SOCKET SocketHandle;
  46. SOCKADDR_STORAGE RemoteAddress;
  47. INT RemoteAddressLen;
  48. HANDLE ThreadHandle;
  49. SHORT ServicePort;
  50. } TCP_CLIENT_INFO, *PTCP_CLIENT_INFO;
  51. #define MAX_TCP_CLIENTS 1000
  52. PTCP_CLIENT_INFO TcpClients = NULL;
  53. #define LISTEN_BACKLOG 5
  54. #define MAX_IDLE_TICKS 10 * 60 * 1000 // 10 minutes
  55. #define SELECT_TIMEOUT 5 * 60 // 5 minutes
  56. DWORD MaxTcpClients = MAX_TCP_CLIENTS;
  57. DWORD MaxIdleTicks = MAX_IDLE_TICKS;
  58. DWORD SelectTimeout = SELECT_TIMEOUT;
  59. PFD_SET ReadfdsStore, Readfds;
  60. SHORT TcpEchoPort;
  61. SHORT UdpEchoPort;
  62. SHORT TcpDiscardPort;
  63. SHORT UdpDiscardPort;
  64. SHORT TcpChargenPort;
  65. SHORT UdpChargenPort;
  66. SHORT TcpDaytimePort;
  67. SHORT UdpDaytimePort;
  68. SHORT TcpQotdPort;
  69. SHORT UdpQotdPort;
  70. #define INVALID_PORT 0
  71. BOOL DoTcpEcho = TRUE;
  72. BOOL DoUdpEcho = TRUE;
  73. BOOL DoTcpDiscard = TRUE;
  74. BOOL DoUdpDiscard = TRUE;
  75. BOOL DoTcpChargen = TRUE;
  76. BOOL DoUdpChargen = TRUE;
  77. BOOL DoTcpDaytime = TRUE;
  78. BOOL DoUdpDaytime = TRUE;
  79. BOOL DoTcpQotd = TRUE;
  80. BOOL DoUdpQotd = TRUE;
  81. struct {
  82. PBOOL Boolean;
  83. PWSTR ValueName;
  84. } RegistryBooleans[] = {
  85. &DoTcpEcho, L"EnableTcpEcho",
  86. &DoUdpEcho, L"EnableUdpEcho",
  87. &DoTcpDiscard, L"EnableTcpDiscard",
  88. &DoUdpDiscard, L"EnableUdpDiscard",
  89. &DoTcpChargen, L"EnableTcpChargen",
  90. &DoUdpChargen, L"EnableUdpChargen",
  91. &DoTcpDaytime, L"EnableTcpDaytime",
  92. &DoUdpDaytime, L"EnableUdpDaytime",
  93. &DoTcpQotd, L"EnableTcpQotd",
  94. &DoUdpQotd, L"EnableUdpQotd",
  95. NULL, NULL
  96. };
  97. struct {
  98. PDWORD Dword;
  99. PWSTR ValueName;
  100. } RegistryDwords[] = {
  101. &MaxTcpClients, L"MaxTcpClients",
  102. &MaxIdleTicks, L"MaxIdleTicks",
  103. &SelectTimeout, L"SelectTimeout",
  104. &IoBufferSize, L"IoBufferSize",
  105. NULL, NULL
  106. };
  107. SERVICE_STATUS SimpServiceStatus;
  108. SERVICE_STATUS_HANDLE SimpServiceStatusHandle;
  109. HANDLE SimpPauseEvent = NULL;
  110. SOCKET SimpQuitSocket;
  111. BOOL SimpServiceExit = FALSE;
  112. PVOID ChargenBuffer = NULL;
  113. DWORD ChargenBufferSize;
  114. PVOID QotdBuffer = NULL;
  115. DWORD QotdQuoteCount;
  116. struct {
  117. DWORD QuoteLength;
  118. PCHAR Quote;
  119. } *QotdStrings = NULL;
  120. PWSTR QotdFileName = NULL;
  121. HANDLE QotdFileHandle = NULL;
  122. HANDLE QotdFileMapping = NULL;
  123. VOID
  124. AnnounceServiceStatus (
  125. VOID
  126. );
  127. VOID
  128. ControlResponse(
  129. DWORD opCode
  130. );
  131. VOID
  132. AbortTcpClient (
  133. IN SOCKET Socket
  134. );
  135. INT
  136. AcceptTcpClient (
  137. IN SOCKET ListenSocket,
  138. IN SHORT Port
  139. );
  140. VOID
  141. DeleteTcpClient (
  142. IN DWORD ArraySlot,
  143. IN BOOLEAN Graceful
  144. );
  145. VOID
  146. DoSimpleServices (
  147. VOID
  148. );
  149. VOID
  150. FormatDaytimeResponse (
  151. IN PCHAR Buffer,
  152. IN PDWORD BufferLength
  153. );
  154. VOID
  155. FormatQotdResponse (
  156. IN PCHAR Buffer,
  157. IN PDWORD BufferLength
  158. );
  159. SHORT
  160. GetServicePort (
  161. IN PCHAR Service,
  162. IN PCHAR Protocol
  163. );
  164. INT
  165. InitializeChargen (
  166. VOID
  167. );
  168. INT
  169. InitializeQotdQuotes (
  170. VOID
  171. );
  172. INT
  173. ReadRegistry (
  174. VOID
  175. );
  176. BOOL
  177. OpenTcpSocket (
  178. OUT SOCKET *pSocket,
  179. IN INT FamIdx,
  180. IN SHORT Port
  181. );
  182. BOOL
  183. OpenUdpSocket (
  184. OUT SOCKET *pSocket,
  185. IN INT FamIdx,
  186. IN SHORT Port
  187. );
  188. INT
  189. SimpInitializeEventLog (
  190. VOID
  191. );
  192. VOID
  193. SimpTerminateEventLog(
  194. VOID
  195. );
  196. VOID
  197. SimpLogEvent(
  198. DWORD Message,
  199. WORD SubStringCount,
  200. CHAR *SubStrings[],
  201. DWORD ErrorCode
  202. );
  203. DWORD
  204. ThreadEntry (
  205. LPVOID lpThreadParameter
  206. );
  207. INT
  208. ProcessFamily(
  209. IN INT FamIdx)
  210. {
  211. INT err=NO_ERROR;
  212. INT i;
  213. SOCKADDR_STORAGE remoteAddr;
  214. INT remoteAddrLength;
  215. u_long one = 1;
  216. if ( family[FamIdx].tcpEcho != INVALID_SOCKET && FD_ISSET( family[FamIdx].tcpEcho, Readfds ) ) {
  217. i = AcceptTcpClient( family[FamIdx].tcpEcho, TcpEchoPort );
  218. }
  219. if ( family[FamIdx].tcpDiscard != INVALID_SOCKET && FD_ISSET( family[FamIdx].tcpDiscard, Readfds ) ) {
  220. i = AcceptTcpClient( family[FamIdx].tcpDiscard, TcpDiscardPort );
  221. }
  222. if ( family[FamIdx].tcpDaytime != INVALID_SOCKET && FD_ISSET( family[FamIdx].tcpDaytime, Readfds ) ) {
  223. SOCKET acceptSocket;
  224. DWORD length=IoBufferSize;
  225. //
  226. // A client is making a TCP daytime request. First accept
  227. // the connection, then send the current time-of-day string
  228. // to the client, then close the socket.
  229. //
  230. acceptSocket = accept( family[FamIdx].tcpDaytime, NULL, NULL );
  231. if ( acceptSocket != INVALID_SOCKET ) {
  232. FormatDaytimeResponse( IoBuffer, &length );
  233. send( acceptSocket, IoBuffer, length, 0 );
  234. err = closesocket( acceptSocket );
  235. ASSERT( err != SOCKET_ERROR );
  236. }
  237. }
  238. if ( family[FamIdx].tcpChargen != INVALID_SOCKET && FD_ISSET( family[FamIdx].tcpChargen, Readfds ) ) {
  239. i = AcceptTcpClient( family[FamIdx].tcpChargen, TcpChargenPort );
  240. if ( i != -1 ) {
  241. one = 1;
  242. err = ioctlsocket( TcpClients[i].SocketHandle, FIONBIO, &one );
  243. if ( err == SOCKET_ERROR ) {
  244. DeleteTcpClient( i, FALSE );
  245. }
  246. }
  247. }
  248. if ( family[FamIdx].tcpQotd != INVALID_SOCKET && FD_ISSET( family[FamIdx].tcpQotd, Readfds ) ) {
  249. SOCKET acceptSocket;
  250. DWORD length = IoBufferSize;
  251. //
  252. // A client is making a TCP Qotd request. First accept
  253. // the connection, then send the quote of the day
  254. // to the client, then close the socket.
  255. //
  256. acceptSocket = accept( family[FamIdx].tcpQotd, NULL, NULL );
  257. if ( acceptSocket != INVALID_SOCKET ) {
  258. FormatQotdResponse( IoBuffer, &length );
  259. send( acceptSocket, IoBuffer, length, 0 );
  260. err = closesocket( acceptSocket );
  261. ASSERT( err != SOCKET_ERROR );
  262. }
  263. }
  264. // ================================================================
  265. // Udp services.
  266. if ( family[FamIdx].udpEcho != INVALID_SOCKET && FD_ISSET( family[FamIdx].udpEcho, Readfds ) ) {
  267. remoteAddrLength = sizeof(remoteAddr);
  268. err = recvfrom(
  269. family[FamIdx].udpEcho,
  270. IoBuffer,
  271. IoBufferSize,
  272. 0,
  273. (PSOCKADDR)&remoteAddr,
  274. &remoteAddrLength
  275. );
  276. if( ntohs(SS_PORT(&remoteAddr)) > IPPORT_RESERVED
  277. && err != SOCKET_ERROR )
  278. {
  279. err = sendto(
  280. family[FamIdx].udpEcho,
  281. IoBuffer,
  282. err,
  283. 0,
  284. (PSOCKADDR)&remoteAddr,
  285. remoteAddrLength
  286. );
  287. }
  288. }
  289. if ( family[FamIdx].udpDiscard != INVALID_SOCKET && FD_ISSET( family[FamIdx].udpDiscard, Readfds ) ) {
  290. err = recvfrom(
  291. family[FamIdx].udpDiscard,
  292. IoBuffer,
  293. IoBufferSize,
  294. 0,
  295. NULL,
  296. NULL
  297. );
  298. ASSERT( err != SOCKET_ERROR );
  299. // Nothing to sendto in this case.
  300. }
  301. if ( family[FamIdx].udpDaytime != INVALID_SOCKET && FD_ISSET( family[FamIdx].udpDaytime, Readfds ) ) {
  302. DWORD length;
  303. remoteAddrLength = sizeof(remoteAddr);
  304. err = recvfrom(
  305. family[FamIdx].udpDaytime,
  306. IoBuffer,
  307. IoBufferSize,
  308. 0,
  309. (PSOCKADDR)&remoteAddr,
  310. &remoteAddrLength
  311. );
  312. if( (ntohs(SS_PORT(&remoteAddr)) > IPPORT_RESERVED) && (err != SOCKET_ERROR) )
  313. {
  314. length=IoBufferSize;
  315. FormatDaytimeResponse( IoBuffer, &length );
  316. err = sendto(
  317. family[FamIdx].udpDaytime,
  318. IoBuffer,
  319. length,
  320. 0,
  321. (PSOCKADDR)&remoteAddr,
  322. remoteAddrLength
  323. );
  324. }
  325. }
  326. if ( family[FamIdx].udpChargen != INVALID_SOCKET && FD_ISSET( family[FamIdx].udpChargen, Readfds ) ) {
  327. DWORD length;
  328. remoteAddrLength = sizeof(remoteAddr);
  329. err = recvfrom(
  330. family[FamIdx].udpChargen,
  331. IoBuffer,
  332. IoBufferSize,
  333. 0,
  334. (PSOCKADDR)&remoteAddr,
  335. &remoteAddrLength
  336. );
  337. // Infinite loop attack, when we get a request from
  338. // another service. - MohsinA, 30-Jun-97.
  339. if( (ntohs(SS_PORT(&remoteAddr)) > IPPORT_RESERVED) && (err != SOCKET_ERROR) )
  340. {
  341. srand( GetTickCount( ) );
  342. length = (rand( ) * MAX_UDP_CHARGEN_RESPONSE) / RAND_MAX;
  343. if (length > ChargenBufferSize) {
  344. length=ChargenBufferSize;
  345. }
  346. err = sendto(
  347. family[FamIdx].udpChargen,
  348. ChargenBuffer,
  349. length,
  350. 0,
  351. (PSOCKADDR)&remoteAddr,
  352. remoteAddrLength
  353. );
  354. }
  355. }
  356. if ( family[FamIdx].udpQotd != INVALID_SOCKET && FD_ISSET( family[FamIdx].udpQotd, Readfds ) ) {
  357. DWORD length = IoBufferSize;
  358. remoteAddrLength = sizeof(remoteAddr);
  359. err = recvfrom(
  360. family[FamIdx].udpQotd,
  361. IoBuffer,
  362. IoBufferSize,
  363. 0,
  364. (PSOCKADDR)&remoteAddr,
  365. &remoteAddrLength
  366. );
  367. if( (ntohs(SS_PORT(&remoteAddr)) > IPPORT_RESERVED) && (err != SOCKET_ERROR) )
  368. {
  369. FormatQotdResponse( IoBuffer, &length );
  370. err = sendto(
  371. family[FamIdx].udpQotd,
  372. IoBuffer,
  373. length,
  374. 0,
  375. (PSOCKADDR)&remoteAddr,
  376. remoteAddrLength
  377. );
  378. }
  379. }
  380. return err;
  381. }
  382. VOID
  383. ServiceEntry (
  384. IN DWORD argc,
  385. IN LPWSTR argv[],
  386. IN PTCPSVCS_GLOBAL_DATA pGlobalData
  387. )
  388. /*++
  389. Routine Description:
  390. This is the "main" routine for the simple TCP/IP services. The
  391. containing process will call this routine when we're supposed to
  392. start up.
  393. Arguments:
  394. Return Value:
  395. None.
  396. --*/
  397. {
  398. INT err=ERROR_GEN_FAILURE;
  399. TIMEVAL timeout;
  400. INT i, FamIdx;
  401. DWORD maxFdSetSize;
  402. NTSTATUS status;
  403. BOOL bOk;
  404. //
  405. // Initialize all the status fields so that subsequent calls to
  406. // SetServiceStatus need to only update fields that changed.
  407. //
  408. SimpServiceStatus.dwServiceType = SERVICE_WIN32;
  409. SimpServiceStatus.dwCurrentState = SERVICE_START_PENDING;
  410. SimpServiceStatus.dwControlsAccepted = 0;
  411. SimpServiceStatus.dwCheckPoint = 1;
  412. SimpServiceStatus.dwWaitHint = 30000; // 30 seconds
  413. SimpServiceStatus.dwWin32ExitCode = NO_ERROR;
  414. SimpServiceStatus.dwServiceSpecificExitCode = NO_ERROR;
  415. //
  416. // Initialize server to receive service requests by registering the
  417. // control handler.
  418. //
  419. SimpServiceStatusHandle = RegisterServiceCtrlHandler(
  420. TEXT("SimpTcp"),
  421. ControlResponse
  422. );
  423. if ( SimpServiceStatusHandle == 0 ) {
  424. err = GetLastError();
  425. goto exit;
  426. }
  427. AnnounceServiceStatus( );
  428. //
  429. // Initialize our critical section.
  430. //
  431. status = RtlInitializeCriticalSection( &CriticalSection );
  432. if ( !NT_SUCCESS(status) ) {
  433. goto exit;
  434. }
  435. InitializedCriticalSection = TRUE;
  436. //
  437. // Initialize the eventlog.
  438. //
  439. err = SimpInitializeEventLog( );
  440. ASSERT( err == NO_ERROR );
  441. //
  442. // Read all registry information.
  443. //
  444. err = ReadRegistry( );
  445. if ( err != NO_ERROR ) {
  446. goto exit;
  447. }
  448. //
  449. // Allocate memory for the IO buffer.
  450. //
  451. IoBuffer = RtlAllocateHeap( RtlProcessHeap( ), 0, IoBufferSize );
  452. //
  453. // Allocate memory for the array of TCP clients.
  454. //
  455. TcpClients = RtlAllocateHeap(
  456. RtlProcessHeap( ),
  457. 0,
  458. MaxTcpClients * sizeof(TcpClients[0])
  459. );
  460. if ( TcpClients == NULL ) {
  461. err = ERROR_NOT_ENOUGH_MEMORY;
  462. goto exit;
  463. }
  464. //
  465. // Initialize the chargen data buffer.
  466. //
  467. if ( DoTcpChargen || DoUdpChargen ) {
  468. err = InitializeChargen( );
  469. if ( err != NO_ERROR ) {
  470. DoUdpChargen = FALSE;
  471. DoTcpChargen = FALSE;
  472. }
  473. }
  474. //
  475. // Initialize the quote of the day quotes.
  476. //
  477. if ( DoTcpQotd || DoUdpQotd ) {
  478. err = InitializeQotdQuotes( );
  479. if ( err != NO_ERROR ) {
  480. DoUdpQotd = FALSE;
  481. DoTcpQotd = FALSE;
  482. }
  483. }
  484. //
  485. // Initialize client socket array.
  486. //
  487. for ( i = 0; (DWORD)i < MaxTcpClients; i++ ) {
  488. TcpClients[i].SocketHandle = INVALID_SOCKET;
  489. TcpClients[i].ThreadHandle = NULL;
  490. }
  491. //
  492. // Determine how large our FD_SET structures must be, then allocate
  493. // space for them. We have 1 quit socket, plus 10 services * 2 families.
  494. //
  495. maxFdSetSize = FIELD_OFFSET(fd_set, fd_array[1 + NUM_FAMILIES * NUM_SERVICES]);
  496. Readfds = RtlAllocateHeap( RtlProcessHeap( ), 0, maxFdSetSize );
  497. ReadfdsStore = RtlAllocateHeap( RtlProcessHeap( ), 0, maxFdSetSize );
  498. if ( Readfds == NULL || ReadfdsStore == NULL ) {
  499. err = ERROR_NOT_ENOUGH_MEMORY;
  500. goto exit;
  501. }
  502. //
  503. // Initialize the pause event. We use this event to stop activity
  504. // when the service is paused.
  505. //
  506. SimpPauseEvent = CreateEvent( NULL, TRUE, TRUE, NULL );
  507. if ( SimpPauseEvent == NULL ) {
  508. err = GetLastError( );
  509. goto exit;
  510. }
  511. //
  512. // Initialize the Windows Sockets DLL.
  513. //
  514. err = WSAStartup( 0x0101, &WsaData );
  515. if ( err == SOCKET_ERROR ) {
  516. err = GetLastError( );
  517. goto exit;
  518. }
  519. //
  520. // Initialize the FD sets we'll use.
  521. //
  522. FD_ZERO( ReadfdsStore );
  523. //
  524. // Open the "quit" socket. We close this socket when we need to
  525. // shut down in order to wake up the main thread from it's select()
  526. // and begin shutdown.
  527. //
  528. SimpQuitSocket = socket( AF_INET, SOCK_DGRAM, 0 );
  529. if ( SimpQuitSocket != INVALID_SOCKET ) {
  530. FD_SET( SimpQuitSocket, ReadfdsStore );
  531. } else {
  532. err = GetLastError( );
  533. goto exit;
  534. }
  535. //
  536. // First find the port numbers for all our services.
  537. //
  538. TcpEchoPort = GetServicePort( "echo", "tcp" );
  539. if ( TcpEchoPort == INVALID_PORT && DoTcpEcho ) {
  540. SimpLogEvent(
  541. SIMPTCP_CANT_FIND_TCP_ECHO_PORT,
  542. 0,
  543. NULL,
  544. WSAGetLastError( )
  545. );
  546. DoTcpEcho = FALSE;
  547. }
  548. UdpEchoPort = GetServicePort( "echo", "udp" );
  549. if ( UdpEchoPort == INVALID_PORT && DoUdpEcho ) {
  550. SimpLogEvent(
  551. SIMPTCP_CANT_FIND_UDP_ECHO_PORT,
  552. 0,
  553. NULL,
  554. WSAGetLastError( )
  555. );
  556. DoUdpEcho = FALSE;
  557. }
  558. TcpDiscardPort = GetServicePort( "discard", "tcp" );
  559. if ( TcpDiscardPort == INVALID_PORT && DoTcpDiscard ) {
  560. SimpLogEvent(
  561. SIMPTCP_CANT_FIND_TCP_DISCARD_PORT,
  562. 0,
  563. NULL,
  564. WSAGetLastError( )
  565. );
  566. DoTcpDiscard = FALSE;
  567. }
  568. UdpDiscardPort = GetServicePort( "discard", "udp" );
  569. if ( UdpDiscardPort == INVALID_PORT && DoUdpDiscard ) {
  570. SimpLogEvent(
  571. SIMPTCP_CANT_FIND_UDP_DISCARD_PORT,
  572. 0,
  573. NULL,
  574. WSAGetLastError( )
  575. );
  576. DoUdpDiscard = FALSE;
  577. }
  578. TcpDaytimePort = GetServicePort( "daytime", "tcp" );
  579. if ( TcpDaytimePort == INVALID_PORT && DoTcpDaytime ) {
  580. SimpLogEvent(
  581. SIMPTCP_CANT_FIND_TCP_DAYTIME_PORT,
  582. 0,
  583. NULL,
  584. WSAGetLastError( )
  585. );
  586. DoTcpDaytime = FALSE;
  587. }
  588. UdpDaytimePort = GetServicePort( "daytime", "udp" );
  589. if ( UdpDaytimePort == INVALID_PORT && DoUdpDaytime ) {
  590. SimpLogEvent(
  591. SIMPTCP_CANT_FIND_UDP_DAYTIME_PORT,
  592. 0,
  593. NULL,
  594. WSAGetLastError( )
  595. );
  596. DoUdpDaytime = FALSE;
  597. }
  598. TcpChargenPort = GetServicePort( "chargen", "tcp" );
  599. if ( TcpChargenPort == INVALID_PORT && DoTcpChargen ) {
  600. SimpLogEvent(
  601. SIMPTCP_CANT_FIND_TCP_CHARGEN_PORT,
  602. 0,
  603. NULL,
  604. WSAGetLastError( )
  605. );
  606. DoTcpChargen = FALSE;
  607. }
  608. UdpChargenPort = GetServicePort( "chargen", "udp" );
  609. if ( UdpChargenPort == INVALID_PORT && DoUdpChargen ) {
  610. SimpLogEvent(
  611. SIMPTCP_CANT_FIND_UDP_CHARGEN_PORT,
  612. 0,
  613. NULL,
  614. WSAGetLastError( )
  615. );
  616. DoUdpChargen = FALSE;
  617. }
  618. TcpQotdPort = GetServicePort( "qotd", "tcp" );
  619. if ( TcpQotdPort == INVALID_PORT && DoTcpQotd ) {
  620. SimpLogEvent(
  621. SIMPTCP_CANT_FIND_TCP_QOTD_PORT,
  622. 0,
  623. NULL,
  624. WSAGetLastError( )
  625. );
  626. DoTcpQotd = FALSE;
  627. }
  628. UdpQotdPort = GetServicePort( "qotd", "udp" );
  629. if ( UdpQotdPort == INVALID_PORT && DoUdpQotd ) {
  630. SimpLogEvent(
  631. SIMPTCP_CANT_FIND_UDP_QOTD_PORT,
  632. 0,
  633. NULL,
  634. WSAGetLastError( )
  635. );
  636. DoUdpQotd = FALSE;
  637. }
  638. //
  639. // Open, bind, and listen on the necessary ports.
  640. //
  641. if ( DoTcpEcho ) {
  642. bOk = FALSE;
  643. for (i=0; i<NUM_FAMILIES; i++) {
  644. bOk |= OpenTcpSocket( &family[i].tcpEcho, i, TcpEchoPort );
  645. }
  646. if ( !bOk ) {
  647. SimpLogEvent(
  648. SIMPTCP_CANT_OPEN_TCP_ECHO_PORT,
  649. 0,
  650. NULL,
  651. WSAGetLastError( )
  652. );
  653. }
  654. }
  655. if ( DoUdpEcho ) {
  656. bOk = FALSE;
  657. for (i=0; i<NUM_FAMILIES; i++) {
  658. bOk |= OpenUdpSocket( &family[i].udpEcho, i, UdpEchoPort );
  659. }
  660. if ( !bOk ) {
  661. SimpLogEvent(
  662. SIMPTCP_CANT_OPEN_UDP_ECHO_PORT,
  663. 0,
  664. NULL,
  665. WSAGetLastError( )
  666. );
  667. }
  668. }
  669. if ( DoTcpDiscard ) {
  670. bOk = FALSE;
  671. for (i=0; i<NUM_FAMILIES; i++) {
  672. bOk |= OpenTcpSocket( &family[i].tcpDiscard, i, TcpDiscardPort );
  673. }
  674. if ( !bOk ) {
  675. SimpLogEvent(
  676. SIMPTCP_CANT_OPEN_TCP_DISCARD_PORT,
  677. 0,
  678. NULL,
  679. WSAGetLastError( )
  680. );
  681. }
  682. }
  683. if ( DoUdpDiscard ) {
  684. bOk = FALSE;
  685. for (i=0; i<NUM_FAMILIES; i++) {
  686. bOk |= OpenUdpSocket( &family[i].udpDiscard, i, UdpDiscardPort );
  687. }
  688. if ( !bOk ) {
  689. SimpLogEvent(
  690. SIMPTCP_CANT_OPEN_UDP_DISCARD_PORT,
  691. 0,
  692. NULL,
  693. WSAGetLastError( )
  694. );
  695. }
  696. }
  697. if ( DoTcpDaytime ) {
  698. bOk = FALSE;
  699. for (i=0; i<NUM_FAMILIES; i++) {
  700. bOk |= OpenTcpSocket( &family[i].tcpDaytime, i, TcpDaytimePort );
  701. }
  702. if ( !bOk ) {
  703. SimpLogEvent(
  704. SIMPTCP_CANT_OPEN_TCP_DAYTIME_PORT,
  705. 0,
  706. NULL,
  707. WSAGetLastError( )
  708. );
  709. }
  710. }
  711. if ( DoUdpDaytime ) {
  712. bOk = FALSE;
  713. for (i=0; i<NUM_FAMILIES; i++) {
  714. bOk |= OpenUdpSocket( &family[i].udpDaytime, i, UdpDaytimePort );
  715. }
  716. if ( !bOk ) {
  717. SimpLogEvent(
  718. SIMPTCP_CANT_OPEN_UDP_DAYTIME_PORT,
  719. 0,
  720. NULL,
  721. WSAGetLastError( )
  722. );
  723. }
  724. }
  725. if ( DoTcpChargen ) {
  726. bOk = FALSE;
  727. for (i=0; i<NUM_FAMILIES; i++) {
  728. bOk |= OpenTcpSocket( &family[i].tcpChargen, i, TcpChargenPort );
  729. }
  730. if ( !bOk ) {
  731. SimpLogEvent(
  732. SIMPTCP_CANT_OPEN_TCP_CHARGEN_PORT,
  733. 0,
  734. NULL,
  735. WSAGetLastError( )
  736. );
  737. }
  738. }
  739. if ( DoUdpChargen ) {
  740. bOk = FALSE;
  741. for (i=0; i<NUM_FAMILIES; i++) {
  742. bOk |= OpenUdpSocket( &family[i].udpChargen, i, UdpChargenPort );
  743. }
  744. if ( !bOk ) {
  745. SimpLogEvent(
  746. SIMPTCP_CANT_OPEN_UDP_CHARGEN_PORT,
  747. 0,
  748. NULL,
  749. WSAGetLastError( )
  750. );
  751. }
  752. }
  753. if ( DoTcpQotd ) {
  754. bOk = FALSE;
  755. for (i=0; i<NUM_FAMILIES; i++) {
  756. bOk |= OpenTcpSocket( &family[i].tcpQotd, i, TcpQotdPort );
  757. }
  758. if ( !bOk ) {
  759. SimpLogEvent(
  760. SIMPTCP_CANT_OPEN_TCP_QOTD_PORT,
  761. 0,
  762. NULL,
  763. WSAGetLastError( )
  764. );
  765. }
  766. }
  767. if ( DoUdpQotd ) {
  768. bOk = FALSE;
  769. for (i=0; i<NUM_FAMILIES; i++) {
  770. bOk |= OpenUdpSocket( &family[i].udpQotd, i, UdpQotdPort );
  771. }
  772. if ( !bOk ) {
  773. SimpLogEvent(
  774. SIMPTCP_CANT_OPEN_UDP_QOTD_PORT,
  775. 0,
  776. NULL,
  777. WSAGetLastError( )
  778. );
  779. }
  780. }
  781. //
  782. // Announce that we have successfully started.
  783. //
  784. SimpServiceStatus.dwCurrentState = SERVICE_RUNNING;
  785. SimpServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
  786. SERVICE_ACCEPT_PAUSE_CONTINUE;
  787. SimpServiceStatus.dwCheckPoint = 0;
  788. SimpServiceStatus.dwWaitHint = 0;
  789. AnnounceServiceStatus( );
  790. //
  791. // Loop waiting for connect attempts or datagrams, and service them
  792. // when they arrive.
  793. //
  794. for (;;) {
  795. //
  796. // First initialize the FD sets we'll actually use for select().
  797. //
  798. RtlCopyMemory( Readfds, ReadfdsStore, maxFdSetSize );
  799. //
  800. // Now wait for something to happen. Timeout occaisonally
  801. // so that we can kill idle TCP clients.
  802. //
  803. timeout.tv_sec = SelectTimeout;
  804. timeout.tv_usec = 0;
  805. err = select( 0, Readfds, NULL, NULL, &timeout );
  806. //
  807. // If the service is shutting down, stop processing requests
  808. // and exit.
  809. //
  810. if ( SimpServiceExit ) {
  811. err = NO_ERROR;
  812. goto exit;
  813. }
  814. if ( err == SOCKET_ERROR ) {
  815. //
  816. // This is bad. We should do something intelligent here.
  817. //
  818. int MappedErr;
  819. MappedErr= WSAGetLastError();
  820. //
  821. // Log an error and quit
  822. //
  823. SimpLogEvent(
  824. SIMPTCP_SOCKET_ERROR_SERVICE_FAILURE,
  825. 0,
  826. NULL,
  827. MappedErr
  828. );
  829. err = MappedErr;
  830. closesocket( SimpQuitSocket );
  831. goto exit;
  832. }
  833. //
  834. // If the service is paused, wait for it to become unpaused.
  835. //
  836. err = WaitForSingleObject( SimpPauseEvent, INFINITE );
  837. ASSERT( err != WAIT_FAILED );
  838. //
  839. // Figure out what happened and act accordingly.
  840. //
  841. for (FamIdx=0; FamIdx<NUM_FAMILIES; FamIdx++)
  842. {
  843. err = ProcessFamily(FamIdx);
  844. }
  845. } // infinite loop.
  846. exit:
  847. //
  848. // Announce that we're going down.
  849. //
  850. SimpServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
  851. SimpServiceStatus.dwCheckPoint = 1;
  852. SimpServiceStatus.dwWaitHint = 20000; // 20 seconds
  853. SimpServiceStatus.dwWin32ExitCode = err;
  854. SimpServiceStatus.dwServiceSpecificExitCode = err;
  855. AnnounceServiceStatus( );
  856. //
  857. // Delete our critical section.
  858. //
  859. if ( InitializedCriticalSection ) {
  860. InitializedCriticalSection = FALSE;
  861. RtlDeleteCriticalSection( &CriticalSection );
  862. }
  863. //
  864. // Close all opened listening sockets.
  865. //
  866. for (i=0; i<NUM_FAMILIES; i++) {
  867. if ( family[i].tcpEcho != INVALID_SOCKET ) {
  868. closesocket( family[i].tcpEcho );
  869. }
  870. if ( family[i].udpEcho != INVALID_SOCKET ) {
  871. closesocket( family[i].udpEcho );
  872. }
  873. if ( family[i].tcpDiscard != INVALID_SOCKET ) {
  874. closesocket( family[i].tcpDiscard );
  875. }
  876. if ( family[i].udpDiscard != INVALID_SOCKET ) {
  877. closesocket( family[i].udpDiscard );
  878. }
  879. if ( family[i].tcpDaytime != INVALID_SOCKET ) {
  880. closesocket( family[i].tcpDaytime );
  881. }
  882. if ( family[i].udpDaytime != INVALID_SOCKET ) {
  883. closesocket( family[i].udpDaytime );
  884. }
  885. if ( family[i].tcpChargen != INVALID_SOCKET ) {
  886. closesocket( family[i].tcpChargen );
  887. }
  888. if ( family[i].udpChargen != INVALID_SOCKET ) {
  889. closesocket( family[i].udpChargen );
  890. }
  891. }
  892. //
  893. // Close all connected TCP sockets.
  894. //
  895. for ( i = 0; TcpClients != NULL && (DWORD)i < MaxTcpClients; i++ ) {
  896. if ( TcpClients[i].SocketHandle != INVALID_SOCKET ) {
  897. AbortTcpClient( TcpClients[i].SocketHandle );
  898. }
  899. }
  900. //
  901. // Should wait here for all threads to exit!
  902. //
  903. //
  904. // Deinitialize the eventlog.
  905. //
  906. SimpTerminateEventLog( );
  907. //
  908. // Free allocated memory.
  909. //
  910. if ( IoBuffer != NULL ) {
  911. RtlFreeHeap( RtlProcessHeap( ), 0, IoBuffer );
  912. }
  913. if ( TcpClients != NULL ) {
  914. RtlFreeHeap( RtlProcessHeap( ), 0, TcpClients );
  915. }
  916. if ( Readfds != NULL ) {
  917. RtlFreeHeap( RtlProcessHeap( ), 0, Readfds );
  918. }
  919. if ( ReadfdsStore != NULL ) {
  920. RtlFreeHeap( RtlProcessHeap( ), 0, ReadfdsStore );
  921. }
  922. if ( ChargenBuffer != NULL ) {
  923. RtlFreeHeap( RtlProcessHeap( ), 0, ChargenBuffer );
  924. }
  925. if ( QotdBuffer != NULL ) {
  926. UnmapViewOfFile( QotdBuffer );
  927. }
  928. if ( QotdFileMapping != NULL ) {
  929. CloseHandle( QotdFileMapping );
  930. }
  931. if ( QotdFileHandle != NULL ) {
  932. CloseHandle( QotdFileHandle );
  933. }
  934. if ( QotdFileName != NULL ) {
  935. RtlFreeHeap( RtlProcessHeap( ), 0, QotdFileName );
  936. }
  937. if ( QotdStrings != NULL ) {
  938. RtlFreeHeap( RtlProcessHeap( ), 0, QotdStrings );
  939. }
  940. //
  941. // Free SimpPauseEvent's memory
  942. //
  943. if (SimpPauseEvent)
  944. CloseHandle(SimpPauseEvent);
  945. //
  946. // Announce that we're down.
  947. //
  948. SimpServiceStatus.dwCurrentState = SERVICE_STOPPED;
  949. SimpServiceStatus.dwControlsAccepted = 0;
  950. SimpServiceStatus.dwCheckPoint = 0;
  951. SimpServiceStatus.dwWaitHint = 0;
  952. SimpServiceStatus.dwWin32ExitCode = err;
  953. SimpServiceStatus.dwServiceSpecificExitCode = err;
  954. AnnounceServiceStatus( );
  955. return;
  956. } // ServiceEntry
  957. BOOL
  958. OpenTcpSocket (
  959. OUT SOCKET *pSocket,
  960. IN INT FamIdx,
  961. IN SHORT Port
  962. )
  963. {
  964. SOCKADDR_STORAGE localAddr;
  965. INT localAddrLen;
  966. INT err;
  967. INT one = 1;
  968. *pSocket = socket( family[FamIdx].family, SOCK_STREAM, 0 );
  969. if ( *pSocket == INVALID_SOCKET ) {
  970. return FALSE;
  971. }
  972. RtlZeroMemory( &localAddr, sizeof(localAddr) );
  973. SS_PORT(&localAddr) = Port;
  974. localAddr.ss_family = family[FamIdx].family;
  975. err =
  976. setsockopt( *pSocket,
  977. SOL_SOCKET,
  978. SO_EXCLUSIVEADDRUSE,
  979. (char *) &one,
  980. sizeof( one )
  981. );
  982. if( err ){
  983. DEBUG_PRINT(("simptcp: OpenTcpSocket: ExclusiveAddressUse failed %d\n",
  984. GetLastError() ));
  985. closesocket(*pSocket);
  986. *pSocket = INVALID_SOCKET;
  987. return FALSE;
  988. }
  989. err = bind( *pSocket, (PSOCKADDR)&localAddr, sizeof(localAddr) );
  990. if ( err ==SOCKET_ERROR ) {
  991. closesocket(*pSocket);
  992. *pSocket = INVALID_SOCKET;
  993. return FALSE;
  994. }
  995. err = listen( *pSocket, LISTEN_BACKLOG );
  996. if ( err == SOCKET_ERROR ) {
  997. closesocket(*pSocket);
  998. *pSocket = INVALID_SOCKET;
  999. return FALSE;
  1000. }
  1001. err = setsockopt( *pSocket, SOL_SOCKET, SO_KEEPALIVE, (char *)&one, sizeof(one) );
  1002. if ( err == INVALID_SOCKET ) {
  1003. closesocket(*pSocket);
  1004. *pSocket = INVALID_SOCKET;
  1005. return FALSE;
  1006. }
  1007. FD_SET( *pSocket, ReadfdsStore );
  1008. return TRUE;
  1009. } // OpenTcpSocket
  1010. BOOL
  1011. OpenUdpSocket (
  1012. OUT SOCKET *pSocket,
  1013. IN INT FamIdx,
  1014. IN SHORT Port
  1015. )
  1016. {
  1017. SOCKADDR_STORAGE localAddr;
  1018. INT localAddrLen;
  1019. INT err;
  1020. DWORD broadcast_off = 0;
  1021. DWORD on = 1;
  1022. *pSocket = socket( family[FamIdx].family, SOCK_DGRAM, 0 );
  1023. if ( *pSocket == INVALID_SOCKET ) {
  1024. return FALSE;
  1025. }
  1026. RtlZeroMemory( &localAddr, sizeof(localAddr) );
  1027. SS_PORT(&localAddr) = Port;
  1028. localAddr.ss_family = family[FamIdx].family;
  1029. err =
  1030. setsockopt( *pSocket,
  1031. SOL_SOCKET,
  1032. SO_EXCLUSIVEADDRUSE,
  1033. (LPBYTE) &on,
  1034. sizeof( on )
  1035. );
  1036. if( err ){
  1037. DEBUG_PRINT(("simptcp: OpenUdpSocket: ExclusiveAddressUse failed %d\n",
  1038. GetLastError() ));
  1039. closesocket(*pSocket);
  1040. *pSocket = INVALID_SOCKET;
  1041. return FALSE;
  1042. }
  1043. err = bind( *pSocket, (PSOCKADDR)&localAddr, sizeof(localAddr) );
  1044. if ( err == SOCKET_ERROR ) {
  1045. closesocket(*pSocket);
  1046. *pSocket = INVALID_SOCKET;
  1047. return FALSE;
  1048. }
  1049. err =
  1050. setsockopt( *pSocket,
  1051. SOL_SOCKET,
  1052. SO_BROADCAST,
  1053. (LPBYTE) &broadcast_off,
  1054. sizeof( broadcast_off )
  1055. );
  1056. if( err ){
  1057. DEBUG_PRINT(("simptcp: OpenUdpSocket: broadcast_off failed %d\n",
  1058. GetLastError() ));
  1059. closesocket(*pSocket);
  1060. *pSocket = INVALID_SOCKET;
  1061. return FALSE;
  1062. }
  1063. FD_SET( *pSocket, ReadfdsStore );
  1064. return TRUE;
  1065. } // OpenUdpSocket
  1066. INT
  1067. AcceptTcpClient (
  1068. IN SOCKET ListenSocket,
  1069. IN SHORT Port
  1070. )
  1071. {
  1072. SOCKADDR_STORAGE remoteSockaddr;
  1073. INT remoteSockaddrLength;
  1074. DWORD i;
  1075. SOCKET acceptSocket;
  1076. DWORD threadId;
  1077. NTSTATUS status;
  1078. //
  1079. // Always accept the socket first.
  1080. //
  1081. remoteSockaddrLength = sizeof(remoteSockaddr);
  1082. acceptSocket =
  1083. accept( ListenSocket, (PSOCKADDR)&remoteSockaddr, &remoteSockaddrLength );
  1084. if ( acceptSocket == INVALID_SOCKET ) {
  1085. return -1;
  1086. }
  1087. //
  1088. // Use a critical section to protect access to our database of
  1089. // TCP clients.
  1090. //
  1091. status = RtlEnterCriticalSection( &CriticalSection );
  1092. ASSERT( NT_SUCCESS(status) );
  1093. //
  1094. // Attempt to find a TCP client slot.
  1095. //
  1096. for ( i = 0; i < MaxTcpClients; i++ ) {
  1097. if ( TcpClients[i].SocketHandle == INVALID_SOCKET ) {
  1098. break;
  1099. }
  1100. }
  1101. //
  1102. // If we're at the max count of TCP sockets, abort this new
  1103. // socket.
  1104. //
  1105. if ( i >= MaxTcpClients ) {
  1106. AbortTcpClient( acceptSocket );
  1107. status = RtlLeaveCriticalSection( &CriticalSection );
  1108. ASSERT( NT_SUCCESS(status) );
  1109. return -1;
  1110. }
  1111. //
  1112. // Initialize info about this client.
  1113. //
  1114. TcpClients[i].SocketHandle = acceptSocket;
  1115. RtlCopyMemory(
  1116. &TcpClients[i].RemoteAddress,
  1117. &remoteSockaddr,
  1118. sizeof(remoteSockaddr)
  1119. );
  1120. TcpClients[i].ServicePort = Port;
  1121. //
  1122. // We're in multi-threaded mode, so we'll create a separate thread
  1123. // to handle this client.
  1124. //
  1125. TcpClients[i].ThreadHandle = CreateThread(
  1126. NULL,
  1127. 0,
  1128. ThreadEntry,
  1129. UlongToPtr(i),
  1130. 0,
  1131. &threadId
  1132. );
  1133. if ( TcpClients[i].ThreadHandle == NULL ) {
  1134. AbortTcpClient( acceptSocket );
  1135. TcpClients[i].SocketHandle = INVALID_SOCKET;
  1136. status = RtlLeaveCriticalSection( &CriticalSection );
  1137. ASSERT( NT_SUCCESS(status) );
  1138. return -1;
  1139. }
  1140. //
  1141. // The created thread will handle the connected client.
  1142. //
  1143. status = RtlLeaveCriticalSection( &CriticalSection );
  1144. ASSERT( NT_SUCCESS(status) );
  1145. return -1;
  1146. } // AcceptTcpClient
  1147. VOID
  1148. AbortTcpClient (
  1149. IN SOCKET Socket
  1150. )
  1151. {
  1152. LINGER lingerInfo;
  1153. INT err;
  1154. //
  1155. // First set the linger timeout on the socket to 0. This will cause
  1156. // the connection to be reset.
  1157. //
  1158. lingerInfo.l_onoff = 1;
  1159. lingerInfo.l_linger = 0;
  1160. err = setsockopt(
  1161. Socket,
  1162. SOL_SOCKET,
  1163. SO_LINGER,
  1164. (char *)&lingerInfo,
  1165. sizeof(lingerInfo)
  1166. );
  1167. if ( err == SOCKET_ERROR ) {
  1168. //
  1169. // There's not too much we can do. Just close the socket.
  1170. //
  1171. ASSERT(FALSE);
  1172. closesocket( Socket );
  1173. return;
  1174. }
  1175. //
  1176. // Now close the socket.
  1177. //
  1178. err = closesocket( Socket );
  1179. ASSERT( err != SOCKET_ERROR );
  1180. return;
  1181. } // AbortTcpClient
  1182. VOID
  1183. DeleteTcpClient (
  1184. IN DWORD ArraySlot,
  1185. IN BOOLEAN Graceful
  1186. )
  1187. {
  1188. INT err;
  1189. NTSTATUS status;
  1190. status = RtlEnterCriticalSection( &CriticalSection );
  1191. ASSERT( NT_SUCCESS(status) );
  1192. ASSERT( TcpClients[ArraySlot].SocketHandle != INVALID_SOCKET );
  1193. //
  1194. // If this is to be an abortive disconnect, reset the connection.
  1195. // Otherwise just close it normally.
  1196. //
  1197. if ( !Graceful ) {
  1198. AbortTcpClient( TcpClients[ArraySlot].SocketHandle );
  1199. } else {
  1200. LINGER lingerInfo;
  1201. INT one;
  1202. //
  1203. // Set the socket to blocking.
  1204. //
  1205. one = 0;
  1206. ioctlsocket( TcpClients[ArraySlot].SocketHandle, FIONBIO, &one );
  1207. //
  1208. // Set the socket to linger no more than 60 seconds.
  1209. //
  1210. lingerInfo.l_onoff = 1;
  1211. lingerInfo.l_linger = 60;
  1212. setsockopt( TcpClients[ArraySlot].SocketHandle, SOL_SOCKET,
  1213. SO_LINGER, (char *)&lingerInfo, sizeof(lingerInfo) );
  1214. err = closesocket( TcpClients[ArraySlot].SocketHandle );
  1215. ASSERT( err != SOCKET_ERROR );
  1216. }
  1217. //
  1218. // Close the thread handle, if appropriate.
  1219. //
  1220. if ( TcpClients[ArraySlot].ThreadHandle != NULL ) {
  1221. CloseHandle( TcpClients[ArraySlot].ThreadHandle );
  1222. TcpClients[ArraySlot].ThreadHandle = NULL;
  1223. }
  1224. //
  1225. // Set the handle in the TCP clients array to INVALID_SOCKET so that we
  1226. // know that it is free.
  1227. //
  1228. TcpClients[ArraySlot].SocketHandle = INVALID_SOCKET;
  1229. status = RtlLeaveCriticalSection( &CriticalSection );
  1230. ASSERT( NT_SUCCESS(status) );
  1231. return;
  1232. } // DeleteTcpClient
  1233. VOID
  1234. FormatDaytimeResponse (
  1235. IN PCHAR Buffer,
  1236. IN PDWORD BufferLength
  1237. )
  1238. {
  1239. SYSTEMTIME timeStruct;
  1240. int Status;
  1241. int StringSize;
  1242. char Buf1[MAX_DATE_BUFFER_SIZE];
  1243. char Buf2[MAX_DATE_BUFFER_SIZE];
  1244. *BufferLength=sprintf(Buffer,"");
  1245. GetLocalTime( &timeStruct );
  1246. Status = GetDateFormatA((LCID)LOCALE_SYSTEM_DEFAULT,
  1247. 0,
  1248. &timeStruct,
  1249. NULL,
  1250. Buf1,
  1251. MAX_DATE_BUFFER_SIZE);
  1252. if (Status == 0) {
  1253. return;
  1254. }
  1255. Status = GetTimeFormatA((LCID)LOCALE_SYSTEM_DEFAULT,
  1256. 0,
  1257. &timeStruct,
  1258. NULL,
  1259. Buf2,
  1260. MAX_DATE_BUFFER_SIZE);
  1261. if (Status == 0) {
  1262. return;
  1263. }
  1264. *BufferLength=sprintf(Buffer,"%s %s\n",Buf2,Buf1);
  1265. return;
  1266. } // FormatDaytimeResponse
  1267. VOID
  1268. FormatQotdResponse (
  1269. IN PCHAR Buffer,
  1270. IN PDWORD BufferLength
  1271. )
  1272. {
  1273. INT index;
  1274. UINT Length;
  1275. if (QotdQuoteCount == 0) {
  1276. sprintf(Buffer,"");
  1277. *BufferLength=strlen(Buffer);
  1278. return;
  1279. }
  1280. //
  1281. // Choose a random quote index.
  1282. //
  1283. index = (rand( ) * (QotdQuoteCount - 1)) / RAND_MAX;
  1284. //
  1285. // Copy the quote into the output buffer. We want to make sure
  1286. // we don't overflow the "Buffer" passed in.
  1287. //
  1288. Length = QotdStrings[index].QuoteLength;
  1289. if (*BufferLength < Length) {
  1290. Length = *BufferLength;
  1291. } else {
  1292. *BufferLength = Length;
  1293. }
  1294. strncpy( Buffer, QotdStrings[index].Quote, Length);
  1295. return;
  1296. } // FormatDaytimeResponse
  1297. INT
  1298. InitializeQotdQuotes (
  1299. VOID
  1300. )
  1301. {
  1302. BY_HANDLE_FILE_INFORMATION fileInformation;
  1303. PCHAR buffer;
  1304. DWORD i,CurQuoteIndex;
  1305. if ( QotdFileName == NULL ) {
  1306. return ERROR_FILE_NOT_FOUND;
  1307. }
  1308. //
  1309. // Open the file containing quote information.
  1310. //
  1311. QotdFileHandle = CreateFileW(
  1312. QotdFileName,
  1313. GENERIC_READ,
  1314. FILE_SHARE_READ,
  1315. NULL,
  1316. OPEN_EXISTING,
  1317. FILE_ATTRIBUTE_NORMAL,
  1318. NULL
  1319. );
  1320. if ( QotdFileHandle == INVALID_HANDLE_VALUE ) {
  1321. SimpLogEvent(
  1322. SIMPTCP_CANT_OPEN_QUOTE_FILE,
  1323. 0,
  1324. NULL,
  1325. GetLastError( )
  1326. );
  1327. return GetLastError( );
  1328. }
  1329. //
  1330. // Determine the size of the QOTD file.
  1331. //
  1332. if ( !GetFileInformationByHandle( QotdFileHandle, &fileInformation ) ) {
  1333. SimpLogEvent(
  1334. SIMPTCP_CANT_OPEN_QUOTE_FILE,
  1335. 0,
  1336. NULL,
  1337. GetLastError( )
  1338. );
  1339. return GetLastError( );
  1340. }
  1341. //
  1342. // Create a file mapping for the quotes file and map it into
  1343. // the address space of this process.
  1344. //
  1345. QotdFileMapping = CreateFileMapping(
  1346. QotdFileHandle,
  1347. NULL,
  1348. PAGE_READONLY,
  1349. 0,
  1350. 0,
  1351. NULL
  1352. );
  1353. if ( QotdFileMapping == NULL ) {
  1354. SimpLogEvent(
  1355. SIMPTCP_CANT_OPEN_QUOTE_FILE,
  1356. 0,
  1357. NULL,
  1358. GetLastError( )
  1359. );
  1360. return GetLastError( );
  1361. }
  1362. QotdBuffer = MapViewOfFile(
  1363. QotdFileMapping,
  1364. FILE_MAP_READ,
  1365. 0,
  1366. 0,
  1367. 0
  1368. );
  1369. if ( QotdBuffer == NULL ) {
  1370. SimpLogEvent(
  1371. SIMPTCP_CANT_OPEN_QUOTE_FILE,
  1372. 0,
  1373. NULL,
  1374. GetLastError( )
  1375. );
  1376. return GetLastError( );
  1377. }
  1378. //
  1379. // Count the number of lines in the file. The number of lines
  1380. // corresponds to the number of quotes.
  1381. //
  1382. QotdQuoteCount = 0;
  1383. buffer = (PCHAR)QotdBuffer;
  1384. for ( i = 0; i < fileInformation.nFileSizeLow; i++ ) {
  1385. if ( *buffer++ == '%' ) {
  1386. QotdQuoteCount++;
  1387. }
  1388. }
  1389. //
  1390. // Allocate a buffer to hold the quote array.
  1391. //
  1392. QotdStrings = RtlAllocateHeap(
  1393. RtlProcessHeap( ),
  1394. 0,
  1395. sizeof(QotdStrings[0]) * QotdQuoteCount
  1396. );
  1397. if ( QotdStrings == NULL ) {
  1398. return ERROR_NOT_ENOUGH_MEMORY;
  1399. }
  1400. //
  1401. // Initialize the quote array.
  1402. //
  1403. buffer = (PCHAR)QotdBuffer;
  1404. CurQuoteIndex=0;
  1405. for ( i = 0; i < QotdQuoteCount; i++ ) {
  1406. QotdStrings[CurQuoteIndex].Quote = buffer;
  1407. while ( (DWORD_PTR)buffer < (DWORD_PTR)QotdBuffer +
  1408. fileInformation.nFileSizeLow &&
  1409. *buffer++ != '%' );
  1410. QotdStrings[CurQuoteIndex].QuoteLength =
  1411. (DWORD)((DWORD_PTR)buffer - (DWORD_PTR)QotdStrings[CurQuoteIndex].Quote) - 1;
  1412. buffer += 2;
  1413. //
  1414. // If this quote if longer than the IO buffer size, skip over
  1415. // it. We can't use it.
  1416. //
  1417. if ( QotdStrings[CurQuoteIndex].QuoteLength < IoBufferSize ) {
  1418. // Got a valid one
  1419. CurQuoteIndex++;
  1420. }
  1421. }
  1422. QotdQuoteCount=CurQuoteIndex;
  1423. //
  1424. // Initialize the random-number generator.
  1425. //
  1426. srand( GetTickCount( ) );
  1427. return NO_ERROR;
  1428. } // InitializeQotdQuotes
  1429. #define CHARGEN_LINE_LENGTH 72
  1430. #define CHARGEN_REAL_LINE_LENGTH (CHARGEN_LINE_LENGTH + 2)
  1431. #define CHARGEN_MIN_CHAR ' '
  1432. #define CHARGEN_MAX_CHAR '~'
  1433. #define CHARGEN_DIFFERENCE (CHARGEN_MAX_CHAR - CHARGEN_MIN_CHAR)
  1434. #define CHARGEN_LINE_COUNT (CHARGEN_DIFFERENCE)
  1435. #define CHARGEN_BUFFER_LENGTH ((CHARGEN_LINE_LENGTH + 2) * (CHARGEN_LINE_COUNT))
  1436. INT
  1437. InitializeChargen (
  1438. VOID
  1439. )
  1440. {
  1441. DWORD line;
  1442. BYTE startChar = 0;
  1443. DWORD i;
  1444. //
  1445. // Allocate a buffer for the chargen data.
  1446. //
  1447. ChargenBufferSize = CHARGEN_BUFFER_LENGTH;
  1448. ChargenBuffer = RtlAllocateHeap(
  1449. RtlProcessHeap( ),
  1450. 0,
  1451. ChargenBufferSize
  1452. );
  1453. if ( ChargenBuffer == NULL ) {
  1454. return ERROR_NOT_ENOUGH_MEMORY;
  1455. }
  1456. //
  1457. // Fill in the buffer with the required pattern.
  1458. //
  1459. for ( line = 0; line < CHARGEN_LINE_COUNT; line++ ) {
  1460. for ( i = 0; i < CHARGEN_LINE_LENGTH; i++ ) {
  1461. *((PCHAR)ChargenBuffer + (line * CHARGEN_REAL_LINE_LENGTH) + i) =
  1462. (CHAR)( ((startChar + i) % CHARGEN_DIFFERENCE) + CHARGEN_MIN_CHAR);
  1463. }
  1464. *((PCHAR)ChargenBuffer + (line * CHARGEN_REAL_LINE_LENGTH) + i) = 0x0D;
  1465. *((PCHAR)ChargenBuffer + (line * CHARGEN_REAL_LINE_LENGTH) + i + 1) = 0x0A;
  1466. startChar++;
  1467. }
  1468. return NO_ERROR;
  1469. } // InitializeQotdQuotes
  1470. SHORT
  1471. GetServicePort (
  1472. IN PCHAR Service,
  1473. IN PCHAR Protocol
  1474. )
  1475. {
  1476. PSERVENT serviceEntry;
  1477. //
  1478. // Get a servent structure for the specified service.
  1479. //
  1480. serviceEntry = getservbyname( Service, Protocol );
  1481. if ( serviceEntry == NULL ) {
  1482. // log an error!
  1483. return INVALID_PORT;
  1484. }
  1485. //
  1486. // Return the port for the specified service.
  1487. //
  1488. return serviceEntry->s_port;
  1489. } // GetServicePort
  1490. VOID
  1491. AnnounceServiceStatus (
  1492. VOID
  1493. )
  1494. /*++
  1495. Routine Description:
  1496. Announces the service's status to the service controller.
  1497. Arguments:
  1498. None.
  1499. Return Value:
  1500. None.
  1501. --*/
  1502. {
  1503. //
  1504. // Service status handle is NULL if RegisterServiceCtrlHandler failed.
  1505. //
  1506. if ( SimpServiceStatusHandle == 0 ) {
  1507. return;
  1508. }
  1509. //
  1510. // Call SetServiceStatus, ignoring any errors.
  1511. //
  1512. SetServiceStatus(SimpServiceStatusHandle, &SimpServiceStatus);
  1513. } // AnnounceServiceStatus
  1514. VOID
  1515. ControlResponse(
  1516. DWORD opCode
  1517. )
  1518. {
  1519. BOOL announce = TRUE;
  1520. BOOL err;
  1521. //
  1522. // Determine the type of service control message and modify the
  1523. // service status, if necessary.
  1524. //
  1525. switch( opCode ) {
  1526. case SERVICE_CONTROL_STOP:
  1527. //
  1528. // Announce that we are in the process of stopping.
  1529. //
  1530. SimpServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
  1531. AnnounceServiceStatus( );
  1532. //
  1533. // Remember that we're stopping.
  1534. //
  1535. SimpServiceExit = TRUE;
  1536. //
  1537. // Close a socket that the main select()er thread is
  1538. // waiting on. This will cause the select to wake up
  1539. // and shutdown processing to commence.
  1540. //
  1541. closesocket( SimpQuitSocket );
  1542. //
  1543. // Let the main thread announce when the stop is done.
  1544. //
  1545. announce = FALSE;
  1546. break;
  1547. case SERVICE_CONTROL_PAUSE:
  1548. //
  1549. // Announce that we are in the process of pausing.
  1550. //
  1551. SimpServiceStatus.dwCurrentState = SERVICE_PAUSE_PENDING;
  1552. AnnounceServiceStatus( );
  1553. //
  1554. // Remember that we're paused.
  1555. //
  1556. err = ResetEvent( SimpPauseEvent );
  1557. ASSERT( err );
  1558. //
  1559. // Announce that we're now paused.
  1560. //
  1561. SimpServiceStatus.dwCurrentState = SERVICE_PAUSED;
  1562. break;
  1563. case SERVICE_CONTROL_CONTINUE:
  1564. //
  1565. // Announce that continue is pending.
  1566. //
  1567. SimpServiceStatus.dwCurrentState = SERVICE_CONTINUE_PENDING;
  1568. AnnounceServiceStatus( );
  1569. //
  1570. // Remember that we're no longer paused.
  1571. //
  1572. err = SetEvent( SimpPauseEvent );
  1573. ASSERT( err );
  1574. //
  1575. // Announce that we're active now.
  1576. //
  1577. SimpServiceStatus.dwCurrentState = SERVICE_RUNNING;
  1578. break;
  1579. case SERVICE_CONTROL_INTERROGATE:
  1580. break;
  1581. default:
  1582. break;
  1583. }
  1584. if ( announce ) {
  1585. AnnounceServiceStatus( );
  1586. }
  1587. } // ControlResponse
  1588. INT
  1589. ReadRegistry (
  1590. VOID
  1591. )
  1592. {
  1593. HKEY simptcpKey = NULL;
  1594. ULONG error;
  1595. ULONG i;
  1596. DWORD dwordBuffer;
  1597. DWORD bufferLength;
  1598. DWORD type;
  1599. DWORD qotdFileNameLength, Length;
  1600. PWSTR fileName;
  1601. //
  1602. // First open our parameters key.
  1603. //
  1604. error = RegOpenKeyExW(
  1605. HKEY_LOCAL_MACHINE,
  1606. L"SYSTEM\\CurrentControlSet\\Services\\SimpTcp\\Parameters",
  1607. 0,
  1608. MAXIMUM_ALLOWED,
  1609. &simptcpKey
  1610. );
  1611. if ( error != NO_ERROR ) {
  1612. return error;
  1613. }
  1614. //
  1615. // Read BOOLEANs from the registry.
  1616. //
  1617. for ( i = 0; RegistryBooleans[i].Boolean != NULL; i++ ) {
  1618. bufferLength = sizeof(dwordBuffer);
  1619. error = RegQueryValueExW(
  1620. simptcpKey,
  1621. RegistryBooleans[i].ValueName,
  1622. NULL,
  1623. &type,
  1624. (PVOID)&dwordBuffer,
  1625. &bufferLength
  1626. );
  1627. //
  1628. // If we fail to read one of these for some reason, just skip it
  1629. // and move on to the next one.
  1630. //
  1631. if ( error != NO_ERROR ) {
  1632. continue;
  1633. }
  1634. if ( dwordBuffer == 0 ) {
  1635. *RegistryBooleans[i].Boolean = FALSE;
  1636. } else {
  1637. *RegistryBooleans[i].Boolean = TRUE;
  1638. }
  1639. }
  1640. //
  1641. // Read DWORDs from the registry.
  1642. //
  1643. for ( i = 0; RegistryDwords[i].Dword != NULL; i++ ) {
  1644. bufferLength = sizeof(RegistryDwords[i].Dword);
  1645. RegQueryValueExW(
  1646. simptcpKey,
  1647. RegistryDwords[i].ValueName,
  1648. NULL,
  1649. &type,
  1650. (PVOID)RegistryDwords[i].Dword,
  1651. &bufferLength
  1652. );
  1653. }
  1654. //
  1655. // Read other known values from the registry. Determine the size
  1656. // of the QOTD file name. We need this so that we can allocate
  1657. // enough memory to hold it.
  1658. //
  1659. qotdFileNameLength = 0;
  1660. error = RegQueryValueExW(
  1661. simptcpKey,
  1662. L"QotdFileName",
  1663. NULL,
  1664. &type,
  1665. NULL,
  1666. &qotdFileNameLength
  1667. );
  1668. if ( error == ERROR_MORE_DATA || error == NO_ERROR ) {
  1669. fileName = RtlAllocateHeap(
  1670. RtlProcessHeap( ),
  1671. 0,
  1672. qotdFileNameLength
  1673. );
  1674. if ( fileName == NULL ) {
  1675. return NO_ERROR;
  1676. }
  1677. error = RegQueryValueExW(
  1678. simptcpKey,
  1679. L"QotdFileName",
  1680. NULL,
  1681. &type,
  1682. (PVOID)fileName,
  1683. &qotdFileNameLength
  1684. );
  1685. if ( error != NO_ERROR ) {
  1686. RtlFreeHeap( RtlProcessHeap( ), 0, fileName );
  1687. return NO_ERROR;
  1688. }
  1689. //
  1690. // Expand the file name.
  1691. //
  1692. qotdFileNameLength = ExpandEnvironmentStringsW( fileName, NULL, 0 );
  1693. if (qotdFileNameLength == 0) {
  1694. RtlFreeHeap( RtlProcessHeap( ), 0, fileName );
  1695. return GetLastError();
  1696. }
  1697. QotdFileName = RtlAllocateHeap(
  1698. RtlProcessHeap( ),
  1699. 0,
  1700. qotdFileNameLength * sizeof(UNICODE_NULL)
  1701. );
  1702. if ( QotdFileName == NULL ) {
  1703. RtlFreeHeap( RtlProcessHeap( ), 0, fileName );
  1704. return NO_ERROR;
  1705. }
  1706. Length = ExpandEnvironmentStringsW( fileName, QotdFileName,
  1707. qotdFileNameLength );
  1708. if (Length == 0) {
  1709. RtlFreeHeap( RtlProcessHeap( ), 0, fileName );
  1710. RtlFreeHeap( RtlProcessHeap( ), 0, QotdFileName );
  1711. return GetLastError();
  1712. }
  1713. }
  1714. return NO_ERROR;
  1715. } // ReadRegistry
  1716. DWORD
  1717. ThreadEntry (
  1718. LPVOID lpThreadParameter
  1719. )
  1720. {
  1721. DWORD i = PtrToUlong(lpThreadParameter);
  1722. PVOID ioBuffer;
  1723. INT err;
  1724. BOOLEAN graceful = TRUE;
  1725. //
  1726. // First, set the send and receive timeouts for the socket. This
  1727. // prevents a dead client from tying up our resources for too long.
  1728. //
  1729. err = setsockopt( TcpClients[i].SocketHandle, SOL_SOCKET, SO_SNDTIMEO,
  1730. (char *)&MaxIdleTicks, sizeof(MaxIdleTicks) );
  1731. if ( err == SOCKET_ERROR ) {
  1732. DeleteTcpClient( i, FALSE );
  1733. return 0;
  1734. }
  1735. err = setsockopt( TcpClients[i].SocketHandle, SOL_SOCKET, SO_RCVTIMEO,
  1736. (char *)&MaxIdleTicks, sizeof(MaxIdleTicks) );
  1737. if ( err == SOCKET_ERROR ) {
  1738. DeleteTcpClient( i, FALSE );
  1739. return 0;
  1740. }
  1741. //
  1742. // Get a buffer to use locally for IO on the socket.
  1743. //
  1744. ioBuffer = RtlAllocateHeap( RtlProcessHeap( ), 0, IoBufferSize );
  1745. if ( ioBuffer == NULL ) {
  1746. DeleteTcpClient( i, FALSE );
  1747. return 0;
  1748. }
  1749. //
  1750. // Now service the client as appropriate.
  1751. //
  1752. if ( TcpClients[i].ServicePort == TcpEchoPort ) {
  1753. //
  1754. // If there is data on a client's echo socket,
  1755. // receive some data and send it back.
  1756. //
  1757. do {
  1758. err = recv(
  1759. TcpClients[i].SocketHandle,
  1760. ioBuffer,
  1761. IoBufferSize,
  1762. 0
  1763. );
  1764. if ( err == SOCKET_ERROR ) {
  1765. graceful = FALSE;
  1766. }
  1767. if ( err > 0 ) {
  1768. err = send(
  1769. TcpClients[i].SocketHandle,
  1770. ioBuffer,
  1771. err,
  1772. 0
  1773. );
  1774. if ( err == SOCKET_ERROR ) {
  1775. graceful = FALSE;
  1776. }
  1777. } else if ( err < 0 ) {
  1778. graceful = FALSE;
  1779. }
  1780. } while ( err > 0 );
  1781. } else if ( TcpClients[i].ServicePort == TcpChargenPort ) {
  1782. INT one;
  1783. INT error;
  1784. TIMEVAL timeout;
  1785. //
  1786. // Set the socket to nonblocking.
  1787. //
  1788. one = 1;
  1789. err = ioctlsocket( TcpClients[i].SocketHandle, FIONBIO, &one );
  1790. if ( err == SOCKET_ERROR ) {
  1791. graceful = FALSE;
  1792. }
  1793. //
  1794. // Calculate the select() timeout.
  1795. //
  1796. timeout.tv_sec = MaxIdleTicks / 1000;
  1797. timeout.tv_usec = MaxIdleTicks % 1000;
  1798. //
  1799. // Loop sending data.
  1800. //
  1801. do {
  1802. err = send(
  1803. TcpClients[i].SocketHandle,
  1804. ChargenBuffer,
  1805. ChargenBufferSize,
  1806. 0
  1807. );
  1808. if ( err == SOCKET_ERROR ) {
  1809. error = GetLastError( );
  1810. if ( error != WSAEWOULDBLOCK ) {
  1811. graceful = FALSE;
  1812. } else {
  1813. struct {
  1814. INT Count;
  1815. SOCKET Handle;
  1816. } readfds = { 0, 0 };
  1817. struct {
  1818. INT Count;
  1819. SOCKET Handle;
  1820. } writefds = { 0, 0 };
  1821. //
  1822. // The socket's send queue is blocked. Wait for it to
  1823. // become unblocked.
  1824. //
  1825. FD_SET( TcpClients[i].SocketHandle, (PFD_SET)&readfds );
  1826. FD_SET( TcpClients[i].SocketHandle, (PFD_SET)&writefds );
  1827. err = select(
  1828. 1,
  1829. (PFD_SET)&readfds,
  1830. (PFD_SET)&writefds,
  1831. NULL,
  1832. &timeout
  1833. );
  1834. if ( err <= 0 ) {
  1835. graceful = FALSE;
  1836. }
  1837. }
  1838. }
  1839. err = recv(
  1840. TcpClients[i].SocketHandle,
  1841. ioBuffer,
  1842. IoBufferSize,
  1843. 0
  1844. );
  1845. if ( err == SOCKET_ERROR ) {
  1846. if ( WSAGetLastError( ) != WSAEWOULDBLOCK ) {
  1847. graceful = FALSE;
  1848. } else {
  1849. err = 1;
  1850. }
  1851. }
  1852. } while ( err > 0 );
  1853. } else if ( TcpClients[i].ServicePort == TcpDiscardPort ) {
  1854. //
  1855. // If there is data on a client's socket, just
  1856. // receive some data and discard it.
  1857. //
  1858. do {
  1859. err = recv(
  1860. TcpClients[i].SocketHandle,
  1861. ioBuffer,
  1862. IoBufferSize,
  1863. 0
  1864. );
  1865. if ( err == SOCKET_ERROR ) {
  1866. graceful = FALSE;
  1867. }
  1868. } while ( err > 0 );
  1869. } else {
  1870. //
  1871. // Something bad has happened. Internal data
  1872. // structures are corrupt.
  1873. //
  1874. ASSERT( FALSE );
  1875. }
  1876. //
  1877. // Free the socket and the IO buffer and return.
  1878. //
  1879. DeleteTcpClient( i, graceful );
  1880. RtlFreeHeap( RtlProcessHeap( ), 0, ioBuffer );
  1881. return 0;
  1882. } // ThreadEntry