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