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