2008-05-24 16:05:49 +08:00
|
|
|
/* tinyproxy - A fast light-weight HTTP proxy
|
|
|
|
* Copyright (C) 1998 Steven Young <sdyoung@miranda.org>
|
|
|
|
* Copyright (C) 1998-2002 Robert James Kaes <rjkaes@users.sourceforge.net>
|
|
|
|
* Copyright (C) 2000 Chris Lightfoot <chris@ex-parrot.com>
|
2000-02-17 01:32:49 +08:00
|
|
|
*
|
2008-05-24 16:05:49 +08:00
|
|
|
* 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.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/* The initialize routine. Basically sets up all the initial stuff (logfile,
|
2000-02-17 01:32:49 +08:00
|
|
|
* listening socket, config options, etc.) and then sits there and loops
|
|
|
|
* over the new connections until the daemon is closed. Also has additional
|
|
|
|
* functions to handle the "user friendly" aspects of a program (usage,
|
|
|
|
* stats, etc.) Like any good program, most of the work is actually done
|
|
|
|
* elsewhere.
|
|
|
|
*/
|
|
|
|
|
2000-09-12 08:03:53 +08:00
|
|
|
#include "tinyproxy.h"
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2000-09-12 08:03:53 +08:00
|
|
|
#include "anonymous.h"
|
2000-02-17 01:32:49 +08:00
|
|
|
#include "buffer.h"
|
2004-08-14 05:03:11 +08:00
|
|
|
#include "conffile.h"
|
2002-05-24 02:27:01 +08:00
|
|
|
#include "daemon.h"
|
|
|
|
#include "heap.h"
|
2000-02-17 01:32:49 +08:00
|
|
|
#include "filter.h"
|
2002-05-27 02:52:23 +08:00
|
|
|
#include "child.h"
|
2000-09-12 08:03:53 +08:00
|
|
|
#include "log.h"
|
|
|
|
#include "reqs.h"
|
|
|
|
#include "sock.h"
|
|
|
|
#include "stats.h"
|
|
|
|
#include "utils.h"
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2004-08-25 00:36:22 +08:00
|
|
|
RETSIGTYPE takesig(int sig);
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2008-05-24 16:05:49 +08:00
|
|
|
/*
|
2000-02-17 01:32:49 +08:00
|
|
|
* Global Structures
|
|
|
|
*/
|
2000-09-12 08:03:53 +08:00
|
|
|
struct config_s config;
|
2000-02-17 01:32:49 +08:00
|
|
|
float load = 0.00;
|
2005-08-15 11:54:31 +08:00
|
|
|
unsigned int received_sighup = FALSE; /* boolean */
|
|
|
|
unsigned int processed_config_file = FALSE; /* boolean */
|
2000-02-17 01:32:49 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Handle a signal
|
|
|
|
*/
|
2004-08-25 00:36:22 +08:00
|
|
|
RETSIGTYPE
|
2001-11-22 08:31:10 +08:00
|
|
|
takesig(int sig)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2005-08-15 11:54:31 +08:00
|
|
|
pid_t pid;
|
|
|
|
int status;
|
2002-05-24 02:27:01 +08:00
|
|
|
|
2005-08-15 11:54:31 +08:00
|
|
|
switch (sig) {
|
|
|
|
case SIGHUP:
|
|
|
|
received_sighup = TRUE;
|
|
|
|
break;
|
2002-04-19 00:57:06 +08:00
|
|
|
|
2005-08-15 11:54:31 +08:00
|
|
|
case SIGTERM:
|
|
|
|
config.quit = TRUE;
|
|
|
|
break;
|
2002-05-24 02:27:01 +08:00
|
|
|
|
2005-08-15 11:54:31 +08:00
|
|
|
case SIGCHLD:
|
|
|
|
while ((pid = waitpid(-1, &status, WNOHANG)) > 0) ;
|
|
|
|
break;
|
|
|
|
}
|
2000-12-08 11:35:07 +08:00
|
|
|
|
2005-08-15 11:54:31 +08:00
|
|
|
return;
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2000-09-12 08:03:53 +08:00
|
|
|
* Display the version information for the user.
|
|
|
|
*/
|
2001-11-22 08:31:10 +08:00
|
|
|
static void
|
|
|
|
display_version(void)
|
2000-09-12 08:03:53 +08:00
|
|
|
{
|
2005-08-15 11:54:31 +08:00
|
|
|
printf("%s %s (%s)\n", PACKAGE, VERSION, TARGET_SYSTEM);
|
2001-08-27 05:17:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display the copyright and license for this program.
|
|
|
|
*/
|
2001-11-22 08:31:10 +08:00
|
|
|
static void
|
|
|
|
display_license(void)
|
2001-08-27 05:17:30 +08:00
|
|
|
{
|
2005-08-15 11:54:31 +08:00
|
|
|
display_version();
|
2001-08-27 05:17:30 +08:00
|
|
|
|
2005-08-15 11:54:31 +08:00
|
|
|
printf("\
|
2001-08-27 05:17:30 +08:00
|
|
|
Copyright 1998 Steven Young (sdyoung@well.com)\n\
|
2002-04-08 05:36:39 +08:00
|
|
|
Copyright 1998-2002 Robert James Kaes (rjkaes@users.sourceforge.net)\n\
|
2001-08-27 05:17:30 +08:00
|
|
|
Copyright 1999 George Talusan (gstalusan@uwaterloo.ca)\n\
|
|
|
|
Copyright 2000 Chris Lightfoot (chris@ex-parrot.com)\n\
|
|
|
|
\n\
|
|
|
|
This program is free software; you can redistribute it and/or modify\n\
|
|
|
|
it under the terms of the GNU General Public License as published by\n\
|
|
|
|
the Free Software Foundation; either version 2, or (at your option)\n\
|
|
|
|
any later version.\n\
|
2000-09-12 08:03:53 +08:00
|
|
|
\n\
|
2001-08-27 05:17:30 +08:00
|
|
|
This program is distributed in the hope that it will be useful,\n\
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of\n\
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n\
|
|
|
|
GNU General Public License for more details.\n\
|
2000-09-12 08:03:53 +08:00
|
|
|
\n\
|
2001-08-27 05:17:30 +08:00
|
|
|
You should have received a copy of the GNU General Public License\n\
|
|
|
|
along with this program; if not, write to the Free Software\n\
|
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.\n");
|
2000-09-12 08:03:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Display usage to the user.
|
2000-02-17 01:32:49 +08:00
|
|
|
*/
|
2001-11-22 08:31:10 +08:00
|
|
|
static void
|
|
|
|
display_usage(void)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2005-08-15 11:54:31 +08:00
|
|
|
printf("Usage: %s [options]\n", PACKAGE);
|
|
|
|
printf("\
|
2000-09-12 08:03:53 +08:00
|
|
|
Options:\n\
|
|
|
|
-d Operate in DEBUG mode.\n\
|
|
|
|
-c FILE Use an alternate configuration file.\n\
|
|
|
|
-h Display this usage information.\n\
|
2001-08-27 05:17:30 +08:00
|
|
|
-l Display the license.\n\
|
2000-09-12 08:03:53 +08:00
|
|
|
-v Display the version number.\n");
|
|
|
|
|
2005-08-15 11:54:31 +08:00
|
|
|
/* Display the modes compiled into tinyproxy */
|
|
|
|
printf("\nFeatures compiled in:\n");
|
2000-09-12 08:03:53 +08:00
|
|
|
#ifdef XTINYPROXY_ENABLE
|
2005-08-15 11:54:31 +08:00
|
|
|
printf(" XTinyproxy header\n");
|
|
|
|
#endif /* XTINYPROXY */
|
2000-02-17 01:32:49 +08:00
|
|
|
#ifdef FILTER_ENABLE
|
2005-08-15 11:54:31 +08:00
|
|
|
printf(" Filtering\n");
|
|
|
|
#endif /* FILTER_ENABLE */
|
2000-02-17 01:32:49 +08:00
|
|
|
#ifndef NDEBUG
|
2005-08-15 11:54:31 +08:00
|
|
|
printf(" Debugging code\n");
|
|
|
|
#endif /* NDEBUG */
|
2002-06-07 04:28:02 +08:00
|
|
|
#ifdef TRANSPARENT_PROXY
|
2005-08-15 11:54:31 +08:00
|
|
|
printf(" Transparent proxy support\n");
|
2002-06-07 04:28:02 +08:00
|
|
|
#endif /* TRANSPARENT_PROXY */
|
2004-01-27 03:11:52 +08:00
|
|
|
#ifdef REVERSE_SUPPORT
|
2005-08-15 11:54:31 +08:00
|
|
|
printf(" Reverse proxy support\n");
|
|
|
|
#endif /* REVERSE_SUPPORT */
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|
|
|
|
|
2008-07-14 20:10:20 +08:00
|
|
|
static int
|
|
|
|
get_id (char *str)
|
|
|
|
{
|
|
|
|
char *tstr;
|
|
|
|
|
|
|
|
if (str == NULL)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
tstr = str;
|
|
|
|
while (*tstr != 0) {
|
|
|
|
if (!isdigit(*tstr))
|
|
|
|
return -1;
|
|
|
|
tstr++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return atoi(str);
|
|
|
|
}
|
|
|
|
|
2001-11-22 08:31:10 +08:00
|
|
|
int
|
|
|
|
main(int argc, char **argv)
|
2000-02-17 01:32:49 +08:00
|
|
|
{
|
2005-08-15 11:54:31 +08:00
|
|
|
int optch;
|
|
|
|
unsigned int godaemon = TRUE; /* boolean */
|
|
|
|
struct passwd *thisuser = NULL;
|
|
|
|
struct group *thisgroup = NULL;
|
|
|
|
FILE *config_file;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Disable the creation of CORE files right up front.
|
|
|
|
*/
|
2002-05-27 08:46:24 +08:00
|
|
|
#if defined(HAVE_SETRLIMIT) && defined(NDEBUG)
|
2005-08-15 11:54:31 +08:00
|
|
|
struct rlimit core_limit = { 0, 0 };
|
|
|
|
if (setrlimit(RLIMIT_CORE, &core_limit) < 0) {
|
|
|
|
fprintf(stderr, "%s: Could not set the core limit to zero.\n",
|
|
|
|
argv[0]);
|
|
|
|
exit(EX_SOFTWARE);
|
|
|
|
}
|
|
|
|
#endif /* HAVE_SETRLIMIT */
|
|
|
|
|
|
|
|
/* Default configuration file location */
|
|
|
|
config.config_file = DEFAULT_CONF_FILE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Process the various options
|
|
|
|
*/
|
|
|
|
while ((optch = getopt(argc, argv, "c:vldh")) != EOF) {
|
|
|
|
switch (optch) {
|
|
|
|
case 'v':
|
|
|
|
display_version();
|
|
|
|
exit(EX_OK);
|
|
|
|
case 'l':
|
|
|
|
display_license();
|
|
|
|
exit(EX_OK);
|
|
|
|
case 'd':
|
|
|
|
godaemon = FALSE;
|
|
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
config.config_file = safestrdup(optarg);
|
|
|
|
if (!config.config_file) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"%s: Could not allocate memory.\n",
|
|
|
|
argv[0]);
|
|
|
|
exit(EX_SOFTWARE);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 'h':
|
|
|
|
default:
|
|
|
|
display_usage();
|
|
|
|
exit(EX_OK);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
log_message(LOG_INFO, "Initializing " PACKAGE " ...");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make sure the HTML error pages array is NULL to begin with.
|
|
|
|
* (FIXME: Should have a better API for all this)
|
|
|
|
*/
|
|
|
|
config.errorpages = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read in the settings from the config file.
|
|
|
|
*/
|
2004-08-14 05:03:11 +08:00
|
|
|
config_file = fopen(config.config_file, "r");
|
|
|
|
if (!config_file) {
|
2005-08-15 11:54:31 +08:00
|
|
|
fprintf(stderr,
|
|
|
|
"%s: Could not open configuration file \"%s\".\n",
|
|
|
|
argv[0], config.config_file);
|
|
|
|
exit(EX_SOFTWARE);
|
|
|
|
}
|
2004-08-14 11:21:28 +08:00
|
|
|
if (config_compile() || config_parse(&config, config_file)) {
|
2004-08-14 05:03:11 +08:00
|
|
|
fprintf(stderr,
|
|
|
|
"Unable to parse configuration file. Not starting.\n");
|
|
|
|
exit(EX_SOFTWARE);
|
|
|
|
}
|
|
|
|
fclose(config_file);
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2004-08-14 11:21:28 +08:00
|
|
|
/*
|
|
|
|
* Write to a user supplied log file if it's defined. This
|
|
|
|
* will override using the syslog even if syslog is defined.
|
|
|
|
*/
|
|
|
|
if (config.logf_name) {
|
|
|
|
if (open_log_file(config.logf_name) < 0) {
|
|
|
|
fprintf(stderr,
|
2005-08-15 11:54:31 +08:00
|
|
|
"%s: Could not create log file.\n", argv[0]);
|
2004-08-14 11:21:28 +08:00
|
|
|
exit(EX_SOFTWARE);
|
|
|
|
}
|
2005-08-15 11:54:31 +08:00
|
|
|
config.syslog = FALSE; /* disable syslog */
|
2004-08-14 11:21:28 +08:00
|
|
|
} else if (config.syslog) {
|
2005-08-15 11:54:31 +08:00
|
|
|
if (godaemon == TRUE)
|
|
|
|
openlog("tinyproxy", LOG_PID, LOG_DAEMON);
|
|
|
|
else
|
|
|
|
openlog("tinyproxy", LOG_PID, LOG_USER);
|
|
|
|
} else {
|
2004-08-14 11:21:28 +08:00
|
|
|
fprintf(stderr,
|
|
|
|
"%s: Either define a logfile or enable syslog logging\n",
|
|
|
|
argv[0]);
|
|
|
|
exit(EX_SOFTWARE);
|
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2005-08-15 11:54:31 +08:00
|
|
|
processed_config_file = TRUE;
|
|
|
|
send_stored_logs();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the default values if they were not set in the config file.
|
|
|
|
*/
|
|
|
|
if (config.port == 0) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"%s: You MUST set a Port in the configuration file.\n",
|
|
|
|
argv[0]);
|
|
|
|
exit(EX_SOFTWARE);
|
|
|
|
}
|
|
|
|
if (!config.stathost) {
|
|
|
|
log_message(LOG_INFO, "Setting stathost to \"%s\".",
|
|
|
|
DEFAULT_STATHOST);
|
|
|
|
config.stathost = DEFAULT_STATHOST;
|
|
|
|
}
|
2008-07-14 20:10:20 +08:00
|
|
|
if (!config.user) {
|
2005-08-15 11:54:31 +08:00
|
|
|
log_message(LOG_WARNING,
|
|
|
|
"You SHOULD set a UserName in the configuration file. Using current user instead.");
|
|
|
|
}
|
|
|
|
if (config.idletimeout == 0) {
|
|
|
|
log_message(LOG_WARNING,
|
|
|
|
"Invalid idle time setting. Only values greater than zero allowed; therefore setting idle timeout to %u seconds.",
|
|
|
|
MAX_IDLE_TIME);
|
|
|
|
config.idletimeout = MAX_IDLE_TIME;
|
|
|
|
}
|
|
|
|
|
|
|
|
init_stats();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If ANONYMOUS is turned on, make sure that Content-Length is
|
|
|
|
* in the list of allowed headers, since it is required in a
|
|
|
|
* HTTP/1.0 request. Also add the Content-Type header since it goes
|
|
|
|
* hand in hand with Content-Length.
|
|
|
|
* - rjkaes
|
|
|
|
*/
|
|
|
|
if (is_anonymous_enabled()) {
|
|
|
|
anonymous_insert("Content-Length");
|
|
|
|
anonymous_insert("Content-Type");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (godaemon == TRUE)
|
|
|
|
makedaemon();
|
2002-05-24 02:27:01 +08:00
|
|
|
|
2005-08-15 11:54:31 +08:00
|
|
|
if (config.pidpath) {
|
|
|
|
if (pidfile_create(config.pidpath) < 0) {
|
|
|
|
fprintf(stderr, "%s: Could not create PID file.\n",
|
|
|
|
argv[0]);
|
|
|
|
exit(EX_OSERR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (set_signal_handler(SIGPIPE, SIG_IGN) == SIG_ERR) {
|
|
|
|
fprintf(stderr, "%s: Could not set the \"SIGPIPE\" signal.\n",
|
|
|
|
argv[0]);
|
|
|
|
exit(EX_OSERR);
|
|
|
|
}
|
2000-09-12 08:03:53 +08:00
|
|
|
#ifdef FILTER_ENABLE
|
2005-08-15 11:54:31 +08:00
|
|
|
if (config.filter)
|
|
|
|
filter_init();
|
|
|
|
#endif /* FILTER_ENABLE */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start listening on the selected port.
|
|
|
|
*/
|
|
|
|
if (child_listening_sock(config.port) < 0) {
|
|
|
|
fprintf(stderr, "%s: Could not create listening socket.\n",
|
|
|
|
argv[0]);
|
|
|
|
exit(EX_OSERR);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Switch to a different user.
|
|
|
|
*/
|
|
|
|
if (geteuid() == 0) {
|
|
|
|
if (config.group && strlen(config.group) > 0) {
|
2008-07-14 20:10:20 +08:00
|
|
|
int gid = get_id(config.group);
|
|
|
|
if (gid < 0) {
|
|
|
|
thisgroup = getgrnam(config.group);
|
|
|
|
if (!thisgroup) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"%s: Unable to find "
|
|
|
|
"group \"%s\".\n",
|
|
|
|
argv[0], config.group);
|
|
|
|
exit(EX_NOUSER);
|
|
|
|
}
|
|
|
|
gid = thisgroup->gr_gid;
|
|
|
|
}
|
|
|
|
if (setgid(gid) < 0) {
|
2005-08-15 11:54:31 +08:00
|
|
|
fprintf(stderr,
|
2008-07-14 20:10:20 +08:00
|
|
|
"%s: Unable to change to "
|
|
|
|
"group \"%s\".\n",
|
2005-08-15 11:54:31 +08:00
|
|
|
argv[0], config.group);
|
|
|
|
exit(EX_CANTCREAT);
|
|
|
|
}
|
|
|
|
log_message(LOG_INFO, "Now running as group \"%s\".",
|
|
|
|
config.group);
|
|
|
|
}
|
2008-07-14 20:10:20 +08:00
|
|
|
if (config.user && strlen(config.user) > 0) {
|
|
|
|
int uid = get_id(config.user);
|
|
|
|
if (uid < 0) {
|
|
|
|
thisuser = getpwnam(config.user);
|
|
|
|
if (!thisuser) {
|
|
|
|
fprintf(stderr,
|
|
|
|
"%s: Unable to find "
|
|
|
|
"user \"%s\".",
|
|
|
|
argv[0], config.user);
|
|
|
|
exit(EX_NOUSER);
|
|
|
|
}
|
|
|
|
uid = thisuser->pw_uid;
|
|
|
|
}
|
|
|
|
if (setuid(uid) < 0) {
|
2005-08-15 11:54:31 +08:00
|
|
|
fprintf(stderr,
|
|
|
|
"%s: Unable to change to user \"%s\".",
|
2008-07-14 20:10:20 +08:00
|
|
|
argv[0], config.user);
|
2005-08-15 11:54:31 +08:00
|
|
|
exit(EX_CANTCREAT);
|
|
|
|
}
|
|
|
|
log_message(LOG_INFO, "Now running as user \"%s\".",
|
2008-07-14 20:10:20 +08:00
|
|
|
config.user);
|
2005-08-15 11:54:31 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
log_message(LOG_WARNING,
|
|
|
|
"Not running as root, so not changing UID/GID.");
|
|
|
|
}
|
2003-02-27 06:37:38 +08:00
|
|
|
|
2005-08-15 11:54:31 +08:00
|
|
|
if (child_pool_create() < 0) {
|
|
|
|
fprintf(stderr, "%s: Could not create the pool of children.",
|
|
|
|
argv[0]);
|
|
|
|
exit(EX_SOFTWARE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* These signals are only for the parent process.
|
|
|
|
*/
|
|
|
|
log_message(LOG_INFO, "Setting the various signals.");
|
|
|
|
if (set_signal_handler(SIGCHLD, takesig) == SIG_ERR) {
|
|
|
|
fprintf(stderr, "%s: Could not set the \"SIGCHLD\" signal.\n",
|
|
|
|
argv[0]);
|
|
|
|
exit(EX_OSERR);
|
|
|
|
}
|
|
|
|
if (set_signal_handler(SIGTERM, takesig) == SIG_ERR) {
|
|
|
|
fprintf(stderr, "%s: Could not set the \"SIGTERM\" signal.\n",
|
|
|
|
argv[0]);
|
|
|
|
exit(EX_OSERR);
|
|
|
|
}
|
|
|
|
if (set_signal_handler(SIGHUP, takesig) == SIG_ERR) {
|
|
|
|
fprintf(stderr, "%s: Could not set the \"SIGHUP\" signal.\n",
|
|
|
|
argv[0]);
|
|
|
|
exit(EX_OSERR);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Start the main loop.
|
|
|
|
*/
|
|
|
|
log_message(LOG_INFO, "Starting main loop. Accepting connections.");
|
|
|
|
|
|
|
|
child_main_loop();
|
|
|
|
|
|
|
|
log_message(LOG_INFO, "Shutting down.");
|
|
|
|
|
|
|
|
child_kill_children();
|
|
|
|
child_close_sock();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove the PID file.
|
|
|
|
*/
|
|
|
|
if (unlink(config.pidpath) < 0) {
|
|
|
|
log_message(LOG_WARNING,
|
|
|
|
"Could not remove PID file \"%s\": %s.",
|
|
|
|
config.pidpath, strerror(errno));
|
|
|
|
}
|
2000-02-17 01:32:49 +08:00
|
|
|
#ifdef FILTER_ENABLE
|
2005-08-15 11:54:31 +08:00
|
|
|
if (config.filter)
|
|
|
|
filter_destroy();
|
|
|
|
#endif /* FILTER_ENABLE */
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2005-08-15 11:54:31 +08:00
|
|
|
if (config.syslog)
|
|
|
|
closelog();
|
|
|
|
else
|
|
|
|
close_log_file();
|
2000-02-17 01:32:49 +08:00
|
|
|
|
2005-08-15 11:54:31 +08:00
|
|
|
exit(EX_OK);
|
2000-02-17 01:32:49 +08:00
|
|
|
}
|