Imported Upstream version 0.3
[anytun.git] / src / signalController.cpp
1 /*
2  *  anytun
3  *
4  *  The secure anycast tunneling protocol (satp) defines a protocol used
5  *  for communication between any combination of unicast and anycast
6  *  tunnel endpoints.  It has less protocol overhead than IPSec in Tunnel
7  *  mode and allows tunneling of every ETHER TYPE protocol (e.g.
8  *  ethernet, ip, arp ...). satp directly includes cryptography and
9  *  message authentication based on the methodes used by SRTP.  It is
10  *  intended to deliver a generic, scaleable and secure solution for
11  *  tunneling and relaying of packets of any protocol.
12  *
13  *
14  *  Copyright (C) 2007-2008 Othmar Gsenger, Erwin Nindl, 
15  *                          Christian Pointner <satp@wirdorange.org>
16  *
17  *  This file is part of Anytun.
18  *
19  *  Anytun is free software: you can redistribute it and/or modify
20  *  it under the terms of the GNU General Public License version 3 as
21  *  published by the Free Software Foundation.
22  *
23  *  Anytun is distributed in the hope that it will be useful,
24  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
25  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26  *  GNU General Public License for more details.
27  *
28  *  You should have received a copy of the GNU General Public License
29  *  along with anytun.  If not, see <http://www.gnu.org/licenses/>.
30  */
31
32 #include <map>
33 #include <iostream>
34
35 #include "signalController.h"
36 #include "log.h"
37 #include "anytunError.h"
38 #include "threadUtils.hpp"
39
40 #ifndef _MSC_VER
41 #include <csignal>
42 #include <boost/bind.hpp>
43 #else
44 #include <windows.h>
45 #endif
46
47 SignalController* SignalController::inst = NULL;
48 Mutex SignalController::instMutex;
49 SignalController& gSignalController = SignalController::instance();
50
51 SignalController& SignalController::instance()
52 {
53         Lock lock(instMutex);
54         static instanceCleaner c;
55         if(!inst)
56                 inst = new SignalController();
57
58         return *inst;
59 }
60
61 int SigErrorHandler::handle(const std::string& msg)
62 {
63   AnytunError::throwErr() << msg;
64
65   return 0;
66 }
67
68 #ifndef _MSC_VER
69
70 int SigIntHandler::handle()
71 {
72   cLog.msg(Log::PRIO_NOTICE) << "SIG-Int caught, exiting";
73
74   return 1;
75 }
76
77 int SigQuitHandler::handle()
78 {
79   cLog.msg(Log::PRIO_NOTICE) << "SIG-Quit caught, exiting";
80
81   return 1;
82 }
83
84 int SigHupHandler::handle()
85 {
86   cLog.msg(Log::PRIO_NOTICE) << "SIG-Hup caught";
87
88   return 0;
89 }
90
91 int SigTermHandler::handle()
92 {
93   cLog.msg(Log::PRIO_NOTICE) << "SIG-Term caughtm, exiting";
94
95   return 1;
96 }
97
98 int SigUsr1Handler::handle()
99 {
100   cLog.msg(Log::PRIO_NOTICE) << "SIG-Usr1 caught";
101
102   return 0;
103 }
104
105 int SigUsr2Handler::handle()
106 {
107   cLog.msg(Log::PRIO_NOTICE) << "SIG-Usr2 caught";
108
109   return 0;
110 }
111 #else
112 int CtrlCHandler::handle()
113 {
114   cLog.msg(Log::PRIO_NOTICE) << "CTRL-C Event received, exitting";
115
116   return 1;
117 }
118
119 int CtrlBreakHandler::handle()
120 {
121   cLog.msg(Log::PRIO_NOTICE) << "CTRL-Break Event received, ignoring";
122
123   return 0;
124 }
125
126 int CtrlCloseHandler::handle()
127 {
128   cLog.msg(Log::PRIO_NOTICE) << "Close Event received, exitting";
129
130   return 1;
131 }
132
133 int CtrlLogoffHandler::handle()
134 {
135   cLog.msg(Log::PRIO_NOTICE) << "LogOff Event received, exitting";
136
137   return 1;
138 }
139
140 int CtrlShutdownHandler::handle()
141 {
142   cLog.msg(Log::PRIO_NOTICE) << "Shutdown Event received, exitting";
143
144   return 1;
145 }
146 #endif
147
148 SignalController::~SignalController() 
149 {
150   for(HandlerMap::iterator it = handler.begin(); it != handler.end(); ++it)
151     delete it->second;
152
153 #ifndef _MSC_VER
154   if(thread) delete thread;
155 #endif
156 }
157
158 #ifndef _MSC_VER
159 void SignalController::handle()
160 {
161   sigset_t signal_set;
162   int sigNum;
163
164   while(1) 
165   {
166     sigfillset(&signal_set);
167     sigwait(&signal_set, &sigNum);
168     inject(sigNum);
169   }
170 }
171 #else
172 bool SignalController::handle(DWORD ctrlType)
173 {
174   gSignalController.inject(ctrlType);
175   return true;
176 }
177 #endif
178
179 void SignalController::init()
180 {
181 #ifndef _MSC_VER
182   sigset_t signal_set;
183   
184   sigfillset(&signal_set);        
185   sigdelset(&signal_set, SIGCHLD);
186   sigdelset(&signal_set, SIGSEGV);
187   sigdelset(&signal_set, SIGBUS);
188   sigdelset(&signal_set, SIGFPE);
189
190 #if defined(BOOST_HAS_PTHREADS)
191   pthread_sigmask(SIG_BLOCK, &signal_set, NULL);
192 #else
193 #error The signalhandler works only with pthreads
194 #endif
195   
196   thread = new boost::thread(boost::bind(&SignalController::handle, this));
197
198   handler[SIGINT] = new SigIntHandler;
199   handler[SIGQUIT] = new SigQuitHandler;
200   handler[SIGHUP] = new SigHupHandler;
201   handler[SIGTERM] = new SigTermHandler;
202   handler[SIGUSR1] = new SigUsr1Handler;
203   handler[SIGUSR2] = new SigUsr2Handler;
204 #else
205   if(!SetConsoleCtrlHandler((PHANDLER_ROUTINE)SignalController::handle, true))
206     AnytunError::throwErr() << "Error on SetConsoleCtrlhandler: " << AnytunErrno(GetLastError());
207
208   handler[CTRL_C_EVENT] = new CtrlCHandler;
209   handler[CTRL_BREAK_EVENT] = new CtrlBreakHandler;
210   handler[CTRL_CLOSE_EVENT] = new CtrlCloseHandler;
211   handler[CTRL_LOGOFF_EVENT] = new CtrlLogoffHandler;
212   handler[CTRL_SHUTDOWN_EVENT] = new CtrlShutdownHandler;
213 #endif
214
215   handler[SIGERROR] = new SigErrorHandler;
216 }
217
218 void SignalController::inject(int sig, const std::string& msg)
219 {
220   {
221     Lock lock(sigQueueMutex);
222     sigQueue.push(SigPair(sig, msg));
223   }
224   sigQueueSem.up();
225 }
226
227 int SignalController::run()
228 {
229   while(1) {
230     sigQueueSem.down();
231     SigPair sig;
232     {
233       Lock lock(sigQueueMutex);
234       sig = sigQueue.front();
235       sigQueue.pop();
236     }
237     
238     HandlerMap::iterator it = handler.find(sig.first);
239     if(it != handler.end())
240     {
241       int ret;
242       if(sig.second == "")
243         ret = it->second->handle();
244       else
245         ret = it->second->handle(sig.second);
246
247       if(ret)
248         return ret;
249     }
250     else
251       cLog.msg(Log::PRIO_NOTICE) << "SIG " << sig.first << " caught with message '" << sig.second << "'- ignoring";
252   }
253   return 0;
254 }
255