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