adding missing dx headers
[reactos.git] / reactos / services / tcpsvcs / tcpsvcs.c
1 /*
2 * ReactOS Services
3 * Copyright (C) 2005 ReactOS Team
4 *
5 * LICENCE: GPL - See COPYING in the top level directory
6 * PROJECT: ReactOS simple TCP/IP services
7 * FILE: apps/utils/net/tcpsvcs/tcpsvcs.c
8 * PURPOSE: Provide CharGen, Daytime, Discard, Echo, and Qotd services
9 * PROGRAMMERS: Ged Murphy (gedmurphy@gmail.com)
10 * REVISIONS:
11 * GM 04/10/05 Created
12 *
13 */
14 /*
15 * TODO:
16 * - fix bug when terminating chargen server
17 * - log info in the event logger (when it's implemented)
18 */
19
20
21 #include "tcpsvcs.h"
22
23 //#define NDEBUG
24 //#include <debug.h>
25
26
27 /*
28 * globals
29 */
30 VOID WINAPI ServiceMain(DWORD argc, LPTSTR argv[]);
31
32 static SERVICE_STATUS hServStatus;
33 static SERVICE_STATUS_HANDLE hSStat;
34
35 FILE *hLogFile;
36 BOOL bShutDown = FALSE;
37 BOOL bPause = FALSE;
38
39 LPCTSTR LogFileName = "\\tcpsvcs_log.log";
40 LPTSTR ServiceName = _T("Simp Tcp");
41 //LPTSTR DisplayName = _T("Simple TCP/IP Services");
42
43 static SERVICES
44 Services[NUM_SERVICES] =
45 {
46 {ECHO_PORT, _T("Echo"), EchoHandler},
47 {DISCARD_PORT, _T("Discard"), DiscardHandler},
48 {DAYTIME_PORT, _T("Daytime"), DaytimeHandler},
49 {QOTD_PORT, _T("QOTD"), QotdHandler},
50 {CHARGEN_PORT, _T("Chargen"), ChargenHandler}
51 };
52
53
54 int
55 main(int argc, char *argv[])
56 {
57 SERVICE_TABLE_ENTRY ServiceTable[] =
58 {
59 {ServiceName, ServiceMain},
60 {NULL, NULL}
61 };
62
63 //DPRINT("Starting tcpsvcs service. See \system32%s for logs\n", LogFileName);
64
65 if (! StartServiceCtrlDispatcher(ServiceTable))
66 LogEvent(_T("failed to start the service control dispatcher\n"), -1, TRUE);
67
68 //DPRINT("Shutdown tcpsvcs service\n");
69
70 return 0;
71 }
72
73
74 VOID WINAPI
75 ServiceMain(DWORD argc, LPTSTR argv[])
76 {
77 TCHAR LogFilePath[MAX_PATH];
78
79 if(! GetSystemDirectory(LogFilePath, MAX_PATH))
80 return;
81
82 _tcscat(LogFilePath, LogFileName);
83
84 hLogFile = fopen(LogFilePath, _T("a+"));
85 if (hLogFile == NULL)
86 {
87 TCHAR buf[50];
88
89 _stprintf(buf, _T("Could not open log file: %s\n"), LogFilePath);
90 MessageBox(NULL, buf, NULL, MB_OK);
91 return;
92 }
93
94
95 LogEvent(_T("Entering ServiceMain\n"), 0, FALSE);
96
97 hServStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
98 hServStatus.dwCurrentState = SERVICE_START_PENDING;
99 hServStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
100 SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE;
101 hServStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
102 hServStatus.dwServiceSpecificExitCode = NO_ERROR;
103 hServStatus.dwCheckPoint = 0;
104 hServStatus.dwWaitHint = 2*CS_TIMEOUT;
105
106 hSStat = RegisterServiceCtrlHandler(ServiceName, ServerCtrlHandler);
107 if (hSStat == 0)
108 LogEvent(_T("Failed to register service\n"), -1, TRUE);
109
110 LogEvent(_T("Control handler registered successfully\n"), 0, FALSE);
111 SetServiceStatus (hSStat, &hServStatus);
112 LogEvent(_T("Service status set to SERVICE_START_PENDING\n"), 0, FALSE);
113
114 if (CreateServers() != 0)
115 {
116 hServStatus.dwCurrentState = SERVICE_STOPPED;
117 hServStatus.dwServiceSpecificExitCode = 1;
118 SetServiceStatus(hSStat, &hServStatus);
119 return;
120 }
121
122 LogEvent(_T("Service threads shut down. Set SERVICE_STOPPED status\n"), 0, FALSE);
123 /* We will only return here when the ServiceSpecific function
124 completes, indicating system shutdown. */
125 UpdateStatus (SERVICE_STOPPED, 0);
126 LogEvent(_T("Service status set to SERVICE_STOPPED\n"), 0, FALSE);
127 LogEvent(_T("Leaving ServiceMain\n"), 0, FALSE);
128
129 fclose(hLogFile);
130
131 return;
132
133 }
134
135 VOID WINAPI
136 ServerCtrlHandler(DWORD Control)
137 {
138 switch (Control)
139 {
140 case SERVICE_CONTROL_SHUTDOWN: /* fall through */
141 case SERVICE_CONTROL_STOP:
142 LogEvent(_T("stopping service\n"), 0, FALSE);
143 InterlockedExchange((LONG *)&bShutDown, TRUE);
144 UpdateStatus(SERVICE_STOP_PENDING, -1);
145 break;
146 case SERVICE_CONTROL_PAUSE: /* not yet implemented */
147 LogEvent(_T("pausing service\n"), 0, FALSE);
148 InterlockedExchange((LONG *)&bPause, TRUE);
149 break;
150 case SERVICE_CONTROL_CONTINUE:
151 LogEvent(_T("continuing service\n"), 0, FALSE);
152 InterlockedExchange((LONG *)&bPause, FALSE);
153 break;
154 case SERVICE_CONTROL_INTERROGATE:
155 break;
156 default:
157 if (Control > 127 && Control < 256) /* user defined */
158 break;
159 }
160 UpdateStatus(-1, -1); /* increment checkpoint */
161 return;
162 }
163
164
165 void UpdateStatus (int NewStatus, int Check)
166 /* Set a new service status and checkpoint (either specific value or increment) */
167 {
168 if (Check < 0 )
169 hServStatus.dwCheckPoint++;
170 else
171 hServStatus.dwCheckPoint = Check;
172
173 if (NewStatus >= 0)
174 hServStatus.dwCurrentState = NewStatus;
175
176 if (! SetServiceStatus (hSStat, &hServStatus))
177 LogEvent(_T("Cannot set service status\n"), -1, TRUE);
178
179 return;
180 }
181
182 INT
183 CreateServers()
184 {
185 DWORD dwThreadId[NUM_SERVICES];
186 HANDLE hThread[NUM_SERVICES];
187 WSADATA wsaData;
188 TCHAR buf[256];
189 INT i;
190 DWORD RetVal;
191
192 if ((RetVal = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
193 {
194 _stprintf(buf, _T("WSAStartup() failed : %lu\n"), RetVal);
195 LogEvent(buf, RetVal, TRUE);
196 return -1;
197 }
198
199 UpdateStatus(-1, -1); /* increment checkpoint */
200
201 LogEvent(_T("Creating server Threads\n"), 0, FALSE);
202
203 /* Create MAX_THREADS worker threads. */
204 for( i=0; i<NUM_SERVICES; i++ )
205 {
206 _stprintf(buf, _T("Starting %s server....\n"), Services[i].Name);
207 LogEvent(buf, 0, FALSE);
208
209 hThread[i] = CreateThread(
210 NULL, // default security attributes
211 0, // use default stack size
212 StartServer, // thread function
213 &Services[i], // argument to thread function
214 0, // use default creation flags
215 &dwThreadId[i]); // returns the thread identifier
216
217 /* Check the return value for success. */
218 if (hThread[i] == NULL)
219 {
220 _stprintf(buf, _T("Failed to start %s server....\n"), Services[i].Name);
221 /* don't exit process via LogEvent. We want to exit via the server
222 * which failed to start, which could mean i=0 */
223 LogEvent(buf, 0, TRUE);
224 ExitProcess(i);
225 }
226 }
227
228 LogEvent(_T("setting service status to running\n"), 0, FALSE);
229
230 UpdateStatus(SERVICE_RUNNING, 0);
231
232 /* Wait until all threads have terminated. */
233 WaitForMultipleObjects(NUM_SERVICES, hThread, TRUE, INFINITE);
234
235 /* Close all thread handles upon completion. */
236 for(i=0; i<NUM_SERVICES; i++)
237 {
238 CloseHandle(hThread[i]);
239 }
240
241 LogEvent(_T("Detaching Winsock2...\n"), 0, FALSE);
242 WSACleanup();
243
244 return 0;
245 }
246
247
248 /* LogEvent is similar to the ReportError function used elsewhere
249 For a service, however, we ReportEvent rather than write to standard
250 error. Eventually, this function should go into the utility
251 library. */
252 VOID
253 LogEvent (LPCTSTR UserMessage, DWORD ExitCode, BOOL PrintErrorMsg)
254 {
255 DWORD eMsgLen, ErrNum = GetLastError ();
256 LPTSTR lpvSysMsg;
257 TCHAR MessageBuffer[512];
258
259
260
261 if (PrintErrorMsg)
262 {
263 eMsgLen = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
264 FORMAT_MESSAGE_FROM_SYSTEM, NULL,
265 ErrNum, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
266 (LPTSTR)&lpvSysMsg, 0, NULL);
267
268 _stprintf(MessageBuffer, _T("%s %s ErrNum = %lu. ExitCode = %lu."),
269 UserMessage, lpvSysMsg, ErrNum, ExitCode);
270 HeapFree(GetProcessHeap (), 0, lpvSysMsg);
271 }
272 else
273 {
274 _stprintf(MessageBuffer, _T("%s"), UserMessage);
275 }
276
277 fputs (MessageBuffer, hLogFile);
278
279 if (ExitCode != 0)
280 ExitProcess(ExitCode);
281 else
282 return;
283 }