1*c2c66affSColin Finck /*
2*c2c66affSColin Finck * PROJECT: ReactOS simple TCP/IP services
3*c2c66affSColin Finck * LICENSE: GPL - See COPYING in the top level directory
4*c2c66affSColin Finck * FILE: base/services/tcpsvcs/tcpsvcs.c
5*c2c66affSColin Finck * PURPOSE: Provide CharGen, Daytime, Discard, Echo, and Qotd services
6*c2c66affSColin Finck * COPYRIGHT: Copyright 2005 - 2008 Ged Murphy <gedmurphy@reactos.org>
7*c2c66affSColin Finck *
8*c2c66affSColin Finck */
9*c2c66affSColin Finck
10*c2c66affSColin Finck #include "tcpsvcs.h"
11*c2c66affSColin Finck
12*c2c66affSColin Finck #include <winsvc.h>
13*c2c66affSColin Finck
14*c2c66affSColin Finck static WCHAR ServiceName[] = L"tcpsvcs";
15*c2c66affSColin Finck
16*c2c66affSColin Finck volatile BOOL bShutdown = FALSE;
17*c2c66affSColin Finck volatile BOOL bPause = FALSE;
18*c2c66affSColin Finck
19*c2c66affSColin Finck typedef struct _ServiceInfo
20*c2c66affSColin Finck {
21*c2c66affSColin Finck SERVICE_STATUS servStatus;
22*c2c66affSColin Finck SERVICE_STATUS_HANDLE hStatus;
23*c2c66affSColin Finck } SERVICEINFO, *PSERVICEINFO;
24*c2c66affSColin Finck
25*c2c66affSColin Finck static SERVICES
26*c2c66affSColin Finck Services[NUM_SERVICES] =
27*c2c66affSColin Finck {
28*c2c66affSColin Finck {ECHO_PORT, L"Echo", EchoHandler},
29*c2c66affSColin Finck {DISCARD_PORT, L"Discard", DiscardHandler},
30*c2c66affSColin Finck {DAYTIME_PORT, L"Daytime", DaytimeHandler},
31*c2c66affSColin Finck {QOTD_PORT, L"QOTD", QotdHandler},
32*c2c66affSColin Finck {CHARGEN_PORT, L"Chargen", ChargenHandler}
33*c2c66affSColin Finck };
34*c2c66affSColin Finck
35*c2c66affSColin Finck
36*c2c66affSColin Finck static VOID
UpdateStatus(PSERVICEINFO pServInfo,DWORD NewStatus,DWORD Check)37*c2c66affSColin Finck UpdateStatus(PSERVICEINFO pServInfo,
38*c2c66affSColin Finck DWORD NewStatus,
39*c2c66affSColin Finck DWORD Check)
40*c2c66affSColin Finck {
41*c2c66affSColin Finck WCHAR szSet[50];
42*c2c66affSColin Finck
43*c2c66affSColin Finck if (Check > 0)
44*c2c66affSColin Finck pServInfo->servStatus.dwCheckPoint += Check;
45*c2c66affSColin Finck else
46*c2c66affSColin Finck pServInfo->servStatus.dwCheckPoint = Check;
47*c2c66affSColin Finck
48*c2c66affSColin Finck if (NewStatus > 0)
49*c2c66affSColin Finck pServInfo->servStatus.dwCurrentState = NewStatus;
50*c2c66affSColin Finck
51*c2c66affSColin Finck _snwprintf(szSet,
52*c2c66affSColin Finck 49,
53*c2c66affSColin Finck L"Service state 0x%lx, CheckPoint %lu",
54*c2c66affSColin Finck pServInfo->servStatus.dwCurrentState,
55*c2c66affSColin Finck pServInfo->servStatus.dwCheckPoint);
56*c2c66affSColin Finck LogEvent(szSet, 0, 0, LOG_FILE);
57*c2c66affSColin Finck
58*c2c66affSColin Finck if (!SetServiceStatus(pServInfo->hStatus, &pServInfo->servStatus))
59*c2c66affSColin Finck LogEvent(L"Cannot set service status", GetLastError(), 0, LOG_ALL);
60*c2c66affSColin Finck }
61*c2c66affSColin Finck
62*c2c66affSColin Finck
63*c2c66affSColin Finck static BOOL
CreateServers(PSERVICEINFO pServInfo)64*c2c66affSColin Finck CreateServers(PSERVICEINFO pServInfo)
65*c2c66affSColin Finck {
66*c2c66affSColin Finck DWORD dwThreadId[NUM_SERVICES];
67*c2c66affSColin Finck HANDLE hThread[NUM_SERVICES];
68*c2c66affSColin Finck WSADATA wsaData;
69*c2c66affSColin Finck WCHAR buf[256];
70*c2c66affSColin Finck INT i;
71*c2c66affSColin Finck DWORD RetVal;
72*c2c66affSColin Finck
73*c2c66affSColin Finck if ((RetVal = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
74*c2c66affSColin Finck {
75*c2c66affSColin Finck swprintf(buf, L"WSAStartup() failed : %lu\n", RetVal);
76*c2c66affSColin Finck LogEvent(buf, 0, 100, LOG_ALL);
77*c2c66affSColin Finck return FALSE;
78*c2c66affSColin Finck }
79*c2c66affSColin Finck
80*c2c66affSColin Finck UpdateStatus(pServInfo, 0, 1);
81*c2c66affSColin Finck
82*c2c66affSColin Finck LogEvent(L"\nCreating server Threads", 0, 0, LOG_FILE);
83*c2c66affSColin Finck
84*c2c66affSColin Finck /* Create worker threads. */
85*c2c66affSColin Finck for (i = 0; i < NUM_SERVICES; i++)
86*c2c66affSColin Finck {
87*c2c66affSColin Finck swprintf(buf, L"Creating thread for %s server", Services[i].lpName);
88*c2c66affSColin Finck LogEvent(buf, 0, 0, LOG_FILE);
89*c2c66affSColin Finck
90*c2c66affSColin Finck hThread[i] = CreateThread(NULL,
91*c2c66affSColin Finck 0,
92*c2c66affSColin Finck StartServer,
93*c2c66affSColin Finck &Services[i],
94*c2c66affSColin Finck 0,
95*c2c66affSColin Finck &dwThreadId[i]);
96*c2c66affSColin Finck
97*c2c66affSColin Finck if (hThread[i] == NULL)
98*c2c66affSColin Finck {
99*c2c66affSColin Finck swprintf(buf, L"\nError creating %s server thread\n", Services[i].lpName);
100*c2c66affSColin Finck LogEvent(buf, GetLastError(), 0, LOG_ALL);
101*c2c66affSColin Finck return FALSE;
102*c2c66affSColin Finck }
103*c2c66affSColin Finck
104*c2c66affSColin Finck UpdateStatus(pServInfo, 0, 1);
105*c2c66affSColin Finck }
106*c2c66affSColin Finck
107*c2c66affSColin Finck LogEvent(L"Setting service status to running", 0, 0, LOG_FILE);
108*c2c66affSColin Finck UpdateStatus(pServInfo, SERVICE_RUNNING, 0);
109*c2c66affSColin Finck
110*c2c66affSColin Finck /* Wait until all threads have terminated. */
111*c2c66affSColin Finck WaitForMultipleObjects(NUM_SERVICES, hThread, TRUE, INFINITE);
112*c2c66affSColin Finck
113*c2c66affSColin Finck for (i = 0; i < NUM_SERVICES; i++)
114*c2c66affSColin Finck {
115*c2c66affSColin Finck if (hThread[i] != NULL)
116*c2c66affSColin Finck CloseHandle(hThread[i]);
117*c2c66affSColin Finck }
118*c2c66affSColin Finck
119*c2c66affSColin Finck LogEvent(L"Detaching Winsock2", 0, 0, LOG_FILE);
120*c2c66affSColin Finck WSACleanup();
121*c2c66affSColin Finck
122*c2c66affSColin Finck return TRUE;
123*c2c66affSColin Finck }
124*c2c66affSColin Finck
125*c2c66affSColin Finck VOID WINAPI
ServerCtrlHandler(DWORD dwControl,DWORD dwEventType,LPVOID lpEventData,LPVOID lpContext)126*c2c66affSColin Finck ServerCtrlHandler(DWORD dwControl,
127*c2c66affSColin Finck DWORD dwEventType,
128*c2c66affSColin Finck LPVOID lpEventData,
129*c2c66affSColin Finck LPVOID lpContext)
130*c2c66affSColin Finck {
131*c2c66affSColin Finck PSERVICEINFO pServInfo = (PSERVICEINFO)lpContext;
132*c2c66affSColin Finck
133*c2c66affSColin Finck switch (dwControl)
134*c2c66affSColin Finck {
135*c2c66affSColin Finck case SERVICE_CONTROL_SHUTDOWN:
136*c2c66affSColin Finck case SERVICE_CONTROL_STOP:
137*c2c66affSColin Finck LogEvent(L"\nSetting the service to SERVICE_STOP_PENDING", 0, 0, LOG_FILE);
138*c2c66affSColin Finck InterlockedExchange((LONG *)&bShutdown, TRUE);
139*c2c66affSColin Finck pServInfo->servStatus.dwWin32ExitCode = 0;
140*c2c66affSColin Finck pServInfo->servStatus.dwWaitHint = 5000;
141*c2c66affSColin Finck UpdateStatus(pServInfo, SERVICE_STOP_PENDING, 1);
142*c2c66affSColin Finck break;
143*c2c66affSColin Finck
144*c2c66affSColin Finck case SERVICE_CONTROL_PAUSE: /* not yet implemented */
145*c2c66affSColin Finck LogEvent(L"Setting the service to SERVICE_PAUSED", 0, 0, LOG_FILE);
146*c2c66affSColin Finck InterlockedExchange((LONG *)&bPause, TRUE);
147*c2c66affSColin Finck UpdateStatus(pServInfo, SERVICE_PAUSED, 0);
148*c2c66affSColin Finck break;
149*c2c66affSColin Finck
150*c2c66affSColin Finck case SERVICE_CONTROL_CONTINUE:
151*c2c66affSColin Finck LogEvent(L"Setting the service to SERVICE_RUNNING", 0, 0, LOG_FILE);
152*c2c66affSColin Finck InterlockedExchange((LONG *)&bPause, FALSE);
153*c2c66affSColin Finck UpdateStatus(pServInfo, SERVICE_RUNNING, 0);
154*c2c66affSColin Finck break;
155*c2c66affSColin Finck
156*c2c66affSColin Finck case SERVICE_CONTROL_INTERROGATE:
157*c2c66affSColin Finck SetServiceStatus(pServInfo->hStatus, &pServInfo->servStatus);
158*c2c66affSColin Finck break;
159*c2c66affSColin Finck
160*c2c66affSColin Finck default:
161*c2c66affSColin Finck if (dwControl > 127 && dwControl < 256) /* user defined */
162*c2c66affSColin Finck LogEvent(L"User defined control code", 0, 0, LOG_FILE);
163*c2c66affSColin Finck else
164*c2c66affSColin Finck LogEvent(L"ERROR: Bad control code", 0, 0, LOG_FILE);
165*c2c66affSColin Finck break;
166*c2c66affSColin Finck }
167*c2c66affSColin Finck }
168*c2c66affSColin Finck
169*c2c66affSColin Finck VOID WINAPI
ServiceMain(DWORD argc,LPWSTR argv[])170*c2c66affSColin Finck ServiceMain(DWORD argc, LPWSTR argv[])
171*c2c66affSColin Finck {
172*c2c66affSColin Finck SERVICEINFO servInfo;
173*c2c66affSColin Finck
174*c2c66affSColin Finck LogEvent(L"Entering ServiceMain.", 0, 0, LOG_FILE);
175*c2c66affSColin Finck
176*c2c66affSColin Finck servInfo.servStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
177*c2c66affSColin Finck servInfo.servStatus.dwCurrentState = SERVICE_STOPPED;
178*c2c66affSColin Finck servInfo.servStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE;
179*c2c66affSColin Finck servInfo.servStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
180*c2c66affSColin Finck servInfo.servStatus.dwServiceSpecificExitCode = 0;
181*c2c66affSColin Finck servInfo.servStatus.dwCheckPoint = 0;
182*c2c66affSColin Finck servInfo.servStatus.dwWaitHint = 2 * CS_TIMEOUT;
183*c2c66affSColin Finck
184*c2c66affSColin Finck LogEvent(L"Registering service control handler", 0, 0, LOG_FILE);
185*c2c66affSColin Finck servInfo.hStatus = RegisterServiceCtrlHandlerExW(ServiceName,
186*c2c66affSColin Finck (LPHANDLER_FUNCTION_EX)ServerCtrlHandler,
187*c2c66affSColin Finck &servInfo);
188*c2c66affSColin Finck if (!servInfo.hStatus)
189*c2c66affSColin Finck LogEvent(L"Failed to register service", GetLastError(), 100, LOG_ALL);
190*c2c66affSColin Finck
191*c2c66affSColin Finck UpdateStatus(&servInfo, SERVICE_START_PENDING, 1);
192*c2c66affSColin Finck
193*c2c66affSColin Finck if (!CreateServers(&servInfo))
194*c2c66affSColin Finck {
195*c2c66affSColin Finck LogEvent(L"Error creating servers", GetLastError(), 1, LOG_ALL);
196*c2c66affSColin Finck servInfo.servStatus.dwServiceSpecificExitCode = 1;
197*c2c66affSColin Finck UpdateStatus(&servInfo, SERVICE_STOPPED, 0);
198*c2c66affSColin Finck return;
199*c2c66affSColin Finck }
200*c2c66affSColin Finck
201*c2c66affSColin Finck LogEvent(L"Service threads shut down. Set SERVICE_STOPPED status", 0, 0, LOG_FILE);
202*c2c66affSColin Finck UpdateStatus(&servInfo, SERVICE_STOPPED, 0);
203*c2c66affSColin Finck
204*c2c66affSColin Finck LogEvent(L"Leaving ServiceMain\n", 0, 0, LOG_FILE);
205*c2c66affSColin Finck }
206*c2c66affSColin Finck
207*c2c66affSColin Finck
_tmain(int argc,LPTSTR argv[])208*c2c66affSColin Finck int _tmain (int argc, LPTSTR argv [])
209*c2c66affSColin Finck {
210*c2c66affSColin Finck SERVICE_TABLE_ENTRYW ServiceTable[] =
211*c2c66affSColin Finck {
212*c2c66affSColin Finck {ServiceName, ServiceMain},
213*c2c66affSColin Finck {NULL, NULL }
214*c2c66affSColin Finck };
215*c2c66affSColin Finck
216*c2c66affSColin Finck if (InitLogging())
217*c2c66affSColin Finck {
218*c2c66affSColin Finck if (!StartServiceCtrlDispatcherW(ServiceTable))
219*c2c66affSColin Finck LogEvent(L"failed to start the service control dispatcher", GetLastError(), 101, LOG_ALL);
220*c2c66affSColin Finck
221*c2c66affSColin Finck UninitLogging();
222*c2c66affSColin Finck }
223*c2c66affSColin Finck
224*c2c66affSColin Finck return 0;
225*c2c66affSColin Finck }
226