Electroneum
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 
43 namespace 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(
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(
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
std::vector< std::vector< _variant_t > > table
::std::string string
Definition: gtest-port.h:1097
const char * name
const T & move(const T &t)
Definition: gtest-port.h:1317
connection< TProtocol > & operator=(const connection< TProtocol > &obj)
bool uninstall_service(std::string const &service_name)