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|interrupt|kill|debug|check|parse\n"
296 " Parse configuration file, then send signal to \n"
297 " running copy (except -k parse) and exit.\n"
298 " -n name Specify service name to use for service operations\n"
299 " default is: " APP_SHORTNAME
".\n"
300 #if USE_WIN32_SERVICE
301 " -r Removes a Windows Service (see -n option).\n"
303 " -s | -l facility\n"
304 " Enable logging to syslog.\n"
305 " -u port Specify ICP port number (default: %d), disable with 0.\n"
306 " -v Print version.\n"
307 " -z Create missing swap directories and then exit.\n"
308 " -C Do not catch fatal signals.\n"
309 " -D OBSOLETE. Scheduled for removal.\n"
310 " -F Don't serve any requests until store is rebuilt.\n"
311 " -N No daemon mode.\n"
312 #if USE_WIN32_SERVICE
314 " Set Windows Service Command line options in Registry.\n"
316 " -R Do not set REUSEADDR on port.\n"
317 " -S Double-check swap during rebuild.\n"
318 " -X Force full debugging.\n"
319 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
320 APP_SHORTNAME
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
325 * Parse the parameters received via command line interface.
327 \param argc Number of options received on command line
328 \param argv List of parameters received on command line
331 mainParseOptions(int argc
, char *argv
[])
336 #if USE_WIN32_SERVICE
337 while ((c
= getopt(argc
, argv
, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
339 while ((c
= getopt(argc
, argv
, "CDFNRSYXa:d:f:hk:m::n:sl:u:vz?")) != -1)
347 * Unset/disabel global option for catchign signals. opt_catch_signals */
348 opt_catch_signals
= 0;
353 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
354 debugs(1,DBG_CRITICAL
, "WARNING: -D command-line option is obsolete.");
359 * Set global option for foreground rebuild. opt_foreground_rebuild */
360 opt_foreground_rebuild
= 1;
365 * Set global option for 'no_daemon' mode. opt_no_daemon */
369 #if USE_WIN32_SERVICE
373 * Set global option. opt_command_lin and WIN32_Command_Line */
374 opt_command_line
= 1;
375 WIN32_Command_Line
= xstrdup(optarg
);
381 * Unset/disable global option opt_reuseaddr */
387 * Set global option opt_store_doublecheck */
388 opt_store_doublecheck
= 1;
393 * Force full debugging */
394 Debug::parseOptions("rotate=0 ALL,9");
395 Debug::override_X
= 1;
396 sigusr2_handle(SIGUSR2
);
401 * Set global option opt_reload_hit_only */
402 opt_reload_hit_only
= 1;
405 #if USE_WIN32_SERVICE
409 * Set global option opt_install_service (to TRUE) */
410 opt_install_service
= TRUE
;
416 * Add optional HTTP port as given following the option */
417 add_http_port(optarg
);
422 * Set global option Debug::log_stderr to the number given follwoign the option */
423 Debug::log_stderr
= atoi(optarg
);
428 * Load the file given instead of the default squid.conf. */
430 ConfigFile
= xstrdup(optarg
);
435 * Run the administrative action given following the option */
437 /** \li When its an unknown option display the usage help. */
438 if ((int) strlen(optarg
) < 1)
441 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
442 /** \li On reconfigure send SIGHUP. */
443 opt_send_signal
= SIGHUP
;
444 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
445 /** \li On rotate send SIGQUIT or SIGUSR1. */
446 #if defined(_SQUID_LINUX_THREADS_)
447 opt_send_signal
= SIGQUIT
;
449 opt_send_signal
= SIGUSR1
;
452 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
453 /** \li On debug send SIGTRAP or SIGUSR2. */
454 #if defined(_SQUID_LINUX_THREADS_)
455 opt_send_signal
= SIGTRAP
;
457 opt_send_signal
= SIGUSR2
;
460 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
461 /** \li On shutdown send SIGTERM. */
462 opt_send_signal
= SIGTERM
;
463 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
464 /** \li On interrupt send SIGINT. */
465 opt_send_signal
= SIGINT
;
466 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
467 /** \li On kill send SIGKILL. */
468 opt_send_signal
= SIGKILL
;
472 else if (!strncmp(optarg
, "restart", strlen(optarg
)))
473 /** \li On restart send SIGTTIN. (exit and restart by parent) */
474 opt_send_signal
= SIGTTIN
;
478 else if (!strncmp(optarg
, "check", strlen(optarg
)))
479 /** \li On check send 0 / SIGNULL. */
480 opt_send_signal
= 0; /* SIGNULL */
481 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
482 /** \li On parse set global flag to re-parse the config file only. */
483 opt_parse_cfg_only
= 1;
491 * Set global malloc_debug_level to the value given following the option.
492 * if none is given it toggles the xmalloc_trace option on/off */
495 malloc_debug_level
= atoi(optarg
);
497 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
505 * Set global option opt_signal_service (to true).
506 * Stores the additional parameter given in global service_name */
507 // XXX: verify that the new name has ONLY alphanumeric characters
509 service_name
= xstrdup(optarg
);
510 opt_signal_service
= true;
513 #if USE_WIN32_SERVICE
517 * Set global option opt_remove_service (to TRUE) */
518 opt_remove_service
= TRUE
;
526 * Stores the syslog facility name in global opt_syslog_facility
527 * then performs actions for -s option. */
528 xfree(opt_syslog_facility
); // ignore any previous options sent
529 opt_syslog_facility
= xstrdup(optarg
);
533 * Initialize the syslog for output */
536 _db_set_syslog(opt_syslog_facility
);
542 fatal("Logging to syslog not available on this platform");
549 * Store the ICP port number given in global option icpPortNumOverride
550 * ensuring its a positive number. */
551 icpPortNumOverride
= atoi(optarg
);
553 if (icpPortNumOverride
< 0)
554 icpPortNumOverride
= 0;
560 * Display squid version and build information. Then exit. */
561 printf("Squid Cache: Version %s\n" ,version_string
);
562 printf("Service Name: %s\n", service_name
);
563 if (strlen(SQUID_BUILD_INFO
))
564 printf("%s\n",SQUID_BUILD_INFO
);
565 printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS
);
567 #if USE_WIN32_SERVICE
569 printf("Compiled as Windows System Service.\n");
579 * Set global option Debug::log_stderr and opt_create_swap_dirs */
580 Debug::log_stderr
= 1;
581 opt_create_swap_dirs
= 1;
589 /** \par h,?, or unknown
590 * \copydoc usage() */
608 signal(sig
, rotate_logs
);
618 ReconfigureSignal
= sig
;
622 signal(sig
, reconfigure
);
630 do_shutdown
= sig
== SIGINT
? -1 : 1;
631 ShutdownSignal
= sig
;
639 const pid_t ppid
= getppid();
641 if (!IamMasterProcess() && ppid
> 1) {
642 // notify master that we are shutting down
643 if (kill(ppid
, SIGUSR1
) < 0)
644 debugs(1, DBG_IMPORTANT
, "Failed to send SIGUSR1 to master process,"
645 " pid " << ppid
<< ": " << xstrerror());
651 if (!IamMasterProcess() && ppid
> 1) {
652 debugs(1, DBG_IMPORTANT
, "Killing master process, pid " << ppid
);
654 if (kill(ppid
, sig
) < 0)
655 debugs(1, DBG_IMPORTANT
, "kill " << ppid
<< ": " << xstrerror());
658 #endif /* KILL_PARENT_OPT */
659 #if SA_RESETHAND == 0
660 signal(SIGTERM
, SIG_DFL
);
662 signal(SIGINT
, SIG_DFL
);
669 serverConnectionsOpen(void)
671 if (IamPrimaryProcess()) {
673 wccpConnectionOpen();
678 wccp2ConnectionOpen();
681 // start various proxying services if we are responsible for them
682 if (IamWorkerProcess()) {
683 clientOpenListenSockets();
702 peerSourceHashInit();
707 serverConnectionsClose(void)
709 assert(shutting_down
|| reconfiguring
);
711 if (IamPrimaryProcess()) {
714 wccpConnectionClose();
718 wccp2ConnectionClose();
721 if (IamWorkerProcess()) {
722 clientConnectionsClose();
723 icpConnectionShutdown();
725 htcpSocketShutdown();
738 mainReconfigureStart(void)
740 debugs(1, DBG_IMPORTANT
, "Reconfiguring Squid Cache (version " << version_string
<< ")...");
743 // Initiate asynchronous closing sequence
744 serverConnectionsClose();
751 Ssl::Helper::GetInstance()->Shutdown();
754 if (Ssl::CertValidationHelper::GetInstance())
755 Ssl::CertValidationHelper::GetInstance()->Shutdown();
756 Ssl::TheGlobalContextStorage
.reconfigureStart();
762 externalAclShutdown();
763 storeDirCloseSwapLogs();
770 eventAdd("mainReconfigureFinish", &mainReconfigureFinish
, NULL
, 0, 1,
775 mainReconfigureFinish(void *)
777 debugs(1, 3, "finishing reconfiguring");
780 enter_suid(); /* root to read config file */
782 // we may have disabled the need for PURGE
783 if (Config2
.onoff
.enable_purge
)
784 Config2
.onoff
.enable_purge
= 2;
786 // parse the config returns a count of errors encountered.
787 const int oldWorkers
= Config
.workers
;
788 if ( parseConfigFile(ConfigFile
) != 0) {
789 // for now any errors are a fatal condition...
792 if (oldWorkers
!= Config
.workers
) {
793 debugs(1, DBG_CRITICAL
, "WARNING: Changing 'workers' (from " <<
794 oldWorkers
<< " to " << Config
.workers
<<
795 ") requires a full restart. It has been ignored by reconfigure.");
796 Config
.workers
= oldWorkers
;
799 RunRegisteredHere(RegisteredRunner::syncConfig
);
801 if (IamPrimaryProcess())
803 CpuAffinityReconfigure();
805 setUmask(Config
.umask
);
808 _db_init(Debug::cache_log
, Debug::debugOptions
);
809 ipcache_restart(); /* clear stuck entries */
810 fqdncache_restart(); /* sigh, fqdncache too */
812 errorInitialize(); /* reload error pages */
815 #if USE_LOADABLE_MODULES
816 LoadableModulesConfigure(Config
.loadable_module_names
);
820 bool enableAdaptation
= false;
822 Adaptation::Icap::TheConfig
.finalize();
823 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
826 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
827 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
829 Adaptation::Config::Finalize(enableAdaptation
);
838 Ssl::Helper::GetInstance()->Init();
841 if (Ssl::CertValidationHelper::GetInstance())
842 Ssl::CertValidationHelper::GetInstance()->Init();
847 authenticateInit(&Auth::TheConfig
);
851 if (IamPrimaryProcess()) {
862 serverConnectionsOpen();
866 storeDirOpenSwapLogs();
868 mimeInit(Config
.mimeTablePathname
);
874 Config
.ClientDelay
.finalize();
877 if (Config
.onoff
.announce
) {
878 if (!eventFind(start_announce
, NULL
))
879 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
881 if (eventFind(start_announce
, NULL
))
882 eventDelete(start_announce
, NULL
);
885 writePidFile(); /* write PID file */
896 authenticateRotate();
898 externalAclShutdown();
900 _db_rotate_log(); /* cache.log */
901 storeDirWriteCleanLogs(1);
902 storeLogRotate(); /* store.log */
903 accessLogRotate(); /* access.log */
905 icapLogRotate(); /*icap.log*/
910 authenticateInit(&Auth::TheConfig
);
916 setEffectiveUser(void)
919 leave_suid(); /* Run as non privilegied user */
925 if (geteuid() == 0) {
926 debugs(0, DBG_CRITICAL
, "Squid is not safe to run as root! If you must");
927 debugs(0, DBG_CRITICAL
, "start Squid as root, then you must configure");
928 debugs(0, DBG_CRITICAL
, "it to run as a non-priveledged user with the");
929 debugs(0, DBG_CRITICAL
, "'cache_effective_user' option in the config file.");
930 fatal("Don't run Squid as root, set 'cache_effective_user'!");
934 /// changes working directory, providing error reporting
936 mainChangeDir(const char *dir
)
941 debugs(50, DBG_CRITICAL
, "cannot change current directory to " << dir
<<
942 ": " << xstrerror());
946 /// set the working directory.
950 static bool chrooted
= false;
951 if (Config
.chroot_dir
&& !chrooted
) {
954 if (chroot(Config
.chroot_dir
) != 0)
955 fatalf("chroot to %s failed: %s", Config
.chroot_dir
, xstrerror());
957 if (!mainChangeDir("/"))
958 fatalf("chdir to / after chroot to %s failed", Config
.chroot_dir
);
961 if (Config
.coredump_dir
&& strcmp("none", Config
.coredump_dir
) != 0) {
962 if (mainChangeDir(Config
.coredump_dir
)) {
963 debugs(0, DBG_IMPORTANT
, "Set Current Directory to " << Config
.coredump_dir
);
968 /* If we don't have coredump_dir or couldn't cd there, report current dir */
969 char pathbuf
[MAXPATHLEN
];
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 */
983 if (opt_catch_signals
) {
984 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
985 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
988 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
989 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
993 if (icpPortNumOverride
!= 1)
994 Config
.Port
.icp
= (unsigned short) icpPortNumOverride
;
996 _db_init(Debug::cache_log
, Debug::debugOptions
);
998 fd_open(fileno(debug_log
), FD_LOG
, Debug::cache_log
);
1000 debugs(1, DBG_CRITICAL
, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
1001 debugs(1, DBG_CRITICAL
, "Service Name: " << service_name
);
1004 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
1005 debugs(1, DBG_CRITICAL
, "Service command line is: " << WIN32_Service_Command_Line
);
1007 debugs(1, DBG_CRITICAL
, "Running on " << WIN32_OS_string
);
1010 debugs(1, DBG_IMPORTANT
, "Process ID " << getpid());
1012 debugs(1, DBG_IMPORTANT
, "Process Roles:" << ProcessRoles());
1015 debugs(1, DBG_IMPORTANT
, "With " << Squid_MaxFD
<< " file descriptors available");
1019 debugs(1, DBG_IMPORTANT
, "With " << _getmaxstdio() << " CRT stdio descriptors available");
1021 if (WIN32_Socks_initialized
)
1022 debugs(1, DBG_IMPORTANT
, "Windows sockets initialized");
1024 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
1025 WIN32_IpAddrChangeMonitorInit();
1030 if (!configured_once
)
1031 disk_init(); /* disk_init must go before ipcache_init() */
1042 Ssl::Helper::GetInstance()->Init();
1046 if (!configured_once
)
1047 Ssl::initialize_session_cache();
1049 if (Ssl::CertValidationHelper::GetInstance())
1050 Ssl::CertValidationHelper::GetInstance()->Init();
1055 authenticateInit(&Auth::TheConfig
);
1059 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
1061 httpReplyInitModule(); /* must go before accepting replies */
1082 malloc_debug(0, malloc_debug_level
);
1086 if (!configured_once
) {
1087 if (unlinkdNeeded())
1094 mimeInit(Config
.mimeTablePathname
);
1100 FwdState::initModule();
1101 /* register the modules in the cache manager menus */
1103 cbdataRegisterWithCacheManager();
1104 /* These use separate calls so that the comm loops can eventually
1110 // TODO: pconn is a good candidate for new-style registration
1111 // PconnModule::GetInstance()->registerWithCacheManager();
1112 // moved to PconnModule::PconnModule()
1115 if (IamPrimaryProcess()) {
1127 serverConnectionsOpen();
1131 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1133 if (Config
.chroot_dir
)
1136 if (!configured_once
)
1137 writePidFile(); /* write PID file */
1139 #if defined(_SQUID_LINUX_THREADS_)
1141 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1143 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1147 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1149 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1153 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1155 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1157 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1161 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1167 #if USE_LOADABLE_MODULES
1168 LoadableModulesConfigure(Config
.loadable_module_names
);
1172 bool enableAdaptation
= false;
1174 // We can remove this dependency on specific adaptation mechanisms
1175 // if we create a generic Registry of such mechanisms. Should we?
1177 Adaptation::Icap::TheConfig
.finalize();
1178 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
1181 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
1182 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
1184 // must be the last adaptation-related finalize
1185 Adaptation::Config::Finalize(enableAdaptation
);
1193 Config
.ClientDelay
.finalize();
1196 if (!configured_once
) {
1197 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1199 if (Config
.onoff
.announce
)
1200 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1202 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1204 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1208 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1212 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1215 configured_once
= 1;
1218 /// unsafe main routine -- may throw
1219 int SquidMain(int argc
, char **argv
);
1220 /// unsafe main routine wrapper to catch exceptions
1221 static int SquidMainSafe(int argc
, char **argv
);
1223 #if USE_WIN32_SERVICE
1224 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1225 extern "C" void WINAPI
1226 SquidWinSvcMain(int argc
, char **argv
)
1228 SquidMainSafe(argc
, argv
);
1232 main(int argc
, char **argv
)
1234 return SquidMainSafe(argc
, argv
);
1239 SquidMainSafe(int argc
, char **argv
)
1242 return SquidMain(argc
, argv
);
1243 } catch (const std::exception
&e
) {
1244 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception: " <<
1248 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception.");
1251 return -1; // not reached
1254 /// computes name and ID for the current kid process
1256 ConfigureCurrentKid(const char *processName
)
1258 // kids are marked with parenthesis around their process names
1259 if (processName
&& processName
[0] == '(') {
1260 if (const char *idStart
= strrchr(processName
, '-')) {
1261 KidIdentifier
= atoi(idStart
+ 1);
1262 const size_t nameLen
= idStart
- (processName
+ 1);
1263 assert(nameLen
< sizeof(TheKidName
));
1264 xstrncpy(TheKidName
, processName
+ 1, nameLen
+ 1);
1265 if (!strcmp(TheKidName
, "squid-coord"))
1266 TheProcessKind
= pkCoordinator
;
1267 else if (!strcmp(TheKidName
, "squid"))
1268 TheProcessKind
= pkWorker
;
1269 else if (!strcmp(TheKidName
, "squid-disk"))
1270 TheProcessKind
= pkDisker
;
1272 TheProcessKind
= pkOther
; // including coordinator
1275 xstrncpy(TheKidName
, APP_SHORTNAME
, sizeof(TheKidName
));
1281 SquidMain(int argc
, char **argv
)
1283 ConfigureCurrentKid(argv
[0]);
1285 Debug::parseOptions(NULL
);
1288 #if defined(SQUID_MAXFD_LIMIT)
1290 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1291 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1295 /* NOP under non-windows */
1296 int WIN32_init_err
=0;
1297 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1298 return WIN32_init_err
;
1300 /* call mallopt() before anything else */
1303 /* Round up all sizes to a multiple of this */
1304 mallopt(M_GRAIN
, 16);
1308 /* biggest size that is considered a small block */
1309 mallopt(M_MXFAST
, 256);
1313 /* allocate this many small blocks at once */
1314 mallopt(M_NLBLKS
, 32);
1317 #endif /* HAVE_MALLOPT */
1319 squid_srandom(time(NULL
));
1323 squid_start
= current_time
;
1325 failure_notify
= fatal_dump
;
1327 #if USE_WIN32_SERVICE
1329 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1333 mainParseOptions(argc
, argv
);
1335 if (opt_parse_cfg_only
) {
1336 Debug::parseOptions("ALL,1");
1339 #if USE_WIN32_SERVICE
1341 if (opt_install_service
) {
1342 WIN32_InstallService();
1346 if (opt_remove_service
) {
1347 WIN32_RemoveService();
1351 if (opt_command_line
) {
1352 WIN32_SetServiceCommandLine();
1358 /* parse configuration file
1359 * note: in "normal" case this used to be called from mainInitialize() */
1364 ConfigFile
= xstrdup(DefaultConfigFile
);
1366 assert(!configured_once
);
1370 storeFsInit(); /* required for config parsing */
1372 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
1375 /* May not be needed for parsing, have not audited for such */
1376 DiskIOModule::SetupAllModules();
1378 /* Shouldn't be needed for config parsing, but have not audited for such */
1379 StoreFileSystem::SetupAllFs();
1381 /* we may want the parsing process to set this up in the future */
1382 Store::Root(new StoreController
);
1383 Auth::Init(); /* required for config parsing. NOP if !USE_AUTH */
1384 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
1386 Format::Token::Init(); // XXX: temporary. Use a runners registry of pre-parse runners instead.
1388 parse_err
= parseConfigFile(ConfigFile
);
1392 if (opt_parse_cfg_only
|| parse_err
> 0)
1395 setUmask(Config
.umask
);
1396 if (-1 == opt_send_signal
)
1397 if (checkRunningPid())
1412 /* send signal to running copy and exit */
1413 if (opt_send_signal
!= -1) {
1414 /* chroot if configured to run inside chroot */
1416 if (Config
.chroot_dir
) {
1426 debugs(1,2, HERE
<< "Doing post-config initialization\n");
1428 RunRegisteredHere(RegisteredRunner::finalizeConfig
);
1429 RunRegisteredHere(RegisteredRunner::claimMemoryNeeds
);
1430 RunRegisteredHere(RegisteredRunner::useConfig
);
1433 if (!opt_no_daemon
&& Config
.workers
> 0)
1436 if (opt_create_swap_dirs
) {
1437 /* chroot if configured to run inside chroot */
1441 debugs(0, DBG_CRITICAL
, "Creating missing swap directories");
1442 Store::Root().create();
1447 if (IamPrimaryProcess())
1453 /* init comm module */
1456 if (opt_no_daemon
) {
1457 /* we have to init fdstat here. */
1458 fd_open(0, FD_LOG
, "stdin");
1459 fd_open(1, FD_LOG
, "stdout");
1460 fd_open(2, FD_LOG
, "stderr");
1463 #if USE_WIN32_SERVICE
1465 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1471 #if USE_WIN32_SERVICE
1473 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1480 SignalEngine signalEngine
;
1482 mainLoop
.registerEngine(&signalEngine
);
1484 /* TODO: stop requiring the singleton here */
1485 mainLoop
.registerEngine(EventScheduler::GetInstance());
1487 StoreRootEngine store_engine
;
1489 mainLoop
.registerEngine(&store_engine
);
1491 CommSelectEngine comm_engine
;
1493 mainLoop
.registerEngine(&comm_engine
);
1495 mainLoop
.setPrimaryEngine(&comm_engine
);
1497 /* use the standard time service */
1498 TimeEngine time_engine
;
1500 mainLoop
.setTimeService(&time_engine
);
1502 if (IamCoordinatorProcess())
1503 AsyncJob::Start(Ipc::Coordinator::Instance());
1504 else if (UsingSmp() && (IamWorkerProcess() || IamDiskProcess()))
1505 AsyncJob::Start(new Ipc::Strand
);
1507 /* at this point we are finished the synchronous startup. */
1512 if (mainLoop
.errcount
== 10)
1513 fatal_dump("Event loop exited with failure.");
1515 /* shutdown squid now */
1528 if (strcmp(Config
.pidFilename
, "none") == 0) {
1529 debugs(0, DBG_IMPORTANT
, "No pid_filename specified. Trusting you know what you are doing.");
1532 pid
= readPidFile();
1535 #if USE_WIN32_SERVICE
1536 if (opt_signal_service
) {
1537 WIN32_sendSignal(opt_send_signal
);
1540 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1541 fprintf(stderr
, "signal to Squid Service:\n");
1542 fprintf(stderr
, "missing -n command line switch.\n");
1548 if (kill(pid
, opt_send_signal
) &&
1549 /* ignore permissions if just running check */
1550 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1551 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1552 fprintf(stderr
, "signal %d to process %d: %s\n",
1553 opt_send_signal
, (int) pid
, xstrerror());
1557 if (opt_send_signal
!= SIGTERM
) {
1558 fprintf(stderr
, "%s: ERROR: No running copy\n", APP_SHORTNAME
);
1561 fprintf(stderr
, "%s: No running copy\n", APP_SHORTNAME
);
1566 /* signal successfully sent */
1570 #if !_SQUID_WINDOWS_
1572 * This function is run when Squid is in daemon mode, just
1573 * before the parent forks and starts up the child process.
1574 * It can be used for admin-specific tasks, such as notifying
1575 * someone that Squid is (re)started.
1578 mainStartScript(const char *prog
)
1580 char script
[MAXPATHLEN
];
1585 xstrncpy(script
, prog
, MAXPATHLEN
);
1587 if ((t
= strrchr(script
, '/'))) {
1589 sl
= strlen(script
);
1592 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1594 if ((cpid
= fork()) == 0) {
1596 execl(script
, squid_start_script
, (char *)NULL
);
1602 rpid
= wait4(cpid
, &status
, 0, NULL
);
1606 rpid
= waitpid(cpid
, &status
, 0);
1609 } while (rpid
!= cpid
);
1613 #endif /* _SQUID_WINDOWS_ */
1616 checkRunningPid(void)
1618 // master process must start alone, but its kids processes may co-exist
1619 if (!IamMasterProcess())
1627 pid
= readPidFile();
1632 if (kill(pid
, 0) < 0)
1635 debugs(0, DBG_CRITICAL
, "Squid is already running! Process ID " << pid
);
1641 watch_child(char *argv
[])
1643 #if !_SQUID_WINDOWS_
1661 if (!IamMasterProcess())
1664 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1666 if ((pid
= fork()) < 0)
1667 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1672 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1678 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1679 ioctl(i
, TIOCNOTTY
, NULL
);
1686 * RBCOLLINS - if cygwin stackdumps when squid is run without
1687 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1688 * 1.1.3. execvp had a bit overflow error in a loop..
1690 /* Connect stdio to /dev/null in daemon mode */
1691 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1694 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1698 if (Debug::log_stderr
< 0) {
1703 // handle shutdown notifications from kids
1704 squid_signal(SIGUSR1
, sig_shutdown
, SA_RESTART
);
1706 if (Config
.workers
> 128) {
1707 syslog(LOG_ALERT
, "Suspiciously high workers value: %d",
1709 // but we keep going in hope that user knows best
1713 syslog(LOG_NOTICE
, "Squid Parent: will start %d kids", (int)TheKids
.count());
1715 // keep [re]starting kids until it is time to quit
1717 mainStartScript(argv
[0]);
1719 // start each kid that needs to be [re]started; once
1720 for (int i
= TheKids
.count() - 1; i
>= 0; --i
) {
1721 Kid
& kid
= TheKids
.get(i
);
1722 if (!kid
.shouldRestart())
1725 if ((pid
= fork()) == 0) {
1727 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1729 argv
[0] = const_cast<char*>(kid
.name().termedBuf());
1731 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1735 syslog(LOG_NOTICE
, "Squid Parent: %s process %d started",
1736 kid
.name().termedBuf(), pid
);
1740 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1742 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1746 pid
= wait3(&status
, 0, NULL
);
1750 pid
= waitpid(-1, &status
, 0);
1753 // Loop to collect all stopped kids before we go to sleep below.
1755 Kid
* kid
= TheKids
.find(pid
);
1758 if (kid
->calledExit()) {
1760 "Squid Parent: %s process %d exited with status %d",
1761 kid
->name().termedBuf(),
1762 kid
->getPid(), kid
->exitStatus());
1763 } else if (kid
->signaled()) {
1765 "Squid Parent: %s process %d exited due to signal %d with status %d",
1766 kid
->name().termedBuf(),
1767 kid
->getPid(), kid
->termSignal(), kid
->exitStatus());
1769 syslog(LOG_NOTICE
, "Squid Parent: %s process %d exited",
1770 kid
->name().termedBuf(), kid
->getPid());
1772 if (kid
->hopeless()) {
1773 syslog(LOG_NOTICE
, "Squid Parent: %s process %d will not"
1774 " be restarted due to repeated, frequent failures",
1775 kid
->name().termedBuf(), kid
->getPid());
1778 syslog(LOG_NOTICE
, "Squid Parent: unknown child process %d exited", pid
);
1781 } while ((pid
= wait3(&status
, WNOHANG
, NULL
)) > 0);
1784 while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0);
1787 if (!TheKids
.someRunning() && !TheKids
.shouldRestartSome()) {
1789 // XXX: Master process has no main loop and, hence, should not call
1790 // RegisteredRunner::startShutdown which promises a loop iteration.
1791 RunRegisteredHere(RegisteredRunner::finishShutdown
);
1794 if (TheKids
.someSignaled(SIGINT
) || TheKids
.someSignaled(SIGTERM
)) {
1795 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1799 if (TheKids
.allHopeless()) {
1800 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1807 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1812 #endif /* _SQUID_WINDOWS_ */
1819 /* XXX: This function is called after the main loop has quit, which
1820 * means that no AsyncCalls would be called, including close handlers.
1821 * TODO: We need to close/shut/free everything that needs calls before
1825 #if USE_WIN32_SERVICE
1826 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1829 debugs(1, DBG_IMPORTANT
, "Shutting down...");
1832 Ssl::Helper::GetInstance()->Shutdown();
1835 if (Ssl::CertValidationHelper::GetInstance())
1836 Ssl::CertValidationHelper::GetInstance()->Shutdown();
1839 externalAclShutdown();
1849 wccpConnectionClose();
1853 wccp2ConnectionClose();
1856 releaseServerSockets();
1857 commCloseAllSockets();
1864 DelayPools::FreePools();
1867 authenticateReset();
1869 #if USE_WIN32_SERVICE
1871 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1874 Store::Root().sync(); /* Flush pending object writes/unlinks */
1876 unlinkdClose(); /* after sync/flush. NOP if !USE_UNLINKD */
1878 storeDirWriteCleanLogs(0);
1881 Store::Root().sync(); /* Flush log writes */
1884 Store::Root().sync(); /* Flush log close */
1885 StoreFileSystem::FreeAllFs();
1886 DiskIOModule::FreeAllModules();
1887 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1891 /*stmemFreeMemory(); */
1893 ipcacheFreeMemory();
1894 fqdncacheFreeMemory();
1896 clientdbFreeMemory();
1897 httpHeaderCleanModule();
1903 // clear StoreController
1912 RunRegisteredHere(RegisteredRunner::finishShutdown
);
1914 if (IamPrimaryProcess()) {
1915 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1917 safeunlink(Config
.pidFilename
, 0);
1922 debugs(1, DBG_IMPORTANT
, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1926 * We used to fclose(debug_log) here if it was set, but then
1927 * we forgot to set it to NULL. That caused some coredumps
1928 * because exit() ends up calling a bunch of destructors and
1929 * such. So rather than forcing the debug_log to close, we'll
1930 * leave it open so that those destructors can write some
1931 * debugging if necessary. The file will be closed anyway when
1932 * the process truly exits.
1935 exit(shutdown_status
);