2 * DEBUG: section 01 Startup and Main Loop
3 * AUTHOR: Harvest Derived
5 * SQUID Web Proxy Cache http://www.squid-cache.org/
6 * ----------------------------------------------------------
8 * Squid is the result of efforts by numerous individuals from
9 * the Internet community; see the CONTRIBUTORS file for full
10 * details. Many organizations have provided support for Squid's
11 * development; see the SPONSORS file for full details. Squid is
12 * Copyrighted (C) 2001 by the Regents of the University of
13 * California; see the COPYRIGHT file for full details. Squid
14 * incorporates software developed and/or copyrighted by other
15 * sources; see the CREDITS file for full details.
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 2 of the License, or
20 * (at your option) any later version.
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
27 * You should have received a copy of the GNU General Public License
28 * along with this program; if not, write to the Free Software
29 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 #include "AccessLogEntry.h"
38 #include "base/RunnersRegistry.h"
39 #include "base/Subscription.h"
40 #include "base/TextException.h"
43 #include "client_db.h"
44 #include "client_side.h"
46 #include "ConfigParser.h"
47 #include "CpuAffinity.h"
49 #include "DiskIO/DiskIOModule.h"
50 #include "errorpage.h"
52 #include "EventLoop.h"
53 #include "ExternalACL.h"
55 #include "format/Token.h"
56 #include "fqdncache.h"
57 #include "fs/Module.h"
61 #include "HttpHeader.h"
62 #include "HttpReply.h"
63 #include "icmp/IcmpSquid.h"
64 #include "icmp/net_db.h"
66 #include "ident/Ident.h"
68 #include "ipc/Coordinator.h"
70 #include "ipc/Strand.h"
75 #include "neighbors.h"
76 #include "parser/Tokenizer.h"
78 #include "peer_sourcehash.h"
79 #include "peer_userhash.h"
80 #include "PeerSelectState.h"
81 #include "profiler/Profiler.h"
84 #include "send-announce.h"
85 #include "SquidConfig.h"
87 #include "SquidTime.h"
89 #include "StatCounters.h"
91 #include "store_log.h"
92 #include "StoreFileSystem.h"
102 #include "adaptation/Config.h"
105 #include "adaptation/ecap/Config.h"
108 #include "adaptation/icap/Config.h"
109 #include "adaptation/icap/icap_log.h"
112 #include "auth/Gadgets.h"
115 #include "ClientDelayConfig.h"
118 #include "DelayPools.h"
120 #if USE_LOADABLE_MODULES
121 #include "LoadableModules.h"
124 #include "ssl/certificate_db.h"
127 #include "ssl/context_storage.h"
128 #include "ssl/helper.h"
131 #include "adaptation/icap/Config.h"
134 #include "adaptation/ecap/Config.h"
137 #include "adaptation/Config.h"
140 #include "esi/Module.h"
143 #include "snmp_core.h"
151 #include <sys/wait.h>
154 #if USE_WIN32_SERVICE
157 static int opt_install_service
= FALSE
;
158 static int opt_remove_service
= FALSE
;
159 static int opt_command_line
= FALSE
;
160 void WIN32_svcstatusupdate(DWORD
, DWORD
);
161 void WINAPI
WIN32_svcHandler(DWORD
);
164 static int opt_signal_service
= FALSE
;
165 static char *opt_syslog_facility
= NULL
;
166 static int icpPortNumOverride
= 1; /* Want to detect "-u 0" */
167 static int configured_once
= 0;
169 static int malloc_debug_level
= 0;
171 static volatile int do_reconfigure
= 0;
172 static volatile int do_rotate
= 0;
173 static volatile int do_shutdown
= 0;
174 static volatile int shutdown_status
= 0;
176 static int RotateSignal
= -1;
177 static int ReconfigureSignal
= -1;
178 static int ShutdownSignal
= -1;
180 static void mainRotate(void);
181 static void mainReconfigureStart(void);
182 static void mainReconfigureFinish(void*);
183 static void mainInitialize(void);
184 static void usage(void);
185 static void mainParseOptions(int argc
, char *argv
[]);
186 static void sendSignal(void);
187 static void serverConnectionsOpen(void);
188 static void serverConnectionsClose(void);
189 static void watch_child(char **);
190 static void setEffectiveUser(void);
191 static void SquidShutdown(void);
192 static void mainSetCwd(void);
193 static int checkRunningPid(void);
196 static const char *squid_start_script
= "squid_start";
200 #include "test_access.c"
203 /** temporary thunk across to the unrefactored store interface */
205 class StoreRootEngine
: public AsyncEngine
209 int checkEvents(int timeout
) {
210 Store::Root().callback();
215 class SignalEngine
: public AsyncEngine
219 virtual int checkEvents(int timeout
);
222 static void StopEventLoop(void *) {
223 if (EventLoop::Running
)
224 EventLoop::Running
->stop();
227 void doShutdown(time_t wait
);
231 SignalEngine::checkEvents(int timeout
)
233 PROF_start(SignalEngine_checkEvents
);
235 if (do_reconfigure
) {
236 mainReconfigureStart();
238 } else if (do_rotate
) {
241 } else if (do_shutdown
) {
242 doShutdown(do_shutdown
> 0 ? (int) Config
.shutdownLifetime
: 0);
245 BroadcastSignalIfAny(DebugSignal
);
246 BroadcastSignalIfAny(RotateSignal
);
247 BroadcastSignalIfAny(ReconfigureSignal
);
248 BroadcastSignalIfAny(ShutdownSignal
);
250 PROF_stop(SignalEngine_checkEvents
);
255 SignalEngine::doShutdown(time_t wait
)
257 debugs(1, DBG_IMPORTANT
, "Preparing for shutdown after " << statCounter
.client_http
.requests
<< " requests");
258 debugs(1, DBG_IMPORTANT
, "Waiting " << wait
<< " seconds for active connections to finish");
262 #if USE_WIN32_SERVICE
263 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, (wait
+ 1) * 1000);
266 /* run the closure code which can be shared with reconfigure */
267 serverConnectionsClose();
269 /* detach the auth components (only do this on full shutdown) */
270 Auth::Scheme::FreeAll();
273 RunRegisteredHere(RegisteredRunner::startShutdown
);
274 eventAdd("SquidShutdown", &StopEventLoop
, this, (double) (wait
+ 1), 1, false);
281 "Usage: %s [-cdhvzCFNRVYX] [-n name] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]"
282 #if USE_WIN32_SERVICE
283 "[-ir] [-O CommandLine]"
286 " -a port Specify HTTP port number (default: %d).\n"
287 " -d level Write debugging to stderr also.\n"
288 " -f file Use given config-file instead of\n"
290 " -h Print help message.\n"
291 #if USE_WIN32_SERVICE
292 " -i Installs as a Windows Service (see -n option).\n"
294 " -k reconfigure|rotate|shutdown|"
298 "interrupt|kill|debug|check|parse\n"
299 " Parse configuration file, then send signal to \n"
300 " running copy (except -k parse) and exit.\n"
301 " -n name Specify service name to use for service operations\n"
302 " default is: " APP_SHORTNAME
".\n"
303 #if USE_WIN32_SERVICE
304 " -r Removes a Windows Service (see -n option).\n"
306 " -s | -l facility\n"
307 " Enable logging to syslog.\n"
308 " -u port Specify ICP port number (default: %d), disable with 0.\n"
309 " -v Print version.\n"
310 " -z Create missing swap directories and then exit.\n"
311 " -C Do not catch fatal signals.\n"
312 " -D OBSOLETE. Scheduled for removal.\n"
313 " -F Don't serve any requests until store is rebuilt.\n"
314 " -N No daemon mode.\n"
315 #if USE_WIN32_SERVICE
317 " Set Windows Service Command line options in Registry.\n"
319 " -R Do not set REUSEADDR on port.\n"
320 " -S Double-check swap during rebuild.\n"
321 " -X Force full debugging.\n"
322 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
323 APP_SHORTNAME
, CACHE_HTTP_PORT
, DefaultConfigFile
, CACHE_ICP_PORT
);
328 * Parse the parameters received via command line interface.
330 \param argc Number of options received on command line
331 \param argv List of parameters received on command line
334 mainParseOptions(int argc
, char *argv
[])
339 #if USE_WIN32_SERVICE
340 while ((c
= getopt(argc
, argv
, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
342 while ((c
= getopt(argc
, argv
, "CDFNRSYXa:d:f:hk:m::n:sl:u:vz?")) != -1)
350 * Unset/disabel global option for catchign signals. opt_catch_signals */
351 opt_catch_signals
= 0;
356 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
357 debugs(1,DBG_CRITICAL
, "WARNING: -D command-line option is obsolete.");
362 * Set global option for foreground rebuild. opt_foreground_rebuild */
363 opt_foreground_rebuild
= 1;
368 * Set global option for 'no_daemon' mode. opt_no_daemon */
372 #if USE_WIN32_SERVICE
376 * Set global option. opt_command_lin and WIN32_Command_Line */
377 opt_command_line
= 1;
378 WIN32_Command_Line
= xstrdup(optarg
);
384 * Unset/disable global option opt_reuseaddr */
390 * Set global option opt_store_doublecheck */
391 opt_store_doublecheck
= 1;
396 * Force full debugging */
397 Debug::parseOptions("rotate=0 ALL,9");
398 Debug::override_X
= 1;
399 sigusr2_handle(SIGUSR2
);
404 * Set global option opt_reload_hit_only */
405 opt_reload_hit_only
= 1;
408 #if USE_WIN32_SERVICE
412 * Set global option opt_install_service (to TRUE) */
413 opt_install_service
= TRUE
;
419 * Add optional HTTP port as given following the option */
420 add_http_port(optarg
);
425 * Set global option Debug::log_stderr to the number given follwoign the option */
426 Debug::log_stderr
= atoi(optarg
);
431 * Load the file given instead of the default squid.conf. */
433 ConfigFile
= xstrdup(optarg
);
438 * Run the administrative action given following the option */
440 /** \li When its an unknown option display the usage help. */
441 if ((int) strlen(optarg
) < 1)
444 if (!strncmp(optarg
, "reconfigure", strlen(optarg
)))
445 /** \li On reconfigure send SIGHUP. */
446 opt_send_signal
= SIGHUP
;
447 else if (!strncmp(optarg
, "rotate", strlen(optarg
)))
448 /** \li On rotate send SIGQUIT or SIGUSR1. */
449 #if defined(_SQUID_LINUX_THREADS_)
450 opt_send_signal
= SIGQUIT
;
452 opt_send_signal
= SIGUSR1
;
455 else if (!strncmp(optarg
, "debug", strlen(optarg
)))
456 /** \li On debug send SIGTRAP or SIGUSR2. */
457 #if defined(_SQUID_LINUX_THREADS_)
458 opt_send_signal
= SIGTRAP
;
460 opt_send_signal
= SIGUSR2
;
463 else if (!strncmp(optarg
, "shutdown", strlen(optarg
)))
464 /** \li On shutdown send SIGTERM. */
465 opt_send_signal
= SIGTERM
;
466 else if (!strncmp(optarg
, "interrupt", strlen(optarg
)))
467 /** \li On interrupt send SIGINT. */
468 opt_send_signal
= SIGINT
;
469 else if (!strncmp(optarg
, "kill", strlen(optarg
)))
470 /** \li On kill send SIGKILL. */
471 opt_send_signal
= SIGKILL
;
475 else if (!strncmp(optarg
, "restart", strlen(optarg
)))
476 /** \li On restart send SIGTTIN. (exit and restart by parent) */
477 opt_send_signal
= SIGTTIN
;
481 else if (!strncmp(optarg
, "check", strlen(optarg
)))
482 /** \li On check send 0 / SIGNULL. */
483 opt_send_signal
= 0; /* SIGNULL */
484 else if (!strncmp(optarg
, "parse", strlen(optarg
)))
485 /** \li On parse set global flag to re-parse the config file only. */
486 opt_parse_cfg_only
= 1;
494 * Set global malloc_debug_level to the value given following the option.
495 * if none is given it toggles the xmalloc_trace option on/off */
498 malloc_debug_level
= atoi(optarg
);
500 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
508 * Set global option opt_signal_service (to true).
509 * Stores the additional parameter given in global service_name */
510 if (optarg
&& *optarg
!= '\0') {
511 const SBuf
t(optarg
);
512 ::Parser::Tokenizer
tok(t
);
513 const CharacterSet chr
= CharacterSet::ALPHA
+CharacterSet::DIGIT
;
514 if (!tok
.prefix(service_name
, chr
) || !tok
.atEnd())
515 fatalf("Expected alphanumeric service name for the -n option but got: " SQUIDSBUFPH
, SQUIDSBUFPRINT(service_name
));
516 if (service_name
.length() > 32)
517 fatalf("Service name (-n option) must be limited to 32 characters but got %u", service_name
.length());
518 opt_signal_service
= true;
520 fatal("A service name is required for the -n option");
524 #if USE_WIN32_SERVICE
528 * Set global option opt_remove_service (to TRUE) */
529 opt_remove_service
= TRUE
;
537 * Stores the syslog facility name in global opt_syslog_facility
538 * then performs actions for -s option. */
539 xfree(opt_syslog_facility
); // ignore any previous options sent
540 opt_syslog_facility
= xstrdup(optarg
);
544 * Initialize the syslog for output */
547 _db_set_syslog(opt_syslog_facility
);
553 fatal("Logging to syslog not available on this platform");
560 * Store the ICP port number given in global option icpPortNumOverride
561 * ensuring its a positive number. */
562 icpPortNumOverride
= atoi(optarg
);
564 if (icpPortNumOverride
< 0)
565 icpPortNumOverride
= 0;
571 * Display squid version and build information. Then exit. */
572 printf("Squid Cache: Version %s\n" ,version_string
);
573 printf("Service Name: " SQUIDSBUFPH
"\n", SQUIDSBUFPRINT(service_name
));
574 if (strlen(SQUID_BUILD_INFO
))
575 printf("%s\n",SQUID_BUILD_INFO
);
576 printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS
);
578 #if USE_WIN32_SERVICE
580 printf("Compiled as Windows System Service.\n");
590 * Set global option Debug::log_stderr and opt_create_swap_dirs */
591 Debug::log_stderr
= 1;
592 opt_create_swap_dirs
= 1;
600 /** \par h,?, or unknown
601 * \copydoc usage() */
619 signal(sig
, rotate_logs
);
629 ReconfigureSignal
= sig
;
633 signal(sig
, reconfigure
);
641 do_shutdown
= sig
== SIGINT
? -1 : 1;
642 ShutdownSignal
= sig
;
650 const pid_t ppid
= getppid();
652 if (!IamMasterProcess() && ppid
> 1) {
653 // notify master that we are shutting down
654 if (kill(ppid
, SIGUSR1
) < 0)
655 debugs(1, DBG_IMPORTANT
, "Failed to send SIGUSR1 to master process,"
656 " pid " << ppid
<< ": " << xstrerror());
662 if (!IamMasterProcess() && ppid
> 1) {
663 debugs(1, DBG_IMPORTANT
, "Killing master process, pid " << ppid
);
665 if (kill(ppid
, sig
) < 0)
666 debugs(1, DBG_IMPORTANT
, "kill " << ppid
<< ": " << xstrerror());
669 #endif /* KILL_PARENT_OPT */
670 #if SA_RESETHAND == 0
671 signal(SIGTERM
, SIG_DFL
);
673 signal(SIGINT
, SIG_DFL
);
680 serverConnectionsOpen(void)
682 if (IamPrimaryProcess()) {
684 wccpConnectionOpen();
689 wccp2ConnectionOpen();
692 // start various proxying services if we are responsible for them
693 if (IamWorkerProcess()) {
694 clientOpenListenSockets();
713 peerSourceHashInit();
718 serverConnectionsClose(void)
720 assert(shutting_down
|| reconfiguring
);
722 if (IamPrimaryProcess()) {
725 wccpConnectionClose();
729 wccp2ConnectionClose();
732 if (IamWorkerProcess()) {
733 clientConnectionsClose();
734 icpConnectionShutdown();
736 htcpSocketShutdown();
749 mainReconfigureStart(void)
751 debugs(1, DBG_IMPORTANT
, "Reconfiguring Squid Cache (version " << version_string
<< ")...");
754 // Initiate asynchronous closing sequence
755 serverConnectionsClose();
762 Ssl::Helper::GetInstance()->Shutdown();
765 if (Ssl::CertValidationHelper::GetInstance())
766 Ssl::CertValidationHelper::GetInstance()->Shutdown();
767 Ssl::TheGlobalContextStorage
.reconfigureStart();
773 externalAclShutdown();
774 storeDirCloseSwapLogs();
781 eventAdd("mainReconfigureFinish", &mainReconfigureFinish
, NULL
, 0, 1,
786 mainReconfigureFinish(void *)
788 debugs(1, 3, "finishing reconfiguring");
791 enter_suid(); /* root to read config file */
793 // we may have disabled the need for PURGE
794 if (Config2
.onoff
.enable_purge
)
795 Config2
.onoff
.enable_purge
= 2;
797 // parse the config returns a count of errors encountered.
798 const int oldWorkers
= Config
.workers
;
799 if ( parseConfigFile(ConfigFile
) != 0) {
800 // for now any errors are a fatal condition...
803 if (oldWorkers
!= Config
.workers
) {
804 debugs(1, DBG_CRITICAL
, "WARNING: Changing 'workers' (from " <<
805 oldWorkers
<< " to " << Config
.workers
<<
806 ") requires a full restart. It has been ignored by reconfigure.");
807 Config
.workers
= oldWorkers
;
810 RunRegisteredHere(RegisteredRunner::syncConfig
);
812 if (IamPrimaryProcess())
814 CpuAffinityReconfigure();
816 setUmask(Config
.umask
);
819 _db_init(Debug::cache_log
, Debug::debugOptions
);
820 ipcache_restart(); /* clear stuck entries */
821 fqdncache_restart(); /* sigh, fqdncache too */
823 errorInitialize(); /* reload error pages */
826 #if USE_LOADABLE_MODULES
827 LoadableModulesConfigure(Config
.loadable_module_names
);
831 bool enableAdaptation
= false;
833 Adaptation::Icap::TheConfig
.finalize();
834 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
837 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
838 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
840 Adaptation::Config::Finalize(enableAdaptation
);
849 Ssl::Helper::GetInstance()->Init();
852 if (Ssl::CertValidationHelper::GetInstance())
853 Ssl::CertValidationHelper::GetInstance()->Init();
858 authenticateInit(&Auth::TheConfig
);
862 if (IamPrimaryProcess()) {
873 serverConnectionsOpen();
877 storeDirOpenSwapLogs();
879 mimeInit(Config
.mimeTablePathname
);
885 Config
.ClientDelay
.finalize();
888 if (Config
.onoff
.announce
) {
889 if (!eventFind(start_announce
, NULL
))
890 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
892 if (eventFind(start_announce
, NULL
))
893 eventDelete(start_announce
, NULL
);
896 writePidFile(); /* write PID file */
907 authenticateRotate();
909 externalAclShutdown();
911 _db_rotate_log(); /* cache.log */
912 storeDirWriteCleanLogs(1);
913 storeLogRotate(); /* store.log */
914 accessLogRotate(); /* access.log */
916 icapLogRotate(); /*icap.log*/
921 authenticateInit(&Auth::TheConfig
);
927 setEffectiveUser(void)
930 leave_suid(); /* Run as non privilegied user */
936 if (geteuid() == 0) {
937 debugs(0, DBG_CRITICAL
, "Squid is not safe to run as root! If you must");
938 debugs(0, DBG_CRITICAL
, "start Squid as root, then you must configure");
939 debugs(0, DBG_CRITICAL
, "it to run as a non-priveledged user with the");
940 debugs(0, DBG_CRITICAL
, "'cache_effective_user' option in the config file.");
941 fatal("Don't run Squid as root, set 'cache_effective_user'!");
945 /// changes working directory, providing error reporting
947 mainChangeDir(const char *dir
)
952 debugs(50, DBG_CRITICAL
, "cannot change current directory to " << dir
<<
953 ": " << xstrerror());
957 /// set the working directory.
961 static bool chrooted
= false;
962 if (Config
.chroot_dir
&& !chrooted
) {
965 if (chroot(Config
.chroot_dir
) != 0)
966 fatalf("chroot to %s failed: %s", Config
.chroot_dir
, xstrerror());
968 if (!mainChangeDir("/"))
969 fatalf("chdir to / after chroot to %s failed", Config
.chroot_dir
);
972 if (Config
.coredump_dir
&& strcmp("none", Config
.coredump_dir
) != 0) {
973 if (mainChangeDir(Config
.coredump_dir
)) {
974 debugs(0, DBG_IMPORTANT
, "Set Current Directory to " << Config
.coredump_dir
);
979 /* If we don't have coredump_dir or couldn't cd there, report current dir */
980 char pathbuf
[MAXPATHLEN
];
981 if (getcwd(pathbuf
, MAXPATHLEN
)) {
982 debugs(0, DBG_IMPORTANT
, "Current Directory is " << pathbuf
);
984 debugs(50, DBG_CRITICAL
, "WARNING: Can't find current directory, getcwd: " << xstrerror());
991 /* chroot if configured to run inside chroot */
994 if (opt_catch_signals
) {
995 squid_signal(SIGSEGV
, death
, SA_NODEFER
| SA_RESETHAND
);
996 squid_signal(SIGBUS
, death
, SA_NODEFER
| SA_RESETHAND
);
999 squid_signal(SIGPIPE
, SIG_IGN
, SA_RESTART
);
1000 squid_signal(SIGCHLD
, sig_child
, SA_NODEFER
| SA_RESTART
);
1004 if (icpPortNumOverride
!= 1)
1005 Config
.Port
.icp
= (unsigned short) icpPortNumOverride
;
1007 _db_init(Debug::cache_log
, Debug::debugOptions
);
1009 fd_open(fileno(debug_log
), FD_LOG
, Debug::cache_log
);
1011 debugs(1, DBG_CRITICAL
, "Starting Squid Cache version " << version_string
<< " for " << CONFIG_HOST_TYPE
<< "...");
1012 debugs(1, DBG_CRITICAL
, "Service Name: " << service_name
);
1015 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
1016 debugs(1, DBG_CRITICAL
, "Service command line is: " << WIN32_Service_Command_Line
);
1018 debugs(1, DBG_CRITICAL
, "Running on " << WIN32_OS_string
);
1021 debugs(1, DBG_IMPORTANT
, "Process ID " << getpid());
1023 debugs(1, DBG_IMPORTANT
, "Process Roles:" << ProcessRoles());
1026 debugs(1, DBG_IMPORTANT
, "With " << Squid_MaxFD
<< " file descriptors available");
1030 debugs(1, DBG_IMPORTANT
, "With " << _getmaxstdio() << " CRT stdio descriptors available");
1032 if (WIN32_Socks_initialized
)
1033 debugs(1, DBG_IMPORTANT
, "Windows sockets initialized");
1035 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
1036 WIN32_IpAddrChangeMonitorInit();
1041 if (!configured_once
)
1042 disk_init(); /* disk_init must go before ipcache_init() */
1053 Ssl::Helper::GetInstance()->Init();
1057 if (!configured_once
)
1058 Ssl::initialize_session_cache();
1060 if (Ssl::CertValidationHelper::GetInstance())
1061 Ssl::CertValidationHelper::GetInstance()->Init();
1066 authenticateInit(&Auth::TheConfig
);
1070 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
1072 httpReplyInitModule(); /* must go before accepting replies */
1093 malloc_debug(0, malloc_debug_level
);
1097 if (!configured_once
) {
1098 if (unlinkdNeeded())
1105 mimeInit(Config
.mimeTablePathname
);
1111 FwdState::initModule();
1112 /* register the modules in the cache manager menus */
1114 cbdataRegisterWithCacheManager();
1115 /* These use separate calls so that the comm loops can eventually
1121 // TODO: pconn is a good candidate for new-style registration
1122 // PconnModule::GetInstance()->registerWithCacheManager();
1123 // moved to PconnModule::PconnModule()
1126 if (IamPrimaryProcess()) {
1138 serverConnectionsOpen();
1142 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
1144 if (Config
.chroot_dir
)
1147 if (!configured_once
)
1148 writePidFile(); /* write PID file */
1150 #if defined(_SQUID_LINUX_THREADS_)
1152 squid_signal(SIGQUIT
, rotate_logs
, SA_RESTART
);
1154 squid_signal(SIGTRAP
, sigusr2_handle
, SA_RESTART
);
1158 squid_signal(SIGUSR1
, rotate_logs
, SA_RESTART
);
1160 squid_signal(SIGUSR2
, sigusr2_handle
, SA_RESTART
);
1164 squid_signal(SIGHUP
, reconfigure
, SA_RESTART
);
1166 squid_signal(SIGTERM
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1168 squid_signal(SIGINT
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1172 squid_signal(SIGTTIN
, shut_down
, SA_NODEFER
| SA_RESETHAND
| SA_RESTART
);
1178 #if USE_LOADABLE_MODULES
1179 LoadableModulesConfigure(Config
.loadable_module_names
);
1183 bool enableAdaptation
= false;
1185 // We can remove this dependency on specific adaptation mechanisms
1186 // if we create a generic Registry of such mechanisms. Should we?
1188 Adaptation::Icap::TheConfig
.finalize();
1189 enableAdaptation
= Adaptation::Icap::TheConfig
.onoff
|| enableAdaptation
;
1192 Adaptation::Ecap::TheConfig
.finalize(); // must be after we load modules
1193 enableAdaptation
= Adaptation::Ecap::TheConfig
.onoff
|| enableAdaptation
;
1195 // must be the last adaptation-related finalize
1196 Adaptation::Config::Finalize(enableAdaptation
);
1204 Config
.ClientDelay
.finalize();
1207 if (!configured_once
) {
1208 eventAdd("storeMaintain", Store::Maintain
, NULL
, 1.0, 1);
1210 if (Config
.onoff
.announce
)
1211 eventAdd("start_announce", start_announce
, NULL
, 3600.0, 1);
1213 eventAdd("ipcache_purgelru", ipcache_purgelru
, NULL
, 10.0, 1);
1215 eventAdd("fqdncache_purgelru", fqdncache_purgelru
, NULL
, 15.0, 1);
1219 eventAdd("cpuProfiling", xprof_event
, NULL
, 1.0, 1);
1223 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools
, NULL
, 15.0, 1);
1226 configured_once
= 1;
1229 /// unsafe main routine -- may throw
1230 int SquidMain(int argc
, char **argv
);
1231 /// unsafe main routine wrapper to catch exceptions
1232 static int SquidMainSafe(int argc
, char **argv
);
1234 #if USE_WIN32_SERVICE
1235 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1236 extern "C" void WINAPI
1237 SquidWinSvcMain(int argc
, char **argv
)
1239 SquidMainSafe(argc
, argv
);
1243 main(int argc
, char **argv
)
1245 return SquidMainSafe(argc
, argv
);
1250 SquidMainSafe(int argc
, char **argv
)
1253 return SquidMain(argc
, argv
);
1254 } catch (const std::exception
&e
) {
1255 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception: " <<
1259 debugs(1, DBG_CRITICAL
, "FATAL: dying from an unhandled exception.");
1262 return -1; // not reached
1265 /// computes name and ID for the current kid process
1267 ConfigureCurrentKid(const char *processName
)
1269 // kids are marked with parenthesis around their process names
1270 if (processName
&& processName
[0] == '(') {
1271 if (const char *idStart
= strrchr(processName
, '-')) {
1272 KidIdentifier
= atoi(idStart
+ 1);
1273 const size_t nameLen
= idStart
- (processName
+ 1);
1274 assert(nameLen
< sizeof(TheKidName
));
1275 xstrncpy(TheKidName
, processName
+ 1, nameLen
+ 1);
1276 if (!strcmp(TheKidName
, "squid-coord"))
1277 TheProcessKind
= pkCoordinator
;
1278 else if (!strcmp(TheKidName
, "squid"))
1279 TheProcessKind
= pkWorker
;
1280 else if (!strcmp(TheKidName
, "squid-disk"))
1281 TheProcessKind
= pkDisker
;
1283 TheProcessKind
= pkOther
; // including coordinator
1286 xstrncpy(TheKidName
, APP_SHORTNAME
, sizeof(TheKidName
));
1292 SquidMain(int argc
, char **argv
)
1294 ConfigureCurrentKid(argv
[0]);
1296 Debug::parseOptions(NULL
);
1299 #if defined(SQUID_MAXFD_LIMIT)
1301 if (SQUID_MAXFD_LIMIT
< Squid_MaxFD
)
1302 Squid_MaxFD
= SQUID_MAXFD_LIMIT
;
1306 /* NOP under non-windows */
1307 int WIN32_init_err
=0;
1308 if ((WIN32_init_err
= WIN32_Subsystem_Init(&argc
, &argv
)))
1309 return WIN32_init_err
;
1311 /* call mallopt() before anything else */
1314 /* Round up all sizes to a multiple of this */
1315 mallopt(M_GRAIN
, 16);
1319 /* biggest size that is considered a small block */
1320 mallopt(M_MXFAST
, 256);
1324 /* allocate this many small blocks at once */
1325 mallopt(M_NLBLKS
, 32);
1328 #endif /* HAVE_MALLOPT */
1330 squid_srandom(time(NULL
));
1334 squid_start
= current_time
;
1336 failure_notify
= fatal_dump
;
1338 #if USE_WIN32_SERVICE
1340 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1344 mainParseOptions(argc
, argv
);
1346 if (opt_parse_cfg_only
) {
1347 Debug::parseOptions("ALL,1");
1350 #if USE_WIN32_SERVICE
1352 if (opt_install_service
) {
1353 WIN32_InstallService();
1357 if (opt_remove_service
) {
1358 WIN32_RemoveService();
1362 if (opt_command_line
) {
1363 WIN32_SetServiceCommandLine();
1369 /* parse configuration file
1370 * note: in "normal" case this used to be called from mainInitialize() */
1375 ConfigFile
= xstrdup(DefaultConfigFile
);
1377 assert(!configured_once
);
1381 storeFsInit(); /* required for config parsing */
1383 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
1386 /* May not be needed for parsing, have not audited for such */
1387 DiskIOModule::SetupAllModules();
1389 /* Shouldn't be needed for config parsing, but have not audited for such */
1390 StoreFileSystem::SetupAllFs();
1392 /* we may want the parsing process to set this up in the future */
1393 Store::Root(new StoreController
);
1394 Auth::Init(); /* required for config parsing. NOP if !USE_AUTH */
1395 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
1397 Format::Token::Init(); // XXX: temporary. Use a runners registry of pre-parse runners instead.
1399 parse_err
= parseConfigFile(ConfigFile
);
1403 if (opt_parse_cfg_only
|| parse_err
> 0)
1406 setUmask(Config
.umask
);
1407 if (-1 == opt_send_signal
)
1408 if (checkRunningPid())
1423 /* send signal to running copy and exit */
1424 if (opt_send_signal
!= -1) {
1425 /* chroot if configured to run inside chroot */
1427 if (Config
.chroot_dir
) {
1437 debugs(1,2, HERE
<< "Doing post-config initialization\n");
1439 RunRegisteredHere(RegisteredRunner::finalizeConfig
);
1440 RunRegisteredHere(RegisteredRunner::claimMemoryNeeds
);
1441 RunRegisteredHere(RegisteredRunner::useConfig
);
1444 if (!opt_no_daemon
&& Config
.workers
> 0)
1447 if (opt_create_swap_dirs
) {
1448 /* chroot if configured to run inside chroot */
1452 debugs(0, DBG_CRITICAL
, "Creating missing swap directories");
1453 Store::Root().create();
1458 if (IamPrimaryProcess())
1464 /* init comm module */
1467 if (opt_no_daemon
) {
1468 /* we have to init fdstat here. */
1469 fd_open(0, FD_LOG
, "stdin");
1470 fd_open(1, FD_LOG
, "stdout");
1471 fd_open(2, FD_LOG
, "stderr");
1474 #if USE_WIN32_SERVICE
1476 WIN32_svcstatusupdate(SERVICE_START_PENDING
, 10000);
1482 #if USE_WIN32_SERVICE
1484 WIN32_svcstatusupdate(SERVICE_RUNNING
, 0);
1491 SignalEngine signalEngine
;
1493 mainLoop
.registerEngine(&signalEngine
);
1495 /* TODO: stop requiring the singleton here */
1496 mainLoop
.registerEngine(EventScheduler::GetInstance());
1498 StoreRootEngine store_engine
;
1500 mainLoop
.registerEngine(&store_engine
);
1502 CommSelectEngine comm_engine
;
1504 mainLoop
.registerEngine(&comm_engine
);
1506 mainLoop
.setPrimaryEngine(&comm_engine
);
1508 /* use the standard time service */
1509 TimeEngine time_engine
;
1511 mainLoop
.setTimeService(&time_engine
);
1513 if (IamCoordinatorProcess())
1514 AsyncJob::Start(Ipc::Coordinator::Instance());
1515 else if (UsingSmp() && (IamWorkerProcess() || IamDiskProcess()))
1516 AsyncJob::Start(new Ipc::Strand
);
1518 /* at this point we are finished the synchronous startup. */
1523 if (mainLoop
.errcount
== 10)
1524 fatal_dump("Event loop exited with failure.");
1526 /* shutdown squid now */
1539 if (strcmp(Config
.pidFilename
, "none") == 0) {
1540 debugs(0, DBG_IMPORTANT
, "No pid_filename specified. Trusting you know what you are doing.");
1543 pid
= readPidFile();
1546 #if USE_WIN32_SERVICE
1547 if (opt_signal_service
) {
1548 WIN32_sendSignal(opt_send_signal
);
1551 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1552 fprintf(stderr
, "signal to Squid Service:\n");
1553 fprintf(stderr
, "missing -n command line switch.\n");
1559 if (kill(pid
, opt_send_signal
) &&
1560 /* ignore permissions if just running check */
1561 !(opt_send_signal
== 0 && errno
== EPERM
)) {
1562 fprintf(stderr
, "%s: ERROR: Could not send ", APP_SHORTNAME
);
1563 fprintf(stderr
, "signal %d to process %d: %s\n",
1564 opt_send_signal
, (int) pid
, xstrerror());
1568 if (opt_send_signal
!= SIGTERM
) {
1569 fprintf(stderr
, "%s: ERROR: No running copy\n", APP_SHORTNAME
);
1572 fprintf(stderr
, "%s: No running copy\n", APP_SHORTNAME
);
1577 /* signal successfully sent */
1581 #if !_SQUID_WINDOWS_
1583 * This function is run when Squid is in daemon mode, just
1584 * before the parent forks and starts up the child process.
1585 * It can be used for admin-specific tasks, such as notifying
1586 * someone that Squid is (re)started.
1589 mainStartScript(const char *prog
)
1591 char script
[MAXPATHLEN
];
1596 xstrncpy(script
, prog
, MAXPATHLEN
);
1598 if ((t
= strrchr(script
, '/'))) {
1600 sl
= strlen(script
);
1603 xstrncpy(&script
[sl
], squid_start_script
, MAXPATHLEN
- sl
);
1605 if ((cpid
= fork()) == 0) {
1607 execl(script
, squid_start_script
, (char *)NULL
);
1613 rpid
= wait4(cpid
, &status
, 0, NULL
);
1617 rpid
= waitpid(cpid
, &status
, 0);
1620 } while (rpid
!= cpid
);
1624 #endif /* _SQUID_WINDOWS_ */
1627 checkRunningPid(void)
1629 // master process must start alone, but its kids processes may co-exist
1630 if (!IamMasterProcess())
1638 pid
= readPidFile();
1643 if (kill(pid
, 0) < 0)
1646 debugs(0, DBG_CRITICAL
, "Squid is already running! Process ID " << pid
);
1652 watch_child(char *argv
[])
1654 #if !_SQUID_WINDOWS_
1672 if (!IamMasterProcess())
1675 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1677 if ((pid
= fork()) < 0)
1678 syslog(LOG_ALERT
, "fork failed: %s", xstrerror());
1683 syslog(LOG_ALERT
, "setsid failed: %s", xstrerror());
1689 if ((i
= open("/dev/tty", O_RDWR
| O_TEXT
)) >= 0) {
1690 ioctl(i
, TIOCNOTTY
, NULL
);
1697 * RBCOLLINS - if cygwin stackdumps when squid is run without
1698 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1699 * 1.1.3. execvp had a bit overflow error in a loop..
1701 /* Connect stdio to /dev/null in daemon mode */
1702 nullfd
= open(_PATH_DEVNULL
, O_RDWR
| O_TEXT
);
1705 fatalf(_PATH_DEVNULL
" %s\n", xstrerror());
1709 if (Debug::log_stderr
< 0) {
1714 // handle shutdown notifications from kids
1715 squid_signal(SIGUSR1
, sig_shutdown
, SA_RESTART
);
1717 if (Config
.workers
> 128) {
1718 syslog(LOG_ALERT
, "Suspiciously high workers value: %d",
1720 // but we keep going in hope that user knows best
1724 syslog(LOG_NOTICE
, "Squid Parent: will start %d kids", (int)TheKids
.count());
1726 // keep [re]starting kids until it is time to quit
1728 mainStartScript(argv
[0]);
1730 // start each kid that needs to be [re]started; once
1731 for (int i
= TheKids
.count() - 1; i
>= 0; --i
) {
1732 Kid
& kid
= TheKids
.get(i
);
1733 if (!kid
.shouldRestart())
1736 if ((pid
= fork()) == 0) {
1738 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1740 argv
[0] = const_cast<char*>(kid
.name().termedBuf());
1742 syslog(LOG_ALERT
, "execvp failed: %s", xstrerror());
1746 syslog(LOG_NOTICE
, "Squid Parent: %s process %d started",
1747 kid
.name().termedBuf(), pid
);
1751 openlog(APP_SHORTNAME
, LOG_PID
| LOG_NDELAY
| LOG_CONS
, LOG_LOCAL4
);
1753 squid_signal(SIGINT
, SIG_IGN
, SA_RESTART
);
1757 pid
= wait3(&status
, 0, NULL
);
1761 pid
= waitpid(-1, &status
, 0);
1764 // Loop to collect all stopped kids before we go to sleep below.
1766 Kid
* kid
= TheKids
.find(pid
);
1769 if (kid
->calledExit()) {
1771 "Squid Parent: %s process %d exited with status %d",
1772 kid
->name().termedBuf(),
1773 kid
->getPid(), kid
->exitStatus());
1774 } else if (kid
->signaled()) {
1776 "Squid Parent: %s process %d exited due to signal %d with status %d",
1777 kid
->name().termedBuf(),
1778 kid
->getPid(), kid
->termSignal(), kid
->exitStatus());
1780 syslog(LOG_NOTICE
, "Squid Parent: %s process %d exited",
1781 kid
->name().termedBuf(), kid
->getPid());
1783 if (kid
->hopeless()) {
1784 syslog(LOG_NOTICE
, "Squid Parent: %s process %d will not"
1785 " be restarted due to repeated, frequent failures",
1786 kid
->name().termedBuf(), kid
->getPid());
1789 syslog(LOG_NOTICE
, "Squid Parent: unknown child process %d exited", pid
);
1792 } while ((pid
= wait3(&status
, WNOHANG
, NULL
)) > 0);
1795 while ((pid
= waitpid(-1, &status
, WNOHANG
)) > 0);
1798 if (!TheKids
.someRunning() && !TheKids
.shouldRestartSome()) {
1800 // XXX: Master process has no main loop and, hence, should not call
1801 // RegisteredRunner::startShutdown which promises a loop iteration.
1802 RunRegisteredHere(RegisteredRunner::finishShutdown
);
1805 if (TheKids
.someSignaled(SIGINT
) || TheKids
.someSignaled(SIGTERM
)) {
1806 syslog(LOG_ALERT
, "Exiting due to unexpected forced shutdown");
1810 if (TheKids
.allHopeless()) {
1811 syslog(LOG_ALERT
, "Exiting due to repeated, frequent failures");
1818 squid_signal(SIGINT
, SIG_DFL
, SA_RESTART
);
1823 #endif /* _SQUID_WINDOWS_ */
1830 /* XXX: This function is called after the main loop has quit, which
1831 * means that no AsyncCalls would be called, including close handlers.
1832 * TODO: We need to close/shut/free everything that needs calls before
1836 #if USE_WIN32_SERVICE
1837 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1840 debugs(1, DBG_IMPORTANT
, "Shutting down...");
1843 Ssl::Helper::GetInstance()->Shutdown();
1846 if (Ssl::CertValidationHelper::GetInstance())
1847 Ssl::CertValidationHelper::GetInstance()->Shutdown();
1850 externalAclShutdown();
1860 wccpConnectionClose();
1864 wccp2ConnectionClose();
1867 releaseServerSockets();
1868 commCloseAllSockets();
1875 DelayPools::FreePools();
1878 authenticateReset();
1880 #if USE_WIN32_SERVICE
1882 WIN32_svcstatusupdate(SERVICE_STOP_PENDING
, 10000);
1885 Store::Root().sync(); /* Flush pending object writes/unlinks */
1887 unlinkdClose(); /* after sync/flush. NOP if !USE_UNLINKD */
1889 storeDirWriteCleanLogs(0);
1892 Store::Root().sync(); /* Flush log writes */
1895 Store::Root().sync(); /* Flush log close */
1896 StoreFileSystem::FreeAllFs();
1897 DiskIOModule::FreeAllModules();
1898 #if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
1902 /*stmemFreeMemory(); */
1904 ipcacheFreeMemory();
1905 fqdncacheFreeMemory();
1907 clientdbFreeMemory();
1908 httpHeaderCleanModule();
1914 // clear StoreController
1921 RunRegisteredHere(RegisteredRunner::finishShutdown
);
1925 if (IamPrimaryProcess()) {
1926 if (Config
.pidFilename
&& strcmp(Config
.pidFilename
, "none") != 0) {
1928 safeunlink(Config
.pidFilename
, 0);
1933 debugs(1, DBG_IMPORTANT
, "Squid Cache (Version " << version_string
<< "): Exiting normally.");
1937 * We used to fclose(debug_log) here if it was set, but then
1938 * we forgot to set it to NULL. That caused some coredumps
1939 * because exit() ends up calling a bunch of destructors and
1940 * such. So rather than forcing the debug_log to close, we'll
1941 * leave it open so that those destructors can write some
1942 * debugging if necessary. The file will be closed anyway when
1943 * the process truly exits.
1946 exit(shutdown_status
);