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