void sighandler_func(int signal) { IBRCOMMON_LOGGER_TAG(TAG,notice) << "got signal " << signal << IBRCOMMON_LOGGER_ENDL; switch (signal) { case SIGTERM: case SIGINT: { //stop waiting and stop running, on SIGINT or SIGTERM ibrcommon::MutexLock l(_wait_cond); _running = false; _wait_cond.signal(true); break; } #ifndef __WIN32__ case SIGUSR1: { //stop waiting on SIGUSR1 -> "quickscan" ibrcommon::MutexLock l(_wait_cond); _wait_abort = true; _wait_cond.signal(true); break; } #endif default: break; } }
// on interruption do this! void sighandler(int signal) { // do not handle further signals if the shutdown is in progress if (_shutdown) return; switch (signal) { case SIGTERM: case SIGINT: { ibrcommon::MutexLock l(_shutdown_cond); _shutdown = true; _shutdown_cond.signal(true); break; } case SIGUSR1: if (!_debug) { ibrcommon::Logger::addStream(std::cout, ibrcommon::Logger::LOGGER_DEBUG, logopts); _debug = true; } _dtnd.setDebug(99); break; case SIGUSR2: _dtnd.setDebug(0); break; case SIGHUP: _dtnd.reload(); break; default: // dummy handler break; } }
int __daemon_run() { // catch process signals signal(SIGINT, sighandler); signal(SIGTERM, sighandler); signal(SIGHUP, sighandler); signal(SIGQUIT, sighandler); signal(SIGUSR1, sighandler); signal(SIGUSR2, sighandler); sigset_t blockset; sigemptyset(&blockset); sigaddset(&blockset, SIGPIPE); ::sigprocmask(SIG_BLOCK, &blockset, NULL); dtn::daemon::Configuration &conf = dtn::daemon::Configuration::getInstance(); // set default logging tag ibrcommon::Logger::setDefaultTag("DTNEngine"); // enable ring-buffer ibrcommon::Logger::enableBuffer(200); // enable timestamps in logging if requested if (conf.getLogger().display_timestamps()) { logopts = (~(ibrcommon::Logger::LOG_DATETIME) & logopts) | ibrcommon::Logger::LOG_TIMESTAMP; } // init syslog ibrcommon::Logger::enableAsync(); // enable asynchronous logging feature (thread-safe) ibrcommon::Logger::enableSyslog("ibrdtn-daemon", LOG_PID, LOG_DAEMON, logsys); if (!conf.getDebug().quiet()) { if (conf.getLogger().verbose()) { // add logging to the cout ibrcommon::Logger::addStream(std::cout, logstd | ibrcommon::Logger::LOGGER_NOTICE, logopts); } else { // add logging to the cout ibrcommon::Logger::addStream(std::cout, logstd, logopts); } // add logging to the cerr ibrcommon::Logger::addStream(std::cerr, logerr, logopts); } // activate debugging if (conf.getDebug().enabled() && !conf.getDebug().quiet()) { // init logger ibrcommon::Logger::setVerbosity(conf.getDebug().level()); ibrcommon::Logger::addStream(std::cout, ibrcommon::Logger::LOGGER_DEBUG, logopts); _debug = true; } // load the configuration file conf.load(); try { const ibrcommon::File &lf = conf.getLogger().getLogfile(); ibrcommon::Logger::setLogfile(lf, ibrcommon::Logger::LOGGER_ALL ^ ibrcommon::Logger::LOGGER_DEBUG, logopts); } catch (const dtn::daemon::Configuration::ParameterNotSetException&) { }; // initialize the daemon up to runlevel "Routing Extensions" _dtnd.init(dtn::daemon::RUNLEVEL_ROUTING_EXTENSIONS); #ifdef HAVE_LIBDAEMON if (conf.getDaemon().daemonize()) { /* Send OK to parent process */ daemon_retval_send(0); daemon_log(LOG_INFO, "Sucessfully started"); } #endif ibrcommon::MutexLock l(_shutdown_cond); while (!_shutdown) _shutdown_cond.wait(); _dtnd.init(dtn::daemon::RUNLEVEL_ZERO); // stop the asynchronous logger ibrcommon::Logger::stop(); return 0; }
/* * main application method */ int main( int argc, char** argv ) { // catch process signals ibrcommon::SignalHandler sighandler(sighandler_func); sighandler.handle(SIGINT); sighandler.handle(SIGTERM); #ifndef __WIN32__ sighandler.handle(SIGUSR1); #endif // configration object config_t conf; // read the configuration read_configuration(argc, argv, conf); init_logger(conf); // initialize sighandler after possible exit call sighandler.initialize(); // init working directory if (conf.workdir.length() > 0) { ibrcommon::File blob_path(conf.workdir); if (blob_path.exists()) { ibrcommon::BLOB::changeProvider(new ibrcommon::FileBLOBProvider(blob_path), true); } } // backoff for reconnect unsigned int backoff = 2; ibrcommon::File outbox_file(conf.outbox); // create new file lists fileset new_files, prev_files, deleted_files, files_to_send; filelist observed_files; hashlist sent_hashes; // observed root file io::ObservedFile root(ibrcommon::File("/")); #ifdef HAVE_LIBTFFS io::FatImageReader *imagereader = NULL; #endif if (outbox_file.exists() && !outbox_file.isDirectory()) { #ifdef HAVE_LIBTFFS conf.fat = true; imagereader = new io::FatImageReader(conf.outbox); const io::FATFile fat_root(*imagereader, conf.path); root = io::ObservedFile(fat_root); #else IBRCOMMON_LOGGER_TAG(TAG,error) << "ERROR: image-file provided, but this tool has been compiled without libtffs support!" << IBRCOMMON_LOGGER_ENDL; return -1; #endif } else { if (!outbox_file.exists()) { ibrcommon::File::createDirectory(outbox_file); } root = io::ObservedFile(outbox_file); } IBRCOMMON_LOGGER_TAG(TAG,info) << "-- dtnoutbox --" << IBRCOMMON_LOGGER_ENDL; // loop, if no stop if requested while (_running) { try { // Create a stream to the server using TCP. ibrcommon::vaddress addr("localhost", 4550); ibrcommon::socketstream conn(new ibrcommon::tcpsocket(addr)); // Initiate a client for synchronous receiving dtn::api::Client client(conf.name, conn, dtn::api::Client::MODE_SENDONLY); // Connect to the server. Actually, this function initiate the // stream protocol by starting the thread and sending the contact header. client.connect(); // reset backoff if connected backoff = 2; // check the connection while (_running) { // get all files fileset current_files; root.findFiles(current_files); // determine deleted files fileset deleted_files; std::set_difference(prev_files.begin(), prev_files.end(), current_files.begin(), current_files.end(), std::inserter(deleted_files, deleted_files.begin())); // remove deleted files from observation for (fileset::const_iterator iter = deleted_files.begin(); iter != deleted_files.end(); ++iter) { const io::ObservedFile &deletedFile = (*iter); // remove references in the sent_hashes for (hashlist::iterator hash_it = sent_hashes.begin(); hash_it != sent_hashes.end(); /* blank */) { if ((*hash_it).getPath() == deletedFile.getFile().getPath()) { sent_hashes.erase(hash_it++); } else { ++hash_it; } } // remove from observed files observed_files.remove(deletedFile); // output IBRCOMMON_LOGGER_TAG(TAG,info) << "file removed: " << deletedFile.getFile().getBasename() << IBRCOMMON_LOGGER_ENDL; } // determine new files fileset new_files; std::set_difference(current_files.begin(), current_files.end(), prev_files.begin(), prev_files.end(), std::inserter(new_files, new_files.begin())); // add new files to observation for (fileset::const_iterator iter = new_files.begin(); iter != new_files.end(); ++iter) { const io::ObservedFile &of = (*iter); int reg_ret = regexec(&conf.regex, of.getFile().getBasename().c_str(), 0, NULL, 0); if (!reg_ret && !conf.invert) continue; if (reg_ret && conf.invert) continue; // print error message, if regex error occurs if (reg_ret && reg_ret != REG_NOMATCH) { char msgbuf[100]; regerror(reg_ret,&conf.regex,msgbuf,sizeof(msgbuf)); IBRCOMMON_LOGGER_TAG(TAG,info) << "ERROR: regex match failed : " << std::string(msgbuf) << IBRCOMMON_LOGGER_ENDL; } // add new file to the observed set observed_files.push_back(of); // log output IBRCOMMON_LOGGER_TAG(TAG, info) << "file found: " << of.getFile().getBasename() << IBRCOMMON_LOGGER_ENDL; } // store current files for the next round prev_files.clear(); prev_files.insert(current_files.begin(), current_files.end()); IBRCOMMON_LOGGER_TAG(TAG, notice) << "file statistics: " << observed_files.size() << " observed, " << deleted_files.size() << " deleted, " << new_files.size() << " new" << IBRCOMMON_LOGGER_ENDL; // find files to send, create std::list files_to_send.clear(); IBRCOMMON_LOGGER_TAG(TAG, notice) << "updating observed files:" << IBRCOMMON_LOGGER_ENDL; for (filelist::iterator iter = observed_files.begin(); iter != observed_files.end(); ++iter) { io::ObservedFile &of = (*iter); // tick and update all files of.update(); if (of.getStableCounter() > conf.rounds) { if (sent_hashes.find(of.getHash()) == sent_hashes.end()) { sent_hashes.insert(of.getHash()); files_to_send.insert(*iter); } } IBRCOMMON_LOGGER_TAG(TAG, notice) << "\t" << of.getFile().getBasename() << ": " << of.getStableCounter() << IBRCOMMON_LOGGER_ENDL; } if (!files_to_send.empty()) { std::stringstream ss; for (fileset::const_iterator it = files_to_send.begin(); it != files_to_send.end(); ++it) { ss << (*it).getFile().getBasename() << " "; } IBRCOMMON_LOGGER_TAG("dtnoutbox",info) << "files sent: " << ss.str() << IBRCOMMON_LOGGER_ENDL; try { // create a blob ibrcommon::BLOB::Reference blob = ibrcommon::BLOB::create(); // write files into BLOB while it is locked { ibrcommon::BLOB::iostream stream = blob.iostream(); io::TarUtils::write(*stream, root, files_to_send); } // create a new bundle dtn::data::EID destination = EID(conf.destination); // create a new bundle dtn::data::Bundle b; // set destination b.destination = destination; // add payload block using the blob b.push_back(blob); // set destination address to non-singleton, if configured if (conf.bundle_group) b.set(dtn::data::PrimaryBlock::DESTINATION_IS_SINGLETON, false); // send the bundle client << b; client.flush(); } catch (const ibrcommon::IOException &e) { IBRCOMMON_LOGGER_TAG(TAG,error) << "send failed: " << e.what() << IBRCOMMON_LOGGER_ENDL; } } // wait defined seconds ibrcommon::MutexLock l(_wait_cond); IBRCOMMON_LOGGER_TAG(TAG, notice) << conf.interval <<" ms wait" << IBRCOMMON_LOGGER_ENDL; while (!_wait_abort && _running) { _wait_cond.wait(conf.interval); } _wait_abort = false; } // clean up regex regfree(&conf.regex); // close the client connection client.close(); // close the connection conn.close(); } catch (const ibrcommon::socket_exception&) { if (_running) { IBRCOMMON_LOGGER_TAG(TAG,error) << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << IBRCOMMON_LOGGER_ENDL; ibrcommon::Thread::sleep(backoff * 1000); // if backoff < 10 minutes if (backoff < 600) { // set a new backoff backoff = backoff * 2; } } } catch (const ibrcommon::IOException&) { if (_running) { IBRCOMMON_LOGGER_TAG(TAG,error) << "Connection to bundle daemon failed. Retry in " << backoff << " seconds." << IBRCOMMON_LOGGER_ENDL; ibrcommon::Thread::sleep(backoff * 1000); // if backoff < 10 minutes if (backoff < 600) { // set a new backoff backoff = backoff * 2; } } } catch (const std::exception&) { }; } // clear observed files observed_files.clear(); #ifdef HAVE_LIBTFFS // clean-up if (imagereader != NULL) delete imagereader; #endif return (EXIT_SUCCESS); }