📄 fatcontroller.cpp
字号:
//Please refer to http://dansguardian.org/?page=copyright2//for the license for this code.//Written by Daniel Barron (daniel@jadeb//.com).//For support go to http://groups.yahoo.com/group/dansguardian// This program is free software; you can redistribute it and/or modify// it under the terms of the GNU General Public License as published by// the Free Software Foundation; either version 2 of the License, or// (at your option) any later version.//// This program is distributed in the hope that it will be useful,// but WITHOUT ANY WARRANTY; without even the implied warranty of// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the// GNU General Public License for more details.//// You should have received a copy of the GNU General Public License// along with this program; if not, write to the Free Software// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA#include "autoconf/platform.h"#include <syslog.h>#include "FatController.hpp"#include <csignal>#ifdef __BSD #include <sys/wait.h>#else #include <wait.h>#endif#include <sys/stat.h>#include "ConnectionHandler.hpp"#include "DynamicURLList.hpp"#include "String.hpp"#include "Socket.hpp"#include "UDSocket.hpp"#include "SysV.hpp"#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <pwd.h>#include <cerrno>#include <unistd.h>#include <fcntl.h>#include <fstream>#include <sys/time.h>#include <sys/poll.h>#ifdef __GCCVER3 #include <istream>#else #include <istream.h>#endifextern OptionContainer o;extern bool isDaemonised;int FatController::controlIt(int pidfilefd) { o.lm.garbageCollect(); serversock.reset(); if (o.no_logger == 0) { ipcsock.reset(); } else { ipcsock.close(); } urllistsock.reset(); peersock.reset(); pid_t loggerpid = 0; // to hold the logging process pid pid_t urllistpid = 0; // to hold the logging process pid (zero to stop // warning int rc, serversockfd, fds; serversockfd = serversock.getFD(); if (serversockfd < 0) { if (!isDaemonised) { std::cerr << "Error creating server socket" << std::endl; } syslog(LOG_ERR, "%s","Error creating server socket"); return 1; // if the socket fd is not +ve then the socket // creation failed } if (o.no_logger == 0) { if (ipcsock.getFD() < 0) { if (!isDaemonised) { std::cerr << "Error creating ipc socket" << std::endl; } syslog(LOG_ERR, "%s","Error creating ipc socket"); return 1; // if the socket fd is not +ve then the socket // creation failed } } bool needdrop = false; if (o.filter_port < 1024) { #ifdef DGDEBUG std::cout << "seteuiding for low port binding" << std::endl; #endif needdrop = true; int rc; #ifdef __HPUX rc = setreuid(-1, o.root_user); #else rc = seteuid(o.root_user); #endif if (rc == -1) { syslog(LOG_ERR, "%s","Unable to seteuid() to bind filter port."); #ifdef DGDEBUG std::cerr << "Unable to seteuid() to bind filter port." << std::endl; #endif return 1; } } if (o.filter_ip.length() > 6) { // filter ip specified in conf // listen/bind to a port and ip if (serversock.bind(o.filter_ip, o.filter_port)) { if (!isDaemonised) { std::cerr << "Error binding server socket (is something else running on the filter port and ip? [" << o.filter_port << " " << o.filter_ip << "])" << std::endl; } syslog(LOG_ERR, "%s","Error binding server socket (is something else running on the filter port and ip?"); return 1; } } else { // listen/bind to a port if (serversock.bind(o.filter_port)) { if (!isDaemonised) { std::cerr << "Error binding server socket (is something else running on the filter port? [" << o.filter_port << "])" << std::endl; } syslog(LOG_ERR, "%s","Error binding server socket (is something else running on the filter port?"); return 1; } } if (needdrop) { int rc; #ifdef __HPUX rc = setreuid(-1, o.proxy_user); #else rc = seteuid(o.proxy_user); // become low priv again #endif if (rc == -1) { syslog(LOG_ERR, "%s","Unable to re-seteuid()"); #ifdef DGDEBUG std::cerr << "Unable to re-seteuid()" << std::endl; #endif return 1; // seteuid failed for some reason so exit with error } } // Needs deleting if its there// unlink(o.ipc_filename.c_str()); // this would normally be in a -r situation.// disabled as requested by Christopher Weimann <csw@k12hq.com>// Fri, 11 Feb 2005 15:42:28 -0500 // Needs deleting if its there unlink(o.urlipc_filename.c_str()); // this would normally be in a -r situation. if (o.no_logger == 0) { if (ipcsock.bind((char*) o.ipc_filename.c_str())) { // bind to file if (!isDaemonised) { std::cerr << "Error binding ipc server file (try using the SysV to stop DansGuardian then try starting it again or doing an 'rm " << o.ipc_filename << "')." << std::endl; } syslog(LOG_ERR, "%s","Error binding ipc server file (try using the SysV to stop DansGuardian then try starting it again or doing an 'rm /tmp/.dguardianipc' or whatever you have it configured to)."); return 1; } } if (o.url_cache_number > 0) { if (urllistsock.bind((char*) o.urlipc_filename.c_str())) { // bind to file if (!isDaemonised) { std::cerr << "Error binding urllistsock server file (try using the SysV to stop DansGuardian then try starting it again or doing an 'rm " << o.urlipc_filename << "')." << std::endl; } syslog(LOG_ERR, "%s","Error binding urllistsock server file (try using the SysV to stop DansGuardian then try starting it again or doing an 'rm /tmp/.dguardianurlipc' or whatever you have it configured to)."); return 1; } } if (serversock.listen(256)) { // set it to listen mode with a kernel // queue of 256 backlog connections if (!isDaemonised) { std::cerr << "Error listening to server socket" << std::endl; } syslog(LOG_ERR, "%s","Error listening to server socket"); return 1; } if (o.no_logger == 0) { if (ipcsock.listen(256)) { // set it to listen mode with a kernel // queue of 256 backlog connections if (!isDaemonised) { std::cerr << "Error listening to ipc server file" << std::endl; } syslog(LOG_ERR, "%s","Error listening to ipc server file"); return 1; } } if (o.url_cache_number > 0) { if (urllistsock.listen(256)) { // set it to listen mode with a kernel // queue of 256 backlog connections if (!isDaemonised) { std::cerr << "Error listening to url ipc server file" << std::endl; } syslog(LOG_ERR, "%s","Error listening to url ipc server file"); return 1; } } if (peersock.getFD() < 0) { if (!isDaemonised) { std::cerr << "Error creating peer socket" << std::endl; } syslog(LOG_ERR, "%s","Error creating peer socket"); return 1; // if the socket fd is not +ve then the socket // creation failed } peersock.close(); // We need to do this as we won't be using the // fd created by the contructor as it will be // set to the ones accepted(). if (!daemonise(pidfilefd)) { // become a detached daemon if (!isDaemonised) { std::cerr << "Error daemonising" << std::endl; } syslog(LOG_ERR, "%s","Error daemonising"); return 1; } // We are now a daemon so all errors need to go in the syslog, rather // than being reported on screen as we've detached from the console and // trying to write to stdout will not be nice. struct sigaction sa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_IGN; if (sigaction(SIGPIPE, &sa, NULL)) { // ignore SIGPIPE so we can handle // premature disconections better syslog(LOG_ERR, "%s","Error ignoring SIGPIPE"); return(1); } memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_IGN; if (sigaction(SIGHUP, &sa, NULL)) { // ignore HUP syslog(LOG_ERR, "%s","Error ignoring HUP"); return(1); } // Next thing we need to do is to split into two processes - one to // handle incoming TCP connections from the clients and one to handle // incoming UDS ipc from our forked children. This helps reduce // bottlenecks by not having only one select() loop. if (o.no_logger == 0) { loggerpid = fork(); // make a child processes copy of self to be logger if (loggerpid == 0) { // ma ma! i am the child serversock.close(); // we don't need our copy of this so close it urllistsock.close(); // we don't need our copy of this so close it logListener(o.log_location, o.logconerror); #ifdef DGDEBUG std::cout << "Log listener exiting" << std::endl; #endif _exit(0); // is reccomended for child and daemons to use this instead } } if (o.url_cache_number > 0) { urllistpid = fork(); // make a child processes copy of self to be logger if (urllistpid == 0) { // ma ma! i am the child serversock.close(); // we don't need our copy of this so close it if (o.no_logger == 0) { ipcsock.close(); // we don't need our copy of this so close it } urlListListener(o.logconerror); #ifdef DGDEBUG std::cout << "URL List listener exiting" << std::endl; #endif _exit(0); // is reccomended for child and daemons to use this instead } } // I am the parent process here onwards. #ifdef DGDEBUG std::cout << "Parent process created children" << std::endl; #endif if (o.url_cache_number > 0) { urllistsock.close(); // we don't need our copy of this so close it } if (o.no_logger == 0) { ipcsock.close(); // we don't need our copy of this so close it } memset(&sa, 0, sizeof(sa)); if (o.soft_restart == 0) { sa.sa_handler = &sig_term; // register sig_term as our handler } else { sa.sa_handler = &sig_termsafe; } if (sigaction(SIGTERM, &sa, NULL)) { // when the parent process gets a // sigterm we need to kill our // children which this will do, // then we need to exit syslog(LOG_ERR, "%s","Error registering SIGTERM handler"); return(1); } memset(&sa, 0, sizeof(sa)); sa.sa_handler = &sig_hup; // register sig_hup as our handler if (sigaction(SIGHUP, &sa, NULL)) { // when the parent process gets a // sighup we need to kill our // children which this will do, // then we need to read config syslog(LOG_ERR, "%s","Error registering SIGHUP handler"); return(1); } memset(&sa, 0, sizeof(sa)); sa.sa_handler = &sig_usr1; // register sig_usr1 as our handler if (sigaction(SIGUSR1, &sa, NULL)) { // when the parent process gets a // sigusr1 we need to hup our // children to make them exit // then we need to read fg config syslog(LOG_ERR, "%s","Error registering SIGUSR handler"); return(1); } #ifdef DGDEBUG std::cout << "Parent process sig handlers done" << std::endl; #endif struct timeval quicksleep; // used later on for a short sleep quicksleep.tv_sec = 0; quicksleep.tv_usec = 10000; // = 10ms = 0.01sec struct timeval qscopy; // copy to use as select() can modify numchildren = 0; // to keep count of our children busychildren = 0; // to keep count of our children freechildren = 0; // to keep count of our children childrenpids = new int[o.max_children]; // so when one exits we know // who childrenstates = new int[o.max_children]; // so we know what // they're up to fds = o.max_children + 1; pids = new struct pollfd[fds]; int i; time_t tnow; time_t tmaxspare; time(&tmaxspare); #ifdef DGDEBUG std::cout << "Parent process pid structs allocated" << std::endl; #endif for(i = 0; i < o.max_children; i++) { childrenpids[i] = -1; childrenstates[i] = -1; pids[i + 1].fd = -1; pids[i + 1].events = POLLIN; } pids[0].fd = serversockfd; pids[0].events = POLLIN; #ifdef DGDEBUG std::cout << "Parent process pid structs zeroed" << std::endl; #endif failurecount = 0; // as we don't exit on an error with select() // due to the fact that these errors do happen // every so often on a fully working, but busy // system, we just watch for too many errors // consecutivly. waitingfor = 0; rc = preFork(o.min_children); sleep(1); // need to allow some of the forks to complete #ifdef DGDEBUG std::cout << "Parent process preforked rc:" << rc << std::endl; std::cout << "Parent process pid:" << getpid() << std::endl; #endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -