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