[USB-BRINGUP-TRUNK]
[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 = 5000;
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 SetServiceStatus(pServInfo->hStatus, &pServInfo->servStatus);
156 break;
157
158 default:
159 if (dwControl > 127 && dwControl < 256) /* user defined */
160 LogEvent(L"User defined control code", 0, 0, LOG_FILE);
161 else
162 LogEvent(L"ERROR: Bad control code", 0, 0, LOG_FILE);
163 break;
164 }
165 }
166
167 VOID WINAPI
168 ServiceMain(DWORD argc, LPWSTR argv[])
169 {
170 SERVICEINFO servInfo;
171
172 LogEvent(L"Entering ServiceMain.", 0, 0, LOG_FILE);
173
174 servInfo.servStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
175 servInfo.servStatus.dwCurrentState = SERVICE_STOPPED;
176 servInfo.servStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE;
177 servInfo.servStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
178 servInfo.servStatus.dwServiceSpecificExitCode = 0;
179 servInfo.servStatus.dwCheckPoint = 0;
180 servInfo.servStatus.dwWaitHint = 2 * CS_TIMEOUT;
181
182 LogEvent(L"Registering service control handler", 0, 0, LOG_FILE);
183 servInfo.hStatus = RegisterServiceCtrlHandlerExW(ServiceName,
184 (LPHANDLER_FUNCTION_EX)ServerCtrlHandler,
185 &servInfo);
186 if (!servInfo.hStatus)
187 LogEvent(L"Failed to register service", GetLastError(), 100, LOG_ALL);
188
189 UpdateStatus(&servInfo, SERVICE_START_PENDING, 1);
190
191 if (!CreateServers(&servInfo))
192 {
193 LogEvent(L"Error creating servers", GetLastError(), 1, LOG_ALL);
194 servInfo.servStatus.dwServiceSpecificExitCode = 1;
195 UpdateStatus(&servInfo, SERVICE_STOPPED, 0);
196 return;
197 }
198
199 LogEvent(L"Service threads shut down. Set SERVICE_STOPPED status", 0, 0, LOG_FILE);
200 UpdateStatus(&servInfo, SERVICE_STOPPED, 0);
201
202 LogEvent(L"Leaving ServiceMain\n", 0, 0, LOG_FILE);
203 }
204
205
206 int _tmain (int argc, LPTSTR argv [])
207 {
208 SERVICE_TABLE_ENTRYW ServiceTable[] =
209 {
210 {ServiceName, ServiceMain},
211 {NULL, NULL }
212 };
213
214 if (InitLogging())
215 {
216 if (!StartServiceCtrlDispatcherW(ServiceTable))
217 LogEvent(L"failed to start the service control dispatcher", GetLastError(), 101, LOG_ALL);
218
219 UninitLogging();
220 }
221
222 return 0;
223 }