📄 fatcontroller.cpp
字号:
if (rc < 0) { ttg = true; syslog(LOG_ERR, "%s","Error creating initial fork pool - exiting..."); } bool preforked = true; int tofind; reloadconfig = false; while (failurecount < 30 && !ttg && !reloadconfig) { // loop, essentially, for ever until 30 // consecutive errors in which case something // is badly wrong. // OR, its timetogo - got a sigterm // OR, we need to exit to reread config if (gentlereload) { #ifdef DGDEBUG cout << "gentle reload activated" << endl; #endif o.deleteFilterGroups(); if (!o.readFilterGroupConf()) { reloadconfig = true; // filter groups problem so lets // try and reload entire config instead // if that fails it will bomb out } else { o.filter_groups_list.reset(); if (!o.readfgfile(o.filter_groups_list_location.c_str())) { reloadconfig = true; // filter groups problem... } else { o.lm.garbageCollect(); hupAllChildren(); preFork(o.min_children); gentlereload = false; } } flushURLCache(); continue; } // Lets take the opportunity to clean up our dead children if any for(i = 0; i <= o.max_children; i++) { pids[i].revents = 0; } mopUpAfterKids(); rc = poll(pids, fds, 60 * 1000); mopUpAfterKids(); if (rc < 0) { // was an error #ifdef DGDEBUG std::cout << "errno:" << errno << " " << strerror(errno) << std::endl; #endif if (errno == EINTR) { continue; // was interupted by a signal so restart } failurecount++; // log the error/failure continue; // then continue with the looping } tofind = rc; if (rc > 0) { if ((pids[0].revents & POLLIN) > 0) { tofind--; } } if (tofind > 0) { if (checkKidReadyStatus(tofind)) { preforked = false; // we are no longer waiting last prefork } } freechildren = numchildren - busychildren; #ifdef DGDEBUG std::cout << "numchildren:" << numchildren << std::endl; std::cout << "busychildren:" << busychildren << std::endl; std::cout << "freechildren:" << freechildren << std::endl; std::cout << "waitingfor:" << waitingfor << std::endl; #endif if (rc > 0) { if ((pids[0].revents & (POLLERR | POLLHUP | POLLNVAL)) > 0) { ttg = true; syslog(LOG_ERR, "%s","Error with main listening socket. Exiting."); continue; } if ((pids[0].revents & POLLIN) > 0) { // socket ready to accept() a connection failurecount = 0; // something is clearly working so reset count if (freechildren < 1 && numchildren < o.max_children) { if (!preforked) { rc = preFork(1); if (rc < 0) { syslog(LOG_ERR, "%s","Error forking 1 extra process."); failurecount++; } preforked = true; } qscopy = quicksleep; // use copy as select() can modify it select(0, NULL, NULL, NULL, &qscopy); // is a very quick sleep() continue; } if (freechildren > 0) { tellChildAccept(getFreeChild()); } else { qscopy = quicksleep; // use copy as select() can modify it select(0, NULL, NULL, NULL, &qscopy); // is a very quick sleep() } } } if (freechildren < o.minspare_children && !preforked && numchildren < o.max_children) { rc = preFork(o.prefork_children); preforked = true; if (rc < 0) { syslog(LOG_ERR, "%s","Error forking preforkchildren extra processes."); failurecount++; } } if (freechildren <= o.maxspare_children) { time(&tmaxspare); } if (freechildren > o.maxspare_children) { time(&tnow); if ((tnow - tmaxspare) > (2 * 60)) { // 2 * 60 cullChildren(freechildren - o.maxspare_children); } } } cullChildren(numchildren); // remove the fork pool of spare children for (int i = 0; i < o.max_children; i++) { if (pids[i + 1].fd != -1) { try { close(pids[i + 1].fd); } catch (exception& e) {} } } if (numchildren > 0) { hupAllChildren(); sleep(2); // give them a small chance to exit nicely before we force // hmmmm I wonder if sleep() will get interupted by sigchlds? } if (numchildren > 0) { killAllChildren(); } // we might not giving enough time for defuncts to be created and then // mopped but on exit or reload config they'll get mopped up sleep(1); mopUpAfterKids(); delete[] childrenpids; delete[] childrenstates; delete[] pids; // 3 deletes good, memory leaks bad if (failurecount >= 30) { syslog(LOG_ERR, "%s","Exiting due to high failure count."); #ifdef DGDEBUG std::cout << "Exiting due to high failure count." << std::endl; #endif } #ifdef DGDEBUG std::cout << "Main parent process exiting." << std::endl; #endif serversock.close(); // be nice and neat if (o.url_cache_number > 0) { urllistsock.close(); } memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_DFL; if (sigaction(SIGTERM, &sa, NULL)) { // restore sig handler // in child process #ifdef DGDEBUG std::cerr << "Error resetting signal for SIGTERM" << std::endl; #endif syslog(LOG_ERR, "%s","Error resetting signal for SIGTERM"); } memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_IGN; if (sigaction(SIGHUP, &sa, NULL)) { // restore sig handler // in child process #ifdef DGDEBUG std::cerr << "Error resetting signal for SIGHUP" << std::endl; #endif syslog(LOG_ERR, "%s","Error resetting signal for SIGHUP"); } memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_IGN; if (sigaction(SIGUSR1, &sa, NULL)) { // restore sig handler // in child process #ifdef DGDEBUG std::cerr << "Error resetting signal for SIGUSR1" << std::endl; #endif syslog(LOG_ERR, "%s","Error resetting signal for SIGUSR1"); } memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_DFL; if (sigaction(SIGPIPE, &sa, NULL)) { // restore sig handler // in child process #ifdef DGDEBUG std::cerr << "Error resetting signal for SIGPIPE" << std::endl; #endif syslog(LOG_ERR, "%s","Error resetting signal for SIGPIPE"); } if (sig_term_killall) { struct sigaction sa, oldsa; memset(&sa, 0, sizeof(sa)); sa.sa_handler = SIG_IGN; sigaction(SIGTERM, &sa, &oldsa); // ignore sigterm for us kill(0, SIGTERM); // send everyone in this process group a TERM // which causes them to exit as the default action // but it also seems to send itself a TERM // so we ignore it sigaction(SIGTERM, &oldsa, NULL); // restore prev state } if (reloadconfig) { if( o.no_logger == 0 ) { ::kill(loggerpid, SIGTERM); // get rid of logger } if (o.url_cache_number > 0) { ::kill(urllistpid, SIGTERM); // get rid of url cache } return 2; } if (ttg) { if( o.no_logger == 0 ) { ::kill(loggerpid, SIGTERM); // get rid of logger } if (o.url_cache_number > 0) { ::kill(urllistpid, SIGTERM); // get rid of url cache } return 0; } if (o.logconerror == 1) { syslog(LOG_ERR, "%s","Main parent process exiting."); } return 1; // It is only possible to reach here with an error}// this is used by dansguardian.cpp, to, yep, test connection to the proxy// If report is true we log the problem. report as false allows the caller// to test multiple times with no errorbool FatController::testProxy(std::string proxyip, int proxyport, bool report) { int sck_inet, conn; Socket sock; sck_inet = sock.getFD(); if (sck_inet == -1) { if (report) { if (!isDaemonised) { std::cerr << "Error creating socket to test proxy connection" << std::endl; } syslog(LOG_ERR, "%s","Error creating socket to test proxy connection"); } return false; } conn = sock.connect(proxyip, proxyport); // hmmm, I wonder what this do if (conn) { if (report) { if (!isDaemonised) { std::cerr << "Error connecting to parent proxy" << std::endl; } syslog(LOG_ERR, "%s","Error connecting to parent proxy"); } return false; }// close(conn); ** delete when confirmed not needed sock.close(); return true; // it worked!}bool FatController::daemonise(int pidfilefd) { if (o.no_daemon == 1) { return true; } #ifdef DGDEBUG return true; // if debug mode is enabled we don't want to detach #endif if (isDaemonised) { return true; // we are already daemonised so this must be a // reload caused by a HUP } int nullfd = -1; if ((nullfd = open("/dev/null", O_WRONLY, 0)) == -1) { syslog(LOG_ERR, "%s","Couldn't open /dev/null"); return false; } pid_t pid; if ((pid = fork()) < 0) { return false; } else if (pid != 0) { if (nullfd != -1) { close(nullfd); } exit(0); // parent goes bye-bye } // child continues dup2(nullfd, 0); // stdin dup2(nullfd, 1); // stdout dup2(nullfd, 2); // stderr close(nullfd); setsid(); // become session leader chdir("/"); // change working directory umask(0); // clear our file mode creation mask SysV sysv; int rc = sysv.writePIDFile(pidfilefd); // also closes the fd if (rc != 0) { syslog(LOG_ERR, "%s","Error writing to the dansguardian.pid file."); return false; } isDaemonised = true; return true;}int FatController::preFork(int num) { if (num < waitingfor) { return 3; // waiting for forks already } #ifdef DGDEBUG std::cout << "attempting to prefork:" << num << std::endl; #endif int sv[2]; pid_t child_pid; while(num--) { if (numchildren >= o.max_children) { return 2; // too many - geddit? } if(socketpair(AF_UNIX,SOCK_STREAM,0,sv) < 0) { return -1; // error } child_pid = fork(); if (child_pid == -1) { // fork failed, for example, if the // process is not allowed to create // any more syslog(LOG_ERR, "%s","Unable to fork() any more."); #ifdef DGDEBUG std::cout << "Unable to fork() any more." << std::endl; std::cout << strerror(errno) << std::endl; std::cout << "numchildren:" << numchildren << std::endl; #endif failurecount++; // log the error/failure // A DoS attack on a server allocated // too many children in the conf will // kill the server. But this is user // error. sleep(1); // need to wait until we have a spare slot num--; continue; // Nothing doing, go back to listening } else if(child_pid == 0) { // I am the child - I am alive! close(sv[0]); // we only need our copy of this tidyUpForChild(); if (!dropPrivCompletely()) { return -1; //error } // no need to deallocate memory etc as already done when fork()ed int rc = handleConnections(sv[1]); try { close(sv[1]); // connection to parent } catch (exception& e) {} try { serversock.close(); // listening connection
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -