Search:

SENF Extensible Network Framework

  • Home
  • Download
  • Wiki
  • BerliOS
  • ChangeLog
  • Browse SVN
  • Bug Tracker
  • Overview
  • Examples
  • HowTos
  • Glossary
  • PPI
  • Packets
  • Scheduler
  • Socket
  • Utils
  • Console
  • Daemon
  • Logger
  • Termlib
  • Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

Daemon.cc

Go to the documentation of this file.
00001 // $Id: Daemon.cc 1790 2011-06-06 16:32:21Z tho $
00002 //
00003 // Copyright (C) 2007
00004 // Fraunhofer (FOKUS)
00005 // Competence Center NETwork research (NET), St. Augustin, GERMANY
00006 //     Stefan Bund <g0dil@berlios.de>
00007 //
00008 // This program is free software; you can redistribute it and/or modify
00009 // it under the terms of the GNU General Public License as published by
00010 // the Free Software Foundation; either version 2 of the License, or
00011 // (at your option) any later version.
00012 //
00013 // This program is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016 // GNU General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU General Public License
00019 // along with this program; if not, write to the
00020 // Free Software Foundation, Inc.,
00021 // 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00022 
00026 #include "Daemon.hh"
00027 #include "Daemon.ih"
00028 
00029 // Custom includes
00030 #include <sys/types.h>
00031 #include <sys/stat.h>
00032 #include <sys/wait.h>
00033 #include <unistd.h>
00034 #include <limits.h>
00035 #include <fcntl.h>
00036 #include <errno.h>
00037 #include <signal.h>
00038 #ifdef SENF_BACKTRACE
00039    #include <execinfo.h>
00040 #endif
00041 #include <sstream>
00042 #include <algorithm>
00043 #include <boost/algorithm/string/predicate.hpp>
00044 #include <boost/algorithm/string/trim.hpp>
00045 #include <boost/format.hpp>
00046 #include <senf/Utils/Exception.hh>
00047 #include <senf/Utils/membind.hh>
00048 #include <senf/Utils/Backtrace.hh>
00049 #include <senf/Utils/signalnames.hh>
00050 
00051 // #define __USE_GNU
00052 #include <ucontext.h>
00053 
00054 //#include "Daemon.mpp"
00055 #define prefix_
00056 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00057 
00058 #define LIBC_CALL(fn, args) if (fn args < 0) \
00059     SENF_THROW_SYSTEM_EXCEPTION(#fn "()")
00060 
00061 #define LIBC_CALL_RV(var, fn, args) \
00062     int var (fn args); if (var < 0) SENF_THROW_SYSTEM_EXCEPTION(#fn "()")
00063 
00064 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00065 // senf::Daemon
00066 
00067 prefix_ senf::Daemon::~Daemon()
00068 {
00069     if (pidfileCreated_) {
00070         try {
00071             LIBC_CALL( ::unlink, (pidfile_.c_str()) );
00072         } catch (Exception & e) {
00073             // e << "; could not unlink " << pidfile_.c_str();
00074             // throw;
00075         }
00076     }
00077 }
00078 
00079 prefix_ void senf::Daemon::daemonize(bool v)
00080 {
00081     daemonize_ = v;
00082 }
00083 
00084 prefix_ bool senf::Daemon::daemon()
00085 {
00086     return daemonize_;
00087 }
00088 
00089 prefix_ int senf::Daemon::argc()
00090 {
00091     return argc_;
00092 }
00093 
00094 prefix_ char const ** senf::Daemon::argv()
00095 {
00096     return argv_;
00097 }
00098 
00099 namespace {
00100 
00101     struct IsDaemonOpt {
00102         bool operator()(std::string const & str) const {
00103             return str == "--no-daemon"
00104                 || boost::starts_with(str, std::string("--pid-file="))
00105                 || boost::starts_with(str, std::string("--console-log="));
00106         }
00107     };
00108 }
00109 
00110 prefix_ void senf::Daemon::removeDaemonArgs()
00111 {
00112     char const ** last (std::remove_if(argv_+1, argv_+argc_, IsDaemonOpt()));
00113     *last = 0;
00114     argc_ = last - argv_;
00115 }
00116 
00117 prefix_ void senf::Daemon::consoleLog(std::string const & path, StdStream which)
00118 {
00119     switch (which) {
00120     case StdOut : stdoutLog_ = path; break;
00121     case StdErr : stderrLog_ = path; break;
00122     case Both : stdoutLog_ = path; stderrLog_ = path; break;
00123     }
00124 }
00125 
00126 
00127 prefix_ void senf::Daemon::openLog()
00128 {
00129     int fd (-1);
00130     if (! stdoutLog_.empty()) {
00131         fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
00132         if (fd < 0)
00133             SENF_THROW_SYSTEM_EXCEPTION("")
00134                   << " Could not open \"" << stdoutLog_ << "\" for redirecting stdout.";
00135         stdout_ = fd;
00136     }
00137     if (! stderrLog_.empty()) {
00138         if (stderrLog_ == stdoutLog_) {
00139             stderr_ = ::dup(fd);
00140             if (stderr_ < 0)
00141                 SENF_THROW_SYSTEM_EXCEPTION("::dup()");
00142         }
00143         else {
00144             fd = ::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666);
00145             if (fd < 0)
00146                 SENF_THROW_SYSTEM_EXCEPTION("")
00147                     << " Could not open \"" << stderrLog_ << "\" for redirecting stderr.";
00148             stderr_ = fd;
00149         }
00150     }
00151 }
00152 
00153 prefix_ void senf::Daemon::logReopen()
00154 {
00155     if (! stdoutLog_.empty()) {
00156         int fd (::open(stdoutLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666));
00157         if (fd < 0)
00158             goto error;
00159         if (::dup2(fd, 1) < 0)
00160             goto error;
00161         if (stderrLog_ == stdoutLog_) {
00162             if (::dup2(fd, 2) < 0)
00163                 goto error;
00164             return;
00165         }
00166     }
00167     if (! stderrLog_.empty()) {
00168         int fd (::open(stderrLog_.c_str(), O_WRONLY | O_APPEND | O_CREAT, 0666));
00169         if (fd < 0)
00170             goto error;
00171         if (::dup2(fd, 2) < 0)
00172             goto error;
00173     }
00174     return;
00175 
00176  error:
00177     SENF_LOG(
00178         (senf::log::CRITICAL)
00179         ("log-file reopen failed: (" << errno << ") " << ::strerror(errno)) );
00180 }
00181 
00182 prefix_ void senf::Daemon::pidFile(std::string const & f)
00183 {
00184     pidfile_ = f;
00185 }
00186 
00187 namespace {
00188     bool signaled (false);
00189     void waitusr(int) {
00190         signaled = true;
00191     }
00192 }
00193 
00194 prefix_ void senf::Daemon::detach()
00195 {
00196     if (daemonize_ && ! detached_) {
00197         // Wow .. ouch ..
00198         // To ensure all data is written to the console log file in the correct order, we suspend
00199         // execution here until the parent process tells us to continue via SIGUSR1: We block
00200         // SIGUSR1 and install our own signal handler saving the old handler and signal mask. Then
00201         // we close stdin/stderr which will send a HUP condition to the parent process. We wait for
00202         // SIGUSR1 and reinstall the old signal mask and action.
00203         ::sigset_t oldsig;
00204         ::sigset_t usrsig;
00205         ::sigemptyset(&usrsig);
00206         LIBC_CALL( ::sigaddset, (&usrsig, SIGUSR1) );
00207         LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &usrsig, &oldsig) );
00208         struct ::sigaction oldact;
00209         struct ::sigaction usract;
00210         ::memset(&usract, 0, sizeof(usract));
00211         usract.sa_handler = &waitusr;
00212         LIBC_CALL( ::sigaction, (SIGUSR1, &usract, &oldact) );
00213         ::sigset_t waitsig (oldsig);
00214         LIBC_CALL( ::sigdelset, (&waitsig, SIGUSR1) );
00215 
00216         LIBC_CALL_RV( nul, ::open, ("/dev/null", O_WRONLY) );
00217         LIBC_CALL( ::dup2, (stdout_ == -1 ? nul : stdout_, 1) );
00218         LIBC_CALL( ::dup2, (stderr_ == -1 ? nul : stderr_, 2) );
00219         LIBC_CALL( ::close, (nul) );
00220 
00221         signaled = false;
00222         while (! signaled) {
00223             ::sigsuspend(&waitsig);
00224             if (errno != EINTR)
00225                 SENF_THROW_SYSTEM_EXCEPTION("::sigsuspend()");
00226         }
00227 
00228         LIBC_CALL( ::sigaction, (SIGUSR1, &oldact, 0) );
00229         LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
00230 
00231         detached_ = true;
00232     }
00233 }
00234 
00235 namespace {
00236     /* Purposely *not* derived from std::exception */
00237     struct DaemonExitException {
00238         DaemonExitException(unsigned c) : code(c) {}
00239         unsigned code;
00240     };
00241 }
00242 
00243 prefix_ void senf::Daemon::exit(unsigned code)
00244 {
00245     throw DaemonExitException(code);
00246 }
00247 
00248 prefix_ int senf::Daemon::start(int argc, char const ** argv)
00249 {
00250     argc_ = argc;
00251     argv_ = argv;
00252 
00253     try {
00254         configure();
00255 
00256         if (daemonize_) {
00257             openLog();
00258             fork();
00259         }
00260         installSighandlers();
00261         if (! pidfile_.empty()) {
00262             if (pidfileCreate())
00263                 pidfileCreated_ = true;
00264             else {
00265                 std::cerr << "PID file '" << pidfile_
00266                           << "' creation failed. Daemon running ?" << std::endl;
00267                 return 1;
00268             }
00269         }
00270 
00271         main();
00272     }
00273     catch (DaemonExitException & e) {
00274         return e.code;
00275     }
00276 
00277 #ifndef SENF_DEBUG
00278 
00279     catch (std::exception & e) {
00280         std::cerr << "\n*** Fatal exception: " << e.what() << "\n" << std::endl;
00281         return 1;
00282     }
00283     catch (...) {
00284         std::cerr << "\n*** Fatal exception: (unknown)" << "\n" << std::endl;
00285         return 1;
00286     }
00287 
00288 #   endif
00289 
00290     return 0;
00291 }
00292 
00293 prefix_ senf::Daemon & senf::Daemon::instance()
00294 {
00295     BOOST_ASSERT( instance_ );
00296     return *instance_;
00297 }
00298 
00299 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00300 // protected members
00301 
00302 prefix_ senf::Daemon::Daemon()
00303     : argc_(0), argv_(0), daemonize_(true), stdout_(-1), stderr_(-1), pidfile_(""),
00304       pidfileCreated_(false), detached_(false)
00305 {
00306     BOOST_ASSERT( ! instance_ );
00307     instance_ = this;
00308 }
00309 
00310 senf::Daemon * senf::Daemon::instance_ (0);
00311 
00312 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00313 // private members
00314 
00315 prefix_ void senf::Daemon::configure()
00316 {
00317     // int i (not unsigned) since argc_ is int ...
00318     for (int i (1); i<argc_; ++i) {
00319         std::string argv (argv_[i]);
00320         if (argv == "--no-daemon")
00321             daemonize(false);
00322         else if (boost::starts_with(argv, "--console-log=")) {
00323             std::string arg (argv.substr(14u));
00324             std::string::size_type komma (arg.find(','));
00325             if (komma == std::string::npos) {
00326                 boost::trim(arg);
00327                 if (arg == std::string("none")) consoleLog("");
00328                 else if (!arg.empty())          consoleLog(arg);
00329             } else {
00330                 std::string arg1 (arg,0,komma);
00331                 std::string arg2 (arg,komma+1);
00332                 boost::trim(arg1);
00333                 boost::trim(arg2);
00334                 if (arg1 == std::string("none")) consoleLog("",StdOut);
00335                 else if (! arg1.empty() )        consoleLog(arg1, StdOut);
00336                 if (arg2 == std::string("none")) consoleLog("",StdErr);
00337                 else if (! arg2.empty() )        consoleLog(arg2, StdErr);
00338             }
00339         }
00340         else if (boost::starts_with(argv, "--pid-file="))
00341             pidFile(std::string(std::string(argv_[i]), 11u));
00342     }
00343 }
00344 
00345 prefix_ void senf::Daemon::main()
00346 {
00347     init();
00348     detach();
00349     run();
00350 }
00351 
00352 prefix_ void senf::Daemon::init()
00353 {}
00354 
00355 prefix_ void senf::Daemon::run()
00356 {}
00357 
00358 prefix_ void senf::Daemon::fork()
00359 {
00360     int coutpipe[2];
00361     int cerrpipe[2];
00362 
00363     LIBC_CALL_RV( nul, ::open, ("/dev/null", O_RDONLY) );
00364     LIBC_CALL( ::dup2, (nul, 0) );
00365     LIBC_CALL( ::close, (nul) );
00366     LIBC_CALL( ::pipe, (coutpipe) );
00367     LIBC_CALL( ::pipe, (cerrpipe) );
00368 
00369     // We need to block the SIGCHLD signal here so we don't miss it, if the child
00370     // dies immediately
00371     ::sigset_t oldsig;
00372     ::sigset_t cldsig;
00373     ::sigemptyset(&cldsig);
00374     LIBC_CALL( ::sigaddset, (&cldsig, SIGCHLD) );
00375     LIBC_CALL( ::sigprocmask, (SIG_BLOCK, &cldsig, &oldsig) );
00376 
00377     if (! senf::scheduler::empty() ) {
00378         std::cerr <<
00379             "\n"
00380             "*** WARNING ***\n"
00381             "Scheduler not empty before fork(). THIS MUST NOT HAPPEN.\n"
00382             "The scheduler will be reinitialized by the fork() and lose all registrations.\n\n";
00383         senf::scheduler::detail::EventManager::instance().listEvents(std::cerr);
00384         std::cerr <<
00385             "\n*** WARNING ***\n"
00386             "\n";
00387     }
00388 
00389     LIBC_CALL_RV( pid, ::fork, () );
00390 
00391     if (pid == 0) {
00392         // Daemon process
00393 
00394         LIBC_CALL( ::dup2, (coutpipe[1],1) );
00395         LIBC_CALL( ::dup2, (cerrpipe[1],2) );
00396         LIBC_CALL( ::close, (coutpipe[0]) );
00397         LIBC_CALL( ::close, (coutpipe[1]) );
00398         LIBC_CALL( ::close, (cerrpipe[0]) );
00399         LIBC_CALL( ::close, (cerrpipe[1]) );
00400         LIBC_CALL( ::setsid, () );
00401         LIBC_CALL( ::sigprocmask, (SIG_SETMASK, &oldsig, 0) );
00402 
00403         senf::scheduler::restart();
00404         return;
00405     }
00406 
00407     // Ouch ... ensure, the daemon watcher does not remove the pidfile ...
00408     pidfile_ = "";
00409 
00410     LIBC_CALL( ::close, (coutpipe[1]) );
00411     LIBC_CALL( ::close, (cerrpipe[1]) );
00412 
00413     senf::scheduler::restart();
00414 
00415     detail::DaemonWatcher watcher (pid, coutpipe[0], cerrpipe[0], stdout_, stderr_);
00416     watcher.run();
00417 
00418     ::_exit(0);
00419 }
00420 
00421 prefix_ bool senf::Daemon::pidfileCreate()
00422 {
00423     // Create temporary file pidfile_.hostname.pid and hard-link it to pidfile_ If the hardlink
00424     // fails, the pidfile exists. If the link count of the temporary file is not 2 after this, there
00425     // was some race condition, probably over NFS.
00426 
00427     std::string tempname;
00428     boost::format linkErrorFormat(" Could not link \"%1%\" to \"%2%\".");
00429 
00430     {
00431         char hostname[HOST_NAME_MAX+1];
00432         LIBC_CALL( ::gethostname, (hostname, HOST_NAME_MAX+1) );
00433         hostname[HOST_NAME_MAX] = 0;
00434         std::stringstream tempname_s;
00435         tempname_s << pidfile_ << "." << hostname << "." << ::getpid();
00436         tempname = tempname_s.str();
00437     }
00438 
00439     while (1) {
00440         {
00441             std::ofstream pidf (tempname.c_str());
00442             if (! pidf)
00443                 SENF_THROW_SYSTEM_EXCEPTION("")
00444                       << " Could not open pidfile \"" << tempname << "\" for output.";
00445             pidf << ::getpid() << std::endl;
00446             if (! pidf)
00447                 SENF_THROW_SYSTEM_EXCEPTION("")
00448                       << " Could not write to pidfile \"" << tempname << "\".";
00449         }
00450 
00451         if (::link(tempname.c_str(), pidfile_.c_str()) < 0) {
00452             if (errno != EEXIST)
00453                 SENF_THROW_SYSTEM_EXCEPTION("") << linkErrorFormat % pidfile_ % tempname;
00454         }
00455         else {
00456             struct ::stat s;
00457             LIBC_CALL( ::stat, (tempname.c_str(), &s) );
00458             LIBC_CALL( ::unlink, (tempname.c_str()) );
00459             return s.st_nlink == 2;
00460         }
00461 
00462         // pidfile exists. Check, whether the pid in the pidfile still exists.
00463         {
00464             int old_pid (-1);
00465             std::ifstream pidf (pidfile_.c_str());
00466             if ( ! (pidf >> old_pid)
00467                  || old_pid < 0
00468                  || ::kill(old_pid, 0) >= 0
00469                  || errno == EPERM ) {
00470                 LIBC_CALL( ::unlink, (tempname.c_str()) );
00471                 return false;
00472             }
00473         }
00474 
00475         // If we reach this point, the pid file exists but the process mentioned within the
00476         // pid file does *not* exists. We assume, the pid file to be stale.
00477 
00478         // I hope, the following procedure is without race condition: We remove our generated
00479         // temporary pid file and recreate it as hard-link to the old pid file. Now we check, that
00480         // the hard-link count of this file is 2. If it is not, we terminate, since someone else
00481         // must have already created his hardlink. We then truncate the file and write our pid.
00482 
00483         LIBC_CALL( ::unlink, (tempname.c_str() ));
00484         if (::link(pidfile_.c_str(), tempname.c_str()) < 0) {
00485             if (errno != ENOENT)
00486                 SENF_THROW_SYSTEM_EXCEPTION("") << linkErrorFormat % tempname % pidfile_;
00487             // Hmm ... the pidfile mysteriously disappeared ... try again.
00488             continue;
00489         }
00490 
00491         {
00492             struct ::stat s;
00493             LIBC_CALL( ::stat, (tempname.c_str(), &s) );
00494             if (s.st_nlink != 2) {
00495                 LIBC_CALL( ::unlink, (tempname.c_str()) );
00496                 return false;
00497             }
00498         }
00499 
00500         {
00501             std::ofstream pidf (tempname.c_str());
00502             pidf << ::getpid() << std::endl;
00503         }
00504 
00505         LIBC_CALL( ::unlink, (tempname.c_str()) );
00506         break;
00507     }
00508     return true;
00509 }
00510 
00511 
00512 #ifdef SENF_DEBUG
00513 
00514 namespace {
00515     void fatalSignalsHandler(int sig, ::siginfo_t * info, void * arg)
00516     {
00517         // ::ucontext_t * ucontext = static_cast<ucontext_t*>(arg);
00518         std::cerr << "\n" << "Signal " << senf::signalName(sig) << '(' << sig << ')'
00519                   << " received\n";
00520 
00521         if (sig == SIGSEGV)
00522             std::cerr << "Invalid memory access at " << info->si_addr << "\n";
00523 #ifdef SENF_BACKTRACE
00524         static void * entries[SENF_DEBUG_BACKTRACE_NUMCALLERS];
00525         int nEntries( ::backtrace(entries, SENF_DEBUG_BACKTRACE_NUMCALLERS) );
00526 
00527         // Hack the callers address into the backtrace
00528         // entries[1] = reinterpret_cast<void *>(ucontext->uc_mcontext.gregs[REG_EIP]);
00529 
00530         std::cerr << "Backtrace:\n";
00531         senf::formatBacktrace(std::cerr, entries, nEntries);
00532         std::cerr << "-- \n";
00533 #endif //SENF_BACKTRACE
00534         if (sig != SIGUSR2) {
00535             ::signal(sig, SIG_DFL);
00536             ::kill(::getpid(), sig);
00537         }
00538     }
00539 
00540 }
00541 
00542 #endif // SENF_DEBUG
00543 
00544 namespace {
00545     void sighupHandler(int sig)
00546     {
00547         senf::Daemon::instance().logReopen();
00548     }
00549 }
00550 
00551 prefix_ void senf::Daemon::installSighandlers()
00552 {
00553     struct ::sigaction sa;
00554 
00555     ::sigemptyset(&sa.sa_mask);
00556     sa.sa_handler = &sighupHandler;
00557     sa.sa_flags = SA_RESTART;
00558 
00559     ::sigaction(SIGHUP,   &sa, NULL);
00560 
00561     sa.sa_handler = SIG_IGN;
00562     ::sigaction(SIGPIPE, &sa, NULL);
00563 
00564 #ifdef SENF_DEBUG
00565     sa.sa_sigaction = &fatalSignalsHandler;
00566     sa.sa_flags = SA_RESTART | SA_SIGINFO;
00567 
00568     ::sigaction(SIGILL,    &sa, NULL);
00569     ::sigaction(SIGTRAP,   &sa, NULL);
00570     ::sigaction(SIGABRT,   &sa, NULL);
00571     ::sigaction(SIGFPE,    &sa, NULL);
00572     ::sigaction(SIGBUS,    &sa, NULL);
00573     ::sigaction(SIGSEGV,   &sa, NULL);
00574 #ifdef SIGSTKFLT //SIGSTKFLT is used for stack faults on coprocessors. That condition doesn't exist on MIPS
00575     ::sigaction(SIGSTKFLT, &sa, NULL);
00576 #endif
00577     ::sigaction(SIGSYS,    &sa, NULL);
00578     ::sigaction(SIGUSR2,   &sa, NULL);
00579 #endif
00580 }
00581 
00582 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00583 // senf::detail::DaemonWatcher
00584 
00585 prefix_ senf::detail::DaemonWatcher::DaemonWatcher(int pid, int coutpipe, int cerrpipe,
00586                                                    int stdout, int stderr)
00587     : childPid_(pid), coutpipe_(coutpipe), cerrpipe_(cerrpipe), stdout_(stdout),
00588       stderr_(stderr), sigChld_(false),
00589       cldSignal_ (SIGCHLD, senf::membind(&DaemonWatcher::sigChld, this)),
00590       timer_ ("senf::detail::DaemonWatcher::childOk", senf::membind(&DaemonWatcher::childOk, this)),
00591       coutForwarder_(coutpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 1)),
00592       cerrForwarder_(cerrpipe_, boost::bind(&DaemonWatcher::pipeClosed, this, 2))
00593 {
00594     coutForwarder_.addTarget(1);
00595     if (stdout_ >= 0)
00596         coutForwarder_.addTarget(stdout_);
00597     cerrForwarder_.addTarget(2);
00598     if (stderr_ >= 0)
00599         cerrForwarder_.addTarget(stderr_);
00600 }
00601 
00602 prefix_ void senf::detail::DaemonWatcher::run()
00603 {
00604     scheduler::process();
00605 }
00606 
00607 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00608 // private members
00609 
00610 prefix_ void senf::detail::DaemonWatcher::pipeClosed(int id)
00611 {
00612     switch (id) {
00613     case 1 : coutpipe_ = -1; break;
00614     case 2 : cerrpipe_ = -1; break;
00615     }
00616 
00617     if (coutpipe_ == -1 && cerrpipe_ == -1) {
00618         if (sigChld_)
00619             childDied(); // does not return
00620         if (::kill(childPid_, SIGUSR1) < 0 && errno != ESRCH)
00621             SENF_THROW_SYSTEM_EXCEPTION("::kill()");
00622         timer_.timeout(scheduler::eventTime() + ClockService::seconds(1));
00623     }
00624 }
00625 
00626 prefix_ void senf::detail::DaemonWatcher::sigChld(siginfo_t const &)
00627 {
00628     sigChld_ = true;
00629     if (coutpipe_ == -1 && cerrpipe_ == -1)
00630         childDied(); // does not return
00631 }
00632 
00633 prefix_ void senf::detail::DaemonWatcher::childDied()
00634 {
00635     int status (0);
00636     if (::waitpid(childPid_,&status,0) < 0) SENF_THROW_SYSTEM_EXCEPTION("::waitpid()");
00637     if (WIFSIGNALED(status)) {
00638         ::signal(WTERMSIG(status),SIG_DFL);
00639         ::kill(::getpid(), WTERMSIG(status));
00640         // should not be reached
00641         ::_exit(126);
00642     }
00643     if (WEXITSTATUS(status) == 0)
00644         ::_exit(127);
00645     ::_exit(WEXITSTATUS(status));
00646 }
00647 
00648 prefix_ void senf::detail::DaemonWatcher::childOk()
00649 {
00650     scheduler::terminate();
00651 }
00652 
00653 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00654 // senf::detail::DaemonWatcher::Forwarder
00655 
00656 prefix_ senf::detail::DaemonWatcher::Forwarder::Forwarder(int src, Callback cb)
00657     : src_(src), cb_(cb),
00658       readevent_("senf::detail::DaemonWatcher::Forwarder::readevent", senf::membind(&Forwarder::readData, this),
00659                  src_, scheduler::FdEvent::EV_READ)
00660 {}
00661 
00662 prefix_ senf::detail::DaemonWatcher::Forwarder::~Forwarder()
00663 {
00664     targets_.clear_and_destroy(DestroyDelete());
00665 }
00666 
00667 prefix_ void senf::detail::DaemonWatcher::Forwarder::addTarget(int fd)
00668 {
00669     targets_.push_back(*(new Target(*this, fd)));
00670 }
00671 
00672 prefix_ void senf::detail::DaemonWatcher::Forwarder::readData(int event)
00673 {
00674     char buf[1024];
00675     int n (0);
00676 
00677     while (1) {
00678         n = ::read(src_,buf,1024);
00679         if (n<0) {
00680             if (errno != EINTR)
00681                 SENF_THROW_SYSTEM_EXCEPTION("::read()");
00682         }
00683         else
00684             break;
00685     }
00686 
00687     if (n == 0) {
00688         if (buffer_.empty())
00689             cb_();
00690         src_ = -1;
00691         readevent_.disable();
00692         return;
00693     }
00694 
00695     if (targets_.empty())
00696         return;
00697 
00698     for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
00699         if (i->offset >= buffer_.size())
00700             i->writeevent.enable();
00701 
00702     buffer_.insert(buffer_.end(), buf, buf+n);
00703 }
00704 
00705 prefix_ void senf::detail::DaemonWatcher::Forwarder::writeData(int event, Target * target)
00706 {
00707     if (event != scheduler::FdEvent::EV_WRITE) {
00708         // Broken pipe while writing data ? Not much, we can do here, we just drop the data
00709         targets_.erase_and_destroy(Targets::current(*target),DestroyDelete());
00710         if (targets_.empty() && src_ == -1)
00711             cb_();
00712         return;
00713     }
00714 
00715     char buf[1024];
00716     int n (buffer_.size() - target->offset > 1024 ? 1024 : buffer_.size() - target->offset);
00717     std::copy(buffer_.begin() + target->offset, buffer_.begin() + target->offset + n, buf);
00718 
00719     int w (::write(target->fd, buf, n));
00720     if (w < 0) {
00721         if (errno != EINTR) SENF_THROW_SYSTEM_EXCEPTION("::write()");
00722         return;
00723     }
00724     target->offset += w;
00725 
00726     n = std::min_element(
00727         targets_.begin(), targets_.end(),
00728         boost::bind(&Target::offset, _1) < boost::bind(&Target::offset, _2))->offset;
00729 
00730     buffer_.erase(buffer_.begin(), buffer_.begin()+n);
00731 
00732     for (Targets::iterator i (targets_.begin()); i != targets_.end(); ++i)
00733         i->offset -= n;
00734 
00735     if (target->offset >= buffer_.size())
00736         target->writeevent.disable();
00737     if (src_ == -1 && (buffer_.empty() || targets_.empty()))
00738         cb_();
00739 }
00740 
00741 #undef LIBC_CALL
00742 #undef LIBC_CALL_RV
00743 
00744 //-/////////////////////////////////////////////////////////////////////////////////////////////////
00745 #undef prefix_
00746 //#include "Daemon.mpp"
00747 
00748 
00749 // Local Variables:
00750 // mode: c++
00751 // fill-column: 100
00752 // comment-column: 40
00753 // c-file-style: "senf"
00754 // indent-tabs-mode: nil
00755 // ispell-local-dictionary: "american"
00756 // compile-command: "scons -u test"
00757 // End:

Contact: senf-dev@lists.berlios.de | © 2006-2010 Fraunhofer Institute for Open Communication Systems, Network Research