xref: /reactos/base/services/tcpsvcs/tcpsvcs.c (revision c2c66aff)
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