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