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