xref: /reactos/base/services/tcpsvcs/tcpsvcs.c (revision d2aeaba5)
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%lx, 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 }
226