Added headers
[tpot/pegasus/.git] / src / Pegasus / Common / ServiceWindows.cpp
1 //%/////////////////////////////////////////////////////////////////////////////\r
2 //\r
3 // Copyright (c) 2000, 2001 The Open group, BMC Software, Tivoli Systems, IBM\r
4 //\r
5 // Permission is hereby granted, free of charge, to any person obtaining a copy\r
6 // of this software and associated documentation files (the "Software"), to \r
7 // deal in the Software without restriction, including without limitation the \r
8 // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or \r
9 // sell copies of the Software, and to permit persons to whom the Software is\r
10 // furnished to do so, subject to the following conditions:\r
11 // \r
12 // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN \r
13 // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED\r
14 // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT\r
15 // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR \r
16 // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT \r
17 // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN \r
18 // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\r
19 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\r
20 //\r
21 //==============================================================================\r
22 //\r
23 // Author: Mike Brasher (mbrasher@bmc.com)\r
24 //\r
25 // Modified By:\r
26 //\r
27 //%/////////////////////////////////////////////////////////////////////////////\r
28 \r
29 #include <windows.h>\r
30 #include <cstdio>\r
31 #include <string>\r
32 #include <fstream>\r
33 #include <cstdlib>\r
34 #include "Service.h"\r
35 \r
36 PEGASUS_NAMESPACE_BEGIN\r
37 \r
38 using namespace std;\r
39 \r
40 struct ClientData\r
41 {\r
42     int argc;\r
43     char** argv;\r
44 };\r
45 \r
46 static const char* _serviceName = "";\r
47 static HANDLE _terminateEvent = NULL;\r
48 static SERVICE_STATUS_HANDLE _serviceStatusHandle = NULL;\r
49 static HANDLE _threadHandle = 0;\r
50 static BOOL _serviceRunning = FALSE;\r
51 static BOOL _servicePaused = FALSE;\r
52 static SERVICE_TABLE_ENTRY _serviceTable[2];\r
53 static ServiceHandler* _serviceHandler = 0;\r
54 static ClientData _clientData;\r
55 \r
56 static void _stopService() \r
57 {\r
58     _serviceRunning = FALSE;\r
59     SetEvent(_terminateEvent);\r
60 }\r
61 \r
62 static BOOL _sendStatusToSCM(\r
63     DWORD dwCurrentState,\r
64     DWORD dwWin32ExitCode, \r
65     DWORD dwServiceSpecificExitCode,\r
66     DWORD dwCheckPoint,\r
67     DWORD dwWaitHint)\r
68 {\r
69     SERVICE_STATUS serviceStatus;\r
70 \r
71     serviceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;\r
72     serviceStatus.dwCurrentState = dwCurrentState;\r
73 \r
74     if (dwCurrentState == SERVICE_START_PENDING)\r
75         serviceStatus.dwControlsAccepted = 0;\r
76     else\r
77     {\r
78         serviceStatus.dwControlsAccepted = \r
79             SERVICE_ACCEPT_STOP |\r
80             SERVICE_ACCEPT_PAUSE_CONTINUE |\r
81             SERVICE_ACCEPT_SHUTDOWN;\r
82     }\r
83 \r
84     if (dwServiceSpecificExitCode == 0)\r
85         serviceStatus.dwWin32ExitCode = dwWin32ExitCode;\r
86     else\r
87         serviceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;\r
88 \r
89     serviceStatus.dwServiceSpecificExitCode = dwServiceSpecificExitCode;\r
90     serviceStatus.dwCheckPoint = dwCheckPoint;\r
91     serviceStatus.dwWaitHint = dwWaitHint;\r
92 \r
93     BOOL success = SetServiceStatus(_serviceStatusHandle, &serviceStatus);\r
94 \r
95     if (!success)\r
96         _stopService();\r
97 \r
98     return success;\r
99 }\r
100 \r
101 static void _resumeService() \r
102 {\r
103     _servicePaused = FALSE;\r
104     ResumeThread(_threadHandle);\r
105 }\r
106 \r
107 static void _pauseService() \r
108 {\r
109     _servicePaused = TRUE;\r
110     SuspendThread(_threadHandle);\r
111 }\r
112 \r
113 static void _terminate(DWORD error)\r
114 {\r
115     if (_terminateEvent)\r
116         CloseHandle(_terminateEvent);\r
117 \r
118     if (_serviceStatusHandle)\r
119         _sendStatusToSCM(SERVICE_STOPPED, error, 0, 0, 0);\r
120 \r
121     if (_threadHandle)\r
122         CloseHandle(_threadHandle);\r
123 }\r
124 \r
125 static DWORD _serviceThread(LPDWORD param)\r
126 {\r
127     ClientData* clientData = (ClientData*)param;\r
128     int status = _serviceHandler->main(clientData->argc, clientData->argv);\r
129     return status;\r
130 }\r
131 \r
132 static void _serviceCtrlHandler(DWORD controlCode) \r
133 {\r
134     DWORD  currentState = 0;\r
135 \r
136     switch(controlCode)\r
137     {\r
138         case SERVICE_CONTROL_STOP:\r
139         {\r
140             SERVICE_STOP_PENDING;\r
141             _sendStatusToSCM( SERVICE_STOP_PENDING, NO_ERROR, 0, 1, 5000);\r
142             _stopService();\r
143             _serviceHandler->stop();\r
144             return;\r
145         }\r
146 \r
147         case SERVICE_CONTROL_PAUSE:\r
148         {\r
149             if (_serviceRunning && !_servicePaused)\r
150             {\r
151                 _sendStatusToSCM(SERVICE_PAUSE_PENDING, NO_ERROR, 0, 1, 1000);\r
152                 _pauseService();\r
153                 currentState = SERVICE_PAUSED;\r
154                 _serviceHandler->pause();\r
155             }\r
156             break;\r
157         }\r
158 \r
159         case SERVICE_CONTROL_CONTINUE:\r
160         {\r
161             if (_serviceRunning && _servicePaused)\r
162             {\r
163                 _sendStatusToSCM( \r
164                     SERVICE_CONTINUE_PENDING, NO_ERROR, 0, 1, 1000);\r
165                 _resumeService();\r
166                 currentState = SERVICE_RUNNING;\r
167                 _serviceHandler->resume();\r
168             }\r
169             break;\r
170         }\r
171 \r
172         case SERVICE_CONTROL_INTERROGATE:\r
173         case SERVICE_CONTROL_SHUTDOWN:\r
174         default:\r
175             break;\r
176     }\r
177 \r
178     _sendStatusToSCM(currentState, NO_ERROR, 0, 0, 0);\r
179 }\r
180 \r
181 static void _serviceMain(DWORD argc, LPTSTR *argv) \r
182 {\r
183     // Register the service control handler:\r
184 \r
185     _serviceStatusHandle = RegisterServiceCtrlHandler(\r
186         _serviceName, (LPHANDLER_FUNCTION)_serviceCtrlHandler);\r
187 \r
188     if (!_serviceStatusHandle)\r
189     {\r
190         _terminate(GetLastError()); \r
191         return;\r
192     }\r
193 \r
194     if (!_sendStatusToSCM(SERVICE_START_PENDING, NO_ERROR, 0, 1, 5000))\r
195     {\r
196         _terminate(GetLastError()); \r
197         return;\r
198     }\r
199 \r
200     if (!(_terminateEvent = CreateEvent (0, TRUE, FALSE, 0)))\r
201     {\r
202         _terminate(GetLastError());\r
203         return;\r
204     }\r
205 \r
206     if (!_sendStatusToSCM(SERVICE_START_PENDING, NO_ERROR, 0, 2, 1000))\r
207     {\r
208         _terminate(GetLastError()); \r
209         return;\r
210     }\r
211 \r
212     if (!_sendStatusToSCM(SERVICE_START_PENDING, NO_ERROR, 0, 3, 5000))\r
213     {\r
214         _terminate(GetLastError()); \r
215         return;\r
216     }\r
217 \r
218     // Create the service thread:\r
219 \r
220     _clientData.argc = argc;\r
221     _clientData.argv = argv;\r
222     DWORD id;\r
223 \r
224     _threadHandle = CreateThread(\r
225         0, 0, (LPTHREAD_START_ROUTINE)_serviceThread, &_clientData, 0, &id); \r
226 \r
227     if (_threadHandle)\r
228         _serviceRunning = TRUE;\r
229     else\r
230     {\r
231         _terminate(GetLastError());\r
232         return;\r
233     }\r
234 \r
235     // Send status to SCM:\r
236 \r
237     if (!_sendStatusToSCM( SERVICE_RUNNING, NO_ERROR, 0, 0, 0))\r
238     {\r
239         _terminate(GetLastError()); \r
240         return;\r
241     }\r
242 \r
243     // Wait for termination!\r
244 \r
245     WaitForSingleObject(_terminateEvent, INFINITE);\r
246     _terminate(0);\r
247 }\r
248 \r
249 bool Service::run(\r
250     int argc,\r
251     char** argv,\r
252     const char* serviceName, \r
253     ServiceHandler* serviceHandler,\r
254     bool detach)\r
255 {\r
256     if (!detach)\r
257     {\r
258         serviceHandler->main(argc, argv);\r
259         return false;\r
260     }\r
261 \r
262     _serviceHandler = serviceHandler;\r
263 \r
264     _serviceName = serviceName;\r
265     _serviceTable[0].lpServiceName = (char*)serviceName;\r
266     _serviceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)_serviceMain;\r
267     _serviceTable[1].lpServiceName = NULL;\r
268     _serviceTable[1].lpServiceProc = NULL;\r
269 \r
270     return StartServiceCtrlDispatcher(_serviceTable) ? true : false;\r
271 }\r
272 \r
273 PEGASUS_NAMESPACE_END\r