Electroneum
Loading...
Searching...
No Matches
windows_service_runner.h
Go to the documentation of this file.
1// Copyrights(c) 2017-2021, The Electroneum Project
2// Copyrights(c) 2014-2019, The Monero Project
3//
4// All rights reserved.
5//
6// Redistribution and use in source and binary forms, with or without modification, are
7// permitted provided that the following conditions are met:
8//
9// 1. Redistributions of source code must retain the above copyright notice, this list of
10// conditions and the following disclaimer.
11//
12// 2. Redistributions in binary form must reproduce the above copyright notice, this list
13// of conditions and the following disclaimer in the documentation and/or other
14// materials provided with the distribution.
15//
16// 3. Neither the name of the copyright holder nor the names of its contributors may be
17// used to endorse or promote products derived from this software without specific
18// prior written permission.
19//
20// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
21// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
23// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
25// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
27// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
28// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30#pragma once
31
32#ifdef WIN32
33
34#undef UNICODE
35#undef _UNICODE
36
38#include <memory>
39#include <string>
40#include <vector>
41#include <windows.h>
42
43namespace windows {
44 namespace
45 {
46 std::vector<char> vecstring(std::string const & str)
47 {
48 std::vector<char> result{str.begin(), str.end()};
49 result.push_back('\0');
50 return result;
51 }
52 }
53
54 template <typename T_handler>
55 class t_service_runner final
56 {
57 private:
58 SERVICE_STATUS_HANDLE m_status_handle{nullptr};
59 SERVICE_STATUS m_status{};
60 boost::mutex m_lock{};
61 std::string m_name;
62 T_handler m_handler;
63
64 static std::unique_ptr<t_service_runner<T_handler>> sp_instance;
65 public:
66 t_service_runner(
67 std::string name
68 , T_handler handler
69 )
70 : m_name{std::move(name)}
71 , m_handler{std::move(handler)}
72 {
73 m_status.dwServiceType = SERVICE_WIN32;
74 m_status.dwCurrentState = SERVICE_STOPPED;
75 m_status.dwControlsAccepted = 0;
76 m_status.dwWin32ExitCode = NO_ERROR;
77 m_status.dwServiceSpecificExitCode = NO_ERROR;
78 m_status.dwCheckPoint = 0;
79 m_status.dwWaitHint = 0;
80 }
81
82 t_service_runner & operator=(t_service_runner && other)
83 {
84 if (this != &other)
85 {
86 m_status_handle = std::move(other.m_status_handle);
87 m_status = std::move(other.m_status);
88 m_name = std::move(other.m_name);
89 m_handler = std::move(other.m_handler);
90 }
91 return *this;
92 }
93
94 static void run(
95 std::string name
96 , T_handler handler
97 )
98 {
99 sp_instance.reset(new t_service_runner<T_handler>{
100 std::move(name)
101 , std::move(handler)
102 });
103
104 sp_instance->run_();
105 }
106
107 private:
108 void run_()
109 {
110 SERVICE_TABLE_ENTRY table[] =
111 {
112 { vecstring(m_name).data(), &service_main }
113 , { 0, 0 }
114 };
115
116 StartServiceCtrlDispatcher(table);
117 }
118
119 void report_status(DWORD status)
120 {
121 m_status.dwCurrentState = status;
122 if (status == SERVICE_RUNNING)
123 {
124 m_status.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
125 }
126 else if(status == SERVICE_STOP_PENDING)
127 {
128 m_status.dwControlsAccepted = 0;
129 }
130 SetServiceStatus(m_status_handle, &m_status);
131 }
132
133 static void WINAPI service_main(DWORD argc, LPSTR * argv)
134 {
135 sp_instance->service_main_(argc, argv);
136 }
137
138 void service_main_(DWORD argc, LPSTR * argv)
139 {
140 m_status_handle = RegisterServiceCtrlHandler(m_name.c_str(), &on_state_change_request);
141 if (m_status_handle == nullptr) return;
142
143 report_status(SERVICE_START_PENDING);
144
145 report_status(SERVICE_RUNNING);
146
147 m_handler.run();
148
149 on_state_change_request_(SERVICE_CONTROL_STOP);
150
151 // Ensure that the service is uninstalled
152 uninstall_service(m_name);
153 }
154
155 static void WINAPI on_state_change_request(DWORD control_code)
156 {
157 sp_instance->on_state_change_request_(control_code);
158 }
159
160 void on_state_change_request_(DWORD control_code)
161 {
162 switch (control_code)
163 {
164 case SERVICE_CONTROL_INTERROGATE:
165 break;
166 case SERVICE_CONTROL_SHUTDOWN:
167 case SERVICE_CONTROL_STOP:
168 report_status(SERVICE_STOP_PENDING);
169 m_handler.stop();
170 report_status(SERVICE_STOPPED);
171 break;
172 case SERVICE_CONTROL_PAUSE:
173 break;
174 case SERVICE_CONTROL_CONTINUE:
175 break;
176 default:
177 break;
178 }
179 }
180 };
181
182 template <typename T_handler>
183 std::unique_ptr<t_service_runner<T_handler>> t_service_runner<T_handler>::sp_instance;
184}
185
186#endif
connection< TProtocol > & operator=(const connection< TProtocol > &obj)
const char * name
std::vector< std::vector< _variant_t > > table
const T & move(const T &t)
bool uninstall_service(std::string const &service_name)