Add tcpsvcs to the services directory.
[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 * - Start tcpsvcs as a service.
17 * - write debugging function and print all dbg info via that.
18 *
19 */
20
21 #include <stdio.h>
22 #include <winsock2.h>
23 #include <tchar.h>
24 #include "tcpsvcs.h"
25
26 #if 0
27 /*
28 * globals
29 */
30 static SERVICE_STATUS hServStatus;
31 static SERVICE_STATUS_HANDLE hSStat;
32 FILE *hLogFile;
33 BOOL bLogEvents = TRUE;
34 BOOL ShutDown, PauseFlag;
35 LPCTSTR LogFileName = "tcpsvcs_log.log";
36
37 static SERVICE_TABLE_ENTRY
38 ServiceTable[2] =
39 {
40 {_T("tcpsvcs"), ServiceMain},
41 {NULL, NULL}
42 };
43 #endif
44
45 static SERVICES
46 Services[NUM_SERVICES] =
47 {
48 {ECHO_PORT, _T("Echo"), EchoHandler},
49 {DISCARD_PORT, _T("Discard"), DiscardHandler},
50 {DAYTIME_PORT, _T("Daytime"), DaytimeHandler},
51 {QOTD_PORT, _T("QOTD"), QotdHandler},
52 {CHARGEN_PORT, _T("Chargen"), ChargenHandler}
53 };
54
55
56 int main(void)
57 {
58 DWORD dwThreadId[NUM_SERVICES];
59 HANDLE hThread[NUM_SERVICES];
60 WSADATA wsaData;
61 DWORD RetVal;
62 INT i;
63
64 if ((RetVal = WSAStartup(MAKEWORD(2, 2), &wsaData)) != 0)
65 {
66 _tprintf(_T("WSAStartup() failed : %lu\n"), RetVal);
67 return -1;
68 }
69
70 /* Create MAX_THREADS worker threads. */
71 for( i=0; i<NUM_SERVICES; i++ )
72 {
73 _tprintf(_T("Starting %s server....\n"), Services[i].Name);
74
75 hThread[i] = CreateThread(
76 NULL, // default security attributes
77 0, // use default stack size
78 StartServer, // thread function
79 &Services[i], // argument to thread function
80 0, // use default creation flags
81 &dwThreadId[i]); // returns the thread identifier
82
83 /* Check the return value for success. */
84 if (hThread[i] == NULL)
85 {
86 _tprintf(_T("Failed to start %s server....\n"), Services[i].Name);
87 //ExitProcess(i);
88 }
89 }
90
91 /* Wait until all threads have terminated. */
92 WaitForMultipleObjects(NUM_SERVICES, hThread, TRUE, INFINITE);
93
94 /* Close all thread handles upon completion. */
95 for(i=0; i<NUM_SERVICES; i++)
96 {
97 CloseHandle(hThread[i]);
98 }
99 return 0;
100 }
101
102
103
104 /* code to run tcpsvcs as a service through services.msc */
105 #if 0
106 int
107 main(int argc, char *argv[])
108 {
109 //DPRINT("tcpsvcs: main() started. See tcpsvcs_log.txt for info\n");
110
111 if (!StartServiceCtrlDispatcher(ServiceTable))
112 _tprintf(_T("failed to start the service control dispatcher\n"));
113
114 //DPRINT("tcpsvcs: main() done\n");
115
116 return 0;
117 }
118
119
120 static VOID WINAPI
121 ServiceMain(DWORD argc, LPTSTR argv[])
122 {
123 DWORD i;
124
125 hLogFile = fopen(LogFileName, _T("w+"));
126 if (hLogFile == NULL)
127 return;
128
129 LogEvent(_T("Entering ServiceMain"), 0, FALSE);
130
131 hServStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
132 hServStatus.dwCurrentState = SERVICE_START_PENDING;
133 hServStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
134 SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE;
135 hServStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
136 hServStatus.dwServiceSpecificExitCode = 0;
137 hServStatus.dwCheckPoint = 0;
138 hServStatus.dwWaitHint = 2*CS_TIMEOUT;
139
140 hSStat = RegisterServiceCtrlHandler("tcpsvcs", ServerCtrlHandler);
141 if (hSStat == 0)
142 LogEvent(_T("Failed to register service\n"), 100, TRUE);
143
144 LogEvent(_T("Control handler registered successfully"), 0, FALSE);
145 SetServiceStatus (hSStat, &hServStatus);
146 LogEvent(_T("Service status set to SERVICE_START_PENDING"), 0, FALSE);
147
148 if (CreateServers() != 0)
149 {
150 hServStatus.dwCurrentState = SERVICE_STOPPED;
151 hServStatus.dwServiceSpecificExitCode = 1;
152 SetServiceStatus(hSStat, &hServStatus);
153 return;
154 }
155
156 LogEvent(_T("Service threads shut down. Set SERVICE_STOPPED status"), 0, FALSE);
157 /* We will only return here when the ServiceSpecific function
158 completes, indicating system shutdown. */
159 UpdateStatus (SERVICE_STOPPED, 0);
160 LogEvent(_T("Service status set to SERVICE_STOPPED"), 0, FALSE);
161 fclose(hLogFile); /* Clean up everything, in general */
162 return;
163
164 }
165
166 VOID WINAPI
167 ServerCtrlHandler(DWORD Control)
168 {
169 switch (Control)
170 {
171 case SERVICE_CONTROL_SHUTDOWN: /* fall through */
172 case SERVICE_CONTROL_STOP:
173 ShutDown = TRUE;
174 UpdateStatus(SERVICE_STOP_PENDING, -1);
175 break;
176 case SERVICE_CONTROL_PAUSE:
177 PauseFlag = TRUE;
178 break;
179 case SERVICE_CONTROL_CONTINUE:
180 PauseFlag = FALSE;
181 break;
182 case SERVICE_CONTROL_INTERROGATE:
183 break;
184 default:
185 if (Control > 127 && Control < 256) /* user defined */
186 break;
187 }
188 UpdateStatus(-1, -1); /* increment checkpoint */
189 return;
190 }
191
192
193 void UpdateStatus (int NewStatus, int Check)
194 /* Set a new service status and checkpoint (either specific value or increment) */
195 {
196 if (Check < 0 ) hServStatus.dwCheckPoint++;
197 else hServStatus.dwCheckPoint = Check;
198 if (NewStatus >= 0) hServStatus.dwCurrentState = NewStatus;
199 if (!SetServiceStatus (hSStat, &hServStatus))
200 LogEvent (_T("Cannot set service status"), 101, TRUE);
201 return;
202 }
203
204 INT
205 CreateServers()
206 {
207 DWORD dwThreadId[NUM_SERVICES];
208 HANDLE hThread[NUM_SERVICES];
209 INT i;
210
211 UpdateStatus(-1, -1); /* increment checkpoint */
212
213 /* Create MAX_THREADS worker threads. */
214 for( i=0; i<NUM_SERVICES; i++ )
215 {
216 _tprintf(_T("Starting %s server....\n"), Services[i].Name);
217
218 hThread[i] = CreateThread(
219 NULL, // default security attributes
220 0, // use default stack size
221 StartServer, // thread function
222 &Services[i], // argument to thread function
223 0, // use default creation flags
224 &dwThreadId[i]); // returns the thread identifier
225
226 /* Check the return value for success. */
227 if (hThread[i] == NULL)
228 {
229 _tprintf(_T("Failed to start %s server....\n"), Services[i].Name);
230 ExitProcess(i);
231 }
232 }
233
234 /* Wait until all threads have terminated. */
235 WaitForMultipleObjects(NUM_SERVICES, hThread, TRUE, INFINITE);
236
237 /* Close all thread handles upon completion. */
238 for(i=0; i<NUM_SERVICES; i++)
239 {
240 CloseHandle(hThread[i]);
241 }
242 return 0;
243 }
244
245
246 /* LogEvent is similar to the ReportError function used elsewhere
247 For a service, however, we ReportEvent rather than write to standard
248 error. Eventually, this function should go into the utility
249 library. */
250 VOID
251 LogEvent (LPCTSTR UserMessage, DWORD ExitCode, BOOL PrintErrorMsg)
252 {
253 DWORD eMsgLen, ErrNum = GetLastError ();
254 LPTSTR lpvSysMsg;
255 TCHAR MessageBuffer[512];
256
257 if (PrintErrorMsg) {
258 eMsgLen = FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
259 FORMAT_MESSAGE_FROM_SYSTEM, NULL,
260 ErrNum, MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
261 (LPTSTR)&lpvSysMsg, 0, NULL);
262
263 _stprintf (MessageBuffer, _T("\n%s %s ErrNum = %d. ExitCode = %d."),
264 UserMessage, lpvSysMsg, ErrNum, ExitCode);
265 HeapFree (GetProcessHeap (), 0, lpvSysMsg);
266 } else {
267 _stprintf (MessageBuffer, _T("\n%s ExitCode = %d."),
268 UserMessage, ExitCode);
269 }
270
271 fputs (MessageBuffer, hLogFile);
272
273 if (ExitCode > 0)
274 ExitProcess (ExitCode);
275 else
276 return;
277 }
278
279 #endif