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