e2f0fec1332680cf84897cc45a4ba4d42cb7b352
[senf.git] / senf / Utils / Daemon / Daemon.cc
1 // $Id$
2 //
3 // Copyright (C) 2007
4 // Fraunhofer Institute for Open Communication Systems (FOKUS)
5 //
6 // The contents of this file are subject to the Fraunhofer FOKUS Public License
7 // Version 1.0 (the "License"); you may not use this file except in compliance
8 // with the License. You may obtain a copy of the License at 
9 // http://senf.berlios.de/license.html
10 //
11 // The Fraunhofer FOKUS Public License Version 1.0 is based on, 
12 // but modifies the Mozilla Public License Version 1.1.
13 // See the full license text for the amendments.
14 //
15 // Software distributed under the License is distributed on an "AS IS" basis, 
16 // WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
17 // for the specific language governing rights and limitations under the License.
18 //
19 // The Original Code is Fraunhofer FOKUS code.
20 //
21 // The Initial Developer of the Original Code is Fraunhofer-Gesellschaft e.V. 
22 // (registered association), Hansastraße 27 c, 80686 Munich, Germany.
23 // All Rights Reserved.
24 //
25 // Contributor(s):
26 //   Stefan Bund <g0dil@berlios.de>
27
28 /** \file
29     \brief Daemon non-inline non-template implementation */
30
31 #include "Daemon.hh"
32 #include "Daemon.ih"
33
34 // Custom includes
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <sys/wait.h>
38 #include <unistd.h>
39 #include <limits.h>
40 #include <fcntl.h>
41 #include <errno.h>
42 #include <signal.h>
43 #ifdef SENF_BACKTRACE
44    #include <execinfo.h>
45 #endif
46 #include <sstream>
47 #include <algorithm>
48 #include <boost/algorithm/string/predicate.hpp>
49 #include <boost/algorithm/string/trim.hpp>
50 #include <boost/format.hpp>
51 #include <senf/Utils/Exception.hh>
52 #include <senf/Utils/membind.hh>
53 #include <senf/Utils/Backtrace.hh>
54 #include <senf/Utils/signalnames.hh>
55
56 // #define __USE_GNU
57 #include <ucontext.h>
58
59 //#include "Daemon.mpp"
60 #define prefix_
61 //-/////////////////////////////////////////////////////////////////////////////////////////////////
62
63 #define LIBC_CALL(fn, args) if (fn args < 0) \
64     SENF_THROW_SYSTEM_EXCEPTION(#fn "()")
65
66 #define LIBC_CALL_RV(var, fn, args) \
67     int var (fn args); if (var < 0) SENF_THROW_SYSTEM_EXCEPTION(#fn "()")
68
69 //-/////////////////////////////////////////////////////////////////////////////////////////////////
70 // senf::Daemon
71
72 prefix_ senf::Daemon::~Daemon()
73 {
74     if (pidfileCreated_) {
75         try {
76             LIBC_CALL( ::unlink, (pidfile_.c_str()) );
77         } catch (Exception & e) {
78             // e << "; could not unlink " << pidfile_.c_str();
79             // throw;
80         }
81     }
82 }
83
84 prefix_ void senf::Daemon::daemonize(bool v)
85 {
86     daemonize_ = v;
87 }
88
89 prefix_ bool senf::Daemon::daemon()
90 {
91     return daemonize_;
92 }
93
94 prefix_ int senf::Daemon::argc()
95 {
96     return argc_;
97 }
98
99 prefix_ char const ** senf::Daemon::argv()
100 {
101     return argv_;
102 }
103
104 namespace {
105
106     struct IsDaemonOpt {
107         bool operator()(std::string const & str) const {
108             return str == "--no-daemon"
109                 || boost::starts_with(str, std::string("--pid-file="))
110                 || boost::starts_with(str, std::string("--console-log="));
111         }
112     };
113 }
114
115 prefix_ void senf::Daemon::removeDaemonArgs()
116 {
117     char const ** last (std::remove_if(argv_+1, argv_+argc_, IsDaemonOpt()));
118     *last = 0;
119     argc_ = last - argv_;
120 }
121
122 prefix_ void senf::Daemon::consoleLog(std::string const & path, StdStream which)
123 {
124     switch (which) {
125     case StdOut : stdoutLog_ = path; break;
126     case StdErr : stderrLog_ = path; break;
127     case Both : stdoutLog_ = path; stderrLog_ = path; break;
128     }
129 }
130
131
132 prefix_ void senf::Daemon::openLog()
133 {
134     int fd (-1);
135     if (! stdoutLog_.empty()) {
136         fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
137         if (fd < 0)
138             SENF_THROW_SYSTEM_EXCEPTION(
139                   " Could not open \"" + stdoutLog_ + "\" for redirecting stdout.");
140         stdout_ = fd;
141     }
142     if (! stderrLog_.empty()) {
143         if (stderrLog_ == stdoutLog_) {
144             stderr_ = ::dup(fd);
145             if (stderr_ < 0)
146                 SENF_THROW_SYSTEM_EXCEPTION("::dup()");
147         }
148         else {
149             fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
150             if (fd < 0)
151                 SENF_THROW_SYSTEM_EXCEPTION(
152                     " Could not open \"" + stderrLog_ + "\" for redirecting stderr.");
153             stderr_ = fd;
154         }
155     }
156 }
157
158 prefix_ void senf::Daemon::logReopen()
159 {
160     if (! stdoutLog_.empty()) {
161         int fd (::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666));
162         if (fd < 0)
163             goto error;
164         if (::dup2(fd, 1) < 0)
165             goto error;
166         if (stderrLog_ == stdoutLog_) {
167             if (::dup2(fd, 2) < 0)
168                 goto error;
169             return;
170         }
171     }
172     if (! stderrLog_.empty()) {
173         int fd (::open(stderrLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666));
174         if (fd < 0)
175             goto error;
176         if (::dup2(fd, 2) < 0)
177             goto error;
178     }
179     return;
180
181  error:
182     SENF_LOG(
183         (senf::log::CRITICAL)
184         ("log-file reopen failed: (" << errno << ") " << ::strerror(errno)) );
185 }
186
187 prefix_ void senf::Daemon::pidFile(std::string const & f)
188 {
189     pidfile_ = f;
190 }
191
192 namespace {
193     bool signaled (false);
194     void waitusr(int) {
195         signaled = true;
196     }
197 }
198
199 prefix_ void senf::Daemon::detach()
200 {
201     if (daemonize_ && ! detached_) {
202         // Wow .. ouch ..
203         // To ensure all data is written to the console log file in the correct order, we suspend
204         // execution here until the parent process tells us to continue via SIGUSR1: We block
205         // SIGUSR1 and install our own signal handler saving the old handler and signal mask. Then
206         // we close stdin/stderr which will send a HUP condition to the parent process. We wait for
207         // SIGUSR1 and reinstall the old signal mask and action.
208         ::sigset_t oldsig;
209         ::sigset_t usrsig;
210         ::sigemptyset(&usrsig);
211         LIBC_CALL( ::sigaddset, (&usrsig, SIGUSR1) );
212         LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &usrsig, &oldsig) );
213         struct ::sigaction oldact;
214         struct ::sigaction usract;
215         ::memset(&usract, 0, sizeof(usract));
216         usract.sa_handler = &waitusr;
217         LIBC_CALL( ::sigaction, (SIGUSR1, &usract, &oldact) );
218         ::sigset_t waitsig (oldsig);
219         LIBC_CALL( ::sigdelset, (&waitsig, SIGUSR1) );
220
221         LIBC_CALL_RV( nul, ::open, ("/dev/null", O_WRONLY) );
222         LIBC_CALL( ::dup2, (stdout_ == -1 ? nul : stdout_, 1) );
223         LIBC_CALL( ::dup2, (stderr_ == -1 ? nul : stderr_, 2) );
224         LIBC_CALL( ::close, (nul) );
225
226         signaled = false;
227         while (! signaled) {
228             ::sigsuspend(&waitsig);
229             if (errno != EINTR)
230                 SENF_THROW_SYSTEM_EXCEPTION("::sigsuspend()");
231         }
232
233         LIBC_CALL( ::sigaction, (SIGUSR1, &oldact, 0) );
234         LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
235
236         detached_ = true;
237     }
238 }
239
240 namespace {
241     /* Purposely *not* derived from std::exception */
242     struct DaemonExitException {
243         DaemonExitException(unsigned c) : code(c) {}
244         unsigned code;
245     };
246 }
247
248 prefix_ void senf::Daemon::exit(unsigned code)
249 {
250     throw DaemonExitException(code);
251 }
252
253 prefix_ int senf::Daemon::start(int argc, char const ** argv)
254 {
255     argc_ = argc;
256     argv_ = argv;
257
258     try {
259         configure();
260
261         if (daemonize_) {
262             openLog();
263             fork();
264         }
265         installSighandlers();
266         if (! pidfile_.empty()) {
267             if (pidfileCreate())
268                 pidfileCreated_ = true;
269             else {
270                 std::cerr << "PID file '" << pidfile_
271                           << "' creation failed. Daemon running ?" << std::endl;
272                 return 1;
273             }
274         }
275
276         main();
277     }
278     catch (DaemonExitException & e) {
279         return e.code;
280     }
281
282 #ifndef SENF_DEBUG
283
284     catch (std::exception & e) {
285         std::cerr << "\n*** Fatal exception: " << e.what() << "\n" << std::endl;
286         return 1;
287     }
288     catch (...) {
289         std::cerr << "\n*** Fatal exception: (unknown)" << "\n" << std::endl;
290         return 1;
291     }
292
293 #   endif
294
295     return 0;
296 }
297
298 prefix_ senf::Daemon & senf::Daemon::instance()
299 {
300     BOOST_ASSERT( instance_ );
301     return *instance_;
302 }
303
304 //-/////////////////////////////////////////////////////////////////////////////////////////////////
305 // protected members
306
307 prefix_ senf::Daemon::Daemon()
308     : argc_(0), argv_(0), daemonize_(true), stdout_(-1), stderr_(-1), pidfile_(""),
309       pidfileCreated_(false), detached_(false)
310 {
311     BOOST_ASSERT( ! instance_ );
312     instance_ = this;
313 }
314
315 senf::Daemon * senf::Daemon::instance_ (0);
316
317 //-/////////////////////////////////////////////////////////////////////////////////////////////////
318 // private members
319
320 prefix_ void senf::Daemon::configure()
321 {
322     // int i (not unsigned) since argc_ is int ...
323     for (int i (1); i<argc_; ++i) {
324         std::string argv (argv_[i]);
325         if (argv == "--no-daemon")
326             daemonize(false);
327         else if (boost::starts_with(argv, "--console-log=")) {
328             std::string arg (argv.substr(14u));
329             std::string::size_type komma (arg.find(','));
330             if (komma == std::string::npos) {
331                 boost::trim(arg);
332                 if (arg == std::string("none")) consoleLog("");
333                 else if (!arg.empty())          consoleLog(arg);
334             } else {
335                 std::string arg1 (arg,0,komma);
336                 std::string arg2 (arg,komma+1);
337                 boost::trim(arg1);
338                 boost::trim(arg2);
339                 if (arg1 == std::string("none")) consoleLog("",StdOut);
340                 else if (! arg1.empty() )        consoleLog(arg1, StdOut);
341                 if (arg2 == std::string("none")) consoleLog("",StdErr);
342                 else if (! arg2.empty() )        consoleLog(arg2, StdErr);
343             }
344         }
345         else if (boost::starts_with(argv, "--pid-file="))
346             pidFile(std::string(std::string(argv_[i]), 11u));
347     }
348 }
349
350 prefix_ void senf::Daemon::main()
351 {
352     init();
353     detach();
354     run();
355 }
356
357 prefix_ void senf::Daemon::init()
358 {}
359
360 prefix_ void senf::Daemon::run()
361 {}
362
363 prefix_ void senf::Daemon::fork()
364 {
365     int coutpipe[2];
366     int cerrpipe[2];
367
368     LIBC_CALL_RV( nul, ::open, ("/dev/null", O_RDONLY) );
369     LIBC_CALL( ::dup2, (nul, 0) );
370     LIBC_CALL( ::close, (nul) );
371     LIBC_CALL( ::pipe, (coutpipe) );
372     LIBC_CALL( ::pipe, (cerrpipe) );
373
374     // We need to block the SIGCHLD signal here so we don't miss it, if the child
375     // dies immediately
376     ::sigset_t oldsig;
377     ::sigset_t cldsig;
378     ::sigemptyset(&cldsig);
379     LIBC_CALL( ::sigaddset, (&cldsig, SIGCHLD) );
380     LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &cldsig, &oldsig) );
381
382     if (! senf::scheduler::empty() ) {
383         std::cerr <<
384             "\n"
385             "*** WARNING ***\n"
386             "Scheduler not empty before fork(). THIS MUST NOT HAPPEN.\n"
387             "The scheduler will be reinitialized by the fork() and lose all registrations.\n\n";
388         senf::scheduler::detail::EventManager::instance().listEvents(std::cerr);
389         std::cerr <<
390             "\n*** WARNING ***\n"
391             "\n";
392     }
393
394     LIBC_CALL_RV( pid, ::fork, () );
395
396     if (pid == 0) {
397         // Daemon process
398
399         LIBC_CALL( ::dup2, (coutpipe[1],1) );
400         LIBC_CALL( ::dup2, (cerrpipe[1],2) );
401         LIBC_CALL( ::close, (coutpipe[0]) );
402         LIBC_CALL( ::close, (coutpipe[1]) );
403         LIBC_CALL( ::close, (cerrpipe[0]) );
404         LIBC_CALL( ::close, (cerrpipe[1]) );
405         LIBC_CALL( ::setsid, () );
406         LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
407
408         senf::scheduler::restart();
409         return;
410     }
411
412     // Ouch ... ensure, the daemon watcher does not remove the pidfile ...
413     pidfile_ = "";
414
415     LIBC_CALL( ::close, (coutpipe[1]) );
416     LIBC_CALL( ::close, (cerrpipe[1]) );
417
418     senf::scheduler::restart();
419
420     detail::DaemonWatcher watcher (pid, coutpipe[0], cerrpipe[0], stdout_, stderr_);
421     watcher.run();
422
423     ::_exit(0);
424 }
425
426 prefix_ bool senf::Daemon::pidfileCreate()
427 {
428     // Create temporary file pidfile_.hostname.pid and hard-link it to pidfile_ If the hardlink
429     // fails, the pidfile exists. If the link count of the temporary file is not 2 after this, there
430     // was some race condition, probably over NFS.
431
432     std::string tempname;
433     boost::format linkErrorFormat(" Could not link \"%1%\" to \"%2%\".");
434
435     {
436         char hostname[HOST_NAME_MAX+1];
437         LIBC_CALL( ::gethostname, (hostname, HOST_NAME_MAX+1) );
438         hostname[HOST_NAME_MAX] = 0;
439         std::stringstream tempname_s;
440         tempname_s << pidfile_ << "." << hostname << "." << ::getpid();
441         tempname = tempname_s.str();
442     }
443
444     while (1) {
445         {
446             std::ofstream pidf (tempname.c_str());
447             if (! pidf)
448                 SENF_THROW_SYSTEM_EXCEPTION(" Could not open pidfile \"" + tempname + "\" for output.");
449             pidf << ::getpid() << std::endl;
450             if (! pidf)
451                 SENF_THROW_SYSTEM_EXCEPTION(" Could not write to pidfile \"" + tempname + "\".");
452         }
453
454         if (::link(tempname.c_str(), pidfile_.c_str()) < 0) {
455             if (errno != EEXIST)
456                 SENF_THROW_SYSTEM_EXCEPTION((linkErrorFormat % pidfile_ % tempname).str());
457         }
458         else {
459             struct ::stat s;
460             LIBC_CALL( ::stat, (tempname.c_str(), &s) );
461             LIBC_CALL( ::unlink, (tempname.c_str()) );
462             return s.st_nlink == 2;
463         }
464
465         // pidfile exists. Check, whether the pid in the pidfile still exists.
466         {
467             int old_pid (-1);
468             std::ifstream pidf (pidfile_.c_str());
469             if ( ! (pidf >> old_pid)
470                  || old_pid < 0
471                  || ::kill(old_pid, 0) >= 0
472                  || errno == EPERM ) {
473                 LIBC_CALL( ::unlink, (tempname.c_str()) );
474                 return false;
475             }
476         }
477
478         // If we reach this point, the pid file exists but the process mentioned within the
479         // pid file does *not* exists. We assume, the pid file to be stale.
480
481         // I hope, the following procedure is without race condition: We remove our generated
482         // temporary pid file and recreate it as hard-link to the old pid file. Now we check, that
483         // the hard-link count of this file is 2. If it is not, we terminate, since someone else
484         // must have already created his hardlink. We then truncate the file and write our pid.
485
486         LIBC_CALL( ::unlink, (tempname.c_str() ));
487         if (::link(pidfile_.c_str(), tempname.c_str()) < 0) {
488             if (errno != ENOENT)
489                 SENF_THROW_SYSTEM_EXCEPTION( (linkErrorFormat % tempname % pidfile_).str());
490             // Hmm ... the pidfile mysteriously disappeared ... try again.
491             continue;
492         }
493
494         {
495             struct ::stat s;
496             LIBC_CALL( ::stat, (tempname.c_str(), &s) );
497             if (s.st_nlink != 2) {
498                 LIBC_CALL( ::unlink, (tempname.c_str()) );
499                 return false;
500             }
501         }
502
503         {
504             std::ofstream pidf (tempname.c_str());
505             pidf << ::getpid() << std::endl;
506         }
507
508         LIBC_CALL( ::unlink, (tempname.c_str()) );
509         break;
510     }
511     return true;
512 }
513
514
515 #ifdef SENF_DEBUG
516
517 namespace {
518     void fatalSignalsHandler(int sig, ::siginfo_t * info, void * arg)
519     {
520         // ::ucontext_t * ucontext = static_cast<ucontext_t*>(arg);
521         std::cerr << "\n" << "Signal " << senf::signalName(sig) << '(' << sig << ')'
522                   << " received\n";
523
524         if (sig == SIGSEGV)
525             std::cerr << "Invalid memory access at " << info->si_addr << "\n";
526 #ifdef SENF_BACKTRACE
527         static void * entries[SENF_DEBUG_BACKTRACE_NUMCALLERS];
528         int nEntries( ::backtrace(entries, SENF_DEBUG_BACKTRACE_NUMCALLERS) );
529
530         // Hack the callers address into the backtrace
531         // entries[1] = reinterpret_cast<void *>(ucontext->uc_mcontext.gregs[REG_EIP]);
532
533         std::cerr << "Backtrace:\n";
534         senf::formatBacktrace(std::cerr, entries, nEntries);
535         std::cerr << "-- \n";
536 #endif //SENF_BACKTRACE
537         if (sig != SIGUSR2) {
538             ::signal(sig, SIG_DFL);
539             ::kill(::getpid(), sig);
540         }
541     }
542
543 }
544
545 #endif // SENF_DEBUG
546
547 namespace {
548     void sighupHandler(int sig)
549     {
550         senf::Daemon::instance().logReopen();
551     }
552 }
553
554 prefix_ void senf::Daemon::installSighandlers()
555 {
556     struct ::sigaction sa;
557
558     ::sigemptyset(&sa.sa_mask);
559     sa.sa_handler = &sighupHandler;
560     sa.sa_flags = SA_RESTART;
561
562     ::sigaction(SIGHUP,   &sa, NULL);
563
564     sa.sa_handler = SIG_IGN;
565     ::sigaction(SIGPIPE, &sa, NULL);
566
567 #ifdef SENF_DEBUG
568     sa.sa_sigaction = &fatalSignalsHandler;
569     sa.sa_flags = SA_RESTART | SA_SIGINFO;
570
571     ::sigaction(SIGILL,    &sa, NULL);
572     ::sigaction(SIGTRAP,   &sa, NULL);
573     ::sigaction(SIGABRT,   &sa, NULL);
574     ::sigaction(SIGFPE,    &sa, NULL);
575     ::sigaction(SIGBUS,    &sa, NULL);
576     ::sigaction(SIGSEGV,   &sa, NULL);
577 #ifdef SIGSTKFLT //SIGSTKFLT is used for stack faults on coprocessors. That condition doesn't exist on MIPS
578     ::sigaction(SIGSTKFLT, &sa, NULL);
579 #endif
580     ::sigaction(SIGSYS,    &sa, NULL);
581     ::sigaction(SIGUSR2,   &sa, NULL);
582 #endif
583 }
584
585 //-/////////////////////////////////////////////////////////////////////////////////////////////////
586 // senf::detail::DaemonWatcher
587
588 prefix_ senf::detail::DaemonWatcher::DaemonWatcher(int pid, int coutpipe, int cerrpipe,
589                                                    int stdout, int stderr)
590     : childPid_(pid), coutpipe_(coutpipe), cerrpipe_(cerrpipe), stdout_(stdout),
591       stderr_(stderr), sigChld_(false),
592       cldSignal_ (SIGCHLD, senf::membind(&DaemonWatcher::sigChld, this)),
593       timer_ ("senf::detail::DaemonWatcher::childOk", senf::membind(&DaemonWatcher::childOk, this)),
594       coutForwarder_(coutpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 1)),
595       cerrForwarder_(cerrpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 2))
596 {
597     coutForwarder_.addTarget(1);
598     if (stdout_ >= 0)
599         coutForwarder_.addTarget(stdout_);
600     cerrForwarder_.addTarget(2);
601     if (stderr_ >= 0)
602         cerrForwarder_.addTarget(stderr_);
603 }
604
605 prefix_ void senf::detail::DaemonWatcher::run()
606 {
607     scheduler::process();
608 }
609
610 //-/////////////////////////////////////////////////////////////////////////////////////////////////
611 // private members
612
613 prefix_ void senf::detail::DaemonWatcher::pipeClosed(int id)
614 {
615     switch (id) {
616     case 1 : coutpipe_ = -1; break;
617     case 2 : cerrpipe_ = -1; break;
618     }
619
620     if (coutpipe_ == -1 && cerrpipe_ == -1) {
621         if (sigChld_)
622             childDied(); // does not return
623         if (::kill(childPid_, SIGUSR1) < 0 && errno != ESRCH)
624             SENF_THROW_SYSTEM_EXCEPTION("::kill()");
625         timer_.timeout(scheduler::eventTime() + ClockService::seconds(1));
626     }
627 }
628
629 prefix_ void senf::detail::DaemonWatcher::sigChld(siginfo_t const &)
630 {
631     sigChld_ = true;
632     if (coutpipe_ == -1 && cerrpipe_ == -1)
633         childDied(); // does not return
634 }
635
636 prefix_ void senf::detail::DaemonWatcher::childDied()
637 {
638     int status (0);
639     if (::waitpid(childPid_,&status,0) < 0) SENF_THROW_SYSTEM_EXCEPTION("::waitpid()");
640     if (WIFSIGNALED(status)) {
641         ::signal(WTERMSIG(status),SIG_DFL);
642         ::kill(::getpid(), WTERMSIG(status));
643         // should not be reached
644         ::_exit(126);
645     }
646     if (WEXITSTATUS(status) == 0)
647         ::_exit(127);
648     ::_exit(WEXITSTATUS(status));
649 }
650
651 prefix_ void senf::detail::DaemonWatcher::childOk()
652 {
653     scheduler::terminate();
654 }
655
656 //-/////////////////////////////////////////////////////////////////////////////////////////////////
657 // senf::detail::DaemonWatcher::Forwarder
658
659 prefix_ senf::detail::DaemonWatcher::Forwarder::Forwarder(int src, Callback cb)
660     : src_(src), cb_(cb),
661       readevent_("senf::detail::DaemonWatcher::Forwarder::readevent", senf::membind(&Forwarder::readData, this),
662                  src_, scheduler::FdEvent::EV_READ)
663 {}
664
665 prefix_ senf::detail::DaemonWatcher::Forwarder::~Forwarder()
666 {
667     targets_.clear_and_destroy(DestroyDelete());
668 }
669
670 prefix_ void senf::detail::DaemonWatcher::Forwarder::addTarget(int fd)
671 {
672     targets_.push_back(*(new Target(*this, fd)));
673 }
674
675 prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(int event)
676 {
677     char buf[1024];
678     int n (0);
679
680     while (1) {
681         n = ::read(src_,buf,1024);
682         if (n<0) {
683             if (errno != EINTR)
684                 SENF_THROW_SYSTEM_EXCEPTION("::read()");
685         }
686         else
687             break;
688     }
689
690     if (n == 0) {
691         if (buffer_.empty())
692             cb_();
693         src_ = -1;
694         readevent_.disable();
695         return;
696     }
697
698     if (targets_.empty())
699         return;
700
701     for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
702         if (i->offset >= buffer_.size())
703             i->writeevent.enable();
704
705     buffer_.insert(buffer_.end(), buf, buf+n);
706 }
707
708 prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(int event, Target * target)
709 {
710     if (event != scheduler::FdEvent::EV_WRITE) {
711         // Broken pipe while writing data ? Not much, we can do here, we just drop the data
712         targets_.erase_and_destroy(Targets::current(*target),DestroyDelete());
713         if (targets_.empty() && src_ == -1)
714             cb_();
715         return;
716     }
717
718     char buf[1024];
719     int n (buffer_.size() - target->offset > 1024 ? 1024 : buffer_.size() - target->offset);
720     std::copy(buffer_.begin() + target->offset, buffer_.begin() + target->offset + n, buf);
721
722     int w (::write(target->fd, buf, n));
723     if (w < 0) {
724         if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::write()");
725         return;
726     }
727     target->offset += w;
728
729     n = std::min_element(
730         targets_.begin(), targets_.end(),
731         boost::bind(&Target::offset, _1) < boost::bind(&Target::offset, _2))->offset;
732
733     buffer_.erase(buffer_.begin(), buffer_.begin()+n);
734
735     for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
736         i->offset -= n;
737
738     if (target->offset >= buffer_.size())
739         target->writeevent.disable();
740     if (src_ == -1 && (buffer_.empty() || targets_.empty()))
741         cb_();
742 }
743
744 #undef LIBC_CALL
745 #undef LIBC_CALL_RV
746
747 //-/////////////////////////////////////////////////////////////////////////////////////////////////
748 #undef prefix_
749 //#include "Daemon.mpp"
750
751 \f
752 // Local Variables:
753 // mode: c++
754 // fill-column: 100
755 // comment-column: 40
756 // c-file-style: "senf"
757 // indent-tabs-mode: nil
758 // ispell-local-dictionary: "american"
759 // compile-command: "scons -u test"
760 // End: