Win32Service.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. #ifdef _WIN32
  2. #define _CRT_SECURE_NO_WARNINGS // to use freopen
  3. #endif
  4. #include "Win32Service.h"
  5. #include <assert.h>
  6. #include <strsafe.h>
  7. #include <windows.h>
  8. #include "Daemon.h"
  9. #include "Log.h"
  10. I2PService *I2PService::s_service = NULL;
  11. BOOL I2PService::isService()
  12. {
  13. BOOL bIsService = FALSE;
  14. HWINSTA hWinStation = GetProcessWindowStation();
  15. if (hWinStation != NULL)
  16. {
  17. USEROBJECTFLAGS uof = { 0 };
  18. if (GetUserObjectInformation(hWinStation, UOI_FLAGS, &uof, sizeof(USEROBJECTFLAGS), NULL) && ((uof.dwFlags & WSF_VISIBLE) == 0))
  19. {
  20. bIsService = TRUE;
  21. }
  22. }
  23. return bIsService;
  24. }
  25. BOOL I2PService::Run(I2PService &service)
  26. {
  27. s_service = &service;
  28. SERVICE_TABLE_ENTRY serviceTable[] =
  29. {
  30. { service.m_name, ServiceMain },
  31. { NULL, NULL }
  32. };
  33. return StartServiceCtrlDispatcher(serviceTable);
  34. }
  35. void WINAPI I2PService::ServiceMain(DWORD dwArgc, PSTR *pszArgv)
  36. {
  37. assert(s_service != NULL);
  38. s_service->m_statusHandle = RegisterServiceCtrlHandler(
  39. s_service->m_name, ServiceCtrlHandler);
  40. if (s_service->m_statusHandle == NULL)
  41. {
  42. throw GetLastError();
  43. }
  44. s_service->Start(dwArgc, pszArgv);
  45. }
  46. void WINAPI I2PService::ServiceCtrlHandler(DWORD dwCtrl)
  47. {
  48. switch (dwCtrl)
  49. {
  50. case SERVICE_CONTROL_STOP: s_service->Stop(); break;
  51. case SERVICE_CONTROL_PAUSE: s_service->Pause(); break;
  52. case SERVICE_CONTROL_CONTINUE: s_service->Continue(); break;
  53. case SERVICE_CONTROL_SHUTDOWN: s_service->Shutdown(); break;
  54. case SERVICE_CONTROL_INTERROGATE: break;
  55. default: break;
  56. }
  57. }
  58. I2PService::I2PService(PSTR pszServiceName,
  59. BOOL fCanStop,
  60. BOOL fCanShutdown,
  61. BOOL fCanPauseContinue)
  62. {
  63. m_name = (pszServiceName == NULL) ? (PSTR)"" : pszServiceName;
  64. m_statusHandle = NULL;
  65. m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
  66. m_status.dwCurrentState = SERVICE_START_PENDING;
  67. DWORD dwControlsAccepted = 0;
  68. if (fCanStop)
  69. dwControlsAccepted |= SERVICE_ACCEPT_STOP;
  70. if (fCanShutdown)
  71. dwControlsAccepted |= SERVICE_ACCEPT_SHUTDOWN;
  72. if (fCanPauseContinue)
  73. dwControlsAccepted |= SERVICE_ACCEPT_PAUSE_CONTINUE;
  74. m_status.dwControlsAccepted = dwControlsAccepted;
  75. m_status.dwWin32ExitCode = NO_ERROR;
  76. m_status.dwServiceSpecificExitCode = 0;
  77. m_status.dwCheckPoint = 0;
  78. m_status.dwWaitHint = 0;
  79. m_fStopping = FALSE;
  80. // Create a manual-reset event that is not signaled at first to indicate
  81. // the stopped signal of the service.
  82. m_hStoppedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  83. if (m_hStoppedEvent == NULL)
  84. {
  85. throw GetLastError();
  86. }
  87. }
  88. I2PService::~I2PService(void)
  89. {
  90. if (m_hStoppedEvent)
  91. {
  92. CloseHandle(m_hStoppedEvent);
  93. m_hStoppedEvent = NULL;
  94. }
  95. }
  96. void I2PService::Start(DWORD dwArgc, PSTR *pszArgv)
  97. {
  98. try
  99. {
  100. SetServiceStatus(SERVICE_START_PENDING);
  101. OnStart(dwArgc, pszArgv);
  102. SetServiceStatus(SERVICE_RUNNING);
  103. }
  104. catch (DWORD dwError)
  105. {
  106. LogPrint(eLogError, "Win32Service Start", dwError);
  107. SetServiceStatus(SERVICE_STOPPED, dwError);
  108. }
  109. catch (...)
  110. {
  111. LogPrint(eLogError, "Win32Service failed to start.", EVENTLOG_ERROR_TYPE);
  112. SetServiceStatus(SERVICE_STOPPED);
  113. }
  114. }
  115. void I2PService::OnStart(DWORD dwArgc, PSTR *pszArgv)
  116. {
  117. LogPrint(eLogInfo, "Win32Service in OnStart", EVENTLOG_INFORMATION_TYPE);
  118. Daemon.start();
  119. //i2p::util::config::OptionParser(dwArgc, pszArgv);
  120. //i2p::util::filesystem::ReadConfigFile(i2p::util::config::mapArgs, i2p::util::config::mapMultiArgs);
  121. //i2p::context.OverrideNTCPAddress(i2p::util::config::GetCharArg("-host", "127.0.0.1"),
  122. // i2p::util::config::GetArg("-port", 17070));
  123. _worker = new std::thread(std::bind(&I2PService::WorkerThread, this));
  124. }
  125. void I2PService::WorkerThread()
  126. {
  127. while (!m_fStopping)
  128. {
  129. ::Sleep(1000); // Simulate some lengthy operations.
  130. }
  131. // Signal the stopped event.
  132. SetEvent(m_hStoppedEvent);
  133. }
  134. void I2PService::Stop()
  135. {
  136. DWORD dwOriginalState = m_status.dwCurrentState;
  137. try
  138. {
  139. SetServiceStatus(SERVICE_STOP_PENDING);
  140. OnStop();
  141. SetServiceStatus(SERVICE_STOPPED);
  142. }
  143. catch (DWORD dwError)
  144. {
  145. LogPrint(eLogInfo, "Win32Service Stop", dwError);
  146. SetServiceStatus(dwOriginalState);
  147. }
  148. catch (...)
  149. {
  150. LogPrint(eLogError, "Win32Service failed to stop.", EVENTLOG_ERROR_TYPE);
  151. SetServiceStatus(dwOriginalState);
  152. }
  153. }
  154. void I2PService::OnStop()
  155. {
  156. // Log a service stop message to the Application log.
  157. LogPrint(eLogInfo, "Win32Service in OnStop", EVENTLOG_INFORMATION_TYPE);
  158. Daemon.stop();
  159. m_fStopping = TRUE;
  160. if (WaitForSingleObject(m_hStoppedEvent, INFINITE) != WAIT_OBJECT_0)
  161. {
  162. throw GetLastError();
  163. }
  164. _worker->join();
  165. delete _worker;
  166. }
  167. void I2PService::Pause()
  168. {
  169. try
  170. {
  171. SetServiceStatus(SERVICE_PAUSE_PENDING);
  172. OnPause();
  173. SetServiceStatus(SERVICE_PAUSED);
  174. }
  175. catch (DWORD dwError)
  176. {
  177. LogPrint(eLogError, "Win32Service Pause", dwError);
  178. SetServiceStatus(SERVICE_RUNNING);
  179. }
  180. catch (...)
  181. {
  182. LogPrint(eLogError, "Win32Service failed to pause.", EVENTLOG_ERROR_TYPE);
  183. SetServiceStatus(SERVICE_RUNNING);
  184. }
  185. }
  186. void I2PService::OnPause()
  187. {
  188. }
  189. void I2PService::Continue()
  190. {
  191. try
  192. {
  193. SetServiceStatus(SERVICE_CONTINUE_PENDING);
  194. OnContinue();
  195. SetServiceStatus(SERVICE_RUNNING);
  196. }
  197. catch (DWORD dwError)
  198. {
  199. LogPrint(eLogError, "Win32Service Continue", dwError);
  200. SetServiceStatus(SERVICE_PAUSED);
  201. }
  202. catch (...)
  203. {
  204. LogPrint(eLogError, "Win32Service failed to resume.", EVENTLOG_ERROR_TYPE);
  205. SetServiceStatus(SERVICE_PAUSED);
  206. }
  207. }
  208. void I2PService::OnContinue()
  209. {
  210. }
  211. void I2PService::Shutdown()
  212. {
  213. try
  214. {
  215. OnShutdown();
  216. SetServiceStatus(SERVICE_STOPPED);
  217. }
  218. catch (DWORD dwError)
  219. {
  220. LogPrint(eLogError, "Win32Service Shutdown", dwError);
  221. }
  222. catch (...)
  223. {
  224. LogPrint(eLogError, "Win32Service failed to shut down.", EVENTLOG_ERROR_TYPE);
  225. }
  226. }
  227. void I2PService::OnShutdown()
  228. {
  229. }
  230. void I2PService::SetServiceStatus(DWORD dwCurrentState,
  231. DWORD dwWin32ExitCode,
  232. DWORD dwWaitHint)
  233. {
  234. static DWORD dwCheckPoint = 1;
  235. m_status.dwCurrentState = dwCurrentState;
  236. m_status.dwWin32ExitCode = dwWin32ExitCode;
  237. m_status.dwWaitHint = dwWaitHint;
  238. m_status.dwCheckPoint =
  239. ((dwCurrentState == SERVICE_RUNNING) ||
  240. (dwCurrentState == SERVICE_STOPPED)) ?
  241. 0 : dwCheckPoint++;
  242. ::SetServiceStatus(m_statusHandle, &m_status);
  243. }
  244. //*****************************************************************************
  245. void FreeHandles(SC_HANDLE schSCManager, SC_HANDLE schService)
  246. {
  247. if (schSCManager)
  248. {
  249. CloseServiceHandle(schSCManager);
  250. schSCManager = NULL;
  251. }
  252. if (schService)
  253. {
  254. CloseServiceHandle(schService);
  255. schService = NULL;
  256. }
  257. }
  258. void InstallService(PCSTR pszServiceName, PCSTR pszDisplayName, DWORD dwStartType, PCSTR pszDependencies, PCSTR pszAccount, PCSTR pszPassword)
  259. {
  260. printf("Try to install Win32Service (%s).\n", pszServiceName);
  261. char szPath[MAX_PATH];
  262. SC_HANDLE schSCManager = NULL;
  263. SC_HANDLE schService = NULL;
  264. if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)) == 0)
  265. {
  266. printf("GetModuleFileName failed w/err 0x%08lx\n", GetLastError());
  267. FreeHandles(schSCManager, schService);
  268. return;
  269. }
  270. char SvcOpt[] = " --daemon";
  271. strncat(szPath, SvcOpt, strlen(SvcOpt));
  272. // Open the local default service control manager database
  273. schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);
  274. if (schSCManager == NULL)
  275. {
  276. printf("OpenSCManager failed w/err 0x%08lx\n", GetLastError());
  277. FreeHandles(schSCManager, schService);
  278. return;
  279. }
  280. // Install the service into SCM by calling CreateService
  281. schService = CreateService(
  282. schSCManager, // SCManager database
  283. pszServiceName, // Name of service
  284. pszDisplayName, // Name to display
  285. SERVICE_QUERY_STATUS, // Desired access
  286. SERVICE_WIN32_OWN_PROCESS, // Service type
  287. dwStartType, // Service start type
  288. SERVICE_ERROR_NORMAL, // Error control type
  289. szPath, // Service's binary
  290. NULL, // No load ordering group
  291. NULL, // No tag identifier
  292. pszDependencies, // Dependencies
  293. pszAccount, // Service running account
  294. pszPassword // Password of the account
  295. );
  296. if (schService == NULL)
  297. {
  298. printf("CreateService failed w/err 0x%08lx\n", GetLastError());
  299. FreeHandles(schSCManager, schService);
  300. return;
  301. }
  302. printf("Win32Service is installed as %s.\n", pszServiceName);
  303. // Centralized cleanup for all allocated resources.
  304. FreeHandles(schSCManager, schService);
  305. }
  306. void UninstallService(PCSTR pszServiceName)
  307. {
  308. printf("Try to uninstall Win32Service (%s).\n", pszServiceName);
  309. SC_HANDLE schSCManager = NULL;
  310. SC_HANDLE schService = NULL;
  311. SERVICE_STATUS ssSvcStatus = {};
  312. // Open the local default service control manager database
  313. schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  314. if (schSCManager == NULL)
  315. {
  316. printf("OpenSCManager failed w/err 0x%08lx\n", GetLastError());
  317. FreeHandles(schSCManager, schService);
  318. return;
  319. }
  320. // Open the service with delete, stop, and query status permissions
  321. schService = OpenService(schSCManager, pszServiceName, SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE);
  322. if (schService == NULL)
  323. {
  324. printf("OpenService failed w/err 0x%08lx\n", GetLastError());
  325. FreeHandles(schSCManager, schService);
  326. return;
  327. }
  328. // Try to stop the service
  329. if (ControlService(schService, SERVICE_CONTROL_STOP, &ssSvcStatus))
  330. {
  331. printf("Stopping %s.\n", pszServiceName);
  332. Sleep(1000);
  333. while (QueryServiceStatus(schService, &ssSvcStatus))
  334. {
  335. if (ssSvcStatus.dwCurrentState == SERVICE_STOP_PENDING)
  336. {
  337. printf(".");
  338. Sleep(1000);
  339. }
  340. else break;
  341. }
  342. if (ssSvcStatus.dwCurrentState == SERVICE_STOPPED)
  343. {
  344. printf("\n%s is stopped.\n", pszServiceName);
  345. }
  346. else
  347. {
  348. printf("\n%s failed to stop.\n", pszServiceName);
  349. }
  350. }
  351. // Now remove the service by calling DeleteService.
  352. if (!DeleteService(schService))
  353. {
  354. printf("DeleteService failed w/err 0x%08lx\n", GetLastError());
  355. FreeHandles(schSCManager, schService);
  356. return;
  357. }
  358. printf("%s is removed.\n", pszServiceName);
  359. // Centralized cleanup for all allocated resources.
  360. FreeHandles(schSCManager, schService);
  361. }