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.

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