2 * DEBUG: section 01 Startup and Main Loop
3 * AUTHOR: Harvest Derived
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 #include "AccessLogEntry.h"
38 #include "base/RunnersRegistry.h"
39 #include "base/Subscription.h"
40 #include "base/TextException.h"
43 #include "client_db.h"
44 #include "client_side.h"
46 #include "ConfigParser.h"
47 #include "CpuAffinity.h"
49 #include "DiskIO/DiskIOModule.h"
50 #include "errorpage.h"
52 #include "EventLoop.h"
53 #include "ExternalACL.h"
55 #include "format/Token.h"
56 #include "fqdncache.h"
57 #include "fs/Module.h"
61 #include "HttpHeader.h"
62 #include "HttpReply.h"
63 #include "icmp/IcmpSquid.h"
64 #include "icmp/net_db.h"
66 #include "ident/Ident.h"
68 #include "ipc/Coordinator.h"
70 #include "ipc/Strand.h"
75 #include "neighbors.h"
76 #include "parser/Tokenizer.h"
78 #include "peer_sourcehash.h"
79 #include "peer_userhash.h"
80 #include "PeerSelectState.h"
81 #include "profiler/Profiler.h"
84 #include "send-announce.h"
85 #include "SquidConfig.h"
87 #include "SquidTime.h"
89 #include "StatCounters.h"
91 #include "store_log.h"
92 #include "StoreFileSystem.h"
102 #include "adaptation/Config.h"
105 #include "adaptation/ecap/Config.h"
108 #include "adaptation/icap/Config.h"
109 #include "adaptation/icap/icap_log.h"
112 #include "auth/Gadgets.h"
115 #include "ClientDelayConfig.h"
118 #include "DelayPools.h"
120 #if USE_LOADABLE_MODULES
121 #include "LoadableModules.h"
124 #include "ssl/certificate_db.h"
127 #include "ssl/context_storage.h"
128 #include "ssl/helper.h"
131 #include "adaptation/icap/Config.h"
134 #include "adaptation/ecap/Config.h"
137 #include "adaptation/Config.h"
140 #include "esi/Module.h"
143 #include "snmp_core.h"
151 #include <sys/wait.h>
154 #if USE_WIN32_SERVICE
157 static int opt_install_service
= FALSE
;
158 static int opt_remove_service
= FALSE
;
159 static int opt_command_line
= FALSE
;
160 void WIN32_svcstatusupdate(DWORD
, DWORD
);
161 void WINAPI
WIN32_svcHandler(DWORD
);
164 static int opt_signal_service
= FALSE
;
165 static char *opt_syslog_facility
= NULL
;
166 static int icpPortNumOverride
= 1; /* Want to detect "-u 0" */
167 static int configured_once
= 0;
169 static int malloc_debug_level
= 0;
171 static volatile int do_reconfigure
= 0;
172 static volatile int do_rotate
= 0;
173 static volatile int do_shutdown
= 0;
174 static volatile int shutdown_status
= 0;
176 static int RotateSignal
= -1;
177 static int ReconfigureSignal
= -1;
178 static int ShutdownSignal
= -1;
180 static void mainRotate(void);
181 static void mainReconfigureStart(void);
182 static void mainReconfigureFinish(void*);
183 static void mainInitialize(void);
184 static void usage(void);
185 static void mainParseOptions(int argc
, char *argv
[]);
186 static void sendSignal(void);
187 static void serverConnectionsOpen(void);
188 static void serverConnectionsClose(void);
189 static void watch_child(char **);
190 static void setEffectiveUser(void);
191 static void SquidShutdown(void);
192 static void mainSetCwd(void);
193 static int checkRunningPid(void);
196 static const char *squid_start_script
= "squid_start";
200 #include "test_access.c"
203 /** temporary thunk across to the unrefactored store interface */
205 class StoreRootEngine
: public AsyncEngine
209 int checkEvents(int timeout
) {
210 Store::Root().callback();
215 class SignalEngine
: public AsyncEngine
219 virtual int checkEvents(int timeout
);
222 static void StopEventLoop(void *) {
223 if (EventLoop::Running
)
224 EventLoop::Running
->stop();
227 void doShutdown(time_t wait
);
231 SignalEngine::checkEvents(int timeout
)
233 PROF_start(SignalEngine_checkEvents
);
235 if (do_reconfigure
) {
236 mainReconfigureStart();
238 } else if (do_rotate
) {
241 } else if (do_shutdown
) {
242 doShutdown(do_shutdown
> 0 ? (int) Config
.shutdownLifetime
: 0);
245 BroadcastSignalIfAny(DebugSignal
);
246 BroadcastSignalIfAny(RotateSignal
);
247 BroadcastSignalIfAny(ReconfigureSignal
);
248 BroadcastSignalIfAny(ShutdownSignal
);
250 PROF_stop(SignalEngine_checkEvents
);
255 SignalEngine::doShutdown(time_t wait
)
257 debugs(1, DBG_IMPORTANT
, "Preparing for shutdown after " << statCounter
.client_http
.requests
<< " requests");
258 debugs(1, DBG_IMPORTANT
, "Waiting " << wait
<< " seconds for active connections to finish");
262 #if USE_WIN32_SERVICE
263 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, (wait
+ 1) * 1000);
266 /* run the closure code which can be shared with reconfigure */
267 serverConnectionsClose();
269 /* detach the auth components (only do this on full shutdown) */
270 Auth::Scheme::FreeAll();
273 RunRegisteredHere(RegisteredRunner::startShutdown
);
274 eventAdd("SquidShutdown", &StopEventLoop
, this, (double) (wait
+ 1), 1, false);
281 "Usage: %s [-cdhvzCFNRVYX] [-n name] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]"
282 #if USE_WIN32_SERVICE
283 "[-ir] [-O CommandLine]"
286 " -a port Specify HTTP port number (default: %d).\n"
287 " -d level Write debugging to stderr also.\n"
288 " -f file Use given config-file instead of\n"
290 " -h Print help message.\n"
291 #if USE_WIN32_SERVICE
292 " -i Installs as a Windows Service (see -n option).\n"
294 " -k reconfigure|rotate|shutdown|"
298 "interrupt|kill|debug|check|parse\n"
299 " Parse configuration file, then send signal to \n"
300 " running copy (except -k parse) and exit.\n"
301 " -n name Specify service name to use for service operations\n"
302 " default is: " APP_SHORTNAME
".\n"
303 #if USE_WIN32_SERVICE
304 " -r Removes a Windows Service (see -n option).\n"
306 " -s | -l facility\n"
307 " Enable logging to syslog.\n"
308 " -u port Specify ICP port number (default: %d), disable with 0.\n"
309 " -v Print version.\n"
310 " -z Create missing swap directories and then exit.\n"
311 " -C Do not catch fatal signals.\n"
312 " -D OBSOLETE. Scheduled for removal.\n"
313 " -F Don't serve any requests until store is rebuilt.\n"
314 " -N No daemon mode.\n"
315 #if USE_WIN32_SERVICE
317 " Set Windows Service Command line options in Registry.\n"
319 " -R Do not set REUSEADDR on port.\n"
320 " -S Double-check swap during rebuild.\n"
321 " -X Force full debugging.\n"
322 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
323 APP_SHORTNAME
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
328 * Parse the parameters received via command line interface.
330 \param argc Number of options received on command line
331 \param argv List of parameters received on command line
334 mainParseOptions(int argc
, char *argv
[])
339 #if USE_WIN32_SERVICE
340 while ((c
= getopt(argc
, argv
, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
342 while ((c
= getopt(argc
, argv
, "CDFNRSYXa:d:f:hk:m::n:sl:u:vz?")) != -1)
350 * Unset/disabel global option for catchign signals. opt_catch_signals */
351 opt_catch_signals
= 0;
356 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
357 debugs(1,DBG_CRITICAL
, "WARNING: -D command-line option is obsolete.");
362 * Set global option for foreground rebuild. opt_foreground_rebuild */
363 opt_foreground_rebuild
= 1;
368 * Set global option for 'no_daemon' mode. opt_no_daemon */
372 #if USE_WIN32_SERVICE
376 * Set global option. opt_command_lin and WIN32_Command_Line */
377 opt_command_line
= 1;
378 WIN32_Command_Line
= xstrdup(optarg
);
384 * Unset/disable global option opt_reuseaddr */
390 * Set global option opt_store_doublecheck */
391 opt_store_doublecheck
= 1;
396 * Force full debugging */
397 Debug::parseOptions("rotate=0 ALL,9");
398 Debug::override_X
= 1;
399 sigusr2_handle(SIGUSR2
);
404 * Set global option opt_reload_hit_only */
405 opt_reload_hit_only
= 1;
408 #if USE_WIN32_SERVICE
412 * Set global option opt_install_service (to TRUE) */
413 opt_install_service
= TRUE
;
419 * Add optional HTTP port as given following the option */
420 add_http_port(optarg
);
425 * Set global option Debug::log_stderr to the number given follwoign the option */
426 Debug::log_stderr
= atoi(optarg
);
431 * Load the file given instead of the default squid.conf. */
433 ConfigFile
= xstrdup(optarg
);
438 * Run the administrative action given following the option */
440 /** \li When its an unknown option display the usage help. */
441 if ((int) strlen(optarg
) < 1)
444 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
445 /** \li On reconfigure send SIGHUP. */
446 opt_send_signal
= SIGHUP
;
447 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
448 /** \li On rotate send SIGQUIT or SIGUSR1. */
449 #if defined(_SQUID_LINUX_THREADS_)
450 opt_send_signal
= SIGQUIT
;
452 opt_send_signal
= SIGUSR1
;
455 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
456 /** \li On debug send SIGTRAP or SIGUSR2. */
457 #if defined(_SQUID_LINUX_THREADS_)
458 opt_send_signal
= SIGTRAP
;
460 opt_send_signal
= SIGUSR2
;
463 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
464 /** \li On shutdown send SIGTERM. */
465 opt_send_signal
= SIGTERM
;
466 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
467 /** \li On interrupt send SIGINT. */
468 opt_send_signal
= SIGINT
;
469 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
470 /** \li On kill send SIGKILL. */
471 opt_send_signal
= SIGKILL
;
475 else if (!strncmp(optarg
, "restart", strlen(optarg
)))
476 /** \li On restart send SIGTTIN. (exit and restart by parent) */
477 opt_send_signal
= SIGTTIN
;
481 else if (!strncmp(optarg
, "check", strlen(optarg
)))
482 /** \li On check send 0 / SIGNULL. */
483 opt_send_signal
= 0; /* SIGNULL */
484 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
485 /** \li On parse set global flag to re-parse the config file only. */
486 opt_parse_cfg_only
= 1;
494 * Set global malloc_debug_level to the value given following the option.
495 * if none is given it toggles the xmalloc_trace option on/off */
498 malloc_debug_level
= atoi(optarg
);
500 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
508 * Set global option opt_signal_service (to true).
509 * Stores the additional parameter given in global service_name */
510 if (optarg
&& *optarg
!= '\0') {
511 const SBuf
t(optarg
);
512 ::Parser::Tokenizer
tok(t
);
513 const CharacterSet chr
= CharacterSet::ALPHA
+CharacterSet::DIGIT
;
514 if (!tok
.prefix(service_name
, chr
))
515 fatalf("Expected alphanumeric service name for the -n option but got: %s", optarg
);
517 fatalf("Garbage after alphanumeric service name in the -n option value: %s", optarg
);
518 if (service_name
.length() > 32)
519 fatalf("Service name (-n option) must be limited to 32 characters but got %u", service_name
.length());
520 opt_signal_service
= true;
522 fatal("A service name is required for the -n option");
526 #if USE_WIN32_SERVICE
530 * Set global option opt_remove_service (to TRUE) */
531 opt_remove_service
= TRUE
;
539 * Stores the syslog facility name in global opt_syslog_facility
540 * then performs actions for -s option. */
541 xfree(opt_syslog_facility
); // ignore any previous options sent
542 opt_syslog_facility
= xstrdup(optarg
);
546 * Initialize the syslog for output */
549 _db_set_syslog(opt_syslog_facility
);
555 fatal("Logging to syslog not available on this platform");
562 * Store the ICP port number given in global option icpPortNumOverride
563 * ensuring its a positive number. */
564 icpPortNumOverride
= atoi(optarg
);
566 if (icpPortNumOverride
< 0)
567 icpPortNumOverride
= 0;
573 * Display squid version and build information. Then exit. */
574 printf("Squid Cache: Version %s\n" ,version_string
);
575 printf("Service Name: " SQUIDSBUFPH
"\n", SQUIDSBUFPRINT(service_name
));
576 if (strlen(SQUID_BUILD_INFO
))
577 printf("%s\n",SQUID_BUILD_INFO
);
578 printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS
);
580 #if USE_WIN32_SERVICE
582 printf("Compiled as Windows System Service.\n");
592 * Set global option Debug::log_stderr and opt_create_swap_dirs */
593 Debug::log_stderr
= 1;
594 opt_create_swap_dirs
= 1;
602 /** \par h,?, or unknown
603 * \copydoc usage() */
621 signal(sig
, rotate_logs
);
631 ReconfigureSignal
= sig
;
635 signal(sig
, reconfigure
);
643 do_shutdown
= sig
== SIGINT
? -1 : 1;
644 ShutdownSignal
= sig
;
652 const pid_t ppid
= getppid();
654 if (!IamMasterProcess() && ppid
> 1) {
655 // notify master that we are shutting down
656 if (kill(ppid
, SIGUSR1
) < 0)
657 debugs(1, DBG_IMPORTANT
, "Failed to send SIGUSR1 to master process,"
658 " pid " << ppid
<< ": " << xstrerror());
664 if (!IamMasterProcess() && ppid
> 1) {
665 debugs(1, DBG_IMPORTANT
, "Killing master process, pid " << ppid
);
667 if (kill(ppid
, sig
) < 0)
668 debugs(1, DBG_IMPORTANT
, "kill " << ppid
<< ": " << xstrerror());
671 #endif /* KILL_PARENT_OPT */
672 #if SA_RESETHAND == 0
673 signal(SIGTERM
, SIG_DFL
);
675 signal(SIGINT
, SIG_DFL
);
682 serverConnectionsOpen(void)
684 if (IamPrimaryProcess()) {
686 wccpConnectionOpen();
691 wccp2ConnectionOpen();
694 // start various proxying services if we are responsible for them
695 if (IamWorkerProcess()) {
696 clientOpenListenSockets();
715 peerSourceHashInit();
720 serverConnectionsClose(void)
722 assert(shutting_down
|| reconfiguring
);
724 if (IamPrimaryProcess()) {
727 wccpConnectionClose();
731 wccp2ConnectionClose();
734 if (IamWorkerProcess()) {
735 clientConnectionsClose();
736 icpConnectionShutdown();
738 htcpSocketShutdown();
751 mainReconfigureStart(void)
753 debugs(1, DBG_IMPORTANT
, "Reconfiguring Squid Cache (version " << version_string
<< ")...");
756 // Initiate asynchronous closing sequence
757 serverConnectionsClose();
764 Ssl::Helper::GetInstance()->Shutdown();
767 if (Ssl::CertValidationHelper::GetInstance())
768 Ssl::CertValidationHelper::GetInstance()->Shutdown();
769 Ssl::TheGlobalContextStorage
.reconfigureStart();
775 externalAclShutdown();
776 storeDirCloseSwapLogs();
783 eventAdd("mainReconfigureFinish", &mainReconfigureFinish
, NULL
, 0, 1,
788 mainReconfigureFinish(void *)
790 debugs(1, 3, "finishing reconfiguring");
793 enter_suid(); /* root to read config file */
795 // we may have disabled the need for PURGE
796 if (Config2
.onoff
.enable_purge
)
797 Config2
.onoff
.enable_purge
= 2;
799 // parse the config returns a count of errors encountered.
800 const int oldWorkers
= Config
.workers
;
801 if ( parseConfigFile(ConfigFile
) != 0) {
802 // for now any errors are a fatal condition...
805 if (oldWorkers
!= Config
.workers
) {
806 debugs(1, DBG_CRITICAL
, "WARNING: Changing 'workers' (from " <<
807 oldWorkers
<< " to " << Config
.workers
<<
808 ") requires a full restart. It has been ignored by reconfigure.");
809 Config
.workers
= oldWorkers
;
812 RunRegisteredHere(RegisteredRunner::syncConfig
);
814 if (IamPrimaryProcess())
816 CpuAffinityReconfigure();
818 setUmask(Config
.umask
);
821 _db_init(Debug::cache_log
, Debug::debugOptions
);
822 ipcache_restart(); /* clear stuck entries */
823 fqdncache_restart(); /* sigh, fqdncache too */
825 errorInitialize(); /* reload error pages */
828 #if USE_LOADABLE_MODULES
829 LoadableModulesConfigure(Config
.loadable_module_names
);
833 bool enableAdaptation
= false;
835 Adaptation::Icap::TheConfig
.finalize();
836 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
839 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
840 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
842 Adaptation::Config::Finalize(enableAdaptation
);
851 Ssl::Helper::GetInstance()->Init();
854 if (Ssl::CertValidationHelper::GetInstance())
855 Ssl::CertValidationHelper::GetInstance()->Init();
860 authenticateInit(&Auth::TheConfig
);
864 if (IamPrimaryProcess()) {
875 serverConnectionsOpen();
879 storeDirOpenSwapLogs();
881 mimeInit(Config
.mimeTablePathname
);
887 Config
.ClientDelay
.finalize();
890 if (Config
.onoff
.announce
) {
891 if (!eventFind(start_announce
, NULL
))
892 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
894 if (eventFind(start_announce
, NULL
))
895 eventDelete(start_announce
, NULL
);
898 writePidFile(); /* write PID file */
909 authenticateRotate();
911 externalAclShutdown();
913 _db_rotate_log(); /* cache.log */
914 storeDirWriteCleanLogs(1);
915 storeLogRotate(); /* store.log */
916 accessLogRotate(); /* access.log */
918 icapLogRotate(); /*icap.log*/
923 authenticateInit(&Auth::TheConfig
);
929 setEffectiveUser(void)
932 leave_suid(); /* Run as non privilegied user */
938 if (geteuid() == 0) {
939 debugs(0, DBG_CRITICAL
, "Squid is not safe to run as root! If you must");
940 debugs(0, DBG_CRITICAL
, "start Squid as root, then you must configure");
941 debugs(0, DBG_CRITICAL
, "it to run as a non-priveledged user with the");
942 debugs(0, DBG_CRITICAL
, "'cache_effective_user' option in the config file.");
943 fatal("Don't run Squid as root, set 'cache_effective_user'!");
947 /// changes working directory, providing error reporting
949 mainChangeDir(const char *dir
)
954 debugs(50, DBG_CRITICAL
, "cannot change current directory to " << dir
<<
955 ": " << xstrerror());
959 /// set the working directory.
963 static bool chrooted
= false;
964 if (Config
.chroot_dir
&& !chrooted
) {
967 if (chroot(Config
.chroot_dir
) != 0)
968 fatalf("chroot to %s failed: %s", Config
.chroot_dir
, xstrerror());
970 if (!mainChangeDir("/"))
971 fatalf("chdir to / after chroot to %s failed", Config
.chroot_dir
);
974 if (Config
.coredump_dir
&& strcmp("none", Config
.coredump_dir
) != 0) {
975 if (mainChangeDir(Config
.coredump_dir
)) {
976 debugs(0, DBG_IMPORTANT
, "Set Current Directory to " << Config
.coredump_dir
);
981 /* If we don't have coredump_dir or couldn't cd there, report current dir */
982 char pathbuf
[MAXPATHLEN
];
983 if (getcwd(pathbuf
, MAXPATHLEN
)) {
984 debugs(0, DBG_IMPORTANT
, "Current Directory is " << pathbuf
);
986 debugs(50, DBG_CRITICAL
, "WARNING: Can't find current directory, getcwd: " << xstrerror());
993 /* chroot if configured to run inside chroot */
996 if (opt_catch_signals
) {
997 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
998 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
1001 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
1002 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
1006 if (icpPortNumOverride
!= 1)
1007 Config
.Port
.icp
= (unsigned short) icpPortNumOverride
;
1009 _db_init(Debug::cache_log
, Debug::debugOptions
);
1011 fd_open(fileno(debug_log
), FD_LOG
, Debug::cache_log
);
1013 debugs(1, DBG_CRITICAL
, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
1014 debugs(1, DBG_CRITICAL
, "Service Name: " << service_name
);
1017 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
1018 debugs(1, DBG_CRITICAL
, "Service command line is: " << WIN32_Service_Command_Line
);
1020 debugs(1, DBG_CRITICAL
, "Running on " << WIN32_OS_string
);
1023 debugs(1, DBG_IMPORTANT
, "Process ID " << getpid());
1025 debugs(1, DBG_IMPORTANT
, "Process Roles:" << ProcessRoles());
1028 debugs(1, DBG_IMPORTANT
, "With " << Squid_MaxFD
<< " file descriptors available");
1032 debugs(1, DBG_IMPORTANT
, "With " << _getmaxstdio() << " CRT stdio descriptors available");
1034 if (WIN32_Socks_initialized
)
1035 debugs(1, DBG_IMPORTANT
, "Windows sockets initialized");
1037 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
1038 WIN32_IpAddrChangeMonitorInit();
1043 if (!configured_once
)
1044 disk_init(); /* disk_init must go before ipcache_init() */
1055 Ssl::Helper::GetInstance()->Init();
1059 if (!configured_once
)
1060 Ssl::initialize_session_cache();
1062 if (Ssl::CertValidationHelper::GetInstance())
1063 Ssl::CertValidationHelper::GetInstance()->Init();
1068 authenticateInit(&Auth::TheConfig
);
1072 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
1074 httpReplyInitModule(); /* must go before accepting replies */
1095 malloc_debug(0, malloc_debug_level
);
1099 if (!configured_once
) {
1100 if (unlinkdNeeded())
1107 mimeInit(Config
.mimeTablePathname
);
1113 FwdState::initModule();
1114 /* register the modules in the cache manager menus */
1116 cbdataRegisterWithCacheManager();
1117 /* These use separate calls so that the comm loops can eventually
1123 // TODO: pconn is a good candidate for new-style registration
1124 // PconnModule::GetInstance()->registerWithCacheManager();
1125 // moved to PconnModule::PconnModule()
1128 if (IamPrimaryProcess()) {
1140 serverConnectionsOpen();
1144 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1146 if (Config
.chroot_dir
)
1149 if (!configured_once
)
1150 writePidFile(); /* write PID file */
1152 #if defined(_SQUID_LINUX_THREADS_)
1154 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1156 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1160 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1162 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1166 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1168 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1170 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1174 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1180 #if USE_LOADABLE_MODULES
1181 LoadableModulesConfigure(Config
.loadable_module_names
);
1185 bool enableAdaptation
= false;
1187 // We can remove this dependency on specific adaptation mechanisms
1188 // if we create a generic Registry of such mechanisms. Should we?
1190 Adaptation::Icap::TheConfig
.finalize();
1191 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
1194 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
1195 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
1197 // must be the last adaptation-related finalize
1198 Adaptation::Config::Finalize(enableAdaptation
);
1206 Config
.ClientDelay
.finalize();
1209 if (!configured_once
) {
1210 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1212 if (Config
.onoff
.announce
)
1213 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1215 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1217 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1221 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1225 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1228 configured_once
= 1;
1231 /// unsafe main routine -- may throw
1232 int SquidMain(int argc
, char **argv
);
1233 /// unsafe main routine wrapper to catch exceptions
1234 static int SquidMainSafe(int argc
, char **argv
);
1236 #if USE_WIN32_SERVICE
1237 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1238 extern "C" void WINAPI
1239 SquidWinSvcMain(int argc
, char **argv
)
1241 SquidMainSafe(argc
, argv
);
1245 main(int argc
, char **argv
)
1247 return SquidMainSafe(argc
, argv
);
1252 SquidMainSafe(int argc
, char **argv
)
1255 return SquidMain(argc
, argv
);
1256 } catch (const std::exception
&e
) {
1257 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception: " <<
1261 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception.");
1264 return -1; // not reached
1267 /// computes name and ID for the current kid process
1269 ConfigureCurrentKid(const char *processName
)
1271 // kids are marked with parenthesis around their process names
1272 if (processName
&& processName
[0] == '(') {
1273 if (const char *idStart
= strrchr(processName
, '-')) {
1274 KidIdentifier
= atoi(idStart
+ 1);
1275 const size_t nameLen
= idStart
- (processName
+ 1);
1276 assert(nameLen
< sizeof(TheKidName
));
1277 xstrncpy(TheKidName
, processName
+ 1, nameLen
+ 1);
1278 if (!strcmp(TheKidName
, "squid-coord"))
1279 TheProcessKind
= pkCoordinator
;
1280 else if (!strcmp(TheKidName
, "squid"))
1281 TheProcessKind
= pkWorker
;
1282 else if (!strcmp(TheKidName
, "squid-disk"))
1283 TheProcessKind
= pkDisker
;
1285 TheProcessKind
= pkOther
; // including coordinator
1288 xstrncpy(TheKidName
, APP_SHORTNAME
, sizeof(TheKidName
));
1294 SquidMain(int argc
, char **argv
)
1296 ConfigureCurrentKid(argv
[0]);
1298 Debug::parseOptions(NULL
);
1301 #if defined(SQUID_MAXFD_LIMIT)
1303 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1304 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1308 /* NOP under non-windows */
1309 int WIN32_init_err
=0;
1310 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1311 return WIN32_init_err
;
1313 /* call mallopt() before anything else */
1316 /* Round up all sizes to a multiple of this */
1317 mallopt(M_GRAIN
, 16);
1321 /* biggest size that is considered a small block */
1322 mallopt(M_MXFAST
, 256);
1326 /* allocate this many small blocks at once */
1327 mallopt(M_NLBLKS
, 32);
1330 #endif /* HAVE_MALLOPT */
1332 squid_srandom(time(NULL
));
1336 squid_start
= current_time
;
1338 failure_notify
= fatal_dump
;
1340 #if USE_WIN32_SERVICE
1342 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1346 mainParseOptions(argc
, argv
);
1348 if (opt_parse_cfg_only
) {
1349 Debug::parseOptions("ALL,1");
1352 #if USE_WIN32_SERVICE
1354 if (opt_install_service
) {
1355 WIN32_InstallService();
1359 if (opt_remove_service
) {
1360 WIN32_RemoveService();
1364 if (opt_command_line
) {
1365 WIN32_SetServiceCommandLine();
1371 /* parse configuration file
1372 * note: in "normal" case this used to be called from mainInitialize() */
1377 ConfigFile
= xstrdup(DefaultConfigFile
);
1379 assert(!configured_once
);
1383 storeFsInit(); /* required for config parsing */
1385 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
1388 /* May not be needed for parsing, have not audited for such */
1389 DiskIOModule::SetupAllModules();
1391 /* Shouldn't be needed for config parsing, but have not audited for such */
1392 StoreFileSystem::SetupAllFs();
1394 /* we may want the parsing process to set this up in the future */
1395 Store::Root(new StoreController
);
1396 Auth::Init(); /* required for config parsing. NOP if !USE_AUTH */
1397 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
1399 Format::Token::Init(); // XXX: temporary. Use a runners registry of pre-parse runners instead.
1401 parse_err
= parseConfigFile(ConfigFile
);
1405 if (opt_parse_cfg_only
|| parse_err
> 0)
1408 setUmask(Config
.umask
);
1409 if (-1 == opt_send_signal
)
1410 if (checkRunningPid())
1425 /* send signal to running copy and exit */
1426 if (opt_send_signal
!= -1) {
1427 /* chroot if configured to run inside chroot */
1429 if (Config
.chroot_dir
) {
1439 debugs(1,2, HERE
<< "Doing post-config initialization\n");
1441 RunRegisteredHere(RegisteredRunner::finalizeConfig
);
1442 RunRegisteredHere(RegisteredRunner::claimMemoryNeeds
);
1443 RunRegisteredHere(RegisteredRunner::useConfig
);
1446 if (!opt_no_daemon
&& Config
.workers
> 0)
1449 if (opt_create_swap_dirs
) {
1450 /* chroot if configured to run inside chroot */
1454 debugs(0, DBG_CRITICAL
, "Creating missing swap directories");
1455 Store::Root().create();
1460 if (IamPrimaryProcess())
1466 /* init comm module */
1469 if (opt_no_daemon
) {
1470 /* we have to init fdstat here. */
1471 fd_open(0, FD_LOG
, "stdin");
1472 fd_open(1, FD_LOG
, "stdout");
1473 fd_open(2, FD_LOG
, "stderr");
1476 #if USE_WIN32_SERVICE
1478 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1484 #if USE_WIN32_SERVICE
1486 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1493 SignalEngine signalEngine
;
1495 mainLoop
.registerEngine(&signalEngine
);
1497 /* TODO: stop requiring the singleton here */
1498 mainLoop
.registerEngine(EventScheduler::GetInstance());
1500 StoreRootEngine store_engine
;
1502 mainLoop
.registerEngine(&store_engine
);
1504 CommSelectEngine comm_engine
;
1506 mainLoop
.registerEngine(&comm_engine
);
1508 mainLoop
.setPrimaryEngine(&comm_engine
);
1510 /* use the standard time service */
1511 TimeEngine time_engine
;
1513 mainLoop
.setTimeService(&time_engine
);
1515 if (IamCoordinatorProcess())
1516 AsyncJob::Start(Ipc::Coordinator::Instance());
1517 else if (UsingSmp() && (IamWorkerProcess() || IamDiskProcess()))
1518 AsyncJob::Start(new Ipc::Strand
);
1520 /* at this point we are finished the synchronous startup. */
1525 if (mainLoop
.errcount
== 10)
1526 fatal_dump("Event loop exited with failure.");
1528 /* shutdown squid now */
1541 if (strcmp(Config
.pidFilename
, "none") == 0) {
1542 debugs(0, DBG_IMPORTANT
, "No pid_filename specified. Trusting you know what you are doing.");
1545 pid
= readPidFile();
1548 #if USE_WIN32_SERVICE
1549 if (opt_signal_service
) {
1550 WIN32_sendSignal(opt_send_signal
);
1553 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1554 fprintf(stderr
, "signal to Squid Service:\n");
1555 fprintf(stderr
, "missing -n command line switch.\n");
1561 if (kill(pid
, opt_send_signal
) &&
1562 /* ignore permissions if just running check */
1563 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1564 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1565 fprintf(stderr
, "signal %d to process %d: %s\n",
1566 opt_send_signal
, (int) pid
, xstrerror());
1570 if (opt_send_signal
!= SIGTERM
) {
1571 fprintf(stderr
, "%s: ERROR: No running copy\n", APP_SHORTNAME
);
1574 fprintf(stderr
, "%s: No running copy\n", APP_SHORTNAME
);
1579 /* signal successfully sent */
1583 #if !_SQUID_WINDOWS_
1585 * This function is run when Squid is in daemon mode, just
1586 * before the parent forks and starts up the child process.
1587 * It can be used for admin-specific tasks, such as notifying
1588 * someone that Squid is (re)started.
1591 mainStartScript(const char *prog
)
1593 char script
[MAXPATHLEN
];
1598 xstrncpy(script
, prog
, MAXPATHLEN
);
1600 if ((t
= strrchr(script
, '/'))) {
1602 sl
= strlen(script
);
1605 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1607 if ((cpid
= fork()) == 0) {
1609 execl(script
, squid_start_script
, (char *)NULL
);
1615 rpid
= wait4(cpid
, &status
, 0, NULL
);
1619 rpid
= waitpid(cpid
, &status
, 0);
1622 } while (rpid
!= cpid
);
1626 #endif /* _SQUID_WINDOWS_ */
1629 checkRunningPid(void)
1631 // master process must start alone, but its kids processes may co-exist
1632 if (!IamMasterProcess())
1640 pid
= readPidFile();
1645 if (kill(pid
, 0) < 0)
1648 debugs(0, DBG_CRITICAL
, "Squid is already running! Process ID " << pid
);
1654 watch_child(char *argv
[])
1656 #if !_SQUID_WINDOWS_
1674 if (!IamMasterProcess())
1677 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1679 if ((pid
= fork()) < 0)
1680 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1685 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1691 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1692 ioctl(i
, TIOCNOTTY
, NULL
);
1699 * RBCOLLINS - if cygwin stackdumps when squid is run without
1700 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1701 * 1.1.3. execvp had a bit overflow error in a loop..
1703 /* Connect stdio to /dev/null in daemon mode */
1704 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1707 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1711 if (Debug::log_stderr
< 0) {
1716 // handle shutdown notifications from kids
1717 squid_signal(SIGUSR1
, sig_shutdown
, SA_RESTART
);
1719 if (Config
.workers
> 128) {
1720 syslog(LOG_ALERT
, "Suspiciously high workers value: %d",
1722 // but we keep going in hope that user knows best
1726 syslog(LOG_NOTICE
, "Squid Parent: will start %d kids", (int)TheKids
.count());
1728 // keep [re]starting kids until it is time to quit
1730 mainStartScript(argv
[0]);
1732 // start each kid that needs to be [re]started; once
1733 for (int i
= TheKids
.count() - 1; i
>= 0; --i
) {
1734 Kid
& kid
= TheKids
.get(i
);
1735 if (!kid
.shouldRestart())
1738 if ((pid
= fork()) == 0) {
1740 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1742 argv
[0] = const_cast<char*>(kid
.name().termedBuf());
1744 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1748 syslog(LOG_NOTICE
, "Squid Parent: %s process %d started",
1749 kid
.name().termedBuf(), pid
);
1753 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1755 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1759 pid
= wait3(&status
, 0, NULL
);
1763 pid
= waitpid(-1, &status
, 0);
1766 // Loop to collect all stopped kids before we go to sleep below.
1768 Kid
* kid
= TheKids
.find(pid
);
1771 if (kid
->calledExit()) {
1773 "Squid Parent: %s process %d exited with status %d",
1774 kid
->name().termedBuf(),
1775 kid
->getPid(), kid
->exitStatus());
1776 } else if (kid
->signaled()) {
1778 "Squid Parent: %s process %d exited due to signal %d with status %d",
1779 kid
->name().termedBuf(),
1780 kid
->getPid(), kid
->termSignal(), kid
->exitStatus());
1782 syslog(LOG_NOTICE
, "Squid Parent: %s process %d exited",
1783 kid
->name().termedBuf(), kid
->getPid());
1785 if (kid
->hopeless()) {
1786 syslog(LOG_NOTICE
, "Squid Parent: %s process %d will not"
1787 " be restarted due to repeated, frequent failures",
1788 kid
->name().termedBuf(), kid
->getPid());
1791 syslog(LOG_NOTICE
, "Squid Parent: unknown child process %d exited", pid
);
1794 } while ((pid
= wait3(&status
, WNOHANG
, NULL
)) > 0);
1797 while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0);
1800 if (!TheKids
.someRunning() && !TheKids
.shouldRestartSome()) {
1802 // XXX: Master process has no main loop and, hence, should not call
1803 // RegisteredRunner::startShutdown which promises a loop iteration.
1804 RunRegisteredHere(RegisteredRunner::finishShutdown
);
1807 if (TheKids
.someSignaled(SIGINT
) || TheKids
.someSignaled(SIGTERM
)) {
1808 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1812 if (TheKids
.allHopeless()) {
1813 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1820 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1825 #endif /* _SQUID_WINDOWS_ */
1832 /* XXX: This function is called after the main loop has quit, which
1833 * means that no AsyncCalls would be called, including close handlers.
1834 * TODO: We need to close/shut/free everything that needs calls before
1838 #if USE_WIN32_SERVICE
1839 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1842 debugs(1, DBG_IMPORTANT
, "Shutting down...");
1845 Ssl::Helper::GetInstance()->Shutdown();
1848 if (Ssl::CertValidationHelper::GetInstance())
1849 Ssl::CertValidationHelper::GetInstance()->Shutdown();
1852 externalAclShutdown();
1862 wccpConnectionClose();
1866 wccp2ConnectionClose();
1869 releaseServerSockets();
1870 commCloseAllSockets();
1877 DelayPools::FreePools();
1880 authenticateReset();
1882 #if USE_WIN32_SERVICE
1884 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1887 Store::Root().sync(); /* Flush pending object writes/unlinks */
1889 unlinkdClose(); /* after sync/flush. NOP if !USE_UNLINKD */
1891 storeDirWriteCleanLogs(0);
1894 Store::Root().sync(); /* Flush log writes */
1897 Store::Root().sync(); /* Flush log close */
1898 StoreFileSystem::FreeAllFs();
1899 DiskIOModule::FreeAllModules();
1900 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1904 /*stmemFreeMemory(); */
1906 ipcacheFreeMemory();
1907 fqdncacheFreeMemory();
1909 clientdbFreeMemory();
1910 httpHeaderCleanModule();
1916 // clear StoreController
1923 RunRegisteredHere(RegisteredRunner::finishShutdown
);
1927 if (IamPrimaryProcess()) {
1928 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1930 safeunlink(Config
.pidFilename
, 0);
1935 debugs(1, DBG_IMPORTANT
, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1939 * We used to fclose(debug_log) here if it was set, but then
1940 * we forgot to set it to NULL. That caused some coredumps
1941 * because exit() ends up calling a bunch of destructors and
1942 * such. So rather than forcing the debug_log to close, we'll
1943 * leave it open so that those destructors can write some
1944 * debugging if necessary. The file will be closed anyway when
1945 * the process truly exits.
1948 exit(shutdown_status
);