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"
57 #include "fs/Module.h"
58 #include "fqdncache.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"
77 #include "PeerSelectState.h"
78 #include "peer_sourcehash.h"
79 #include "peer_userhash.h"
80 #include "profiler/Profiler.h"
83 #include "send-announce.h"
84 #include "store_log.h"
86 #include "SquidConfig.h"
88 #include "SquidTime.h"
90 #include "StatCounters.h"
91 #include "StoreFileSystem.h"
101 #include "adaptation/Config.h"
104 #include "adaptation/ecap/Config.h"
107 #include "adaptation/icap/Config.h"
108 #include "adaptation/icap/icap_log.h"
111 #include "auth/Gadgets.h"
114 #include "ClientDelayConfig.h"
117 #include "DelayPools.h"
119 #if USE_LOADABLE_MODULES
120 #include "LoadableModules.h"
123 #include "ssl/helper.h"
124 #include "ssl/certificate_db.h"
127 #include "ssl/context_storage.h"
130 #include "adaptation/icap/Config.h"
133 #include "adaptation/ecap/Config.h"
136 #include "adaptation/Config.h"
139 #include "esi/Module.h"
142 #include "snmp_core.h"
149 #include <sys/wait.h>
155 #if USE_WIN32_SERVICE
158 static int opt_install_service
= FALSE
;
159 static int opt_remove_service
= FALSE
;
160 static int opt_signal_service
= FALSE
;
161 static int opt_command_line
= FALSE
;
162 void WIN32_svcstatusupdate(DWORD
, DWORD
);
163 void WINAPI
WIN32_svcHandler(DWORD
);
166 #if !defined(SQUID_BUILD_INFO)
167 #define SQUID_BUILD_INFO ""
170 static char *opt_syslog_facility
= NULL
;
171 static int icpPortNumOverride
= 1; /* Want to detect "-u 0" */
172 static int configured_once
= 0;
174 static int malloc_debug_level
= 0;
176 static volatile int do_reconfigure
= 0;
177 static volatile int do_rotate
= 0;
178 static volatile int do_shutdown
= 0;
179 static volatile int shutdown_status
= 0;
181 static int RotateSignal
= -1;
182 static int ReconfigureSignal
= -1;
183 static int ShutdownSignal
= -1;
185 static void mainRotate(void);
186 static void mainReconfigureStart(void);
187 static void mainReconfigureFinish(void*);
188 static void mainInitialize(void);
189 static void usage(void);
190 static void mainParseOptions(int argc
, char *argv
[]);
191 static void sendSignal(void);
192 static void serverConnectionsOpen(void);
193 static void serverConnectionsClose(void);
194 static void watch_child(char **);
195 static void setEffectiveUser(void);
197 void log_trace_done();
198 void log_trace_init(char *);
200 static void SquidShutdown(void);
201 static void mainSetCwd(void);
202 static int checkRunningPid(void);
205 static const char *squid_start_script
= "squid_start";
209 #include "test_access.c"
212 /** temporary thunk across to the unrefactored store interface */
214 class StoreRootEngine
: public AsyncEngine
218 int checkEvents(int timeout
) {
219 Store::Root().callback();
224 class SignalEngine
: public AsyncEngine
228 SignalEngine(EventLoop
&evtLoop
) : loop(evtLoop
) {}
229 virtual int checkEvents(int timeout
);
232 static void StopEventLoop(void * data
) {
233 static_cast<SignalEngine
*>(data
)->loop
.stop();
236 void doShutdown(time_t wait
);
242 SignalEngine::checkEvents(int timeout
)
244 PROF_start(SignalEngine_checkEvents
);
246 if (do_reconfigure
) {
247 mainReconfigureStart();
249 } else if (do_rotate
) {
252 } else if (do_shutdown
) {
253 doShutdown(do_shutdown
> 0 ? (int) Config
.shutdownLifetime
: 0);
256 BroadcastSignalIfAny(DebugSignal
);
257 BroadcastSignalIfAny(RotateSignal
);
258 BroadcastSignalIfAny(ReconfigureSignal
);
259 BroadcastSignalIfAny(ShutdownSignal
);
261 PROF_stop(SignalEngine_checkEvents
);
266 SignalEngine::doShutdown(time_t wait
)
268 debugs(1, DBG_IMPORTANT
, "Preparing for shutdown after " << statCounter
.client_http
.requests
<< " requests");
269 debugs(1, DBG_IMPORTANT
, "Waiting " << wait
<< " seconds for active connections to finish");
273 #if USE_WIN32_SERVICE
274 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, (wait
+ 1) * 1000);
277 /* run the closure code which can be shared with reconfigure */
278 serverConnectionsClose();
280 /* detach the auth components (only do this on full shutdown) */
281 Auth::Scheme::FreeAll();
283 eventAdd("SquidShutdown", &StopEventLoop
, this, (double) (wait
+ 1), 1, false);
290 #if USE_WIN32_SERVICE
291 "Usage: %s [-cdhirvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
293 "Usage: %s [-cdhvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
295 " -a port Specify HTTP port number (default: %d).\n"
296 " -d level Write debugging to stderr also.\n"
297 " -f file Use given config-file instead of\n"
299 " -h Print help message.\n"
300 #if USE_WIN32_SERVICE
301 " -i Installs as a Windows Service (see -n option).\n"
303 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
304 " Parse configuration file, then send signal to \n"
305 " running copy (except -k parse) and exit.\n"
306 #if USE_WIN32_SERVICE
307 " -n name Specify Windows Service name to use for service operations\n"
308 " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME
".\n"
309 " -r Removes a Windows Service (see -n option).\n"
311 " -s | -l facility\n"
312 " Enable logging to syslog.\n"
313 " -u port Specify ICP port number (default: %d), disable with 0.\n"
314 " -v Print version.\n"
315 " -z Create swap directories\n"
316 " -C Do not catch fatal signals.\n"
317 " -D OBSOLETE. Scheduled for removal.\n"
318 " -F Don't serve any requests until store is rebuilt.\n"
319 " -N No daemon mode.\n"
320 #if USE_WIN32_SERVICE
322 " Set Windows Service Command line options in Registry.\n"
324 " -R Do not set REUSEADDR on port.\n"
325 " -S Double-check swap during rebuild.\n"
326 " -X Force full debugging.\n"
327 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
328 APP_SHORTNAME
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
333 * Parse the parameters received via command line interface.
335 \param argc Number of options received on command line
336 \param argv List of parameters received on command line
339 mainParseOptions(int argc
, char *argv
[])
344 #if USE_WIN32_SERVICE
345 while ((c
= getopt(argc
, argv
, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
347 while ((c
= getopt(argc
, argv
, "CDFNRSYXa:d:f:hk:m::sl:u:vz?")) != -1)
355 * Unset/disabel global option for catchign signals. opt_catch_signals */
356 opt_catch_signals
= 0;
361 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
362 debugs(1,DBG_CRITICAL
, "WARNING: -D command-line option is obsolete.");
367 * Set global option for foreground rebuild. opt_foreground_rebuild */
368 opt_foreground_rebuild
= 1;
373 * Set global option for 'no_daemon' mode. opt_no_daemon */
377 #if USE_WIN32_SERVICE
381 * Set global option. opt_command_lin and WIN32_Command_Line */
382 opt_command_line
= 1;
383 WIN32_Command_Line
= xstrdup(optarg
);
389 * Unset/disable global option opt_reuseaddr */
395 * Set global option opt_store_doublecheck */
396 opt_store_doublecheck
= 1;
401 * Force full debugging */
402 Debug::parseOptions("rotate=0 ALL,9");
403 Debug::override_X
= 1;
404 sigusr2_handle(SIGUSR2
);
409 * Set global option opt_reload_hit_only */
410 opt_reload_hit_only
= 1;
413 #if USE_WIN32_SERVICE
417 * Set global option opt_install_service (to TRUE) */
418 opt_install_service
= TRUE
;
424 * Add optional HTTP port as given following the option */
425 add_http_port(optarg
);
430 * Set global option Debug::log_stderr to the number given follwoign the option */
431 Debug::log_stderr
= atoi(optarg
);
436 * Load the file given instead of the default squid.conf. */
438 ConfigFile
= xstrdup(optarg
);
443 * Run the administrative action given following the option */
445 /** \li When its an unknown option display the usage help. */
446 if ((int) strlen(optarg
) < 1)
449 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
450 /** \li On reconfigure send SIGHUP. */
451 opt_send_signal
= SIGHUP
;
452 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
453 /** \li On rotate send SIGQUIT or SIGUSR1. */
454 #if defined(_SQUID_LINUX_THREADS_)
455 opt_send_signal
= SIGQUIT
;
457 opt_send_signal
= SIGUSR1
;
460 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
461 /** \li On debug send SIGTRAP or SIGUSR2. */
462 #if defined(_SQUID_LINUX_THREADS_)
463 opt_send_signal
= SIGTRAP
;
465 opt_send_signal
= SIGUSR2
;
468 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
469 /** \li On shutdown send SIGTERM. */
470 opt_send_signal
= SIGTERM
;
471 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
472 /** \li On interrupt send SIGINT. */
473 opt_send_signal
= SIGINT
;
474 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
475 /** \li On kill send SIGKILL. */
476 opt_send_signal
= SIGKILL
;
480 else if (!strncmp(optarg
, "restart", strlen(optarg
)))
481 /** \li On restart send SIGTTIN. (exit and restart by parent) */
482 opt_send_signal
= SIGTTIN
;
486 else if (!strncmp(optarg
, "check", strlen(optarg
)))
487 /** \li On check send 0 / SIGNULL. */
488 opt_send_signal
= 0; /* SIGNULL */
489 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
490 /** \li On parse set global flag to re-parse the config file only. */
491 opt_parse_cfg_only
= 1;
499 * Set global malloc_debug_level to the value given following the option.
500 * if none is given it toggles the xmalloc_trace option on/off */
503 malloc_debug_level
= atoi(optarg
);
505 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
510 xmalloc_trace
= !xmalloc_trace
;
512 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
517 #if USE_WIN32_SERVICE
521 * Set global option opt_signal_service (to TRUE).
522 * Stores the additional parameter given in global WIN32_Service_name */
523 xfree(WIN32_Service_name
);
525 WIN32_Service_name
= xstrdup(optarg
);
527 opt_signal_service
= TRUE
;
533 * Set global option opt_remove_service (to TRUE) */
534 opt_remove_service
= TRUE
;
542 * Stores the syslog facility name in global opt_syslog_facility
543 * then performs actions for -s option. */
544 opt_syslog_facility
= xstrdup(optarg
);
548 * Initialize the syslog for output */
551 _db_set_syslog(opt_syslog_facility
);
557 fatal("Logging to syslog not available on this platform");
564 * Store the ICP port number given in global option icpPortNumOverride
565 * ensuring its a positive number. */
566 icpPortNumOverride
= atoi(optarg
);
568 if (icpPortNumOverride
< 0)
569 icpPortNumOverride
= 0;
575 * Display squid version and build information. Then exit. */
576 printf("Squid Cache: Version %s\n" ,version_string
);
577 if (strlen(SQUID_BUILD_INFO
))
578 printf("%s\n",SQUID_BUILD_INFO
);
579 printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS
);
581 #if USE_WIN32_SERVICE
583 printf("Compiled as Windows System Service.\n");
593 * Set global option Debug::log_stderr and opt_create_swap_dirs */
594 Debug::log_stderr
= 1;
595 opt_create_swap_dirs
= 1;
603 /** \par h,?, or unknown
604 * \copydoc usage() */
622 signal(sig
, rotate_logs
);
632 ReconfigureSignal
= sig
;
636 signal(sig
, reconfigure
);
644 do_shutdown
= sig
== SIGINT
? -1 : 1;
645 ShutdownSignal
= sig
;
653 const pid_t ppid
= getppid();
655 if (!IamMasterProcess() && ppid
> 1) {
656 // notify master that we are shutting down
657 if (kill(ppid
, SIGUSR1
) < 0)
658 debugs(1, DBG_IMPORTANT
, "Failed to send SIGUSR1 to master process,"
659 " pid " << ppid
<< ": " << xstrerror());
665 if (!IamMasterProcess() && ppid
> 1) {
666 debugs(1, DBG_IMPORTANT
, "Killing master process, pid " << ppid
);
668 if (kill(ppid
, sig
) < 0)
669 debugs(1, DBG_IMPORTANT
, "kill " << ppid
<< ": " << xstrerror());
672 #endif /* KILL_PARENT_OPT */
673 #if SA_RESETHAND == 0
674 signal(SIGTERM
, SIG_DFL
);
676 signal(SIGINT
, SIG_DFL
);
683 serverConnectionsOpen(void)
685 if (IamPrimaryProcess()) {
687 wccpConnectionOpen();
692 wccp2ConnectionOpen();
695 // start various proxying services if we are responsible for them
696 if (IamWorkerProcess()) {
697 clientOpenListenSockets();
717 peerSourceHashInit();
722 serverConnectionsClose(void)
724 assert(shutting_down
|| reconfiguring
);
726 if (IamPrimaryProcess()) {
729 wccpConnectionClose();
733 wccp2ConnectionClose();
736 if (IamWorkerProcess()) {
737 clientHttpConnectionsClose();
738 icpConnectionShutdown();
740 htcpSocketShutdown();
753 mainReconfigureStart(void)
755 debugs(1, DBG_IMPORTANT
, "Reconfiguring Squid Cache (version " << version_string
<< ")...");
758 // Initiate asynchronous closing sequence
759 serverConnectionsClose();
766 Ssl::Helper::GetInstance()->Shutdown();
769 if (Ssl::CertValidationHelper::GetInstance())
770 Ssl::CertValidationHelper::GetInstance()->Shutdown();
771 Ssl::TheGlobalContextStorage
.reconfigureStart();
777 externalAclShutdown();
778 storeDirCloseSwapLogs();
785 eventAdd("mainReconfigureFinish", &mainReconfigureFinish
, NULL
, 0, 1,
790 mainReconfigureFinish(void *)
792 debugs(1, 3, "finishing reconfiguring");
795 enter_suid(); /* root to read config file */
797 // we may have disabled the need for PURGE
798 if (Config2
.onoff
.enable_purge
)
799 Config2
.onoff
.enable_purge
= 2;
801 // parse the config returns a count of errors encountered.
802 const int oldWorkers
= Config
.workers
;
803 if ( parseConfigFile(ConfigFile
) != 0) {
804 // for now any errors are a fatal condition...
807 if (oldWorkers
!= Config
.workers
) {
808 debugs(1, DBG_CRITICAL
, "WARNING: Changing 'workers' (from " <<
809 oldWorkers
<< " to " << Config
.workers
<<
810 ") is not supported and ignored");
811 Config
.workers
= oldWorkers
;
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 */
912 authenticateRotate();
914 externalAclShutdown();
916 _db_rotate_log(); /* cache.log */
917 storeDirWriteCleanLogs(1);
918 storeLogRotate(); /* store.log */
919 accessLogRotate(); /* access.log */
921 icapLogRotate(); /*icap.log*/
929 authenticateInit(&Auth::TheConfig
);
935 setEffectiveUser(void)
938 leave_suid(); /* Run as non privilegied user */
944 if (geteuid() == 0) {
945 debugs(0, DBG_CRITICAL
, "Squid is not safe to run as root! If you must");
946 debugs(0, DBG_CRITICAL
, "start Squid as root, then you must configure");
947 debugs(0, DBG_CRITICAL
, "it to run as a non-priveledged user with the");
948 debugs(0, DBG_CRITICAL
, "'cache_effective_user' option in the config file.");
949 fatal("Don't run Squid as root, set 'cache_effective_user'!");
956 char pathbuf
[MAXPATHLEN
];
958 if (Config
.coredump_dir
) {
959 if (0 == strcmp("none", Config
.coredump_dir
)) {
961 } else if (chdir(Config
.coredump_dir
) == 0) {
962 debugs(0, DBG_IMPORTANT
, "Set Current Directory to " << Config
.coredump_dir
);
965 debugs(50, DBG_CRITICAL
, "chdir: " << Config
.coredump_dir
<< ": " << xstrerror());
969 /* If we don't have coredump_dir or couldn't cd there, report current dir */
970 if (getcwd(pathbuf
, MAXPATHLEN
)) {
971 debugs(0, DBG_IMPORTANT
, "Current Directory is " << pathbuf
);
973 debugs(50, DBG_CRITICAL
, "WARNING: Can't find current directory, getcwd: " << xstrerror());
980 /* chroot if configured to run inside chroot */
982 if (Config
.chroot_dir
&& (chroot(Config
.chroot_dir
) != 0 || chdir("/") != 0)) {
983 fatal("failed to chroot");
986 if (opt_catch_signals
) {
987 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
988 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
991 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
992 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
996 if (icpPortNumOverride
!= 1)
997 Config
.Port
.icp
= (unsigned short) icpPortNumOverride
;
999 _db_init(Debug::cache_log
, Debug::debugOptions
);
1001 fd_open(fileno(debug_log
), FD_LOG
, Debug::cache_log
);
1005 log_trace_init("/tmp/squid.alloc");
1009 debugs(1, DBG_CRITICAL
, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
1012 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
1013 debugs(1, DBG_CRITICAL
, "Running as " << WIN32_Service_name
<< " Windows System Service on " << WIN32_OS_string
);
1014 debugs(1, DBG_CRITICAL
, "Service command line is: " << WIN32_Service_Command_Line
);
1016 debugs(1, DBG_CRITICAL
, "Running on " << WIN32_OS_string
);
1019 debugs(1, DBG_IMPORTANT
, "Process ID " << getpid());
1021 debugs(1, DBG_IMPORTANT
, "Process Roles:" << ProcessRoles());
1024 debugs(1, DBG_IMPORTANT
, "With " << Squid_MaxFD
<< " file descriptors available");
1028 debugs(1, DBG_IMPORTANT
, "With " << _getmaxstdio() << " CRT stdio descriptors available");
1030 if (WIN32_Socks_initialized
)
1031 debugs(1, DBG_IMPORTANT
, "Windows sockets initialized");
1033 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
1034 WIN32_IpAddrChangeMonitorInit();
1039 if (!configured_once
)
1040 disk_init(); /* disk_init must go before ipcache_init() */
1051 Ssl::Helper::GetInstance()->Init();
1055 if (Ssl::CertValidationHelper::GetInstance())
1056 Ssl::CertValidationHelper::GetInstance()->Init();
1061 authenticateInit(&Auth::TheConfig
);
1065 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
1067 httpReplyInitModule(); /* must go before accepting replies */
1088 malloc_debug(0, malloc_debug_level
);
1092 if (!configured_once
) {
1093 if (unlinkdNeeded())
1100 /* after this point we want to see the mallinfo() output */
1102 mimeInit(Config
.mimeTablePathname
);
1108 FwdState::initModule();
1109 /* register the modules in the cache manager menus */
1111 cbdataRegisterWithCacheManager();
1112 /* These use separate calls so that the comm loops can eventually
1118 // TODO: pconn is a good candidate for new-style registration
1119 // PconnModule::GetInstance()->registerWithCacheManager();
1120 // moved to PconnModule::PconnModule()
1123 if (IamPrimaryProcess()) {
1135 serverConnectionsOpen();
1139 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1141 if (Config
.chroot_dir
)
1144 if (!configured_once
)
1145 writePidFile(); /* write PID file */
1147 #if defined(_SQUID_LINUX_THREADS_)
1149 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1151 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1155 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1157 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1161 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1163 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1165 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1169 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1175 #if USE_LOADABLE_MODULES
1176 LoadableModulesConfigure(Config
.loadable_module_names
);
1180 bool enableAdaptation
= false;
1182 // We can remove this dependency on specific adaptation mechanisms
1183 // if we create a generic Registry of such mechanisms. Should we?
1185 Adaptation::Icap::TheConfig
.finalize();
1186 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
1189 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
1190 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
1192 // must be the last adaptation-related finalize
1193 Adaptation::Config::Finalize(enableAdaptation
);
1201 Config
.ClientDelay
.finalize();
1204 if (!configured_once
) {
1205 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1207 if (Config
.onoff
.announce
)
1208 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1210 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1212 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1216 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1220 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1223 configured_once
= 1;
1226 /// unsafe main routine -- may throw
1227 int SquidMain(int argc
, char **argv
);
1228 /// unsafe main routine wrapper to catch exceptions
1229 static int SquidMainSafe(int argc
, char **argv
);
1231 #if USE_WIN32_SERVICE
1232 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1233 extern "C" void WINAPI
1234 SquidWinSvcMain(int argc
, char **argv
)
1236 SquidMainSafe(argc
, argv
);
1240 main(int argc
, char **argv
)
1242 return SquidMainSafe(argc
, argv
);
1247 SquidMainSafe(int argc
, char **argv
)
1250 return SquidMain(argc
, argv
);
1251 } catch (const std::exception
&e
) {
1252 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception: " <<
1256 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception.");
1259 return -1; // not reached
1262 /// computes name and ID for the current kid process
1264 ConfigureCurrentKid(const char *processName
)
1266 // kids are marked with parenthesis around their process names
1267 if (processName
&& processName
[0] == '(') {
1268 if (const char *idStart
= strrchr(processName
, '-')) {
1269 KidIdentifier
= atoi(idStart
+ 1);
1270 const size_t nameLen
= idStart
- (processName
+ 1);
1271 assert(nameLen
< sizeof(TheKidName
));
1272 xstrncpy(TheKidName
, processName
+ 1, nameLen
+ 1);
1273 if (!strcmp(TheKidName
, "squid-coord"))
1274 TheProcessKind
= pkCoordinator
;
1275 else if (!strcmp(TheKidName
, "squid"))
1276 TheProcessKind
= pkWorker
;
1277 else if (!strcmp(TheKidName
, "squid-disk"))
1278 TheProcessKind
= pkDisker
;
1280 TheProcessKind
= pkOther
; // including coordinator
1283 xstrncpy(TheKidName
, APP_SHORTNAME
, sizeof(TheKidName
));
1289 SquidMain(int argc
, char **argv
)
1291 ConfigureCurrentKid(argv
[0]);
1294 sbrk_start
= sbrk(0);
1297 Debug::parseOptions(NULL
);
1300 #if defined(SQUID_MAXFD_LIMIT)
1302 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1303 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1307 /* NOP under non-windows */
1308 int WIN32_init_err
=0;
1309 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1310 return WIN32_init_err
;
1312 /* call mallopt() before anything else */
1315 /* Round up all sizes to a multiple of this */
1316 mallopt(M_GRAIN
, 16);
1320 /* biggest size that is considered a small block */
1321 mallopt(M_MXFAST
, 256);
1325 /* allocate this many small blocks at once */
1326 mallopt(M_NLBLKS
, 32);
1329 #endif /* HAVE_MALLOPT */
1331 squid_srandom(time(NULL
));
1335 squid_start
= current_time
;
1337 failure_notify
= fatal_dump
;
1339 #if USE_WIN32_SERVICE
1341 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1345 mainParseOptions(argc
, argv
);
1347 if (opt_parse_cfg_only
) {
1348 Debug::parseOptions("ALL,1");
1351 #if USE_WIN32_SERVICE
1353 if (opt_install_service
) {
1354 WIN32_InstallService();
1358 if (opt_remove_service
) {
1359 WIN32_RemoveService();
1363 if (opt_command_line
) {
1364 WIN32_SetServiceCommandLine();
1370 /* parse configuration file
1371 * note: in "normal" case this used to be called from mainInitialize() */
1376 ConfigFile
= xstrdup(DefaultConfigFile
);
1378 assert(!configured_once
);
1382 storeFsInit(); /* required for config parsing */
1384 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
1387 /* May not be needed for parsing, have not audited for such */
1388 DiskIOModule::SetupAllModules();
1390 /* Shouldn't be needed for config parsing, but have not audited for such */
1391 StoreFileSystem::SetupAllFs();
1393 /* we may want the parsing process to set this up in the future */
1394 Store::Root(new StoreController
);
1395 Auth::Init(); /* required for config parsing. NOP if !USE_AUTH */
1396 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
1398 Format::Token::Init(); // XXX: temporary. Use a runners registry of pre-parse runners instead.
1400 parse_err
= parseConfigFile(ConfigFile
);
1404 if (opt_parse_cfg_only
|| parse_err
> 0)
1407 setUmask(Config
.umask
);
1408 if (-1 == opt_send_signal
)
1409 if (checkRunningPid())
1424 /* send signal to running copy and exit */
1425 if (opt_send_signal
!= -1) {
1426 /* chroot if configured to run inside chroot */
1428 if (Config
.chroot_dir
) {
1429 if (chroot(Config
.chroot_dir
))
1430 fatal("failed to chroot");
1441 debugs(1,2, HERE
<< "Doing post-config initialization\n");
1443 ActivateRegistered(rrFinalizeConfig
);
1444 ActivateRegistered(rrClaimMemoryNeeds
);
1445 ActivateRegistered(rrAfterConfig
);
1448 if (!opt_no_daemon
&& Config
.workers
> 0)
1451 if (opt_create_swap_dirs
) {
1452 /* chroot if configured to run inside chroot */
1454 if (Config
.chroot_dir
&& chroot(Config
.chroot_dir
)) {
1455 fatal("failed to chroot");
1459 debugs(0, DBG_CRITICAL
, "Creating Swap Directories");
1460 Store::Root().create();
1465 if (IamPrimaryProcess())
1471 /* init comm module */
1474 if (opt_no_daemon
) {
1475 /* we have to init fdstat here. */
1476 fd_open(0, FD_LOG
, "stdin");
1477 fd_open(1, FD_LOG
, "stdout");
1478 fd_open(2, FD_LOG
, "stderr");
1481 #if USE_WIN32_SERVICE
1483 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1489 #if USE_WIN32_SERVICE
1491 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1498 SignalEngine
signalEngine(mainLoop
);
1500 mainLoop
.registerEngine(&signalEngine
);
1502 /* TODO: stop requiring the singleton here */
1503 mainLoop
.registerEngine(EventScheduler::GetInstance());
1505 StoreRootEngine store_engine
;
1507 mainLoop
.registerEngine(&store_engine
);
1509 CommSelectEngine comm_engine
;
1511 mainLoop
.registerEngine(&comm_engine
);
1513 mainLoop
.setPrimaryEngine(&comm_engine
);
1515 /* use the standard time service */
1516 TimeEngine time_engine
;
1518 mainLoop
.setTimeService(&time_engine
);
1520 if (IamCoordinatorProcess())
1521 AsyncJob::Start(Ipc::Coordinator::Instance());
1522 else if (UsingSmp() && (IamWorkerProcess() || IamDiskProcess()))
1523 AsyncJob::Start(new Ipc::Strand
);
1525 /* at this point we are finished the synchronous startup. */
1530 if (mainLoop
.errcount
== 10)
1531 fatal_dump("Event loop exited with failure.");
1533 /* shutdown squid now */
1546 if (strcmp(Config
.pidFilename
, "none") == 0) {
1547 debugs(0, DBG_IMPORTANT
, "No pid_filename specified. Trusting you know what you are doing.");
1550 pid
= readPidFile();
1553 #if USE_WIN32_SERVICE
1554 if (opt_signal_service
) {
1555 WIN32_sendSignal(opt_send_signal
);
1558 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1559 fprintf(stderr
, "signal to Squid Service:\n");
1560 fprintf(stderr
, "missing -n command line switch.\n");
1566 if (kill(pid
, opt_send_signal
) &&
1567 /* ignore permissions if just running check */
1568 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1569 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1570 fprintf(stderr
, "signal %d to process %d: %s\n",
1571 opt_send_signal
, (int) pid
, xstrerror());
1575 if (opt_send_signal
!= SIGTERM
) {
1576 fprintf(stderr
, "%s: ERROR: No running copy\n", APP_SHORTNAME
);
1579 fprintf(stderr
, "%s: No running copy\n", APP_SHORTNAME
);
1584 /* signal successfully sent */
1588 #if !_SQUID_WINDOWS_
1590 * This function is run when Squid is in daemon mode, just
1591 * before the parent forks and starts up the child process.
1592 * It can be used for admin-specific tasks, such as notifying
1593 * someone that Squid is (re)started.
1596 mainStartScript(const char *prog
)
1598 char script
[MAXPATHLEN
];
1603 xstrncpy(script
, prog
, MAXPATHLEN
);
1605 if ((t
= strrchr(script
, '/'))) {
1607 sl
= strlen(script
);
1610 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1612 if ((cpid
= fork()) == 0) {
1614 execl(script
, squid_start_script
, (char *)NULL
);
1620 rpid
= wait4(cpid
, &status
, 0, NULL
);
1624 rpid
= waitpid(cpid
, &status
, 0);
1627 } while (rpid
!= cpid
);
1631 #endif /* _SQUID_WINDOWS_ */
1634 checkRunningPid(void)
1636 // master process must start alone, but its kids processes may co-exist
1637 if (!IamMasterProcess())
1645 pid
= readPidFile();
1650 if (kill(pid
, 0) < 0)
1653 debugs(0, DBG_CRITICAL
, "Squid is already running! Process ID " << pid
);
1659 watch_child(char *argv
[])
1661 #if !_SQUID_WINDOWS_
1679 if (!IamMasterProcess())
1682 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1684 if ((pid
= fork()) < 0)
1685 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1690 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1696 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1697 ioctl(i
, TIOCNOTTY
, NULL
);
1704 * RBCOLLINS - if cygwin stackdumps when squid is run without
1705 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1706 * 1.1.3. execvp had a bit overflow error in a loop..
1708 /* Connect stdio to /dev/null in daemon mode */
1709 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1712 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1716 if (Debug::log_stderr
< 0) {
1721 // handle shutdown notifications from kids
1722 squid_signal(SIGUSR1
, sig_shutdown
, SA_RESTART
);
1724 if (Config
.workers
> 128) {
1725 syslog(LOG_ALERT
, "Suspiciously high workers value: %d",
1727 // but we keep going in hope that user knows best
1731 syslog(LOG_NOTICE
, "Squid Parent: will start %d kids", (int)TheKids
.count());
1733 // keep [re]starting kids until it is time to quit
1735 mainStartScript(argv
[0]);
1737 // start each kid that needs to be [re]started; once
1738 for (int i
= TheKids
.count() - 1; i
>= 0; --i
) {
1739 Kid
& kid
= TheKids
.get(i
);
1740 if (!kid
.shouldRestart())
1743 if ((pid
= fork()) == 0) {
1745 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1747 argv
[0] = const_cast<char*>(kid
.name().termedBuf());
1749 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1753 syslog(LOG_NOTICE
, "Squid Parent: %s process %d started",
1754 kid
.name().termedBuf(), pid
);
1758 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1760 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1764 pid
= wait3(&status
, 0, NULL
);
1768 pid
= waitpid(-1, &status
, 0);
1771 // Loop to collect all stopped kids before we go to sleep below.
1773 Kid
* kid
= TheKids
.find(pid
);
1776 if (kid
->calledExit()) {
1778 "Squid Parent: %s process %d exited with status %d",
1779 kid
->name().termedBuf(),
1780 kid
->getPid(), kid
->exitStatus());
1781 } else if (kid
->signaled()) {
1783 "Squid Parent: %s process %d exited due to signal %d with status %d",
1784 kid
->name().termedBuf(),
1785 kid
->getPid(), kid
->termSignal(), kid
->exitStatus());
1787 syslog(LOG_NOTICE
, "Squid Parent: %s process %d exited",
1788 kid
->name().termedBuf(), kid
->getPid());
1790 if (kid
->hopeless()) {
1791 syslog(LOG_NOTICE
, "Squid Parent: %s process %d will not"
1792 " be restarted due to repeated, frequent failures",
1793 kid
->name().termedBuf(), kid
->getPid());
1796 syslog(LOG_NOTICE
, "Squid Parent: unknown child process %d exited", pid
);
1799 } while ((pid
= wait3(&status
, WNOHANG
, NULL
)) > 0);
1802 while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0);
1805 if (!TheKids
.someRunning() && !TheKids
.shouldRestartSome()) {
1807 DeactivateRegistered(rrAfterConfig
);
1808 DeactivateRegistered(rrClaimMemoryNeeds
);
1809 DeactivateRegistered(rrFinalizeConfig
);
1812 if (TheKids
.someSignaled(SIGINT
) || TheKids
.someSignaled(SIGTERM
)) {
1813 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1817 if (TheKids
.allHopeless()) {
1818 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1825 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1830 #endif /* _SQUID_WINDOWS_ */
1837 /* XXX: This function is called after the main loop has quit, which
1838 * means that no AsyncCalls would be called, including close handlers.
1839 * TODO: We need to close/shut/free everything that needs calls before
1843 #if USE_WIN32_SERVICE
1844 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1847 debugs(1, DBG_IMPORTANT
, "Shutting down...");
1850 Ssl::Helper::GetInstance()->Shutdown();
1853 if (Ssl::CertValidationHelper::GetInstance())
1854 Ssl::CertValidationHelper::GetInstance()->Shutdown();
1857 externalAclShutdown();
1867 wccpConnectionClose();
1871 wccp2ConnectionClose();
1874 releaseServerSockets();
1875 commCloseAllSockets();
1882 DelayPools::FreePools();
1885 authenticateReset();
1887 #if USE_WIN32_SERVICE
1889 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1892 Store::Root().sync(); /* Flush pending object writes/unlinks */
1894 unlinkdClose(); /* after sync/flush. NOP if !USE_UNLINKD */
1896 storeDirWriteCleanLogs(0);
1899 Store::Root().sync(); /* Flush log writes */
1902 Store::Root().sync(); /* Flush log close */
1903 StoreFileSystem::FreeAllFs();
1904 DiskIOModule::FreeAllModules();
1905 DeactivateRegistered(rrAfterConfig
);
1906 DeactivateRegistered(rrClaimMemoryNeeds
);
1907 DeactivateRegistered(rrFinalizeConfig
);
1908 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1912 /*stmemFreeMemory(); */
1914 ipcacheFreeMemory();
1915 fqdncacheFreeMemory();
1917 clientdbFreeMemory();
1918 httpHeaderCleanModule();
1926 if (opt_no_daemon
) {
1933 // clear StoreController
1944 xmalloc_find_leaks();
1946 debugs(1, DBG_CRITICAL
, "Memory used after shutdown: " << xmalloc_total
);
1955 if (IamPrimaryProcess()) {
1956 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1958 safeunlink(Config
.pidFilename
, 0);
1963 debugs(1, DBG_IMPORTANT
, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1967 * We used to fclose(debug_log) here if it was set, but then
1968 * we forgot to set it to NULL. That caused some coredumps
1969 * because exit() ends up calling a bunch of destructors and
1970 * such. So rather than forcing the debug_log to close, we'll
1971 * leave it open so that those destructors can write some
1972 * debugging if necessary. The file will be closed anyway when
1973 * the process truly exits.
1976 exit(shutdown_status
);