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