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"
150 #include <sys/wait.h>
153 #if USE_WIN32_SERVICE
156 static int opt_install_service
= FALSE
;
157 static int opt_remove_service
= FALSE
;
158 static int opt_command_line
= FALSE
;
159 void WIN32_svcstatusupdate(DWORD
, DWORD
);
160 void WINAPI
WIN32_svcHandler(DWORD
);
163 static int opt_signal_service
= FALSE
;
164 static char *opt_syslog_facility
= NULL
;
165 static int icpPortNumOverride
= 1; /* Want to detect "-u 0" */
166 static int configured_once
= 0;
168 static int malloc_debug_level
= 0;
170 static volatile int do_reconfigure
= 0;
171 static volatile int do_rotate
= 0;
172 static volatile int do_shutdown
= 0;
173 static volatile int shutdown_status
= 0;
175 static int RotateSignal
= -1;
176 static int ReconfigureSignal
= -1;
177 static int ShutdownSignal
= -1;
179 static void mainRotate(void);
180 static void mainReconfigureStart(void);
181 static void mainReconfigureFinish(void*);
182 static void mainInitialize(void);
183 static void usage(void);
184 static void mainParseOptions(int argc
, char *argv
[]);
185 static void sendSignal(void);
186 static void serverConnectionsOpen(void);
187 static void serverConnectionsClose(void);
188 static void watch_child(char **);
189 static void setEffectiveUser(void);
190 static void SquidShutdown(void);
191 static void mainSetCwd(void);
192 static int checkRunningPid(void);
195 static const char *squid_start_script
= "squid_start";
199 #include "test_access.c"
202 /** temporary thunk across to the unrefactored store interface */
204 class StoreRootEngine
: public AsyncEngine
208 int checkEvents(int timeout
) {
209 Store::Root().callback();
214 class SignalEngine
: public AsyncEngine
218 virtual int checkEvents(int timeout
);
221 static void StopEventLoop(void *) {
222 if (EventLoop::Running
)
223 EventLoop::Running
->stop();
226 void doShutdown(time_t wait
);
230 SignalEngine::checkEvents(int timeout
)
232 PROF_start(SignalEngine_checkEvents
);
234 if (do_reconfigure
) {
235 mainReconfigureStart();
237 } else if (do_rotate
) {
240 } else if (do_shutdown
) {
241 doShutdown(do_shutdown
> 0 ? (int) Config
.shutdownLifetime
: 0);
244 BroadcastSignalIfAny(DebugSignal
);
245 BroadcastSignalIfAny(RotateSignal
);
246 BroadcastSignalIfAny(ReconfigureSignal
);
247 BroadcastSignalIfAny(ShutdownSignal
);
249 PROF_stop(SignalEngine_checkEvents
);
254 SignalEngine::doShutdown(time_t wait
)
256 debugs(1, DBG_IMPORTANT
, "Preparing for shutdown after " << statCounter
.client_http
.requests
<< " requests");
257 debugs(1, DBG_IMPORTANT
, "Waiting " << wait
<< " seconds for active connections to finish");
261 #if USE_WIN32_SERVICE
262 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, (wait
+ 1) * 1000);
265 /* run the closure code which can be shared with reconfigure */
266 serverConnectionsClose();
268 /* detach the auth components (only do this on full shutdown) */
269 Auth::Scheme::FreeAll();
272 RunRegisteredHere(RegisteredRunner::startShutdown
);
273 eventAdd("SquidShutdown", &StopEventLoop
, this, (double) (wait
+ 1), 1, false);
280 "Usage: %s [-cdhvzCFNRVYX] [-n name] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]"
281 #if USE_WIN32_SERVICE
282 "[-ir] [-O CommandLine]"
285 " -a port Specify HTTP port number (default: %d).\n"
286 " -d level Write debugging to stderr also.\n"
287 " -f file Use given config-file instead of\n"
289 " -h Print help message.\n"
290 #if USE_WIN32_SERVICE
291 " -i Installs as a Windows Service (see -n option).\n"
293 " -k reconfigure|rotate|shutdown|"
297 "interrupt|kill|debug|check|parse\n"
298 " Parse configuration file, then send signal to \n"
299 " running copy (except -k parse) and exit.\n"
300 " -n name Specify service name to use for service operations\n"
301 " default is: " APP_SHORTNAME
".\n"
302 #if USE_WIN32_SERVICE
303 " -r Removes a Windows Service (see -n option).\n"
305 " -s | -l facility\n"
306 " Enable logging to syslog.\n"
307 " -u port Specify ICP port number (default: %d), disable with 0.\n"
308 " -v Print version.\n"
309 " -z Create missing swap directories and then exit.\n"
310 " -C Do not catch fatal signals.\n"
311 " -D OBSOLETE. Scheduled for removal.\n"
312 " -F Don't serve any requests until store is rebuilt.\n"
313 " -N No daemon mode.\n"
314 #if USE_WIN32_SERVICE
316 " Set Windows Service Command line options in Registry.\n"
318 " -R Do not set REUSEADDR on port.\n"
319 " -S Double-check swap during rebuild.\n"
320 " -X Force full debugging.\n"
321 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
322 APP_SHORTNAME
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
327 * Parse the parameters received via command line interface.
329 \param argc Number of options received on command line
330 \param argv List of parameters received on command line
333 mainParseOptions(int argc
, char *argv
[])
338 #if USE_WIN32_SERVICE
339 while ((c
= getopt(argc
, argv
, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
341 while ((c
= getopt(argc
, argv
, "CDFNRSYXa:d:f:hk:m::n:sl:u:vz?")) != -1)
349 * Unset/disabel global option for catchign signals. opt_catch_signals */
350 opt_catch_signals
= 0;
355 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
356 debugs(1,DBG_CRITICAL
, "WARNING: -D command-line option is obsolete.");
361 * Set global option for foreground rebuild. opt_foreground_rebuild */
362 opt_foreground_rebuild
= 1;
367 * Set global option for 'no_daemon' mode. opt_no_daemon */
371 #if USE_WIN32_SERVICE
375 * Set global option. opt_command_lin and WIN32_Command_Line */
376 opt_command_line
= 1;
377 WIN32_Command_Line
= xstrdup(optarg
);
383 * Unset/disable global option opt_reuseaddr */
389 * Set global option opt_store_doublecheck */
390 opt_store_doublecheck
= 1;
395 * Force full debugging */
396 Debug::parseOptions("rotate=0 ALL,9");
397 Debug::override_X
= 1;
398 sigusr2_handle(SIGUSR2
);
403 * Set global option opt_reload_hit_only */
404 opt_reload_hit_only
= 1;
407 #if USE_WIN32_SERVICE
411 * Set global option opt_install_service (to TRUE) */
412 opt_install_service
= TRUE
;
418 * Add optional HTTP port as given following the option */
419 add_http_port(optarg
);
424 * Set global option Debug::log_stderr to the number given follwoign the option */
425 Debug::log_stderr
= atoi(optarg
);
430 * Load the file given instead of the default squid.conf. */
432 ConfigFile
= xstrdup(optarg
);
437 * Run the administrative action given following the option */
439 /** \li When its an unknown option display the usage help. */
440 if ((int) strlen(optarg
) < 1)
443 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
444 /** \li On reconfigure send SIGHUP. */
445 opt_send_signal
= SIGHUP
;
446 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
447 /** \li On rotate send SIGQUIT or SIGUSR1. */
448 #if defined(_SQUID_LINUX_THREADS_)
449 opt_send_signal
= SIGQUIT
;
451 opt_send_signal
= SIGUSR1
;
454 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
455 /** \li On debug send SIGTRAP or SIGUSR2. */
456 #if defined(_SQUID_LINUX_THREADS_)
457 opt_send_signal
= SIGTRAP
;
459 opt_send_signal
= SIGUSR2
;
462 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
463 /** \li On shutdown send SIGTERM. */
464 opt_send_signal
= SIGTERM
;
465 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
466 /** \li On interrupt send SIGINT. */
467 opt_send_signal
= SIGINT
;
468 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
469 /** \li On kill send SIGKILL. */
470 opt_send_signal
= SIGKILL
;
474 else if (!strncmp(optarg
, "restart", strlen(optarg
)))
475 /** \li On restart send SIGTTIN. (exit and restart by parent) */
476 opt_send_signal
= SIGTTIN
;
480 else if (!strncmp(optarg
, "check", strlen(optarg
)))
481 /** \li On check send 0 / SIGNULL. */
482 opt_send_signal
= 0; /* SIGNULL */
483 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
484 /** \li On parse set global flag to re-parse the config file only. */
485 opt_parse_cfg_only
= 1;
493 * Set global malloc_debug_level to the value given following the option.
494 * if none is given it toggles the xmalloc_trace option on/off */
497 malloc_debug_level
= atoi(optarg
);
499 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
507 * Set global option opt_signal_service (to true).
508 * Stores the additional parameter given in global service_name */
509 // XXX: verify that the new name has ONLY alphanumeric characters
511 service_name
= xstrdup(optarg
);
512 opt_signal_service
= true;
515 #if USE_WIN32_SERVICE
519 * Set global option opt_remove_service (to TRUE) */
520 opt_remove_service
= TRUE
;
528 * Stores the syslog facility name in global opt_syslog_facility
529 * then performs actions for -s option. */
530 xfree(opt_syslog_facility
); // ignore any previous options sent
531 opt_syslog_facility
= xstrdup(optarg
);
535 * Initialize the syslog for output */
538 _db_set_syslog(opt_syslog_facility
);
544 fatal("Logging to syslog not available on this platform");
551 * Store the ICP port number given in global option icpPortNumOverride
552 * ensuring its a positive number. */
553 icpPortNumOverride
= atoi(optarg
);
555 if (icpPortNumOverride
< 0)
556 icpPortNumOverride
= 0;
562 * Display squid version and build information. Then exit. */
563 printf("Squid Cache: Version %s\n" ,version_string
);
564 printf("Service Name: %s\n", service_name
);
565 if (strlen(SQUID_BUILD_INFO
))
566 printf("%s\n",SQUID_BUILD_INFO
);
567 printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS
);
569 #if USE_WIN32_SERVICE
571 printf("Compiled as Windows System Service.\n");
581 * Set global option Debug::log_stderr and opt_create_swap_dirs */
582 Debug::log_stderr
= 1;
583 opt_create_swap_dirs
= 1;
591 /** \par h,?, or unknown
592 * \copydoc usage() */
610 signal(sig
, rotate_logs
);
620 ReconfigureSignal
= sig
;
624 signal(sig
, reconfigure
);
632 do_shutdown
= sig
== SIGINT
? -1 : 1;
633 ShutdownSignal
= sig
;
641 const pid_t ppid
= getppid();
643 if (!IamMasterProcess() && ppid
> 1) {
644 // notify master that we are shutting down
645 if (kill(ppid
, SIGUSR1
) < 0)
646 debugs(1, DBG_IMPORTANT
, "Failed to send SIGUSR1 to master process,"
647 " pid " << ppid
<< ": " << xstrerror());
653 if (!IamMasterProcess() && ppid
> 1) {
654 debugs(1, DBG_IMPORTANT
, "Killing master process, pid " << ppid
);
656 if (kill(ppid
, sig
) < 0)
657 debugs(1, DBG_IMPORTANT
, "kill " << ppid
<< ": " << xstrerror());
660 #endif /* KILL_PARENT_OPT */
661 #if SA_RESETHAND == 0
662 signal(SIGTERM
, SIG_DFL
);
664 signal(SIGINT
, SIG_DFL
);
671 serverConnectionsOpen(void)
673 if (IamPrimaryProcess()) {
675 wccpConnectionOpen();
680 wccp2ConnectionOpen();
683 // start various proxying services if we are responsible for them
684 if (IamWorkerProcess()) {
685 clientOpenListenSockets();
704 peerSourceHashInit();
709 serverConnectionsClose(void)
711 assert(shutting_down
|| reconfiguring
);
713 if (IamPrimaryProcess()) {
716 wccpConnectionClose();
720 wccp2ConnectionClose();
723 if (IamWorkerProcess()) {
724 clientHttpConnectionsClose();
725 icpConnectionShutdown();
727 htcpSocketShutdown();
740 mainReconfigureStart(void)
742 debugs(1, DBG_IMPORTANT
, "Reconfiguring Squid Cache (version " << version_string
<< ")...");
745 // Initiate asynchronous closing sequence
746 serverConnectionsClose();
753 Ssl::Helper::GetInstance()->Shutdown();
756 if (Ssl::CertValidationHelper::GetInstance())
757 Ssl::CertValidationHelper::GetInstance()->Shutdown();
758 Ssl::TheGlobalContextStorage
.reconfigureStart();
764 externalAclShutdown();
765 storeDirCloseSwapLogs();
772 eventAdd("mainReconfigureFinish", &mainReconfigureFinish
, NULL
, 0, 1,
777 mainReconfigureFinish(void *)
779 debugs(1, 3, "finishing reconfiguring");
782 enter_suid(); /* root to read config file */
784 // we may have disabled the need for PURGE
785 if (Config2
.onoff
.enable_purge
)
786 Config2
.onoff
.enable_purge
= 2;
788 // parse the config returns a count of errors encountered.
789 const int oldWorkers
= Config
.workers
;
790 if ( parseConfigFile(ConfigFile
) != 0) {
791 // for now any errors are a fatal condition...
794 if (oldWorkers
!= Config
.workers
) {
795 debugs(1, DBG_CRITICAL
, "WARNING: Changing 'workers' (from " <<
796 oldWorkers
<< " to " << Config
.workers
<<
797 ") requires a full restart. It has been ignored by reconfigure.");
798 Config
.workers
= oldWorkers
;
801 RunRegisteredHere(RegisteredRunner::syncConfig
);
803 if (IamPrimaryProcess())
805 CpuAffinityReconfigure();
807 setUmask(Config
.umask
);
810 _db_init(Debug::cache_log
, Debug::debugOptions
);
811 ipcache_restart(); /* clear stuck entries */
812 fqdncache_restart(); /* sigh, fqdncache too */
814 errorInitialize(); /* reload error pages */
817 #if USE_LOADABLE_MODULES
818 LoadableModulesConfigure(Config
.loadable_module_names
);
822 bool enableAdaptation
= false;
824 Adaptation::Icap::TheConfig
.finalize();
825 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
828 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
829 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
831 Adaptation::Config::Finalize(enableAdaptation
);
840 Ssl::Helper::GetInstance()->Init();
843 if (Ssl::CertValidationHelper::GetInstance())
844 Ssl::CertValidationHelper::GetInstance()->Init();
849 authenticateInit(&Auth::TheConfig
);
853 if (IamPrimaryProcess()) {
864 serverConnectionsOpen();
868 storeDirOpenSwapLogs();
870 mimeInit(Config
.mimeTablePathname
);
876 Config
.ClientDelay
.finalize();
879 if (Config
.onoff
.announce
) {
880 if (!eventFind(start_announce
, NULL
))
881 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
883 if (eventFind(start_announce
, NULL
))
884 eventDelete(start_announce
, NULL
);
887 writePidFile(); /* write PID file */
898 authenticateRotate();
900 externalAclShutdown();
902 _db_rotate_log(); /* cache.log */
903 storeDirWriteCleanLogs(1);
904 storeLogRotate(); /* store.log */
905 accessLogRotate(); /* access.log */
907 icapLogRotate(); /*icap.log*/
912 authenticateInit(&Auth::TheConfig
);
918 setEffectiveUser(void)
921 leave_suid(); /* Run as non privilegied user */
927 if (geteuid() == 0) {
928 debugs(0, DBG_CRITICAL
, "Squid is not safe to run as root! If you must");
929 debugs(0, DBG_CRITICAL
, "start Squid as root, then you must configure");
930 debugs(0, DBG_CRITICAL
, "it to run as a non-priveledged user with the");
931 debugs(0, DBG_CRITICAL
, "'cache_effective_user' option in the config file.");
932 fatal("Don't run Squid as root, set 'cache_effective_user'!");
936 /// changes working directory, providing error reporting
938 mainChangeDir(const char *dir
)
943 debugs(50, DBG_CRITICAL
, "cannot change current directory to " << dir
<<
944 ": " << xstrerror());
948 /// set the working directory.
952 static bool chrooted
= false;
953 if (Config
.chroot_dir
&& !chrooted
) {
956 if (chroot(Config
.chroot_dir
) != 0)
957 fatalf("chroot to %s failed: %s", Config
.chroot_dir
, xstrerror());
959 if (!mainChangeDir("/"))
960 fatalf("chdir to / after chroot to %s failed", Config
.chroot_dir
);
963 if (Config
.coredump_dir
&& strcmp("none", Config
.coredump_dir
) != 0) {
964 if (mainChangeDir(Config
.coredump_dir
)) {
965 debugs(0, DBG_IMPORTANT
, "Set Current Directory to " << Config
.coredump_dir
);
970 /* If we don't have coredump_dir or couldn't cd there, report current dir */
971 char pathbuf
[MAXPATHLEN
];
972 if (getcwd(pathbuf
, MAXPATHLEN
)) {
973 debugs(0, DBG_IMPORTANT
, "Current Directory is " << pathbuf
);
975 debugs(50, DBG_CRITICAL
, "WARNING: Can't find current directory, getcwd: " << xstrerror());
982 /* chroot if configured to run inside chroot */
985 if (opt_catch_signals
) {
986 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
987 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
990 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
991 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
995 if (icpPortNumOverride
!= 1)
996 Config
.Port
.icp
= (unsigned short) icpPortNumOverride
;
998 _db_init(Debug::cache_log
, Debug::debugOptions
);
1000 fd_open(fileno(debug_log
), FD_LOG
, Debug::cache_log
);
1002 debugs(1, DBG_CRITICAL
, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
1003 debugs(1, DBG_CRITICAL
, "Service Name: " << service_name
);
1006 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
1007 debugs(1, DBG_CRITICAL
, "Service command line is: " << WIN32_Service_Command_Line
);
1009 debugs(1, DBG_CRITICAL
, "Running on " << WIN32_OS_string
);
1012 debugs(1, DBG_IMPORTANT
, "Process ID " << getpid());
1014 debugs(1, DBG_IMPORTANT
, "Process Roles:" << ProcessRoles());
1017 debugs(1, DBG_IMPORTANT
, "With " << Squid_MaxFD
<< " file descriptors available");
1021 debugs(1, DBG_IMPORTANT
, "With " << _getmaxstdio() << " CRT stdio descriptors available");
1023 if (WIN32_Socks_initialized
)
1024 debugs(1, DBG_IMPORTANT
, "Windows sockets initialized");
1026 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
1027 WIN32_IpAddrChangeMonitorInit();
1032 if (!configured_once
)
1033 disk_init(); /* disk_init must go before ipcache_init() */
1044 Ssl::Helper::GetInstance()->Init();
1048 if (!configured_once
)
1049 Ssl::initialize_session_cache();
1051 if (Ssl::CertValidationHelper::GetInstance())
1052 Ssl::CertValidationHelper::GetInstance()->Init();
1057 authenticateInit(&Auth::TheConfig
);
1061 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
1063 httpReplyInitModule(); /* must go before accepting replies */
1084 malloc_debug(0, malloc_debug_level
);
1088 if (!configured_once
) {
1089 if (unlinkdNeeded())
1096 mimeInit(Config
.mimeTablePathname
);
1102 FwdState::initModule();
1103 /* register the modules in the cache manager menus */
1105 cbdataRegisterWithCacheManager();
1106 /* These use separate calls so that the comm loops can eventually
1112 // TODO: pconn is a good candidate for new-style registration
1113 // PconnModule::GetInstance()->registerWithCacheManager();
1114 // moved to PconnModule::PconnModule()
1117 if (IamPrimaryProcess()) {
1129 serverConnectionsOpen();
1133 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1135 if (Config
.chroot_dir
)
1138 if (!configured_once
)
1139 writePidFile(); /* write PID file */
1141 #if defined(_SQUID_LINUX_THREADS_)
1143 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1145 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1149 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1151 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1155 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1157 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1159 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1163 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1169 #if USE_LOADABLE_MODULES
1170 LoadableModulesConfigure(Config
.loadable_module_names
);
1174 bool enableAdaptation
= false;
1176 // We can remove this dependency on specific adaptation mechanisms
1177 // if we create a generic Registry of such mechanisms. Should we?
1179 Adaptation::Icap::TheConfig
.finalize();
1180 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
1183 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
1184 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
1186 // must be the last adaptation-related finalize
1187 Adaptation::Config::Finalize(enableAdaptation
);
1195 Config
.ClientDelay
.finalize();
1198 if (!configured_once
) {
1199 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1201 if (Config
.onoff
.announce
)
1202 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1204 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1206 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1210 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1214 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1217 configured_once
= 1;
1220 /// unsafe main routine -- may throw
1221 int SquidMain(int argc
, char **argv
);
1222 /// unsafe main routine wrapper to catch exceptions
1223 static int SquidMainSafe(int argc
, char **argv
);
1225 #if USE_WIN32_SERVICE
1226 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1227 extern "C" void WINAPI
1228 SquidWinSvcMain(int argc
, char **argv
)
1230 SquidMainSafe(argc
, argv
);
1234 main(int argc
, char **argv
)
1236 return SquidMainSafe(argc
, argv
);
1241 SquidMainSafe(int argc
, char **argv
)
1244 return SquidMain(argc
, argv
);
1245 } catch (const std::exception
&e
) {
1246 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception: " <<
1250 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception.");
1253 return -1; // not reached
1256 /// computes name and ID for the current kid process
1258 ConfigureCurrentKid(const char *processName
)
1260 // kids are marked with parenthesis around their process names
1261 if (processName
&& processName
[0] == '(') {
1262 if (const char *idStart
= strrchr(processName
, '-')) {
1263 KidIdentifier
= atoi(idStart
+ 1);
1264 const size_t nameLen
= idStart
- (processName
+ 1);
1265 assert(nameLen
< sizeof(TheKidName
));
1266 xstrncpy(TheKidName
, processName
+ 1, nameLen
+ 1);
1267 if (!strcmp(TheKidName
, "squid-coord"))
1268 TheProcessKind
= pkCoordinator
;
1269 else if (!strcmp(TheKidName
, "squid"))
1270 TheProcessKind
= pkWorker
;
1271 else if (!strcmp(TheKidName
, "squid-disk"))
1272 TheProcessKind
= pkDisker
;
1274 TheProcessKind
= pkOther
; // including coordinator
1277 xstrncpy(TheKidName
, APP_SHORTNAME
, sizeof(TheKidName
));
1283 SquidMain(int argc
, char **argv
)
1285 ConfigureCurrentKid(argv
[0]);
1287 Debug::parseOptions(NULL
);
1290 #if defined(SQUID_MAXFD_LIMIT)
1292 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1293 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1297 /* NOP under non-windows */
1298 int WIN32_init_err
=0;
1299 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1300 return WIN32_init_err
;
1302 /* call mallopt() before anything else */
1305 /* Round up all sizes to a multiple of this */
1306 mallopt(M_GRAIN
, 16);
1310 /* biggest size that is considered a small block */
1311 mallopt(M_MXFAST
, 256);
1315 /* allocate this many small blocks at once */
1316 mallopt(M_NLBLKS
, 32);
1319 #endif /* HAVE_MALLOPT */
1321 squid_srandom(time(NULL
));
1325 squid_start
= current_time
;
1327 failure_notify
= fatal_dump
;
1329 #if USE_WIN32_SERVICE
1331 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1335 mainParseOptions(argc
, argv
);
1337 if (opt_parse_cfg_only
) {
1338 Debug::parseOptions("ALL,1");
1341 #if USE_WIN32_SERVICE
1343 if (opt_install_service
) {
1344 WIN32_InstallService();
1348 if (opt_remove_service
) {
1349 WIN32_RemoveService();
1353 if (opt_command_line
) {
1354 WIN32_SetServiceCommandLine();
1360 /* parse configuration file
1361 * note: in "normal" case this used to be called from mainInitialize() */
1366 ConfigFile
= xstrdup(DefaultConfigFile
);
1368 assert(!configured_once
);
1372 storeFsInit(); /* required for config parsing */
1374 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
1377 /* May not be needed for parsing, have not audited for such */
1378 DiskIOModule::SetupAllModules();
1380 /* Shouldn't be needed for config parsing, but have not audited for such */
1381 StoreFileSystem::SetupAllFs();
1383 /* we may want the parsing process to set this up in the future */
1384 Store::Root(new StoreController
);
1385 Auth::Init(); /* required for config parsing. NOP if !USE_AUTH */
1386 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
1388 Format::Token::Init(); // XXX: temporary. Use a runners registry of pre-parse runners instead.
1390 parse_err
= parseConfigFile(ConfigFile
);
1394 if (opt_parse_cfg_only
|| parse_err
> 0)
1397 setUmask(Config
.umask
);
1398 if (-1 == opt_send_signal
)
1399 if (checkRunningPid())
1414 /* send signal to running copy and exit */
1415 if (opt_send_signal
!= -1) {
1416 /* chroot if configured to run inside chroot */
1418 if (Config
.chroot_dir
) {
1428 debugs(1,2, HERE
<< "Doing post-config initialization\n");
1430 RunRegisteredHere(RegisteredRunner::finalizeConfig
);
1431 RunRegisteredHere(RegisteredRunner::claimMemoryNeeds
);
1432 RunRegisteredHere(RegisteredRunner::useConfig
);
1435 if (!opt_no_daemon
&& Config
.workers
> 0)
1438 if (opt_create_swap_dirs
) {
1439 /* chroot if configured to run inside chroot */
1443 debugs(0, DBG_CRITICAL
, "Creating missing swap directories");
1444 Store::Root().create();
1449 if (IamPrimaryProcess())
1455 /* init comm module */
1458 if (opt_no_daemon
) {
1459 /* we have to init fdstat here. */
1460 fd_open(0, FD_LOG
, "stdin");
1461 fd_open(1, FD_LOG
, "stdout");
1462 fd_open(2, FD_LOG
, "stderr");
1465 #if USE_WIN32_SERVICE
1467 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1473 #if USE_WIN32_SERVICE
1475 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1482 SignalEngine signalEngine
;
1484 mainLoop
.registerEngine(&signalEngine
);
1486 /* TODO: stop requiring the singleton here */
1487 mainLoop
.registerEngine(EventScheduler::GetInstance());
1489 StoreRootEngine store_engine
;
1491 mainLoop
.registerEngine(&store_engine
);
1493 CommSelectEngine comm_engine
;
1495 mainLoop
.registerEngine(&comm_engine
);
1497 mainLoop
.setPrimaryEngine(&comm_engine
);
1499 /* use the standard time service */
1500 TimeEngine time_engine
;
1502 mainLoop
.setTimeService(&time_engine
);
1504 if (IamCoordinatorProcess())
1505 AsyncJob::Start(Ipc::Coordinator::Instance());
1506 else if (UsingSmp() && (IamWorkerProcess() || IamDiskProcess()))
1507 AsyncJob::Start(new Ipc::Strand
);
1509 /* at this point we are finished the synchronous startup. */
1514 if (mainLoop
.errcount
== 10)
1515 fatal_dump("Event loop exited with failure.");
1517 /* shutdown squid now */
1530 if (strcmp(Config
.pidFilename
, "none") == 0) {
1531 debugs(0, DBG_IMPORTANT
, "No pid_filename specified. Trusting you know what you are doing.");
1534 pid
= readPidFile();
1537 #if USE_WIN32_SERVICE
1538 if (opt_signal_service
) {
1539 WIN32_sendSignal(opt_send_signal
);
1542 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1543 fprintf(stderr
, "signal to Squid Service:\n");
1544 fprintf(stderr
, "missing -n command line switch.\n");
1550 if (kill(pid
, opt_send_signal
) &&
1551 /* ignore permissions if just running check */
1552 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1553 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1554 fprintf(stderr
, "signal %d to process %d: %s\n",
1555 opt_send_signal
, (int) pid
, xstrerror());
1559 if (opt_send_signal
!= SIGTERM
) {
1560 fprintf(stderr
, "%s: ERROR: No running copy\n", APP_SHORTNAME
);
1563 fprintf(stderr
, "%s: No running copy\n", APP_SHORTNAME
);
1568 /* signal successfully sent */
1572 #if !_SQUID_WINDOWS_
1574 * This function is run when Squid is in daemon mode, just
1575 * before the parent forks and starts up the child process.
1576 * It can be used for admin-specific tasks, such as notifying
1577 * someone that Squid is (re)started.
1580 mainStartScript(const char *prog
)
1582 char script
[MAXPATHLEN
];
1587 xstrncpy(script
, prog
, MAXPATHLEN
);
1589 if ((t
= strrchr(script
, '/'))) {
1591 sl
= strlen(script
);
1594 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1596 if ((cpid
= fork()) == 0) {
1598 execl(script
, squid_start_script
, (char *)NULL
);
1604 rpid
= wait4(cpid
, &status
, 0, NULL
);
1608 rpid
= waitpid(cpid
, &status
, 0);
1611 } while (rpid
!= cpid
);
1615 #endif /* _SQUID_WINDOWS_ */
1618 checkRunningPid(void)
1620 // master process must start alone, but its kids processes may co-exist
1621 if (!IamMasterProcess())
1629 pid
= readPidFile();
1634 if (kill(pid
, 0) < 0)
1637 debugs(0, DBG_CRITICAL
, "Squid is already running! Process ID " << pid
);
1643 watch_child(char *argv
[])
1645 #if !_SQUID_WINDOWS_
1663 if (!IamMasterProcess())
1666 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1668 if ((pid
= fork()) < 0)
1669 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1674 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1680 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1681 ioctl(i
, TIOCNOTTY
, NULL
);
1688 * RBCOLLINS - if cygwin stackdumps when squid is run without
1689 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1690 * 1.1.3. execvp had a bit overflow error in a loop..
1692 /* Connect stdio to /dev/null in daemon mode */
1693 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1696 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1700 if (Debug::log_stderr
< 0) {
1705 // handle shutdown notifications from kids
1706 squid_signal(SIGUSR1
, sig_shutdown
, SA_RESTART
);
1708 if (Config
.workers
> 128) {
1709 syslog(LOG_ALERT
, "Suspiciously high workers value: %d",
1711 // but we keep going in hope that user knows best
1715 syslog(LOG_NOTICE
, "Squid Parent: will start %d kids", (int)TheKids
.count());
1717 // keep [re]starting kids until it is time to quit
1719 mainStartScript(argv
[0]);
1721 // start each kid that needs to be [re]started; once
1722 for (int i
= TheKids
.count() - 1; i
>= 0; --i
) {
1723 Kid
& kid
= TheKids
.get(i
);
1724 if (!kid
.shouldRestart())
1727 if ((pid
= fork()) == 0) {
1729 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1731 argv
[0] = const_cast<char*>(kid
.name().termedBuf());
1733 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1737 syslog(LOG_NOTICE
, "Squid Parent: %s process %d started",
1738 kid
.name().termedBuf(), pid
);
1742 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1744 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1748 pid
= wait3(&status
, 0, NULL
);
1752 pid
= waitpid(-1, &status
, 0);
1755 // Loop to collect all stopped kids before we go to sleep below.
1757 Kid
* kid
= TheKids
.find(pid
);
1760 if (kid
->calledExit()) {
1762 "Squid Parent: %s process %d exited with status %d",
1763 kid
->name().termedBuf(),
1764 kid
->getPid(), kid
->exitStatus());
1765 } else if (kid
->signaled()) {
1767 "Squid Parent: %s process %d exited due to signal %d with status %d",
1768 kid
->name().termedBuf(),
1769 kid
->getPid(), kid
->termSignal(), kid
->exitStatus());
1771 syslog(LOG_NOTICE
, "Squid Parent: %s process %d exited",
1772 kid
->name().termedBuf(), kid
->getPid());
1774 if (kid
->hopeless()) {
1775 syslog(LOG_NOTICE
, "Squid Parent: %s process %d will not"
1776 " be restarted due to repeated, frequent failures",
1777 kid
->name().termedBuf(), kid
->getPid());
1780 syslog(LOG_NOTICE
, "Squid Parent: unknown child process %d exited", pid
);
1783 } while ((pid
= wait3(&status
, WNOHANG
, NULL
)) > 0);
1786 while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0);
1789 if (!TheKids
.someRunning() && !TheKids
.shouldRestartSome()) {
1791 // XXX: Master process has no main loop and, hence, should not call
1792 // RegisteredRunner::startShutdown which promises a loop iteration.
1793 RunRegisteredHere(RegisteredRunner::finishShutdown
);
1796 if (TheKids
.someSignaled(SIGINT
) || TheKids
.someSignaled(SIGTERM
)) {
1797 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1801 if (TheKids
.allHopeless()) {
1802 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1809 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1814 #endif /* _SQUID_WINDOWS_ */
1821 /* XXX: This function is called after the main loop has quit, which
1822 * means that no AsyncCalls would be called, including close handlers.
1823 * TODO: We need to close/shut/free everything that needs calls before
1827 #if USE_WIN32_SERVICE
1828 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1831 debugs(1, DBG_IMPORTANT
, "Shutting down...");
1834 Ssl::Helper::GetInstance()->Shutdown();
1837 if (Ssl::CertValidationHelper::GetInstance())
1838 Ssl::CertValidationHelper::GetInstance()->Shutdown();
1841 externalAclShutdown();
1851 wccpConnectionClose();
1855 wccp2ConnectionClose();
1858 releaseServerSockets();
1859 commCloseAllSockets();
1866 DelayPools::FreePools();
1869 authenticateReset();
1871 #if USE_WIN32_SERVICE
1873 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1876 Store::Root().sync(); /* Flush pending object writes/unlinks */
1878 unlinkdClose(); /* after sync/flush. NOP if !USE_UNLINKD */
1880 storeDirWriteCleanLogs(0);
1883 Store::Root().sync(); /* Flush log writes */
1886 Store::Root().sync(); /* Flush log close */
1887 StoreFileSystem::FreeAllFs();
1888 DiskIOModule::FreeAllModules();
1889 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1893 /*stmemFreeMemory(); */
1895 ipcacheFreeMemory();
1896 fqdncacheFreeMemory();
1898 clientdbFreeMemory();
1899 httpHeaderCleanModule();
1905 // clear StoreController
1912 RunRegisteredHere(RegisteredRunner::finishShutdown
);
1916 if (IamPrimaryProcess()) {
1917 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1919 safeunlink(Config
.pidFilename
, 0);
1924 debugs(1, DBG_IMPORTANT
, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1928 * We used to fclose(debug_log) here if it was set, but then
1929 * we forgot to set it to NULL. That caused some coredumps
1930 * because exit() ends up calling a bunch of destructors and
1931 * such. So rather than forcing the debug_log to close, we'll
1932 * leave it open so that those destructors can write some
1933 * debugging if necessary. The file will be closed anyway when
1934 * the process truly exits.
1937 exit(shutdown_status
);