//=========================================================================== // @(#) $Name: cflowd-2-1-b1 $ // @(#) $Id: cfdcollect.cc,v 1.12 1999/08/18 06:56:12 dwm Exp $ //=========================================================================== // CAIDA Copyright Notice // // By accessing this software, cflowd, you are duly informed // of and agree to be bound by the conditions described below in this // notice: // // This software product, cflowd, is developed by Daniel W. McRobb, and // copyrighted(C) 1998 by the University of California, San Diego // (UCSD), with all rights reserved. UCSD administers the CAIDA grant, // NCR-9711092, under which part of this code was developed. // // There is no charge for cflowd software. You can redistribute it // and/or modify it under the terms of the GNU General Public License, // v. 2 dated June 1991 which is incorporated by reference herein. // cflowd is distributed WITHOUT ANY WARRANTY, IMPLIED OR EXPRESS, OF // MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE or that the use // of it will not infringe on any third party's intellectual property // rights. // // You should have received a copy of the GNU GPL along with cflowd. // Copies can also be obtained from: // // http://www.gnu.org/copyleft/gpl.html // // or by writing to: // // University of California, San Diego // // SDSC/CAIDA // 9500 Gilman Dr., MS-0505 // La Jolla, CA 92093 - 0505 USA // // Or contact: // // info@caida.org //=========================================================================== extern "C" { #include "aclocal.h" #include #if HAVE_SYS_FILIO_H #define BSD_COMP 1 #endif #include #include #include #include #include #include #include #include #include #include #include #if HAVE_SYS_SELECT_H #include #endif } #include #include #include "Arts.hh" #include "ArtsPortTable.hh" #include "ArtsProtocolTable.hh" #include "ArtsAsMatrix.hh" #include "ArtsNetMatrix.hh" #include "CflowdCisco.hh" #include "CflowdVersion.hh" #include "CfdcollectConfig.hh" #include "Signal.hh" static const string rcsid = "@(#) $Name: cflowd-2-1-b1 $ $Id: cfdcollect.cc,v 1.12 1999/08/18 06:56:12 dwm Exp $"; static CflowdVersion g_cflowdVersion = CflowdVersion(rcsid); static CfdcollectConfig g_config; extern int LoadCfdcollectConfigFile(const char *configFileName, CfdcollectConfig & config); //------------------------------------------------------------------------- // static void Daemonize() //......................................................................... // Become a daemon process. //------------------------------------------------------------------------- static void Daemonize() { int rc; int fd; rc = fork(); if (rc > 0) exit(0); if (rc < 0) { syslog(LOG_ERR,"[E] fork() failed: %m {%s:%d}",__FILE__,__LINE__); syslog(LOG_ERR,"[E] exiting {%s:%d}",__FILE__,__LINE__); exit(1); } // disassociate from process group setpgid(0,getpid()); // ignore terminal I/O signals #ifdef SIGTTOU signal(SIGTTOU, SIG_IGN); #endif // disassociate from control terminal if ((fd = open("/dev/tty",O_RDWR)) >= 0) { ioctl(fd,TIOCNOTTY,(char *)0); close(fd); } return; } //------------------------------------------------------------------------- // static void HandleSigHup(int signalSumber) //......................................................................... // SIGHUP handler. //------------------------------------------------------------------------- static void HandleSigHup(int signalSumber) { syslog(LOG_INFO,"[I] SIGHUP received, reloading..."); return; } //------------------------------------------------------------------------- // static void HandleSigAlrm(int signalSumber) //......................................................................... // SIGALRM handler. //------------------------------------------------------------------------- static void HandleSigAlrm(int signalSumber) { syslog(LOG_INFO,"[I] awakened by alarm."); return; } //-------------------------------------------------------------------------- // static void RemovePidFile() //.......................................................................... // Removes the PID file (where we store our process ID). //-------------------------------------------------------------------------- static void RemovePidFile() { if (unlink(g_config.PidFile().c_str()) < 0) { syslog(LOG_ERR,"[E] unlink(\"%s\") failed: %m {%s:%d}", g_config.PidFile().c_str(),__FILE__,__LINE__); } return; } //-------------------------------------------------------------------------- // static int UpdatePidFile() //.......................................................................... // Puts process ID into file named by g_config.pidFileName. // Returns 0. //-------------------------------------------------------------------------- static int UpdatePidFile() { pid_t processId; ofstream pidFileStream(g_config.PidFile().c_str()); if (! pidFileStream) { syslog(LOG_ERR,"[E] unable to open pidfile '%s': %m {%s:%d}", g_config.PidFile().c_str(),__FILE__,__LINE__); return(-1); } processId = getpid(); pidFileStream << processId << endl; pidFileStream.close(); return(0); } //------------------------------------------------------------------------- // static void HandleSigTerm(int signalSumber) //......................................................................... // SIGTERM handler. //------------------------------------------------------------------------- static void HandleSigTerm(int signalSumber) { syslog(LOG_INFO,"[I] received SIGTERM. Exiting."); RemovePidFile(); exit(1); } //---------------------------------------------------------------------------- // static void HandleSigUsr1(int signalNumber) //............................................................................ // SIGUSR1 handler. //---------------------------------------------------------------------------- static void HandleSigUsr1(int signalNumber) { syslog(LOG_INFO,"[I] received SIGUSR1."); return; } //------------------------------------------------------------------------- // void Usage(const char *argv0) //......................................................................... // //------------------------------------------------------------------------- void Usage(const char *argv0) { cerr << "usage: " << argv0 << " configfile" << endl; return; } //------------------------------------------------------------------------- // int main(int argc, char *argv[]) //......................................................................... // //------------------------------------------------------------------------- int main(int argc, char *argv[]) { time_t now; vector::iterator cflowdIter; time_t sleepTime; bool canSleep; Signal sigHup(SIGHUP); Signal sigAlarm(SIGALRM); Signal sigTerm(SIGTERM); Signal sigUsr1(SIGUSR1); if (argc != 2) { Usage(argv[0]); exit(1); } if (LoadCfdcollectConfigFile(argv[1],g_config) < 0) { cerr << "failed to load config file '" << argv[1] << "': " << strerror(errno) << endl; Usage(argv[0]); exit(1); } Daemonize(); openlog("cfdcollect",LOG_PID,g_config.LogFacility()); syslog(LOG_INFO, "[I] cfdcollect (version %s) started with %d cflowd instances.", g_cflowdVersion.Name().c_str(),g_config.CflowdServers().size()); UpdatePidFile(); // install signal handlers sigHup.InstallHandler(HandleSigHup); sigAlarm.InstallHandler(HandleSigAlrm); sigTerm.InstallHandler(HandleSigTerm); for (;;) { sigHup.Unblock(); if (sigHup.Caught()) { sigHup.Catch(); g_config.Clear(); LoadCfdcollectConfigFile(argv[1],g_config); openlog("cfdcollect",LOG_PID,g_config.LogFacility()); syslog(LOG_INFO,"[I] Reloaded, now have %d cflowd instances.", g_config.CflowdServers().size()); } sigHup.Block(); time(&now); sleepTime = 1000000; canSleep = true; for (cflowdIter = g_config.CflowdServers().begin(); cflowdIter != g_config.CflowdServers().end(); cflowdIter++) { if (now >= (*cflowdIter).NextPollTime()) { canSleep = false; break; } if (((*cflowdIter).NextPollTime() - now) < sleepTime) { sleepTime = (*cflowdIter).NextPollTime() - now; } } struct itimerval timerValue; if (canSleep) { sigset_t sigSuspendMask; // set a timer, then sigsuspend() sigfillset(&sigSuspendMask); sigdelset(&sigSuspendMask,SIGALRM); sigdelset(&sigSuspendMask,SIGTERM); sigdelset(&sigSuspendMask,SIGHUP); timerValue.it_interval.tv_sec = 0; timerValue.it_interval.tv_usec = 0; timerValue.it_value.tv_sec = sleepTime; timerValue.it_value.tv_usec = 0; syslog(LOG_INFO,"[I] sleeping for %d seconds.",sleepTime); sigHup.Unblock(); setitimer(ITIMER_REAL,&timerValue,(struct itimerval *)NULL); sigsuspend(&sigSuspendMask); timerValue.it_interval.tv_sec = 0; timerValue.it_interval.tv_usec = 0; timerValue.it_value.tv_sec = 0; timerValue.it_value.tv_usec = 0; setitimer(ITIMER_REAL,&timerValue,(struct itimerval *)NULL); sigAlarm.Catch(); sigHup.Block(); } for (cflowdIter = g_config.CflowdServers().begin(); cflowdIter != g_config.CflowdServers().end(); cflowdIter++) { if (now > (*cflowdIter).NextPollTime()) { // Block SIGTERM. sigTerm.Block(); // set a timer so we don't block in read if a host doesn't // respond. We use a value of 600 seconds; this is just // an off-the-cuff value and subject to change (but note // the intent is to prevent a really long hang time in // a blocked read()). timerValue.it_interval.tv_sec = 0; timerValue.it_interval.tv_usec = 0; timerValue.it_value.tv_sec = 600; timerValue.it_value.tv_usec = 0; setitimer(ITIMER_REAL,&timerValue,(struct itimerval *)NULL); // get the data. (*cflowdIter).GetData(g_config.DataDir(),g_config.FilePrefix(), sigAlarm); // cancel the timer. timerValue.it_interval.tv_sec = 0; timerValue.it_interval.tv_usec = 0; timerValue.it_value.tv_sec = 0; timerValue.it_value.tv_usec = 0; setitimer(ITIMER_REAL,&timerValue,(struct itimerval *)NULL); // Mark SIGALRM as caught. sigAlarm.Catch(); // unblock SIGTERM. sigTerm.Unblock(); } } // for (cflowdIter = g_config.CflowdServers().begin(); ...) } // for (;;) exit(0); }