Electroneum
Loading...
Searching...
No Matches
service_impl_base.h
Go to the documentation of this file.
1// Copyright (c) 2006-2013, Andrey N. Sabelnikov, www.sabelnikov.net
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are met:
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above copyright
9// notice, this list of conditions and the following disclaimer in the
10// documentation and/or other materials provided with the distribution.
11// * Neither the name of the Andrey N. Sabelnikov nor the
12// names of its contributors may be used to endorse or promote products
13// derived from this software without specific prior written permission.
14//
15// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER BE LIABLE FOR ANY
19// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25//
26
27
28#ifndef _SERVICE_IMPL_BASE_H_
29#define _SERVICE_IMPL_BASE_H_
30
31#pragma comment(lib, "advapi32.lib")
32
33
34namespace epee
35{
37 public:
39 virtual ~service_impl_base();
40
41 virtual const char *get_name() = 0;
42 virtual const char *get_caption() = 0;
43 virtual const char *get_description() = 0;
44
45 bool run_service();
46 virtual bool install();
47 virtual bool remove();
48 virtual bool init();
49 void set_control_accepted(unsigned controls);
50 void set_status(unsigned state, unsigned pending = 0);
51 unsigned get_control_accepted();
52
53 private:
54 virtual void service_main() = 0;
55 virtual unsigned service_handler(unsigned control, unsigned event_code,
56 void *pdata) = 0;
57 //-------------------------------------------------------------------------
58 static service_impl_base*& instance();
59 //-------------------------------------------------------------------------
60 static DWORD __stdcall _service_handler(DWORD control, DWORD event,
61 void *pdata, void *pcontext);
62 static void __stdcall service_entry(DWORD argc, char **pargs);
63 virtual SERVICE_FAILURE_ACTIONSA* get_failure_actions();
64
65 private:
66 SC_HANDLE m_manager;
67 SC_HANDLE m_service;
68 SERVICE_STATUS_HANDLE m_status_handle;
69 DWORD m_accepted_control;
70};
71
73 m_manager = 0;
74 m_service = 0;
75 m_status_handle = 0;
76 m_accepted_control = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN
77 | SERVICE_ACCEPT_PAUSE_CONTINUE;
78
79 instance() = this;
80}
81//-----------------------------------------------------------------------------
83 if (m_service) {
84 ::CloseServiceHandle(m_service);
85 }
86 m_service = 0;
87 if (m_manager) {
88 ::CloseServiceHandle(m_manager);
89 }
90 m_manager = 0;
91 instance() = 0;
92}
93//-----------------------------------------------------------------------------
94inline service_impl_base*& service_impl_base::instance() {
95 static service_impl_base *pservice = NULL;
96 return pservice;
97}
98//-----------------------------------------------------------------------------
99inline
101 CHECK_AND_ASSERT(!m_service, false);
102 const char *psz_descr = get_description();
103 SERVICE_FAILURE_ACTIONSA* fail_acts = get_failure_actions();
104
105 char sz_path[MAX_PATH];
106 ::GetModuleFileNameA(0, sz_path, sizeof(sz_path));
107 ::GetShortPathNameA(sz_path, sz_path, sizeof(sz_path));
108
109 while (TRUE) {
110 if (!m_manager) {
111 m_manager = ::OpenSCManager(NULL, NULL, GENERIC_ALL);
112 if (!m_manager) {
113 int err = GetLastError();
114 LOG_ERROR(
115 "Failed to OpenSCManager(), last err="
116 << log_space::get_win32_err_descr(err));
117 break;
118 }
119 }
120 m_service = ::CreateServiceA(m_manager, get_name(), get_caption(),
121 SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_DEMAND_START,
122 SERVICE_ERROR_IGNORE, sz_path, 0, 0, 0, 0, 0);
123 if (!m_service) {
124 int err = GetLastError();
125 LOG_ERROR(
126 "Failed to CreateService(), last err="
127 << log_space::get_win32_err_descr(err));
128 break;
129 }
130
131 if (psz_descr) {
132 SERVICE_DESCRIPTIONA sd = { (char*) psz_descr };
133 if (!::ChangeServiceConfig2A(m_service, SERVICE_CONFIG_DESCRIPTION,
134 &sd)) {
135 int err = GetLastError();
136 LOG_ERROR(
137 "Failed to ChangeServiceConfig2(SERVICE_CONFIG_DESCRIPTION), last err="
138 << log_space::get_win32_err_descr(err));
139 break;
140 }
141 }
142
143 if (fail_acts) {
144 if (!::ChangeServiceConfig2A(m_service, SERVICE_CONFIG_FAILURE_ACTIONS,
145 fail_acts)) {
146 int err = GetLastError();
147 LOG_ERROR(
148 "Failed to ChangeServiceConfig2(SERVICE_CONFIG_FAILURE_ACTIONS), last err="
149 << log_space::get_win32_err_descr(err));
150 break;
151 }
152 }
153 LOG_PRINT("Installed succesfully.", LOG_LEVEL_0);
154 return true;
155 }
156 LOG_PRINT("Failed to install.", LOG_LEVEL_0);
157 return false;
158}
159//-----------------------------------------------------------------------------
160inline
162 CHECK_AND_ASSERT(!m_service, false);
163
164 while (TRUE) {
165 if (!m_manager) {
166 m_manager = ::OpenSCManager(0, 0, GENERIC_ALL);
167 if (!m_manager) {
168 int err = GetLastError();
169 LOG_ERROR(
170 "Failed to OpenSCManager(), last err="
171 << log_space::get_win32_err_descr(err));
172 break;
173 }
174 }
175
176 if (!m_service) {
177 m_service = ::OpenServiceA(m_manager, get_name(), SERVICE_STOP | DELETE);
178 if (!m_service) {
179 int err = GetLastError();
180 LOG_ERROR(
181 "Failed to OpenService(), last err="
182 << log_space::get_win32_err_descr(err));
183 break;
184 }
185 }
186
187 SERVICE_STATUS status = { };
188 if (!::ControlService(m_service, SERVICE_CONTROL_STOP, &status)) {
189 int err = ::GetLastError();
190 if (err == ERROR_SHUTDOWN_IN_PROGRESS)
191 continue;
192 else if (err != ERROR_SERVICE_NOT_ACTIVE) {
193 LOG_ERROR(
194 "Failed to ControlService(SERVICE_CONTROL_STOP), last err="
195 << log_space::get_win32_err_descr(err));
196 break;
197 }
198 }
199
200 if (!::DeleteService(m_service)) {
201 int err = ::GetLastError();
202 LOG_ERROR(
203 "Failed to ControlService(SERVICE_CONTROL_STOP), last err="
204 << log_space::get_win32_err_descr(err));
205 break;
206 }
207
208 LOG_PRINT("Removed successfully.", LOG_LEVEL_0);
209 break;
210 }
211
212 return true;
213}
214//-----------------------------------------------------------------------------
215inline
217 return true;
218}
219//-----------------------------------------------------------------------------
220inline
222 CHECK_AND_ASSERT(!m_service, false);
223
224 long error_code = 0;
225
226 SERVICE_TABLE_ENTRYA service_table[2];
227 ZeroMemory(&service_table, sizeof(service_table));
228
229 service_table->lpServiceName = (char*) get_name();
230 service_table->lpServiceProc = service_entry;
231
232 LOG_PRINT("[+] Start service control dispatcher for \"" << get_name() << "\"",
233 LOG_LEVEL_1);
234
235 error_code = 1;
236 BOOL res = ::StartServiceCtrlDispatcherA(service_table);
237 if (!res) {
238 int err = GetLastError();
239 LOG_PRINT(
240 "[+] Error starting service control dispatcher, err="
241 << log_space::get_win32_err_descr(err), LOG_LEVEL_1);
242 return false;
243 } else {
244 LOG_PRINT("[+] End service control dispatcher for \"" << get_name() << "\"",
245 LOG_LEVEL_1);
246 }
247 return true;
248}
249//-----------------------------------------------------------------------------
250inline DWORD __stdcall service_impl_base::_service_handler(DWORD control,
251 DWORD event, void *pdata, void *pcontext) {
252 CHECK_AND_ASSERT(pcontext, ERROR_CALL_NOT_IMPLEMENTED);
253
254 service_impl_base *pservice = (service_impl_base*) pcontext;
255 return pservice->service_handler(control, event, pdata);
256}
257//-----------------------------------------------------------------------------
258inline
259void __stdcall service_impl_base::service_entry(DWORD argc, char **pargs) {
260 service_impl_base *pme = instance();
261 LOG_PRINT("instance: " << pme, LOG_LEVEL_4);
262 if (!pme) {
263 LOG_ERROR("Error: at service_entry() pme = NULL");
264 return;
265 }
266 pme->m_status_handle = ::RegisterServiceCtrlHandlerExA(pme->get_name(),
267 _service_handler, pme);
268
269 pme->set_status(SERVICE_RUNNING);
270 pme->service_main();
271 pme->set_status(SERVICE_STOPPED);
272}
273//-----------------------------------------------------------------------------
274inline
276 if (!m_status_handle)
277 return;
278
279 SERVICE_STATUS status = { 0 };
280 status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
281 status.dwCurrentState = state;
282 status.dwControlsAccepted = m_accepted_control;
283 /*status.dwWin32ExitCode = NO_ERROR;
284 status.dwServiceSpecificExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
285 status.dwCheckPoint = 0;
286 status.dwWaitHint = 0;
287
288 status.dwCurrentState = state;*/
289
290 if (state == SERVICE_START_PENDING || state == SERVICE_STOP_PENDING
291 || state == SERVICE_CONTINUE_PENDING || state == SERVICE_PAUSE_PENDING) {
292 status.dwWaitHint = 2000;
293 status.dwCheckPoint = pending;
294 }
295 ::SetServiceStatus(m_status_handle, &status);
296}
297//-----------------------------------------------------------------------------------------
298inline
300 m_accepted_control = controls;
301}
302//-----------------------------------------------------------------------------------------
303inline
305 return m_accepted_control;
306}
307//-----------------------------------------------------------------------------------------
308inline SERVICE_FAILURE_ACTIONSA* service_impl_base::get_failure_actions() {
309 // first 3 failures in 30 minutes. Service will be restarted.
310 // do nothing for next failures
311 static SC_ACTION sa[] = { { SC_ACTION_RESTART, 3 * 1000 }, {
312 SC_ACTION_RESTART, 3 * 1000 }, { SC_ACTION_RESTART, 3 * 1000 }, {
313 SC_ACTION_NONE, 0 } };
314
315 static SERVICE_FAILURE_ACTIONSA sfa = { 1800, // interval for failures counter - 30 min
316 "", NULL, 4, (SC_ACTION*) &sa };
317
318 // TODO: refactor this code, really unsafe!
319 return &sfa;
320}
321}
322
323#endif //_SERVICE_IMPL_BASE_H_
void set_status(unsigned state, unsigned pending=0)
virtual const char * get_name()=0
virtual const char * get_description()=0
virtual const char * get_caption()=0
void set_control_accepted(unsigned controls)
const char * res
#define LOG_ERROR(x)
Definition misc_log_ex.h:98
#define CHECK_AND_ASSERT(expr, fail_ret_val)