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"
77 #include "peer_sourcehash.h"
78 #include "peer_userhash.h"
79 #include "PeerSelectState.h"
80 #include "profiler/Profiler.h"
83 #include "send-announce.h"
84 #include "SquidConfig.h"
86 #include "SquidTime.h"
88 #include "StatCounters.h"
90 #include "store_log.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/certificate_db.h"
126 #include "ssl/context_storage.h"
127 #include "ssl/helper.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_command_line
= FALSE
;
161 void WIN32_svcstatusupdate(DWORD
, DWORD
);
162 void WINAPI
WIN32_svcHandler(DWORD
);
165 static int opt_signal_service
= FALSE
;
166 static char *opt_syslog_facility
= NULL
;
167 static int icpPortNumOverride
= 1; /* Want to detect "-u 0" */
168 static int configured_once
= 0;
170 static int malloc_debug_level
= 0;
172 static volatile int do_reconfigure
= 0;
173 static volatile int do_rotate
= 0;
174 static volatile int do_shutdown
= 0;
175 static volatile int shutdown_status
= 0;
177 static int RotateSignal
= -1;
178 static int ReconfigureSignal
= -1;
179 static int ShutdownSignal
= -1;
181 static void mainRotate(void);
182 static void mainReconfigureStart(void);
183 static void mainReconfigureFinish(void*);
184 static void mainInitialize(void);
185 static void usage(void);
186 static void mainParseOptions(int argc
, char *argv
[]);
187 static void sendSignal(void);
188 static void serverConnectionsOpen(void);
189 static void serverConnectionsClose(void);
190 static void watch_child(char **);
191 static void setEffectiveUser(void);
192 static void SquidShutdown(void);
193 static void mainSetCwd(void);
194 static int checkRunningPid(void);
197 static const char *squid_start_script
= "squid_start";
201 #include "test_access.c"
204 /** temporary thunk across to the unrefactored store interface */
206 class StoreRootEngine
: public AsyncEngine
210 int checkEvents(int timeout
) {
211 Store::Root().callback();
216 class SignalEngine
: public AsyncEngine
220 virtual int checkEvents(int timeout
);
223 static void StopEventLoop(void *) {
224 if (EventLoop::Running
)
225 EventLoop::Running
->stop();
228 void doShutdown(time_t wait
);
232 SignalEngine::checkEvents(int timeout
)
234 PROF_start(SignalEngine_checkEvents
);
236 if (do_reconfigure
) {
237 mainReconfigureStart();
239 } else if (do_rotate
) {
242 } else if (do_shutdown
) {
243 doShutdown(do_shutdown
> 0 ? (int) Config
.shutdownLifetime
: 0);
246 BroadcastSignalIfAny(DebugSignal
);
247 BroadcastSignalIfAny(RotateSignal
);
248 BroadcastSignalIfAny(ReconfigureSignal
);
249 BroadcastSignalIfAny(ShutdownSignal
);
251 PROF_stop(SignalEngine_checkEvents
);
256 SignalEngine::doShutdown(time_t wait
)
258 debugs(1, DBG_IMPORTANT
, "Preparing for shutdown after " << statCounter
.client_http
.requests
<< " requests");
259 debugs(1, DBG_IMPORTANT
, "Waiting " << wait
<< " seconds for active connections to finish");
263 #if USE_WIN32_SERVICE
264 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, (wait
+ 1) * 1000);
267 /* run the closure code which can be shared with reconfigure */
268 serverConnectionsClose();
270 /* detach the auth components (only do this on full shutdown) */
271 Auth::Scheme::FreeAll();
274 RunRegisteredHere(RegisteredRunner::startShutdown
);
275 eventAdd("SquidShutdown", &StopEventLoop
, this, (double) (wait
+ 1), 1, false);
282 "Usage: %s [-cdhvzCFNRVYX] [-n name] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]"
283 #if USE_WIN32_SERVICE
284 "[-ir] [-O CommandLine]"
287 " -a port Specify HTTP port number (default: %d).\n"
288 " -d level Write debugging to stderr also.\n"
289 " -f file Use given config-file instead of\n"
291 " -h Print help message.\n"
292 #if USE_WIN32_SERVICE
293 " -i Installs as a Windows Service (see -n option).\n"
295 " -k reconfigure|rotate|shutdown|"
299 "interrupt|kill|debug|check|parse\n"
300 " Parse configuration file, then send signal to \n"
301 " running copy (except -k parse) and exit.\n"
302 " -n name Specify service name to use for service operations\n"
303 " default is: " APP_SHORTNAME
".\n"
304 #if USE_WIN32_SERVICE
305 " -r Removes a Windows Service (see -n option).\n"
307 " -s | -l facility\n"
308 " Enable logging to syslog.\n"
309 " -u port Specify ICP port number (default: %d), disable with 0.\n"
310 " -v Print version.\n"
311 " -z Create missing swap directories and then exit.\n"
312 " -C Do not catch fatal signals.\n"
313 " -D OBSOLETE. Scheduled for removal.\n"
314 " -F Don't serve any requests until store is rebuilt.\n"
315 " -N No daemon mode.\n"
316 #if USE_WIN32_SERVICE
318 " Set Windows Service Command line options in Registry.\n"
320 " -R Do not set REUSEADDR on port.\n"
321 " -S Double-check swap during rebuild.\n"
322 " -X Force full debugging.\n"
323 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
324 APP_SHORTNAME
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
329 * Parse the parameters received via command line interface.
331 \param argc Number of options received on command line
332 \param argv List of parameters received on command line
335 mainParseOptions(int argc
, char *argv
[])
340 #if USE_WIN32_SERVICE
341 while ((c
= getopt(argc
, argv
, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
343 while ((c
= getopt(argc
, argv
, "CDFNRSYXa:d:f:hk:m::n:sl:u:vz?")) != -1)
351 * Unset/disabel global option for catchign signals. opt_catch_signals */
352 opt_catch_signals
= 0;
357 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
358 debugs(1,DBG_CRITICAL
, "WARNING: -D command-line option is obsolete.");
363 * Set global option for foreground rebuild. opt_foreground_rebuild */
364 opt_foreground_rebuild
= 1;
369 * Set global option for 'no_daemon' mode. opt_no_daemon */
373 #if USE_WIN32_SERVICE
377 * Set global option. opt_command_lin and WIN32_Command_Line */
378 opt_command_line
= 1;
379 WIN32_Command_Line
= xstrdup(optarg
);
385 * Unset/disable global option opt_reuseaddr */
391 * Set global option opt_store_doublecheck */
392 opt_store_doublecheck
= 1;
397 * Force full debugging */
398 Debug::parseOptions("rotate=0 ALL,9");
399 Debug::override_X
= 1;
400 sigusr2_handle(SIGUSR2
);
405 * Set global option opt_reload_hit_only */
406 opt_reload_hit_only
= 1;
409 #if USE_WIN32_SERVICE
413 * Set global option opt_install_service (to TRUE) */
414 opt_install_service
= TRUE
;
420 * Add optional HTTP port as given following the option */
421 add_http_port(optarg
);
426 * Set global option Debug::log_stderr to the number given follwoign the option */
427 Debug::log_stderr
= atoi(optarg
);
432 * Load the file given instead of the default squid.conf. */
434 ConfigFile
= xstrdup(optarg
);
439 * Run the administrative action given following the option */
441 /** \li When its an unknown option display the usage help. */
442 if ((int) strlen(optarg
) < 1)
445 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
446 /** \li On reconfigure send SIGHUP. */
447 opt_send_signal
= SIGHUP
;
448 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
449 /** \li On rotate send SIGQUIT or SIGUSR1. */
450 #if defined(_SQUID_LINUX_THREADS_)
451 opt_send_signal
= SIGQUIT
;
453 opt_send_signal
= SIGUSR1
;
456 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
457 /** \li On debug send SIGTRAP or SIGUSR2. */
458 #if defined(_SQUID_LINUX_THREADS_)
459 opt_send_signal
= SIGTRAP
;
461 opt_send_signal
= SIGUSR2
;
464 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
465 /** \li On shutdown send SIGTERM. */
466 opt_send_signal
= SIGTERM
;
467 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
468 /** \li On interrupt send SIGINT. */
469 opt_send_signal
= SIGINT
;
470 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
471 /** \li On kill send SIGKILL. */
472 opt_send_signal
= SIGKILL
;
476 else if (!strncmp(optarg
, "restart", strlen(optarg
)))
477 /** \li On restart send SIGTTIN. (exit and restart by parent) */
478 opt_send_signal
= SIGTTIN
;
482 else if (!strncmp(optarg
, "check", strlen(optarg
)))
483 /** \li On check send 0 / SIGNULL. */
484 opt_send_signal
= 0; /* SIGNULL */
485 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
486 /** \li On parse set global flag to re-parse the config file only. */
487 opt_parse_cfg_only
= 1;
495 * Set global malloc_debug_level to the value given following the option.
496 * if none is given it toggles the xmalloc_trace option on/off */
499 malloc_debug_level
= atoi(optarg
);
501 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
509 * Set global option opt_signal_service (to true).
510 * Stores the additional parameter given in global service_name */
511 // XXX: verify that the new name has ONLY alphanumeric characters
513 service_name
= xstrdup(optarg
);
514 opt_signal_service
= true;
517 #if USE_WIN32_SERVICE
521 * Set global option opt_remove_service (to TRUE) */
522 opt_remove_service
= TRUE
;
530 * Stores the syslog facility name in global opt_syslog_facility
531 * then performs actions for -s option. */
532 xfree(opt_syslog_facility
); // ignore any previous options sent
533 opt_syslog_facility
= xstrdup(optarg
);
537 * Initialize the syslog for output */
540 _db_set_syslog(opt_syslog_facility
);
546 fatal("Logging to syslog not available on this platform");
553 * Store the ICP port number given in global option icpPortNumOverride
554 * ensuring its a positive number. */
555 icpPortNumOverride
= atoi(optarg
);
557 if (icpPortNumOverride
< 0)
558 icpPortNumOverride
= 0;
564 * Display squid version and build information. Then exit. */
565 printf("Squid Cache: Version %s\n" ,version_string
);
566 printf("Service Name: %s\n", service_name
);
567 if (strlen(SQUID_BUILD_INFO
))
568 printf("%s\n",SQUID_BUILD_INFO
);
569 printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS
);
571 #if USE_WIN32_SERVICE
573 printf("Compiled as Windows System Service.\n");
583 * Set global option Debug::log_stderr and opt_create_swap_dirs */
584 Debug::log_stderr
= 1;
585 opt_create_swap_dirs
= 1;
593 /** \par h,?, or unknown
594 * \copydoc usage() */
612 signal(sig
, rotate_logs
);
622 ReconfigureSignal
= sig
;
626 signal(sig
, reconfigure
);
634 do_shutdown
= sig
== SIGINT
? -1 : 1;
635 ShutdownSignal
= sig
;
643 const pid_t ppid
= getppid();
645 if (!IamMasterProcess() && ppid
> 1) {
646 // notify master that we are shutting down
647 if (kill(ppid
, SIGUSR1
) < 0)
648 debugs(1, DBG_IMPORTANT
, "Failed to send SIGUSR1 to master process,"
649 " pid " << ppid
<< ": " << xstrerror());
655 if (!IamMasterProcess() && ppid
> 1) {
656 debugs(1, DBG_IMPORTANT
, "Killing master process, pid " << ppid
);
658 if (kill(ppid
, sig
) < 0)
659 debugs(1, DBG_IMPORTANT
, "kill " << ppid
<< ": " << xstrerror());
662 #endif /* KILL_PARENT_OPT */
663 #if SA_RESETHAND == 0
664 signal(SIGTERM
, SIG_DFL
);
666 signal(SIGINT
, SIG_DFL
);
673 serverConnectionsOpen(void)
675 if (IamPrimaryProcess()) {
677 wccpConnectionOpen();
682 wccp2ConnectionOpen();
685 // start various proxying services if we are responsible for them
686 if (IamWorkerProcess()) {
687 clientOpenListenSockets();
706 peerSourceHashInit();
711 serverConnectionsClose(void)
713 assert(shutting_down
|| reconfiguring
);
715 if (IamPrimaryProcess()) {
718 wccpConnectionClose();
722 wccp2ConnectionClose();
725 if (IamWorkerProcess()) {
726 clientHttpConnectionsClose();
727 icpConnectionShutdown();
729 htcpSocketShutdown();
742 mainReconfigureStart(void)
744 debugs(1, DBG_IMPORTANT
, "Reconfiguring Squid Cache (version " << version_string
<< ")...");
747 // Initiate asynchronous closing sequence
748 serverConnectionsClose();
755 Ssl::Helper::GetInstance()->Shutdown();
758 if (Ssl::CertValidationHelper::GetInstance())
759 Ssl::CertValidationHelper::GetInstance()->Shutdown();
760 Ssl::TheGlobalContextStorage
.reconfigureStart();
766 externalAclShutdown();
767 storeDirCloseSwapLogs();
774 eventAdd("mainReconfigureFinish", &mainReconfigureFinish
, NULL
, 0, 1,
779 mainReconfigureFinish(void *)
781 debugs(1, 3, "finishing reconfiguring");
784 enter_suid(); /* root to read config file */
786 // we may have disabled the need for PURGE
787 if (Config2
.onoff
.enable_purge
)
788 Config2
.onoff
.enable_purge
= 2;
790 // parse the config returns a count of errors encountered.
791 const int oldWorkers
= Config
.workers
;
792 if ( parseConfigFile(ConfigFile
) != 0) {
793 // for now any errors are a fatal condition...
796 if (oldWorkers
!= Config
.workers
) {
797 debugs(1, DBG_CRITICAL
, "WARNING: Changing 'workers' (from " <<
798 oldWorkers
<< " to " << Config
.workers
<<
799 ") requires a full restart. It has been ignored by reconfigure.");
800 Config
.workers
= oldWorkers
;
803 RunRegisteredHere(RegisteredRunner::syncConfig
);
805 if (IamPrimaryProcess())
807 CpuAffinityReconfigure();
809 setUmask(Config
.umask
);
812 _db_init(Debug::cache_log
, Debug::debugOptions
);
813 ipcache_restart(); /* clear stuck entries */
814 fqdncache_restart(); /* sigh, fqdncache too */
816 errorInitialize(); /* reload error pages */
819 #if USE_LOADABLE_MODULES
820 LoadableModulesConfigure(Config
.loadable_module_names
);
824 bool enableAdaptation
= false;
826 Adaptation::Icap::TheConfig
.finalize();
827 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
830 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
831 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
833 Adaptation::Config::Finalize(enableAdaptation
);
842 Ssl::Helper::GetInstance()->Init();
845 if (Ssl::CertValidationHelper::GetInstance())
846 Ssl::CertValidationHelper::GetInstance()->Init();
851 authenticateInit(&Auth::TheConfig
);
855 if (IamPrimaryProcess()) {
866 serverConnectionsOpen();
870 storeDirOpenSwapLogs();
872 mimeInit(Config
.mimeTablePathname
);
878 Config
.ClientDelay
.finalize();
881 if (Config
.onoff
.announce
) {
882 if (!eventFind(start_announce
, NULL
))
883 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
885 if (eventFind(start_announce
, NULL
))
886 eventDelete(start_announce
, NULL
);
889 writePidFile(); /* write PID file */
900 authenticateRotate();
902 externalAclShutdown();
904 _db_rotate_log(); /* cache.log */
905 storeDirWriteCleanLogs(1);
906 storeLogRotate(); /* store.log */
907 accessLogRotate(); /* access.log */
909 icapLogRotate(); /*icap.log*/
914 authenticateInit(&Auth::TheConfig
);
920 setEffectiveUser(void)
923 leave_suid(); /* Run as non privilegied user */
929 if (geteuid() == 0) {
930 debugs(0, DBG_CRITICAL
, "Squid is not safe to run as root! If you must");
931 debugs(0, DBG_CRITICAL
, "start Squid as root, then you must configure");
932 debugs(0, DBG_CRITICAL
, "it to run as a non-priveledged user with the");
933 debugs(0, DBG_CRITICAL
, "'cache_effective_user' option in the config file.");
934 fatal("Don't run Squid as root, set 'cache_effective_user'!");
938 /// changes working directory, providing error reporting
940 mainChangeDir(const char *dir
)
945 debugs(50, DBG_CRITICAL
, "cannot change current directory to " << dir
<<
946 ": " << xstrerror());
950 /// set the working directory.
954 static bool chrooted
= false;
955 if (Config
.chroot_dir
&& !chrooted
) {
958 if (chroot(Config
.chroot_dir
) != 0)
959 fatalf("chroot to %s failed: %s", Config
.chroot_dir
, xstrerror());
961 if (!mainChangeDir("/"))
962 fatalf("chdir to / after chroot to %s failed", Config
.chroot_dir
);
965 if (Config
.coredump_dir
&& strcmp("none", Config
.coredump_dir
) != 0) {
966 if (mainChangeDir(Config
.coredump_dir
)) {
967 debugs(0, DBG_IMPORTANT
, "Set Current Directory to " << Config
.coredump_dir
);
972 /* If we don't have coredump_dir or couldn't cd there, report current dir */
973 char pathbuf
[MAXPATHLEN
];
974 if (getcwd(pathbuf
, MAXPATHLEN
)) {
975 debugs(0, DBG_IMPORTANT
, "Current Directory is " << pathbuf
);
977 debugs(50, DBG_CRITICAL
, "WARNING: Can't find current directory, getcwd: " << xstrerror());
984 /* chroot if configured to run inside chroot */
987 if (opt_catch_signals
) {
988 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
989 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
992 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
993 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
997 if (icpPortNumOverride
!= 1)
998 Config
.Port
.icp
= (unsigned short) icpPortNumOverride
;
1000 _db_init(Debug::cache_log
, Debug::debugOptions
);
1002 fd_open(fileno(debug_log
), FD_LOG
, Debug::cache_log
);
1004 debugs(1, DBG_CRITICAL
, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
1005 debugs(1, DBG_CRITICAL
, "Service Name: " << service_name
);
1008 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
1009 debugs(1, DBG_CRITICAL
, "Service command line is: " << WIN32_Service_Command_Line
);
1011 debugs(1, DBG_CRITICAL
, "Running on " << WIN32_OS_string
);
1014 debugs(1, DBG_IMPORTANT
, "Process ID " << getpid());
1016 debugs(1, DBG_IMPORTANT
, "Process Roles:" << ProcessRoles());
1019 debugs(1, DBG_IMPORTANT
, "With " << Squid_MaxFD
<< " file descriptors available");
1023 debugs(1, DBG_IMPORTANT
, "With " << _getmaxstdio() << " CRT stdio descriptors available");
1025 if (WIN32_Socks_initialized
)
1026 debugs(1, DBG_IMPORTANT
, "Windows sockets initialized");
1028 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
1029 WIN32_IpAddrChangeMonitorInit();
1034 if (!configured_once
)
1035 disk_init(); /* disk_init must go before ipcache_init() */
1046 Ssl::Helper::GetInstance()->Init();
1050 if (!configured_once
)
1051 Ssl::initialize_session_cache();
1053 if (Ssl::CertValidationHelper::GetInstance())
1054 Ssl::CertValidationHelper::GetInstance()->Init();
1059 authenticateInit(&Auth::TheConfig
);
1063 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
1065 httpReplyInitModule(); /* must go before accepting replies */
1086 malloc_debug(0, malloc_debug_level
);
1090 if (!configured_once
) {
1091 if (unlinkdNeeded())
1098 mimeInit(Config
.mimeTablePathname
);
1104 FwdState::initModule();
1105 /* register the modules in the cache manager menus */
1107 cbdataRegisterWithCacheManager();
1108 /* These use separate calls so that the comm loops can eventually
1114 // TODO: pconn is a good candidate for new-style registration
1115 // PconnModule::GetInstance()->registerWithCacheManager();
1116 // moved to PconnModule::PconnModule()
1119 if (IamPrimaryProcess()) {
1131 serverConnectionsOpen();
1135 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1137 if (Config
.chroot_dir
)
1140 if (!configured_once
)
1141 writePidFile(); /* write PID file */
1143 #if defined(_SQUID_LINUX_THREADS_)
1145 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1147 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1151 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1153 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1157 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1159 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1161 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1165 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1171 #if USE_LOADABLE_MODULES
1172 LoadableModulesConfigure(Config
.loadable_module_names
);
1176 bool enableAdaptation
= false;
1178 // We can remove this dependency on specific adaptation mechanisms
1179 // if we create a generic Registry of such mechanisms. Should we?
1181 Adaptation::Icap::TheConfig
.finalize();
1182 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
1185 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
1186 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
1188 // must be the last adaptation-related finalize
1189 Adaptation::Config::Finalize(enableAdaptation
);
1197 Config
.ClientDelay
.finalize();
1200 if (!configured_once
) {
1201 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1203 if (Config
.onoff
.announce
)
1204 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1206 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1208 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1212 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1216 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1219 configured_once
= 1;
1222 /// unsafe main routine -- may throw
1223 int SquidMain(int argc
, char **argv
);
1224 /// unsafe main routine wrapper to catch exceptions
1225 static int SquidMainSafe(int argc
, char **argv
);
1227 #if USE_WIN32_SERVICE
1228 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1229 extern "C" void WINAPI
1230 SquidWinSvcMain(int argc
, char **argv
)
1232 SquidMainSafe(argc
, argv
);
1236 main(int argc
, char **argv
)
1238 return SquidMainSafe(argc
, argv
);
1243 SquidMainSafe(int argc
, char **argv
)
1246 return SquidMain(argc
, argv
);
1247 } catch (const std::exception
&e
) {
1248 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception: " <<
1252 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception.");
1255 return -1; // not reached
1258 /// computes name and ID for the current kid process
1260 ConfigureCurrentKid(const char *processName
)
1262 // kids are marked with parenthesis around their process names
1263 if (processName
&& processName
[0] == '(') {
1264 if (const char *idStart
= strrchr(processName
, '-')) {
1265 KidIdentifier
= atoi(idStart
+ 1);
1266 const size_t nameLen
= idStart
- (processName
+ 1);
1267 assert(nameLen
< sizeof(TheKidName
));
1268 xstrncpy(TheKidName
, processName
+ 1, nameLen
+ 1);
1269 if (!strcmp(TheKidName
, "squid-coord"))
1270 TheProcessKind
= pkCoordinator
;
1271 else if (!strcmp(TheKidName
, "squid"))
1272 TheProcessKind
= pkWorker
;
1273 else if (!strcmp(TheKidName
, "squid-disk"))
1274 TheProcessKind
= pkDisker
;
1276 TheProcessKind
= pkOther
; // including coordinator
1279 xstrncpy(TheKidName
, APP_SHORTNAME
, sizeof(TheKidName
));
1285 SquidMain(int argc
, char **argv
)
1287 ConfigureCurrentKid(argv
[0]);
1289 Debug::parseOptions(NULL
);
1292 #if defined(SQUID_MAXFD_LIMIT)
1294 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1295 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1299 /* NOP under non-windows */
1300 int WIN32_init_err
=0;
1301 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1302 return WIN32_init_err
;
1304 /* call mallopt() before anything else */
1307 /* Round up all sizes to a multiple of this */
1308 mallopt(M_GRAIN
, 16);
1312 /* biggest size that is considered a small block */
1313 mallopt(M_MXFAST
, 256);
1317 /* allocate this many small blocks at once */
1318 mallopt(M_NLBLKS
, 32);
1321 #endif /* HAVE_MALLOPT */
1323 squid_srandom(time(NULL
));
1327 squid_start
= current_time
;
1329 failure_notify
= fatal_dump
;
1331 #if USE_WIN32_SERVICE
1333 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1337 mainParseOptions(argc
, argv
);
1339 if (opt_parse_cfg_only
) {
1340 Debug::parseOptions("ALL,1");
1343 #if USE_WIN32_SERVICE
1345 if (opt_install_service
) {
1346 WIN32_InstallService();
1350 if (opt_remove_service
) {
1351 WIN32_RemoveService();
1355 if (opt_command_line
) {
1356 WIN32_SetServiceCommandLine();
1362 /* parse configuration file
1363 * note: in "normal" case this used to be called from mainInitialize() */
1368 ConfigFile
= xstrdup(DefaultConfigFile
);
1370 assert(!configured_once
);
1374 storeFsInit(); /* required for config parsing */
1376 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
1379 /* May not be needed for parsing, have not audited for such */
1380 DiskIOModule::SetupAllModules();
1382 /* Shouldn't be needed for config parsing, but have not audited for such */
1383 StoreFileSystem::SetupAllFs();
1385 /* we may want the parsing process to set this up in the future */
1386 Store::Root(new StoreController
);
1387 Auth::Init(); /* required for config parsing. NOP if !USE_AUTH */
1388 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
1390 Format::Token::Init(); // XXX: temporary. Use a runners registry of pre-parse runners instead.
1392 parse_err
= parseConfigFile(ConfigFile
);
1396 if (opt_parse_cfg_only
|| parse_err
> 0)
1399 setUmask(Config
.umask
);
1400 if (-1 == opt_send_signal
)
1401 if (checkRunningPid())
1416 /* send signal to running copy and exit */
1417 if (opt_send_signal
!= -1) {
1418 /* chroot if configured to run inside chroot */
1420 if (Config
.chroot_dir
) {
1430 debugs(1,2, HERE
<< "Doing post-config initialization\n");
1432 RunRegisteredHere(RegisteredRunner::finalizeConfig
);
1433 RunRegisteredHere(RegisteredRunner::claimMemoryNeeds
);
1434 RunRegisteredHere(RegisteredRunner::useConfig
);
1437 if (!opt_no_daemon
&& Config
.workers
> 0)
1440 if (opt_create_swap_dirs
) {
1441 /* chroot if configured to run inside chroot */
1445 debugs(0, DBG_CRITICAL
, "Creating missing swap directories");
1446 Store::Root().create();
1451 if (IamPrimaryProcess())
1457 /* init comm module */
1460 if (opt_no_daemon
) {
1461 /* we have to init fdstat here. */
1462 fd_open(0, FD_LOG
, "stdin");
1463 fd_open(1, FD_LOG
, "stdout");
1464 fd_open(2, FD_LOG
, "stderr");
1467 #if USE_WIN32_SERVICE
1469 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1475 #if USE_WIN32_SERVICE
1477 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1484 SignalEngine signalEngine
;
1486 mainLoop
.registerEngine(&signalEngine
);
1488 /* TODO: stop requiring the singleton here */
1489 mainLoop
.registerEngine(EventScheduler::GetInstance());
1491 StoreRootEngine store_engine
;
1493 mainLoop
.registerEngine(&store_engine
);
1495 CommSelectEngine comm_engine
;
1497 mainLoop
.registerEngine(&comm_engine
);
1499 mainLoop
.setPrimaryEngine(&comm_engine
);
1501 /* use the standard time service */
1502 TimeEngine time_engine
;
1504 mainLoop
.setTimeService(&time_engine
);
1506 if (IamCoordinatorProcess())
1507 AsyncJob::Start(Ipc::Coordinator::Instance());
1508 else if (UsingSmp() && (IamWorkerProcess() || IamDiskProcess()))
1509 AsyncJob::Start(new Ipc::Strand
);
1511 /* at this point we are finished the synchronous startup. */
1516 if (mainLoop
.errcount
== 10)
1517 fatal_dump("Event loop exited with failure.");
1519 /* shutdown squid now */
1532 if (strcmp(Config
.pidFilename
, "none") == 0) {
1533 debugs(0, DBG_IMPORTANT
, "No pid_filename specified. Trusting you know what you are doing.");
1536 pid
= readPidFile();
1539 #if USE_WIN32_SERVICE
1540 if (opt_signal_service
) {
1541 WIN32_sendSignal(opt_send_signal
);
1544 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1545 fprintf(stderr
, "signal to Squid Service:\n");
1546 fprintf(stderr
, "missing -n command line switch.\n");
1552 if (kill(pid
, opt_send_signal
) &&
1553 /* ignore permissions if just running check */
1554 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1555 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1556 fprintf(stderr
, "signal %d to process %d: %s\n",
1557 opt_send_signal
, (int) pid
, xstrerror());
1561 if (opt_send_signal
!= SIGTERM
) {
1562 fprintf(stderr
, "%s: ERROR: No running copy\n", APP_SHORTNAME
);
1565 fprintf(stderr
, "%s: No running copy\n", APP_SHORTNAME
);
1570 /* signal successfully sent */
1574 #if !_SQUID_WINDOWS_
1576 * This function is run when Squid is in daemon mode, just
1577 * before the parent forks and starts up the child process.
1578 * It can be used for admin-specific tasks, such as notifying
1579 * someone that Squid is (re)started.
1582 mainStartScript(const char *prog
)
1584 char script
[MAXPATHLEN
];
1589 xstrncpy(script
, prog
, MAXPATHLEN
);
1591 if ((t
= strrchr(script
, '/'))) {
1593 sl
= strlen(script
);
1596 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1598 if ((cpid
= fork()) == 0) {
1600 execl(script
, squid_start_script
, (char *)NULL
);
1606 rpid
= wait4(cpid
, &status
, 0, NULL
);
1610 rpid
= waitpid(cpid
, &status
, 0);
1613 } while (rpid
!= cpid
);
1617 #endif /* _SQUID_WINDOWS_ */
1620 checkRunningPid(void)
1622 // master process must start alone, but its kids processes may co-exist
1623 if (!IamMasterProcess())
1631 pid
= readPidFile();
1636 if (kill(pid
, 0) < 0)
1639 debugs(0, DBG_CRITICAL
, "Squid is already running! Process ID " << pid
);
1645 watch_child(char *argv
[])
1647 #if !_SQUID_WINDOWS_
1665 if (!IamMasterProcess())
1668 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1670 if ((pid
= fork()) < 0)
1671 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1676 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1682 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1683 ioctl(i
, TIOCNOTTY
, NULL
);
1690 * RBCOLLINS - if cygwin stackdumps when squid is run without
1691 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1692 * 1.1.3. execvp had a bit overflow error in a loop..
1694 /* Connect stdio to /dev/null in daemon mode */
1695 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1698 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1702 if (Debug::log_stderr
< 0) {
1707 // handle shutdown notifications from kids
1708 squid_signal(SIGUSR1
, sig_shutdown
, SA_RESTART
);
1710 if (Config
.workers
> 128) {
1711 syslog(LOG_ALERT
, "Suspiciously high workers value: %d",
1713 // but we keep going in hope that user knows best
1717 syslog(LOG_NOTICE
, "Squid Parent: will start %d kids", (int)TheKids
.count());
1719 // keep [re]starting kids until it is time to quit
1721 mainStartScript(argv
[0]);
1723 // start each kid that needs to be [re]started; once
1724 for (int i
= TheKids
.count() - 1; i
>= 0; --i
) {
1725 Kid
& kid
= TheKids
.get(i
);
1726 if (!kid
.shouldRestart())
1729 if ((pid
= fork()) == 0) {
1731 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1733 argv
[0] = const_cast<char*>(kid
.name().termedBuf());
1735 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1739 syslog(LOG_NOTICE
, "Squid Parent: %s process %d started",
1740 kid
.name().termedBuf(), pid
);
1744 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1746 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1750 pid
= wait3(&status
, 0, NULL
);
1754 pid
= waitpid(-1, &status
, 0);
1757 // Loop to collect all stopped kids before we go to sleep below.
1759 Kid
* kid
= TheKids
.find(pid
);
1762 if (kid
->calledExit()) {
1764 "Squid Parent: %s process %d exited with status %d",
1765 kid
->name().termedBuf(),
1766 kid
->getPid(), kid
->exitStatus());
1767 } else if (kid
->signaled()) {
1769 "Squid Parent: %s process %d exited due to signal %d with status %d",
1770 kid
->name().termedBuf(),
1771 kid
->getPid(), kid
->termSignal(), kid
->exitStatus());
1773 syslog(LOG_NOTICE
, "Squid Parent: %s process %d exited",
1774 kid
->name().termedBuf(), kid
->getPid());
1776 if (kid
->hopeless()) {
1777 syslog(LOG_NOTICE
, "Squid Parent: %s process %d will not"
1778 " be restarted due to repeated, frequent failures",
1779 kid
->name().termedBuf(), kid
->getPid());
1782 syslog(LOG_NOTICE
, "Squid Parent: unknown child process %d exited", pid
);
1785 } while ((pid
= wait3(&status
, WNOHANG
, NULL
)) > 0);
1788 while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0);
1791 if (!TheKids
.someRunning() && !TheKids
.shouldRestartSome()) {
1793 // XXX: Master process has no main loop and, hence, should not call
1794 // RegisteredRunner::startShutdown which promises a loop iteration.
1795 RunRegisteredHere(RegisteredRunner::finishShutdown
);
1798 if (TheKids
.someSignaled(SIGINT
) || TheKids
.someSignaled(SIGTERM
)) {
1799 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1803 if (TheKids
.allHopeless()) {
1804 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1811 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1816 #endif /* _SQUID_WINDOWS_ */
1823 /* XXX: This function is called after the main loop has quit, which
1824 * means that no AsyncCalls would be called, including close handlers.
1825 * TODO: We need to close/shut/free everything that needs calls before
1829 #if USE_WIN32_SERVICE
1830 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1833 debugs(1, DBG_IMPORTANT
, "Shutting down...");
1836 Ssl::Helper::GetInstance()->Shutdown();
1839 if (Ssl::CertValidationHelper::GetInstance())
1840 Ssl::CertValidationHelper::GetInstance()->Shutdown();
1843 externalAclShutdown();
1853 wccpConnectionClose();
1857 wccp2ConnectionClose();
1860 releaseServerSockets();
1861 commCloseAllSockets();
1868 DelayPools::FreePools();
1871 authenticateReset();
1873 #if USE_WIN32_SERVICE
1875 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1878 Store::Root().sync(); /* Flush pending object writes/unlinks */
1880 unlinkdClose(); /* after sync/flush. NOP if !USE_UNLINKD */
1882 storeDirWriteCleanLogs(0);
1885 Store::Root().sync(); /* Flush log writes */
1888 Store::Root().sync(); /* Flush log close */
1889 StoreFileSystem::FreeAllFs();
1890 DiskIOModule::FreeAllModules();
1891 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1895 /*stmemFreeMemory(); */
1897 ipcacheFreeMemory();
1898 fqdncacheFreeMemory();
1900 clientdbFreeMemory();
1901 httpHeaderCleanModule();
1907 // clear StoreController
1914 RunRegisteredHere(RegisteredRunner::finishShutdown
);
1918 if (IamPrimaryProcess()) {
1919 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1921 safeunlink(Config
.pidFilename
, 0);
1926 debugs(1, DBG_IMPORTANT
, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1930 * We used to fclose(debug_log) here if it was set, but then
1931 * we forgot to set it to NULL. That caused some coredumps
1932 * because exit() ends up calling a bunch of destructors and
1933 * such. So rather than forcing the debug_log to close, we'll
1934 * leave it open so that those destructors can write some
1935 * debugging if necessary. The file will be closed anyway when
1936 * the process truly exits.
1939 exit(shutdown_status
);