5252dcfbe883e609c0a72278a66373a56601f981
[senf.git] / Scheduler / Daemon.cc
1 // $Id$
2 //
3 // Copyright (C) 2007 
4 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
5 // Kompetenzzentrum fuer NETwork research (NET)
6 //     Stefan Bund <g0dil@berlios.de>
7 //
8 // This program is free software; you can redistribute it and/or modify
9 // it under the terms of the GNU General Public License as published by
10 // the Free Software Foundation; either version 2 of the License, or
11 // (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 // GNU General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the
20 // Free Software Foundation, Inc.,
21 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
22
23 /** \file
24     \brief Daemon non-inline non-template implementation */
25
26 #include "Daemon.hh"
27 #include "Daemon.ih"
28
29 // Custom includes
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <sys/wait.h>
33 #include <unistd.h>
34 #include <fcntl.h>
35 #include <errno.h>
36 #include <signal.h>
37 #include "../Utils/Exception.hh"
38 #include "../Utils/membind.hh"
39
40 //#include "Daemon.mpp"
41 #define prefix_
42 ///////////////////////////////cc.p////////////////////////////////////////
43
44 #define LIBC_CALL(fn, args) if (fn args < 0) throwErrno(#fn "()")
45 #define LIBC_CALL_RV(var, fn, args) int var (fn args); if (var < 0) throwErrno(#fn "()")
46
47 ///////////////////////////////////////////////////////////////////////////
48 // senf::Daemon
49
50 prefix_ senf::Daemon::~Daemon()
51 {}
52
53 prefix_ void senf::Daemon::daemonize(bool v)
54 {
55     daemonize_ = v;
56 }
57
58 prefix_ bool senf::Daemon::daemon()
59 {
60     return daemonize_;
61 }
62
63 prefix_ void senf::Daemon::consoleLog(std::string path, StdStream which)
64 {
65     int fd (-1);
66     if (! path.empty()) {
67         int fd (::open(path.c_str(), O_WRONLY | O_APPEND));
68         if (fd < 0)
69             throwErrno("::open()");
70     }
71     switch (which) {
72     case StdOut:
73         stdout_ = fd;
74         break;
75     case StdErr:
76         stderr_ = fd;
77         break;
78     case Both:
79         stdout_ = fd;
80         stderr_ = fd;
81         break;
82     }
83 }
84
85 prefix_ void senf::Daemon::pidFile(std::string f, bool unique)
86 {
87     pidfile_ = f;
88     unique_ = unique;
89 }
90
91 prefix_ void senf::Daemon::detach()
92 {
93     LIBC_CALL_RV( nul, ::open, ("/dev/null", O_WRONLY) );
94     LIBC_CALL( ::dup2, (nul, 1) );
95     LIBC_CALL( ::dup2, (nul, 2) );
96     LIBC_CALL( ::close, (nul) );
97 }
98
99 prefix_ int senf::Daemon::start(int argc, char const ** argv)
100 {
101     argc_ = argc;
102     argv_ = argv;
103
104 #   ifdef NDEBUG
105     try {
106 #   endif
107
108     configure();
109     if (daemonize_)
110         fork();
111     if (! pidfile_.empty())
112         pidfileCreate();
113     main();
114
115 #   ifdef NDEBUG
116     }
117     catch (std::exception & e) {
118         std::cerr << "\n*** Fatal exception: " << e.what() << std::endl;
119         return 1;
120     }
121     catch (...) {
122         std::cerr << "\n*** Fatal exception: (unknown)" << std::endl;
123         return 1;
124     }
125 #   endif
126
127     return 0;
128 }
129
130 ////////////////////////////////////////
131 // protected members
132
133 prefix_ senf::Daemon::Daemon()
134     : argc_(0), argv_(0), daemonize_(true), stdout_(-1), stderr_(-1), pidfile_(""), unique_(true),
135       detached_(false)
136 {}
137
138 ////////////////////////////////////////
139 // private members
140
141 prefix_ void senf::Daemon::configure()
142 {}
143
144 prefix_ void senf::Daemon::main()
145 {
146     init();
147     detach();
148     run();
149 }
150
151 prefix_ void senf::Daemon::init()
152 {}
153
154 prefix_ void senf::Daemon::run()
155 {}
156
157 prefix_ void senf::Daemon::fork()
158 {
159     int coutpipe[2];
160     int cerrpipe[2];
161
162     LIBC_CALL_RV( nul, ::open, ("/dev/null", O_RDONLY) );
163     LIBC_CALL( ::dup2, (nul, 0) );
164     LIBC_CALL( ::close, (nul) );
165     LIBC_CALL( ::pipe, (coutpipe) );
166     LIBC_CALL( ::pipe, (cerrpipe) );
167
168     // We need to block the SIGCHLD signal here so we don't miss it, if the child
169     // dies immediately
170     ::sigset_t oldsig;
171     ::sigset_t cldsig;
172     ::sigemptyset(&cldsig);
173     LIBC_CALL( ::sigaddset, (&cldsig, SIGCHLD) );
174     LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &cldsig, &oldsig) );
175     
176     LIBC_CALL_RV( pid, ::fork, () );
177
178     if (pid == 0) {
179         // Daemon process
180
181         LIBC_CALL( ::dup2, (coutpipe[1],1) );
182         LIBC_CALL( ::dup2, (cerrpipe[1],2) );
183         LIBC_CALL( ::close, (coutpipe[0]) );
184         LIBC_CALL( ::close, (coutpipe[1]) );
185         LIBC_CALL( ::close, (cerrpipe[0]) );
186         LIBC_CALL( ::close, (cerrpipe[1]) );
187         LIBC_CALL( ::setsid, () );
188         LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
189         return;
190     }
191
192     LIBC_CALL( ::close, (coutpipe[1]) );
193     LIBC_CALL( ::close, (cerrpipe[1]) );
194
195     detail::DaemonWatcher watcher (pid, coutpipe[0], cerrpipe[0]);
196     watcher.run();
197
198     ::exit(0);
199
200 }
201
202 prefix_ void senf::Daemon::pidfileCreate()
203 {}
204
205 ///////////////////////////////////////////////////////////////////////////
206 // senf::detail::DaemonWatcher
207
208 prefix_ senf::detail::DaemonWatcher::DaemonWatcher(int pid, int coutpipe, int cerrpipe)
209     : childPid_(pid), coutpipe_(coutpipe), cerrpipe_(cerrpipe), 
210       coutForwarder_(coutpipe_, 1, senf::membind(&DaemonWatcher::pipeClosed, this)),
211       cerrForwarder_(cerrpipe_, 2, senf::membind(&DaemonWatcher::pipeClosed, this))
212 {}
213
214 prefix_ void senf::detail::DaemonWatcher::run()
215 {
216     Scheduler::instance().registerSignal(SIGCHLD, senf::membind(&DaemonWatcher::childDied, this));
217     Scheduler::instance().process();
218 }
219
220 ////////////////////////////////////////
221 // private members
222
223 prefix_ void senf::detail::DaemonWatcher::pipeClosed()
224 {
225     if (! timerRunning_) {
226         Scheduler::instance().timeout(Scheduler::instance().eventTime() + ClockService::seconds(1),
227                                       senf::membind(&DaemonWatcher::childOk, this));
228         timerRunning_ = true;
229     }
230 }
231
232 prefix_ void senf::detail::DaemonWatcher::childDied()
233 {
234     int status (0);
235     if (::waitpid(childPid_,&status,0) < 0) throwErrno("::waitpid()");
236     if (WIFSIGNALED(status)) {
237         ::signal(WTERMSIG(status),SIG_DFL);
238         ::kill(::getpid(), WTERMSIG(status));
239         // should not be reached
240         ::exit(1);
241     }
242     if (WEXITSTATUS(status) == 0)
243         ::exit(1);
244     ::exit(WEXITSTATUS(status));
245 }
246
247 prefix_ void senf::detail::DaemonWatcher::childOk()
248 {
249     Scheduler::instance().terminate();
250 }
251
252 ///////////////////////////////////////////////////////////////////////////
253 // senf::detail::DaemonWatcher::Forwarder
254
255 prefix_ senf::detail::DaemonWatcher::Forwarder::Forwarder(int src, int dst, Callback cb)
256     : src_(src), dst_(dst), cb_(cb)
257 {
258     Scheduler::instance().add(src_, senf::membind(&Forwarder::readData, this),
259                               Scheduler::EV_READ);
260 }
261
262 prefix_ senf::detail::DaemonWatcher::Forwarder::~Forwarder()
263 {
264     if (src_ != -1)
265         Scheduler::instance().remove(src_);
266     if (dst_ != -1 && ! buffer_.empty())
267         Scheduler::instance().remove(dst_);
268 }
269
270 prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(Scheduler::EventId event)
271 {
272     char buf[1024];
273     int n (0);
274     while (1) {
275         n = ::read(src_,buf,1024);
276         if (n<0) {
277             if (errno != EINTR) throwErrno("::read()");
278         } else 
279             break;
280     }
281     if (n == 0) {
282         // Hangup
283         Scheduler::instance().remove(src_);
284         if (buffer_.empty())
285             cb_(); 
286         src_ = -1;
287         return;
288     }
289     if (dst_ == -1)
290         // There was an error writing data -> drop it
291         return;
292     if (buffer_.empty())
293         Scheduler::instance().add(dst_, senf::membind(&Forwarder::writeData, this),
294                                   Scheduler::EV_WRITE);
295     buffer_.insert(buffer_.end(), buf, buf+n);
296 }
297
298 prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(Scheduler::EventId event)
299 {    
300     if (event != Scheduler::EV_WRITE) {
301         // Broken pipe while writing data ? Not much, we can do here, we just drop the data
302         Scheduler::instance().remove(dst_);
303         dst_ = -1;
304         if (src_ == -1) cb_();
305         return;
306     }
307     char buf[1024];
308     int n (buffer_.size() > 1024 ? 1024 : buffer_.size());
309     std::copy(buffer_.begin(), buffer_.begin() + n, buf);
310     int w (::write(dst_, buf, n));
311     if (w < 0) {
312         if (errno != EINTR) throwErrno("::write()");
313         return;
314     }
315     buffer_.erase(buffer_.begin(), buffer_.begin()+w);
316     if (buffer_.empty()) {
317         Scheduler::instance().remove(dst_);
318         if (src_ == -1)
319             cb_();
320     }
321 }
322
323 #undef LIBC_CALL
324 #undef LIBC_CALL_RV
325
326 ///////////////////////////////cc.e////////////////////////////////////////
327 #undef prefix_
328 //#include "Daemon.mpp"
329
330 \f
331 // Local Variables:
332 // mode: c++
333 // fill-column: 100
334 // comment-column: 40
335 // c-file-style: "senf"
336 // indent-tabs-mode: nil
337 // ispell-local-dictionary: "american"
338 // compile-command: "scons -u test"
339 // End: