Imported Upstream version 0.3.2
[anytun.git] / src / win32 / winService.cpp
1 /*\r
2  *  anytun\r
3  *\r
4  *  The secure anycast tunneling protocol (satp) defines a protocol used\r
5  *  for communication between any combination of unicast and anycast\r
6  *  tunnel endpoints.  It has less protocol overhead than IPSec in Tunnel\r
7  *  mode and allows tunneling of every ETHER TYPE protocol (e.g.\r
8  *  ethernet, ip, arp ...). satp directly includes cryptography and\r
9  *  message authentication based on the methodes used by SRTP.  It is\r
10  *  intended to deliver a generic, scaleable and secure solution for\r
11  *  tunneling and relaying of packets of any protocol.\r
12  *\r
13  *\r
14  *  Copyright (C) 2007-2009 Othmar Gsenger, Erwin Nindl, \r
15  *                          Christian Pointner <satp@wirdorange.org>\r
16  *\r
17  *  This file is part of Anytun.\r
18  *\r
19  *  Anytun is free software: you can redistribute it and/or modify\r
20  *  it under the terms of the GNU General Public License as published by\r
21  *  the Free Software Foundation, either version 3 of the License, or\r
22  *  any later version.\r
23  *\r
24  *  Anytun is distributed in the hope that it will be useful,\r
25  *  but WITHOUT ANY WARRANTY; without even the implied warranty of\r
26  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
27  *  GNU General Public License for more details.\r
28  *\r
29  *  You should have received a copy of the GNU General Public License\r
30  *  along with anytun.  If not, see <http://www.gnu.org/licenses/>.\r
31  */\r
32 \r
33 #ifdef WIN_SERVICE\r
34 \r
35 #include <iostream>\r
36 \r
37 #include <windows.h>\r
38 \r
39 #include "winService.h"\r
40 #include "../log.h"\r
41 #include "../anytunError.h"\r
42 #include "../threadUtils.hpp"\r
43 \r
44 WinService* WinService::inst = NULL;\r
45 Mutex WinService::instMutex;\r
46 WinService& gWinService = WinService::instance();\r
47 \r
48 WinService& WinService::instance()\r
49 {\r
50         Lock lock(instMutex);\r
51         static instanceCleaner c;\r
52         if(!inst)\r
53                 inst = new WinService();\r
54         \r
55         return *inst;\r
56 }\r
57 \r
58 WinService::~WinService()\r
59 {\r
60   if(started_)\r
61     CloseHandle(stop_event_);\r
62 }\r
63 \r
64 void WinService::install()\r
65 {\r
66   SC_HANDLE schSCManager;\r
67   SC_HANDLE schService;\r
68   char szPath[MAX_PATH];\r
69 \r
70   if(!GetModuleFileNameA(NULL, szPath, MAX_PATH))\r
71     AnytunError::throwErr() << "Error on GetModuleFileName: " << AnytunErrno(GetLastError());\r
72 \r
73   schSCManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);\r
74   if(NULL == schSCManager)\r
75     AnytunError::throwErr() << "Error on OpenSCManager: " << AnytunErrno(GetLastError());\r
76 \r
77   schService = CreateServiceA(schSCManager, SVC_NAME, SVC_NAME, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, \r
78                               SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL, szPath, NULL, NULL, NULL, NULL, NULL);\r
79   if(schService == NULL) {\r
80     CloseServiceHandle(schSCManager);\r
81     AnytunError::throwErr() << "Error on CreateService: " << AnytunErrno(GetLastError());\r
82   }\r
83 \r
84   std::cout << "Service installed successfully" << std::endl; \r
85 \r
86   CloseServiceHandle(schService); \r
87   CloseServiceHandle(schSCManager);\r
88 }\r
89 \r
90 void WinService::uninstall()\r
91 {\r
92   SC_HANDLE schSCManager;\r
93   SC_HANDLE schService;\r
94 \r
95   schSCManager = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);\r
96   if(NULL == schSCManager)\r
97     AnytunError::throwErr() << "Error on OpenSCManager: " << AnytunErrno(GetLastError());\r
98 \r
99   schService = OpenServiceA(schSCManager, SVC_NAME, SERVICE_ALL_ACCESS);\r
100   if(schService == NULL) {\r
101     CloseServiceHandle(schSCManager);\r
102     AnytunError::throwErr() << "Error on CreateService: " << AnytunErrno(GetLastError());\r
103   }\r
104 \r
105   if(!DeleteService(schService)) {\r
106     CloseServiceHandle(schService); \r
107     CloseServiceHandle(schSCManager);\r
108     AnytunError::throwErr() << "Error on DeleteService: " << AnytunErrno(GetLastError());\r
109   }\r
110 \r
111   std::cout << "Service uninstalled successfully" << std::endl; \r
112 \r
113   CloseServiceHandle(schService); \r
114   CloseServiceHandle(schSCManager);\r
115 }\r
116 \r
117 void WinService::start()\r
118 {\r
119   SERVICE_TABLE_ENTRY DispatchTable[] = {\r
120     {SVC_NAME, (LPSERVICE_MAIN_FUNCTION)WinService::main },\r
121     {NULL, NULL}\r
122   };\r
123 \r
124   if(!StartServiceCtrlDispatcherA(DispatchTable))\r
125     AnytunError::throwErr() << "Error on StartServiceCtrlDispatcher: " << AnytunErrno(GetLastError());\r
126 }\r
127 \r
128 void WinService::waitForStop()\r
129 {\r
130   if(!started_)\r
131     AnytunError::throwErr() << "Service not started correctly";\r
132   \r
133   reportStatus(SERVICE_RUNNING, NO_ERROR);\r
134   WaitForSingleObject(stop_event_, INFINITE);\r
135   reportStatus(SERVICE_STOP_PENDING, NO_ERROR);\r
136   cLog.msg(Log::PRIO_NOTICE) << "WinService received stop signal, exitting";\r
137 }\r
138 \r
139 void WinService::stop()\r
140 {\r
141   if(!started_)\r
142     AnytunError::throwErr() << "Service not started correctly";\r
143 \r
144   reportStatus(SERVICE_STOPPED, NO_ERROR);\r
145 }\r
146 \r
147 int real_main(int argc, char* argv[]);\r
148 \r
149 VOID WINAPI WinService::main(DWORD dwArgc, LPTSTR *lpszArgv)\r
150 {\r
151   if(gWinService.started_) {\r
152     cLog.msg(Log::PRIO_ERROR) << "Service is already running";\r
153     return;\r
154   }\r
155 \r
156   gWinService.status_handle_ = RegisterServiceCtrlHandlerA(SVC_NAME, WinService::ctrlHandler);\r
157   if(!gWinService.status_handle_) { \r
158     cLog.msg(Log::PRIO_ERROR) << "Error on RegisterServiceCtrlHandler: " << AnytunErrno(GetLastError());\r
159     return;\r
160   }\r
161   gWinService.status_.dwServiceType = SERVICE_WIN32_OWN_PROCESS; \r
162   gWinService.status_.dwServiceSpecificExitCode = 0;    \r
163   gWinService.reportStatus(SERVICE_START_PENDING, NO_ERROR);\r
164   gWinService.started_ = true;\r
165   \r
166   gWinService.stop_event_ = CreateEvent(NULL, true, false, NULL);\r
167   if(!gWinService.stop_event_) {\r
168     cLog.msg(Log::PRIO_ERROR) << "WinService Error on CreateEvent: " << AnytunErrno(GetLastError());\r
169     gWinService.reportStatus(SERVICE_STOPPED, -1);\r
170     return;\r
171   }\r
172 \r
173   real_main(dwArgc, lpszArgv);\r
174 }\r
175 \r
176 VOID WINAPI WinService::ctrlHandler(DWORD dwCtrl)\r
177 {\r
178   switch(dwCtrl) {\r
179     case SERVICE_CONTROL_STOP: {\r
180       gWinService.reportStatus(SERVICE_STOP_PENDING, NO_ERROR);\r
181       SetEvent(gWinService.stop_event_);\r
182       return;\r
183     }\r
184     case SERVICE_CONTROL_INTERROGATE: break;\r
185     default: break;\r
186   }\r
187   gWinService.reportStatus(gWinService.status_.dwCurrentState, NO_ERROR);\r
188 }\r
189 \r
190 void WinService::reportStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)\r
191 {\r
192   static DWORD dwCheckPoint = 1;\r
193 \r
194   status_.dwCurrentState = dwCurrentState;\r
195   status_.dwWin32ExitCode = dwWin32ExitCode;\r
196   status_.dwWaitHint = dwWaitHint;\r
197 \r
198   if((dwCurrentState == SERVICE_START_PENDING) ||\r
199      (dwCurrentState == SERVICE_STOP_PENDING))\r
200     status_.dwControlsAccepted = 0;\r
201   else \r
202     status_.dwControlsAccepted = SERVICE_ACCEPT_STOP;\r
203 \r
204   if((dwCurrentState == SERVICE_RUNNING) ||\r
205      (dwCurrentState == SERVICE_STOPPED))\r
206     status_.dwCheckPoint = 0;\r
207   else\r
208     status_.dwCheckPoint = dwCheckPoint++;\r
209 \r
210   SetServiceStatus(status_handle_, &status_);\r
211 }\r
212 \r
213 #endif\r