e2969a9e563049aa3f3402e35efa97dc43c2dc51
[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("")
449                       << " Could not open pidfile \"" << tempname << "\" for output.";
450             pidf << ::getpid() << std::endl;
451             if (! pidf)
452                 SENF_THROW_SYSTEM_EXCEPTION("")
453                       << " Could not write to pidfile \"" << tempname << "\".";
454         }
455
456         if (::link(tempname.c_str(), pidfile_.c_str()) < 0) {
457             if (errno != EEXIST)
458                 SENF_THROW_SYSTEM_EXCEPTION("") << linkErrorFormat % pidfile_ % tempname;
459         }
460         else {
461             struct ::stat s;
462             LIBC_CALL( ::stat, (tempname.c_str(), &s) );
463             LIBC_CALL( ::unlink, (tempname.c_str()) );
464             return s.st_nlink == 2;
465         }
466
467         // pidfile exists. Check, whether the pid in the pidfile still exists.
468         {
469             int old_pid (-1);
470             std::ifstream pidf (pidfile_.c_str());
471             if ( ! (pidf >> old_pid)
472                  || old_pid < 0
473                  || ::kill(old_pid, 0) >= 0
474                  || errno == EPERM ) {
475                 LIBC_CALL( ::unlink, (tempname.c_str()) );
476                 return false;
477             }
478         }
479
480         // If we reach this point, the pid file exists but the process mentioned within the
481         // pid file does *not* exists. We assume, the pid file to be stale.
482
483         // I hope, the following procedure is without race condition: We remove our generated
484         // temporary pid file and recreate it as hard-link to the old pid file. Now we check, that
485         // the hard-link count of this file is 2. If it is not, we terminate, since someone else
486         // must have already created his hardlink. We then truncate the file and write our pid.
487
488         LIBC_CALL( ::unlink, (tempname.c_str() ));
489         if (::link(pidfile_.c_str(), tempname.c_str()) < 0) {
490             if (errno != ENOENT)
491                 SENF_THROW_SYSTEM_EXCEPTION("") << linkErrorFormat % tempname % pidfile_;
492             // Hmm ... the pidfile mysteriously disappeared ... try again.
493             continue;
494         }
495
496         {
497             struct ::stat s;
498             LIBC_CALL( ::stat, (tempname.c_str(), &s) );
499             if (s.st_nlink != 2) {
500                 LIBC_CALL( ::unlink, (tempname.c_str()) );
501                 return false;
502             }
503         }
504
505         {
506             std::ofstream pidf (tempname.c_str());
507             pidf << ::getpid() << std::endl;
508         }
509
510         LIBC_CALL( ::unlink, (tempname.c_str()) );
511         break;
512     }
513     return true;
514 }
515
516
517 #ifdef SENF_DEBUG
518
519 namespace {
520     void fatalSignalsHandler(int sig, ::siginfo_t * info, void * arg)
521     {
522         // ::ucontext_t * ucontext = static_cast<ucontext_t*>(arg);
523         std::cerr << "\n" << "Signal " << senf::signalName(sig) << '(' << sig << ')'
524                   << " received\n";
525
526         if (sig == SIGSEGV)
527             std::cerr << "Invalid memory access at " << info->si_addr << "\n";
528 #ifdef SENF_BACKTRACE
529         static void * entries[SENF_DEBUG_BACKTRACE_NUMCALLERS];
530         int nEntries( ::backtrace(entries, SENF_DEBUG_BACKTRACE_NUMCALLERS) );
531
532         // Hack the callers address into the backtrace
533         // entries[1] = reinterpret_cast<void *>(ucontext->uc_mcontext.gregs[REG_EIP]);
534
535         std::cerr << "Backtrace:\n";
536         senf::formatBacktrace(std::cerr, entries, nEntries);
537         std::cerr << "-- \n";
538 #endif //SENF_BACKTRACE
539         if (sig != SIGUSR2) {
540             ::signal(sig, SIG_DFL);
541             ::kill(::getpid(), sig);
542         }
543     }
544
545 }
546
547 #endif // SENF_DEBUG
548
549 namespace {
550     void sighupHandler(int sig)
551     {
552         senf::Daemon::instance().logReopen();
553     }
554 }
555
556 prefix_ void senf::Daemon::installSighandlers()
557 {
558     struct ::sigaction sa;
559
560     ::sigemptyset(&sa.sa_mask);
561     sa.sa_handler = &sighupHandler;
562     sa.sa_flags = SA_RESTART;
563
564     ::sigaction(SIGHUP,   &sa, NULL);
565
566     sa.sa_handler = SIG_IGN;
567     ::sigaction(SIGPIPE, &sa, NULL);
568
569 #ifdef SENF_DEBUG
570     sa.sa_sigaction = &fatalSignalsHandler;
571     sa.sa_flags = SA_RESTART | SA_SIGINFO;
572
573     ::sigaction(SIGILL,    &sa, NULL);
574     ::sigaction(SIGTRAP,   &sa, NULL);
575     ::sigaction(SIGABRT,   &sa, NULL);
576     ::sigaction(SIGFPE,    &sa, NULL);
577     ::sigaction(SIGBUS,    &sa, NULL);
578     ::sigaction(SIGSEGV,   &sa, NULL);
579 #ifdef SIGSTKFLT //SIGSTKFLT is used for stack faults on coprocessors. That condition doesn't exist on MIPS
580     ::sigaction(SIGSTKFLT, &sa, NULL);
581 #endif
582     ::sigaction(SIGSYS,    &sa, NULL);
583     ::sigaction(SIGUSR2,   &sa, NULL);
584 #endif
585 }
586
587 //-/////////////////////////////////////////////////////////////////////////////////////////////////
588 // senf::detail::DaemonWatcher
589
590 prefix_ senf::detail::DaemonWatcher::DaemonWatcher(int pid, int coutpipe, int cerrpipe,
591                                                    int stdout, int stderr)
592     : childPid_(pid), coutpipe_(coutpipe), cerrpipe_(cerrpipe), stdout_(stdout),
593       stderr_(stderr), sigChld_(false),
594       cldSignal_ (SIGCHLD, senf::membind(&DaemonWatcher::sigChld, this)),
595       timer_ ("senf::detail::DaemonWatcher::childOk", senf::membind(&DaemonWatcher::childOk, this)),
596       coutForwarder_(coutpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 1)),
597       cerrForwarder_(cerrpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 2))
598 {
599     coutForwarder_.addTarget(1);
600     if (stdout_ >= 0)
601         coutForwarder_.addTarget(stdout_);
602     cerrForwarder_.addTarget(2);
603     if (stderr_ >= 0)
604         cerrForwarder_.addTarget(stderr_);
605 }
606
607 prefix_ void senf::detail::DaemonWatcher::run()
608 {
609     scheduler::process();
610 }
611
612 //-/////////////////////////////////////////////////////////////////////////////////////////////////
613 // private members
614
615 prefix_ void senf::detail::DaemonWatcher::pipeClosed(int id)
616 {
617     switch (id) {
618     case 1 : coutpipe_ = -1; break;
619     case 2 : cerrpipe_ = -1; break;
620     }
621
622     if (coutpipe_ == -1 && cerrpipe_ == -1) {
623         if (sigChld_)
624             childDied(); // does not return
625         if (::kill(childPid_, SIGUSR1) < 0 && errno != ESRCH)
626             SENF_THROW_SYSTEM_EXCEPTION("::kill()");
627         timer_.timeout(scheduler::eventTime() + ClockService::seconds(1));
628     }
629 }
630
631 prefix_ void senf::detail::DaemonWatcher::sigChld(siginfo_t const &)
632 {
633     sigChld_ = true;
634     if (coutpipe_ == -1 && cerrpipe_ == -1)
635         childDied(); // does not return
636 }
637
638 prefix_ void senf::detail::DaemonWatcher::childDied()
639 {
640     int status (0);
641     if (::waitpid(childPid_,&status,0) < 0) SENF_THROW_SYSTEM_EXCEPTION("::waitpid()");
642     if (WIFSIGNALED(status)) {
643         ::signal(WTERMSIG(status),SIG_DFL);
644         ::kill(::getpid(), WTERMSIG(status));
645         // should not be reached
646         ::_exit(126);
647     }
648     if (WEXITSTATUS(status) == 0)
649         ::_exit(127);
650     ::_exit(WEXITSTATUS(status));
651 }
652
653 prefix_ void senf::detail::DaemonWatcher::childOk()
654 {
655     scheduler::terminate();
656 }
657
658 //-/////////////////////////////////////////////////////////////////////////////////////////////////
659 // senf::detail::DaemonWatcher::Forwarder
660
661 prefix_ senf::detail::DaemonWatcher::Forwarder::Forwarder(int src, Callback cb)
662     : src_(src), cb_(cb),
663       readevent_("senf::detail::DaemonWatcher::Forwarder::readevent", senf::membind(&Forwarder::readData, this),
664                  src_, scheduler::FdEvent::EV_READ)
665 {}
666
667 prefix_ senf::detail::DaemonWatcher::Forwarder::~Forwarder()
668 {
669     targets_.clear_and_destroy(DestroyDelete());
670 }
671
672 prefix_ void senf::detail::DaemonWatcher::Forwarder::addTarget(int fd)
673 {
674     targets_.push_back(*(new Target(*this, fd)));
675 }
676
677 prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(int event)
678 {
679     char buf[1024];
680     int n (0);
681
682     while (1) {
683         n = ::read(src_,buf,1024);
684         if (n<0) {
685             if (errno != EINTR)
686                 SENF_THROW_SYSTEM_EXCEPTION("::read()");
687         }
688         else
689             break;
690     }
691
692     if (n == 0) {
693         if (buffer_.empty())
694             cb_();
695         src_ = -1;
696         readevent_.disable();
697         return;
698     }
699
700     if (targets_.empty())
701         return;
702
703     for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
704         if (i->offset >= buffer_.size())
705             i->writeevent.enable();
706
707     buffer_.insert(buffer_.end(), buf, buf+n);
708 }
709
710 prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(int event, Target * target)
711 {
712     if (event != scheduler::FdEvent::EV_WRITE) {
713         // Broken pipe while writing data ? Not much, we can do here, we just drop the data
714         targets_.erase_and_destroy(Targets::current(*target),DestroyDelete());
715         if (targets_.empty() && src_ == -1)
716             cb_();
717         return;
718     }
719
720     char buf[1024];
721     int n (buffer_.size() - target->offset > 1024 ? 1024 : buffer_.size() - target->offset);
722     std::copy(buffer_.begin() + target->offset, buffer_.begin() + target->offset + n, buf);
723
724     int w (::write(target->fd, buf, n));
725     if (w < 0) {
726         if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::write()");
727         return;
728     }
729     target->offset += w;
730
731     n = std::min_element(
732         targets_.begin(), targets_.end(),
733         boost::bind(&Target::offset, _1) < boost::bind(&Target::offset, _2))->offset;
734
735     buffer_.erase(buffer_.begin(), buffer_.begin()+n);
736
737     for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
738         i->offset -= n;
739
740     if (target->offset >= buffer_.size())
741         target->writeevent.disable();
742     if (src_ == -1 && (buffer_.empty() || targets_.empty()))
743         cb_();
744 }
745
746 #undef LIBC_CALL
747 #undef LIBC_CALL_RV
748
749 //-/////////////////////////////////////////////////////////////////////////////////////////////////
750 #undef prefix_
751 //#include "Daemon.mpp"
752
753 \f
754 // Local Variables:
755 // mode: c++
756 // fill-column: 100
757 // comment-column: 40
758 // c-file-style: "senf"
759 // indent-tabs-mode: nil
760 // ispell-local-dictionary: "american"
761 // compile-command: "scons -u test"
762 // End: