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