4 // Fraunhofer Institut fuer offene Kommunikationssysteme (FOKUS)
5 // Kompetenzzentrum fuer NETwork research (NET)
6 // Stefan Bund <g0dil@berlios.de>
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.
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.
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.
24 \brief Daemon non-inline non-template implementation */
30 #include <sys/types.h>
37 #include "../Utils/Exception.hh"
38 #include "../Utils/membind.hh"
40 //#include "Daemon.mpp"
42 ///////////////////////////////cc.p////////////////////////////////////////
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 "()")
47 ///////////////////////////////////////////////////////////////////////////
50 prefix_ senf::Daemon::~Daemon()
53 prefix_ void senf::Daemon::daemonize(bool v)
58 prefix_ bool senf::Daemon::daemon()
63 prefix_ void senf::Daemon::consoleLog(std::string path, StdStream which)
67 int fd (::open(path.c_str(), O_WRONLY | O_APPEND));
69 throwErrno("::open()");
85 prefix_ void senf::Daemon::pidFile(std::string f, bool unique)
91 prefix_ void senf::Daemon::detach()
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) );
99 prefix_ int senf::Daemon::start(int argc, char const ** argv)
111 if (! pidfile_.empty())
117 catch (std::exception & e) {
118 std::cerr << "\n*** Fatal exception: " << e.what() << std::endl;
122 std::cerr << "\n*** Fatal exception: (unknown)" << std::endl;
130 ////////////////////////////////////////
133 prefix_ senf::Daemon::Daemon()
134 : argc_(0), argv_(0), daemonize_(true), stdout_(-1), stderr_(-1), pidfile_(""), unique_(true),
138 ////////////////////////////////////////
141 prefix_ void senf::Daemon::configure()
144 prefix_ void senf::Daemon::main()
151 prefix_ void senf::Daemon::init()
154 prefix_ void senf::Daemon::run()
157 prefix_ void senf::Daemon::fork()
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) );
168 // We need to block the SIGCHLD signal here so we don't miss it, if the child
172 ::sigemptyset(&cldsig);
173 LIBC_CALL( ::sigaddset, (&cldsig, SIGCHLD) );
174 LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &cldsig, &oldsig) );
176 LIBC_CALL_RV( pid, ::fork, () );
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) );
192 LIBC_CALL( ::close, (coutpipe[1]) );
193 LIBC_CALL( ::close, (cerrpipe[1]) );
195 detail::DaemonWatcher watcher (pid, coutpipe[0], cerrpipe[0]);
202 prefix_ void senf::Daemon::pidfileCreate()
205 ///////////////////////////////////////////////////////////////////////////
206 // senf::detail::DaemonWatcher
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))
214 prefix_ void senf::detail::DaemonWatcher::run()
216 Scheduler::instance().registerSignal(SIGCHLD, senf::membind(&DaemonWatcher::childDied, this));
217 Scheduler::instance().process();
220 ////////////////////////////////////////
223 prefix_ void senf::detail::DaemonWatcher::pipeClosed()
225 if (! timerRunning_) {
226 Scheduler::instance().timeout(Scheduler::instance().eventTime() + ClockService::seconds(1),
227 senf::membind(&DaemonWatcher::childOk, this));
228 timerRunning_ = true;
232 prefix_ void senf::detail::DaemonWatcher::childDied()
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
242 if (WEXITSTATUS(status) == 0)
244 ::exit(WEXITSTATUS(status));
247 prefix_ void senf::detail::DaemonWatcher::childOk()
249 Scheduler::instance().terminate();
252 ///////////////////////////////////////////////////////////////////////////
253 // senf::detail::DaemonWatcher::Forwarder
255 prefix_ senf::detail::DaemonWatcher::Forwarder::Forwarder(int src, int dst, Callback cb)
256 : src_(src), dst_(dst), cb_(cb)
258 Scheduler::instance().add(src_, senf::membind(&Forwarder::readData, this),
262 prefix_ senf::detail::DaemonWatcher::Forwarder::~Forwarder()
265 Scheduler::instance().remove(src_);
266 if (dst_ != -1 && ! buffer_.empty())
267 Scheduler::instance().remove(dst_);
270 prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(Scheduler::EventId event)
275 n = ::read(src_,buf,1024);
277 if (errno != EINTR) throwErrno("::read()");
283 Scheduler::instance().remove(src_);
290 // There was an error writing data -> drop it
293 Scheduler::instance().add(dst_, senf::membind(&Forwarder::writeData, this),
294 Scheduler::EV_WRITE);
295 buffer_.insert(buffer_.end(), buf, buf+n);
298 prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(Scheduler::EventId event)
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_);
304 if (src_ == -1) cb_();
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));
312 if (errno != EINTR) throwErrno("::write()");
315 buffer_.erase(buffer_.begin(), buffer_.begin()+w);
316 if (buffer_.empty()) {
317 Scheduler::instance().remove(dst_);
326 ///////////////////////////////cc.e////////////////////////////////////////
328 //#include "Daemon.mpp"
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"