]> git.ipfire.org Git - thirdparty/squid.git/blame - src/main.cc
Optimized the number of "queue is no longer empty" IpcIo notifications.
[thirdparty/squid.git] / src / main.cc
CommitLineData
30a4f2a8 1/*
262a0e14 2 * $Id$
30a4f2a8 3 *
b510f3a1 4 * DEBUG: section 01 Startup and Main Loop
30a4f2a8 5 * AUTHOR: Harvest Derived
6 *
2b6662ba 7 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 8 * ----------------------------------------------------------
30a4f2a8 9 *
2b6662ba 10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
30a4f2a8 18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
26ac0430 23 *
30a4f2a8 24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
26ac0430 28 *
30a4f2a8 29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
cbdec147 31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 32 *
30a4f2a8 33 */
44a47c6e 34
35#include "squid.h"
450e0c10 36#include "AccessLogEntry.h"
3ff65596
AR
37#if ICAP_CLIENT
38#include "adaptation/icap/icap_log.h"
39#endif
2f1431ea 40#if USE_AUTH
3ad63615 41#include "auth/Gadgets.h"
2f1431ea 42#endif
6d57128b 43#include "base/RunnersRegistry.h"
3d93a84d 44#include "base/TextException.h"
9a0a18de
AJ
45#if USE_DELAY_POOLS
46#include "ClientDelayConfig.h"
47#endif
d841c88d 48#include "comm.h"
62ee09ca 49#include "ConfigParser.h"
96c2bb61 50#include "CpuAffinity.h"
9a0a18de
AJ
51#if USE_DELAY_POOLS
52#include "DelayPools.h"
53#endif
aa839030 54#include "errorpage.h"
a553a5a3 55#include "event.h"
56#include "EventLoop.h"
62ee09ca 57#include "ExternalACL.h"
e6ccf245 58#include "Store.h"
59#include "ICP.h"
4daaf3cb 60#include "ident/Ident.h"
528b2c61 61#include "HttpReply.h"
62ee09ca 62#include "pconn.h"
528b2c61 63#include "Mem.h"
3ad63615
AR
64#include "acl/Asn.h"
65#include "acl/Acl.h"
75faaa7a 66#include "htcp.h"
59b2d47f 67#include "StoreFileSystem.h"
b9ae18aa 68#include "DiskIO/DiskIOModule.h"
40daaeb8 69#include "ipc/Kids.h"
10cefb7b 70#include "ipc/Coordinator.h"
71#include "ipc/Strand.h"
055421ee 72#include "ip/tools.h"
985c86bc 73#include "SquidTime.h"
c8f4eac4 74#include "SwapDir.h"
b6b6f466 75#include "forward.h"
d9e7ee1f 76#include "MemPool.h"
9b5c4a9a
AJ
77#include "icmp/IcmpSquid.h"
78#include "icmp/net_db.h"
f1eaa254 79#include "fs/rock/RockDirMap.h"
44a47c6e 80
57afc994
AR
81#if USE_LOADABLE_MODULES
82#include "LoadableModules.h"
83#endif
84
95d2589c
CT
85#if USE_SSL_CRTD
86#include "ssl/helper.h"
87#include "ssl/certificate_db.h"
88#endif
89
90#if USE_SSL
91#include "ssl/context_storage.h"
92#endif
93
b958cb0f 94#if ICAP_CLIENT
26cc52cb 95#include "adaptation/icap/Config.h"
b958cb0f 96#endif
6e5db507 97#if USE_ECAP
1f3c65fc 98#include "adaptation/ecap/Config.h"
6e5db507 99#endif
b958cb0f
AR
100#if USE_ADAPTATION
101#include "adaptation/Config.h"
102#endif
79039294
AR
103#if USE_SQUID_ESI
104#include "esi/Module.h"
105#endif
7b5b7ba8
CT
106#include "fs/Module.h"
107
25f98340
AJ
108#if HAVE_PATHS_H
109#include <paths.h>
110#endif
1a774556 111
25f98340 112#if USE_WIN32_SERVICE
1a774556 113#include "squid_windows.h"
114#include <process.h>
115
116static int opt_install_service = FALSE;
117static int opt_remove_service = FALSE;
118static int opt_signal_service = FALSE;
119static int opt_command_line = FALSE;
120extern void WIN32_svcstatusupdate(DWORD, DWORD);
121void WINAPI WIN32_svcHandler(DWORD);
122
123#endif
124
4fe75473
FC
125#ifndef SQUID_BUILD_INFO
126#define SQUID_BUILD_INFO ""
127#endif
128
5e6d4736 129static char *opt_syslog_facility = NULL;
30a4f2a8 130static int icpPortNumOverride = 1; /* Want to detect "-u 0" */
e13ee7ad 131static int configured_once = 0;
30a4f2a8 132#if MALLOC_DBG
4d64d74a 133static int malloc_debug_level = 0;
30a4f2a8 134#endif
5cd39a10 135static volatile int do_reconfigure = 0;
136static volatile int do_rotate = 0;
2681d383 137static volatile int do_shutdown = 0;
ae1feb30 138static volatile int shutdown_status = 0;
4d7add01 139
a2c48c98
AR
140static int RotateSignal = -1;
141static int ReconfigureSignal = -1;
142static int ShutdownSignal = -1;
143
5cd39a10 144static void mainRotate(void);
d71e4674
AR
145static void mainReconfigureStart(void);
146static void mainReconfigureFinish(void*);
f5b8bbc4 147static void mainInitialize(void);
f5b8bbc4 148static void usage(void);
63be0a78 149static void mainParseOptions(int argc, char *argv[]);
f5b8bbc4 150static void sendSignal(void);
151static void serverConnectionsOpen(void);
d71e4674 152static void serverConnectionsClose(void);
bbe199dc 153static void watch_child(char **);
85407535 154static void setEffectiveUser(void);
36a97e19 155#if MEM_GEN_TRACE
156extern void log_trace_done();
157extern void log_trace_init(char *);
158#endif
8ff3fa2e 159static void SquidShutdown(void);
b6a2f15e 160static void mainSetCwd(void);
efd900cb 161static int checkRunningPid(void);
85407535 162
b293c4d8 163#ifndef _SQUID_MSWIN_
e18d7fdc 164static const char *squid_start_script = "squid_start";
b293c4d8 165#endif
e18d7fdc 166
9bc73deb 167#if TEST_ACCESS
168#include "test_access.c"
169#endif
170
63be0a78 171/** temporary thunk across to the unrefactored store interface */
8ff3fa2e 172
173class StoreRootEngine : public AsyncEngine
174{
175
176public:
26ac0430 177 int checkEvents(int timeout) {
8ff3fa2e 178 Store::Root().callback();
179 return EVENT_IDLE;
180 };
181};
182
9688b0ae 183class SignalEngine: public AsyncEngine
a553a5a3 184{
185
186public:
e053c141 187 SignalEngine(EventLoop &evtLoop) : loop(evtLoop) {}
9688b0ae 188 virtual int checkEvents(int timeout);
a553a5a3 189
190private:
26ac0430 191 static void StopEventLoop(void * data) {
9688b0ae 192 static_cast<SignalEngine *>(data)->loop.stop();
a553a5a3 193 }
194
9688b0ae 195 void doShutdown(time_t wait);
196
a553a5a3 197 EventLoop &loop;
198};
199
9688b0ae 200int
201SignalEngine::checkEvents(int timeout)
a553a5a3 202{
9688b0ae 203 PROF_start(SignalEngine_checkEvents);
fc68f6b1 204
a553a5a3 205 if (do_reconfigure) {
d71e4674 206 mainReconfigureStart();
a553a5a3 207 do_reconfigure = 0;
a553a5a3 208 } else if (do_rotate) {
209 mainRotate();
210 do_rotate = 0;
211 } else if (do_shutdown) {
9688b0ae 212 doShutdown(do_shutdown > 0 ? (int) Config.shutdownLifetime : 0);
a553a5a3 213 do_shutdown = 0;
26ac0430 214 }
a2c48c98
AR
215 BroadcastSignalIfAny(DebugSignal);
216 BroadcastSignalIfAny(RotateSignal);
217 BroadcastSignalIfAny(ReconfigureSignal);
218 BroadcastSignalIfAny(ShutdownSignal);
a553a5a3 219
9688b0ae 220 PROF_stop(SignalEngine_checkEvents);
221 return EVENT_IDLE;
222}
a553a5a3 223
9688b0ae 224void
225SignalEngine::doShutdown(time_t wait)
226{
227 debugs(1, 1, "Preparing for shutdown after " << statCounter.client_http.requests << " requests");
228 debugs(1, 1, "Waiting " << wait << " seconds for active connections to finish");
8ff3fa2e 229
9688b0ae 230 shutting_down = 1;
231
232#if USE_WIN32_SERVICE
233 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, (wait + 1) * 1000);
234#endif
235
0bcb6908 236 /* run the closure code which can be shared with reconfigure */
9688b0ae 237 serverConnectionsClose();
2f1431ea 238#if USE_AUTH
0bcb6908 239 /* detach the auth components (only do this on full shutdown) */
c6cf8dee 240 Auth::Scheme::FreeAll();
2f1431ea 241#endif
9688b0ae 242 eventAdd("SquidShutdown", &StopEventLoop, this, (double) (wait + 1), 1, false);
a553a5a3 243}
244
b8d8561b 245static void
0673c0ba 246usage(void)
ccff9601 247{
0ee4272b 248 fprintf(stderr,
0e657244 249#if USE_WIN32_SERVICE
8eb28163 250 "Usage: %s [-cdhirvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
0e657244 251#else
8eb28163 252 "Usage: %s [-cdhvzCFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
0e657244 253#endif
62e76326 254 " -a port Specify HTTP port number (default: %d).\n"
255 " -d level Write debugging to stderr also.\n"
256 " -f file Use given config-file instead of\n"
257 " %s\n"
258 " -h Print help message.\n"
0e657244 259#if USE_WIN32_SERVICE
260 " -i Installs as a Windows Service (see -n option).\n"
261#endif
62e76326 262 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
263 " Parse configuration file, then send signal to \n"
264 " running copy (except -k parse) and exit.\n"
0e657244 265#if USE_WIN32_SERVICE
266 " -n name Specify Windows Service name to use for service operations\n"
267 " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME ".\n"
268 " -r Removes a Windows Service (see -n option).\n"
269#endif
5e6d4736 270 " -s | -l facility\n"
271 " Enable logging to syslog.\n"
62e76326 272 " -u port Specify ICP port number (default: %d), disable with 0.\n"
273 " -v Print version.\n"
274 " -z Create swap directories\n"
275 " -C Do not catch fatal signals.\n"
8eb28163 276 " -D OBSOLETE. Scheduled for removal.\n"
62e76326 277 " -F Don't serve any requests until store is rebuilt.\n"
278 " -N No daemon mode.\n"
0e657244 279#if USE_WIN32_SERVICE
280 " -O options\n"
281 " Set Windows Service Command line options in Registry.\n"
282#endif
62e76326 283 " -R Do not set REUSEADDR on port.\n"
284 " -S Double-check swap during rebuild.\n"
62e76326 285 " -X Force full debugging.\n"
286 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
7dbca7a4 287 APP_SHORTNAME, CACHE_HTTP_PORT, DefaultConfigFile, CACHE_ICP_PORT);
77ffc99f 288 exit(1);
ccff9601 289}
290
63be0a78 291/**
292 * Parse the parameters received via command line interface.
293 *
d85b8894
AJ
294 \param argc Number of options received on command line
295 \param argv List of parameters received on command line
63be0a78 296 */
b8d8561b 297static void
298mainParseOptions(int argc, char *argv[])
090089c4 299{
090089c4 300 extern char *optarg;
4d64d74a 301 int c;
090089c4 302
0e657244 303#if USE_WIN32_SERVICE
5e6d4736 304 while ((c = getopt(argc, argv, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
0e657244 305#else
05f1c52c 306 while ((c = getopt(argc, argv, "CDFNRSYXa:d:f:hk:m::sl:u:vz?")) != -1)
0e657244 307#endif
9b7292ce 308 {
309
26ac0430 310 switch (c) {
62e76326 311
312 case 'C':
63be0a78 313 /** \par C
314 * Unset/disabel global option for catchign signals. opt_catch_signals */
62e76326 315 opt_catch_signals = 0;
316 break;
317
318 case 'D':
63be0a78 319 /** \par D
8eb28163
AJ
320 * OBSOLETE: WAS: override to prevent optional startup DNS tests. */
321 debugs(1,DBG_CRITICAL, "WARNING: -D command-line option is obsolete.");
62e76326 322 break;
323
324 case 'F':
63be0a78 325 /** \par F
326 * Set global option for foreground rebuild. opt_foreground_rebuild */
62e76326 327 opt_foreground_rebuild = 1;
328 break;
329
330 case 'N':
63be0a78 331 /** \par N
332 * Set global option for 'no_daemon' mode. opt_no_daemon */
62e76326 333 opt_no_daemon = 1;
334 break;
63be0a78 335
0e657244 336#if USE_WIN32_SERVICE
337
338 case 'O':
63be0a78 339 /** \par O
340 * Set global option. opt_command_lin and WIN32_Command_Line */
0e657244 341 opt_command_line = 1;
342 WIN32_Command_Line = xstrdup(optarg);
343 break;
344#endif
62e76326 345
346 case 'R':
63be0a78 347 /** \par R
348 * Unset/disable global option opt_reuseaddr */
62e76326 349 opt_reuseaddr = 0;
350 break;
351
352 case 'S':
63be0a78 353 /** \par S
354 * Set global option opt_store_doublecheck */
62e76326 355 opt_store_doublecheck = 1;
356 break;
357
62e76326 358 case 'X':
63be0a78 359 /** \par X
360 * Force full debugging */
62493678
AJ
361 Debug::parseOptions("rotate=0 ALL,9");
362 Debug::override_X = 1;
62e76326 363 sigusr2_handle(SIGUSR2);
62e76326 364 break;
365
366 case 'Y':
63be0a78 367 /** \par Y
368 * Set global option opt_reload_hit_only */
62e76326 369 opt_reload_hit_only = 1;
62e76326 370 break;
371
0e657244 372#if USE_WIN32_SERVICE
373
374 case 'i':
63be0a78 375 /** \par i
376 * Set global option opt_install_service (to TRUE) */
0e657244 377 opt_install_service = TRUE;
0e657244 378 break;
0e657244 379#endif
380
62e76326 381 case 'a':
63be0a78 382 /** \par a
383 * Add optional HTTP port as given following the option */
62e76326 384 add_http_port(optarg);
62e76326 385 break;
386
387 case 'd':
63be0a78 388 /** \par d
62493678
AJ
389 * Set global option Debug::log_stderr to the number given follwoign the option */
390 Debug::log_stderr = atoi(optarg);
62e76326 391 break;
392
393 case 'f':
63be0a78 394 /** \par f
395 * Load the file given instead of the default squid.conf. */
62e76326 396 xfree(ConfigFile);
62e76326 397 ConfigFile = xstrdup(optarg);
62e76326 398 break;
399
400 case 'k':
63be0a78 401 /** \par k
402 * Run the administrative action given following the option */
fc68f6b1 403
63be0a78 404 /** \li When its an unknown option display the usage help. */
62e76326 405 if ((int) strlen(optarg) < 1)
406 usage();
407
408 if (!strncmp(optarg, "reconfigure", strlen(optarg)))
63be0a78 409 /** \li On reconfigure send SIGHUP. */
62e76326 410 opt_send_signal = SIGHUP;
411 else if (!strncmp(optarg, "rotate", strlen(optarg)))
63be0a78 412 /** \li On rotate send SIGQUIT or SIGUSR1. */
7e7a0442 413#ifdef _SQUID_LINUX_THREADS_
62e76326 414
415 opt_send_signal = SIGQUIT;
416
e3175d1f 417#else
62e76326 418
419 opt_send_signal = SIGUSR1;
420
e3175d1f 421#endif
62e76326 422
423 else if (!strncmp(optarg, "debug", strlen(optarg)))
63be0a78 424 /** \li On debug send SIGTRAP or SIGUSR2. */
7e7a0442 425#ifdef _SQUID_LINUX_THREADS_
62e76326 426
427 opt_send_signal = SIGTRAP;
428
e3175d1f 429#else
62e76326 430
431 opt_send_signal = SIGUSR2;
432
433#endif
434
435 else if (!strncmp(optarg, "shutdown", strlen(optarg)))
63be0a78 436 /** \li On shutdown send SIGTERM. */
62e76326 437 opt_send_signal = SIGTERM;
438 else if (!strncmp(optarg, "interrupt", strlen(optarg)))
63be0a78 439 /** \li On interrupt send SIGINT. */
62e76326 440 opt_send_signal = SIGINT;
441 else if (!strncmp(optarg, "kill", strlen(optarg)))
63be0a78 442 /** \li On kill send SIGKILL. */
62e76326 443 opt_send_signal = SIGKILL;
ae1feb30 444
445#ifdef SIGTTIN
446
447 else if (!strncmp(optarg, "restart", strlen(optarg)))
63be0a78 448 /** \li On restart send SIGTTIN. (exit and restart by parent) */
449 opt_send_signal = SIGTTIN;
ae1feb30 450
451#endif
452
62e76326 453 else if (!strncmp(optarg, "check", strlen(optarg)))
63be0a78 454 /** \li On check send 0 / SIGNULL. */
62e76326 455 opt_send_signal = 0; /* SIGNULL */
456 else if (!strncmp(optarg, "parse", strlen(optarg)))
63be0a78 457 /** \li On parse set global flag to re-parse the config file only. */
458 opt_parse_cfg_only = 1;
62e76326 459 else
460 usage();
461
462 break;
463
464 case 'm':
63be0a78 465 /** \par m
466 * Set global malloc_debug_level to the value given following the option.
467 * if none is given it toggles the xmalloc_trace option on/off */
62e76326 468 if (optarg) {
30a4f2a8 469#if MALLOC_DBG
fc68f6b1 470 malloc_debug_level = atoi(optarg);
30a4f2a8 471#else
fc68f6b1 472 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
33ab18e8 473#endif
62e76326 474
475 } else {
33ab18e8 476#if XMALLOC_TRACE
62e76326 477 xmalloc_trace = !xmalloc_trace;
33ab18e8 478#else
62e76326 479 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
30a4f2a8 480#endif
62e76326 481 }
d9e7ee1f 482 break;
d9e7ee1f 483
0e657244 484#if USE_WIN32_SERVICE
485
486 case 'n':
63be0a78 487 /** \par n
488 * Set global option opt_signal_service (to TRUE).
489 * Stores the additional parameter given in global WIN32_Service_name */
0e657244 490 xfree(WIN32_Service_name);
491
492 WIN32_Service_name = xstrdup(optarg);
493
494 opt_signal_service = TRUE;
495
496 break;
497
498 case 'r':
63be0a78 499 /** \par r
500 * Set global option opt_remove_service (to TRUE) */
0e657244 501 opt_remove_service = TRUE;
502
503 break;
504
505#endif
506
5e6d4736 507 case 'l':
63be0a78 508 /** \par l
509 * Stores the syslog facility name in global opt_syslog_facility
510 * then performs actions for -s option. */
5e6d4736 511 opt_syslog_facility = xstrdup(optarg);
512
62e76326 513 case 's':
63be0a78 514 /** \par s
515 * Initialize the syslog for output */
c307aec3 516#if HAVE_SYSLOG
62e76326 517
5e6d4736 518 _db_set_syslog(opt_syslog_facility);
0e657244 519
62e76326 520 break;
0e657244 521
c307aec3 522#else
62e76326 523
524 fatal("Logging to syslog not available on this platform");
0e657244 525
62e76326 526 /* NOTREACHED */
527#endif
528
529 case 'u':
63be0a78 530 /** \par u
531 * Store the ICP port number given in global option icpPortNumOverride
532 * ensuring its a positive number. */
62e76326 533 icpPortNumOverride = atoi(optarg);
534
535 if (icpPortNumOverride < 0)
536 icpPortNumOverride = 0;
537
538 break;
539
540 case 'v':
63be0a78 541 /** \par v
542 * Display squid version and build information. Then exit. */
4fe75473
FC
543 printf("Squid Cache: Version %s\n" ,version_string);
544 if (strlen(SQUID_BUILD_INFO))
545 printf("%s\n",SQUID_BUILD_INFO);
546 printf( "configure options: %s\n", SQUID_CONFIGURE_OPTIONS);
62e76326 547
1a774556 548#if USE_WIN32_SERVICE
549
550 printf("Compiled as Windows System Service.\n");
551
552#endif
553
62e76326 554 exit(0);
555
556 /* NOTREACHED */
557
558 case 'z':
63be0a78 559 /** \par z
62493678
AJ
560 * Set global option Debug::log_stderr and opt_create_swap_dirs */
561 Debug::log_stderr = 1;
62e76326 562 opt_create_swap_dirs = 1;
62e76326 563 break;
564
63be0a78 565 case 'h':
566
62e76326 567 case '?':
568
569 default:
63be0a78 570 /** \par h,?, or unknown
571 * \copydoc usage() */
62e76326 572 usage();
573
574 break;
575 }
9b7292ce 576
090089c4 577 }
4d64d74a 578}
090089c4 579
7a2f978b 580/* ARGSUSED */
b293c4d8 581void
9b7292ce 582rotate_logs(int sig)
583{
5cd39a10 584 do_rotate = 1;
a2c48c98 585 RotateSignal = sig;
a50bfe93 586#ifndef _SQUID_MSWIN_
30a4f2a8 587#if !HAVE_SIGACTION
62e76326 588
30a4f2a8 589 signal(sig, rotate_logs);
590#endif
a50bfe93 591#endif
30a4f2a8 592}
593
7a2f978b 594/* ARGSUSED */
b293c4d8 595void
9b7292ce 596reconfigure(int sig)
597{
5cd39a10 598 do_reconfigure = 1;
a2c48c98 599 ReconfigureSignal = sig;
a50bfe93 600#ifndef _SQUID_MSWIN_
30a4f2a8 601#if !HAVE_SIGACTION
62e76326 602
30a4f2a8 603 signal(sig, reconfigure);
604#endif
a50bfe93 605#endif
30a4f2a8 606}
607
b8d8561b 608void
9b7292ce 609shut_down(int sig)
610{
2681d383 611 do_shutdown = sig == SIGINT ? -1 : 1;
a2c48c98 612 ShutdownSignal = sig;
ae1feb30 613#ifdef SIGTTIN
614
615 if (SIGTTIN == sig)
616 shutdown_status = 1;
617
618#endif
ca4b9ee6
DK
619
620 const pid_t ppid = getppid();
621
bd9fe5b4 622 if (!IamMasterProcess() && ppid > 1) {
ca4b9ee6
DK
623 // notify master that we are shutting down
624 if (kill(ppid, SIGUSR1) < 0)
625 debugs(1, DBG_IMPORTANT, "Failed to send SIGUSR1 to master process,"
626 " pid " << ppid << ": " << xstrerror());
627 }
628
a50bfe93 629#ifndef _SQUID_MSWIN_
a67d2b2e 630#if KILL_PARENT_OPT
62e76326 631
bd9fe5b4 632 if (!IamMasterProcess() && ppid > 1) {
ca4b9ee6 633 debugs(1, DBG_IMPORTANT, "Killing master process, pid " << ppid);
62e76326 634
ca4b9ee6
DK
635 if (kill(ppid, sig) < 0)
636 debugs(1, DBG_IMPORTANT, "kill " << ppid << ": " << xstrerror());
88738790 637 }
62e76326 638
0f658b5b 639#endif /* KILL_PARENT_OPT */
6e40f263 640#if SA_RESETHAND == 0
641 signal(SIGTERM, SIG_DFL);
62e76326 642
6e40f263 643 signal(SIGINT, SIG_DFL);
62e76326 644
a50bfe93 645#endif
6e40f263 646#endif
30a4f2a8 647}
648
24382924 649static void
9b7292ce 650serverConnectionsOpen(void)
651{
7de94c8c
AR
652 if (IamPrimaryProcess()) {
653#if USE_WCCP
654
5667a628 655 wccpConnectionOpen();
7de94c8c 656#endif
45aae82b 657
7de94c8c
AR
658#if USE_WCCPv2
659
5667a628 660 wccp2ConnectionOpen();
7de94c8c
AR
661#endif
662 }
095ec2b1
AR
663 // start various proxying services if we are responsible for them
664 if (IamWorkerProcess()) {
5667a628
AR
665 clientOpenListenSockets();
666 icpConnectionsOpen();
ace287ee 667#if USE_HTCP
62e76326 668
5667a628 669 htcpInit();
ace287ee 670#endif
a67d2b2e 671#if SQUID_SNMP
62e76326 672
5667a628 673 snmpConnectionOpen();
320e9f36 674#endif
0b0cfcf2 675
5667a628
AR
676 clientdbInit();
677 icmpEngine.Open();
678 netdbInit();
679 asnInit();
680 ACL::Initialize();
681 peerSelectInit();
682
683 carpInit();
2f1431ea 684#if USE_AUTH
5667a628 685 peerUserHashInit();
2f1431ea 686#endif
5667a628 687 peerSourceHashInit();
7de94c8c 688 }
5f3f8d0e 689}
690
d71e4674 691static void
9b7292ce 692serverConnectionsClose(void)
693{
0a5a8601 694 assert(shutting_down || reconfiguring);
7de94c8c
AR
695
696 if (IamPrimaryProcess()) {
697#if USE_WCCP
698
5667a628 699 wccpConnectionClose();
7de94c8c
AR
700#endif
701#if USE_WCCPv2
702
5667a628 703 wccp2ConnectionClose();
7de94c8c
AR
704#endif
705 }
095ec2b1 706 if (IamWorkerProcess()) {
5667a628
AR
707 clientHttpConnectionsClose();
708 icpConnectionShutdown();
72549e05 709#if USE_HTCP
62e76326 710
5667a628 711 htcpSocketShutdown();
72549e05 712#endif
62e76326 713
5667a628 714 icmpEngine.Close();
a67d2b2e 715#if SQUID_SNMP
62e76326 716
5667a628 717 snmpConnectionShutdown();
320e9f36 718#endif
62e76326 719
5667a628 720 asnFreeMemory();
7de94c8c 721 }
5f3f8d0e 722}
723
b8d8561b 724static void
d71e4674 725mainReconfigureStart(void)
9b7292ce 726{
bf8fe701 727 debugs(1, 1, "Reconfiguring Squid Cache (version " << version_string << ")...");
5cd39a10 728 reconfiguring = 1;
d71e4674
AR
729
730 // Initiate asynchronous closing sequence
15df8349 731 serverConnectionsClose();
17e6c0a1 732 icpConnectionClose();
72549e05 733#if USE_HTCP
62e76326 734
72549e05 735 htcpSocketClose();
736#endif
59ad6d31 737#if SQUID_SNMP
62e76326 738
17e6c0a1 739 snmpConnectionClose();
320e9f36 740#endif
3c573763 741#if USE_DNSSERVERS
62e76326 742
74addf6c 743 dnsShutdown();
3c573763 744#else
62e76326 745
7b724b86 746 idnsShutdown();
eb824054 747#endif
95d2589c
CT
748#if USE_SSL_CRTD
749 Ssl::Helper::GetInstance()->Shutdown();
750#endif
751#if USE_SSL
752 Ssl::TheGlobalContextStorage.reconfigureStart();
753#endif
74addf6c 754 redirectShutdown();
2f1431ea 755#if USE_AUTH
0bcb6908 756 authenticateReset();
2f1431ea 757#endif
d9572179 758 externalAclShutdown();
2db68ce5 759 storeDirCloseSwapLogs();
2e923080 760 storeLogClose();
761 accessLogClose();
3ff65596
AR
762#if ICAP_CLIENT
763 icapLogClose();
764#endif
d71e4674
AR
765
766 eventAdd("mainReconfigureFinish", &mainReconfigureFinish, NULL, 0, 1,
26ac0430 767 false);
d71e4674
AR
768}
769
770static void
26ac0430
AJ
771mainReconfigureFinish(void *)
772{
d71e4674
AR
773 debugs(1, 3, "finishing reconfiguring");
774
c68e9c6b 775 errorClean();
3aa4adbc 776 enter_suid(); /* root to read config file */
936b23cd
AJ
777
778 // we may have disabled the need for PURGE
e1381638 779 if (Config2.onoff.enable_purge)
936b23cd
AJ
780 Config2.onoff.enable_purge = 2;
781
18631119 782 // parse the config returns a count of errors encountered.
13aeac35 783 const int oldWorkers = Config.workers;
f1eaa254 784
18631119
AJ
785 if ( parseConfigFile(ConfigFile) != 0) {
786 // for now any errors are a fatal condition...
787 self_destruct();
788 }
13aeac35
AR
789 if (oldWorkers != Config.workers) {
790 debugs(1, DBG_CRITICAL, "WARNING: Changing 'workers' (from " <<
5667a628
AR
791 oldWorkers << " to " << Config.workers <<
792 ") is not supported and ignored");
13aeac35 793 Config.workers = oldWorkers;
a2c48c98 794 }
936b23cd 795
96c2bb61
AR
796 if (IamPrimaryProcess())
797 CpuAffinityCheck();
798 CpuAffinityReconfigure();
799
c642c141 800 setUmask(Config.umask);
97244680 801 Mem::Report();
3aa4adbc 802 setEffectiveUser();
62493678 803 _db_init(Debug::cache_log, Debug::debugOptions);
429fdbec 804 ipcache_restart(); /* clear stuck entries */
805 fqdncache_restart(); /* sigh, fqdncache too */
0e70aa1e 806 parseEtcHosts();
53ad48e6 807 errorInitialize(); /* reload error pages */
2e923080 808 accessLogInit();
76fc7e57
AJ
809
810#if USE_LOADABLE_MODULES
811 LoadableModulesConfigure(Config.loadable_module_names);
812#endif
813
814#if USE_ADAPTATION
815 bool enableAdaptation = false;
816#if ICAP_CLIENT
817 Adaptation::Icap::TheConfig.finalize();
818 enableAdaptation = Adaptation::Icap::TheConfig.onoff || enableAdaptation;
819#endif
820#if USE_ECAP
821 Adaptation::Ecap::TheConfig.finalize(); // must be after we load modules
822 enableAdaptation = Adaptation::Ecap::TheConfig.onoff || enableAdaptation;
823#endif
824 Adaptation::Config::Finalize(enableAdaptation);
825#endif
d090e020 826
3ff65596
AR
827#if ICAP_CLIENT
828 icapLogOpen();
829#endif
2e923080 830 storeLogOpen();
3c573763 831#if USE_DNSSERVERS
62e76326 832
74addf6c 833 dnsInit();
3c573763 834#else
62e76326 835
7b724b86 836 idnsInit();
eb824054 837#endif
95d2589c
CT
838#if USE_SSL_CRTD
839 Ssl::Helper::GetInstance()->Init();
840#endif
62e76326 841
74addf6c 842 redirectInit();
2f1431ea 843#if USE_AUTH
5817ee13 844 authenticateInit(&Auth::TheConfig);
2f1431ea 845#endif
d9572179 846 externalAclInit();
7de94c8c
AR
847
848 if (IamPrimaryProcess()) {
1f38f50a 849#if USE_WCCP
62e76326 850
5667a628 851 wccpInit();
1f38f50a 852#endif
0b0cfcf2 853#if USE_WCCPv2
854
5667a628 855 wccp2Init();
0b0cfcf2 856#endif
7de94c8c 857 }
62e76326 858
0ffd22bc 859 serverConnectionsOpen();
9c2e9b50 860
3ee2b4f8 861 neighbors_init();
9c2e9b50 862
2db68ce5 863 storeDirOpenSwapLogs();
9c2e9b50 864
9c021a38 865 mimeInit(Config.mimeTablePathname);
9c2e9b50 866
9a0a18de 867#if USE_DELAY_POOLS
b4cd430a
CT
868 Config.ClientDelay.finalize();
869#endif
870
926375e6 871 if (Config.onoff.announce) {
872 if (!eventFind(start_announce, NULL))
873 eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
874 } else {
875 if (eventFind(start_announce, NULL))
876 eventDelete(start_announce, NULL);
877 }
878
b8890359 879 writePidFile(); /* write PID file */
9c2e9b50 880
bf8fe701 881 debugs(1, 1, "Ready to serve requests.");
9c2e9b50 882
5cd39a10 883 reconfiguring = 0;
884}
885
886static void
9b7292ce 887mainRotate(void)
888{
cc192b50 889 icmpEngine.Close();
3c573763 890#if USE_DNSSERVERS
e40aa8da 891 dnsShutdown();
3c573763 892#endif
e40aa8da 893 redirectShutdown();
2f1431ea 894#if USE_AUTH
0bcb6908 895 authenticateRotate();
2f1431ea 896#endif
d9572179 897 externalAclShutdown();
0a6dd8fb 898
5cd39a10 899 _db_rotate_log(); /* cache.log */
900 storeDirWriteCleanLogs(1);
901 storeLogRotate(); /* store.log */
902 accessLogRotate(); /* access.log */
3ff65596
AR
903#if ICAP_CLIENT
904 icapLogRotate(); /*icap.log*/
905#endif
cc192b50 906 icmpEngine.Open();
3c573763 907#if USE_DNSSERVERS
e40aa8da 908 dnsInit();
3c573763 909#endif
e40aa8da 910 redirectInit();
2f1431ea 911#if USE_AUTH
5817ee13 912 authenticateInit(&Auth::TheConfig);
2f1431ea 913#endif
d9572179 914 externalAclInit();
5f3f8d0e 915}
916
067bea91 917static void
9b7292ce 918setEffectiveUser(void)
919{
fc68f6b1 920 keepCapabilities();
85407535 921 leave_suid(); /* Run as non privilegied user */
cd377065 922#ifdef _SQUID_OS2_
62e76326 923
cd377065 924 return;
925#endif
62e76326 926
85407535 927 if (geteuid() == 0) {
bf8fe701 928 debugs(0, 0, "Squid is not safe to run as root! If you must");
929 debugs(0, 0, "start Squid as root, then you must configure");
930 debugs(0, 0, "it to run as a non-priveledged user with the");
931 debugs(0, 0, "'cache_effective_user' option in the config file.");
62e76326 932 fatal("Don't run Squid as root, set 'cache_effective_user'!");
85407535 933 }
934}
935
b6a2f15e 936static void
9b7292ce 937mainSetCwd(void)
938{
4a504376 939 char pathbuf[MAXPATHLEN];
62e76326 940
b6a2f15e 941 if (Config.coredump_dir) {
62e76326 942 if (0 == strcmp("none", Config.coredump_dir)) {
943 (void) 0;
944 } else if (chdir(Config.coredump_dir) == 0) {
bf8fe701 945 debugs(0, 1, "Set Current Directory to " << Config.coredump_dir);
62e76326 946 return;
947 } else {
bf8fe701 948 debugs(50, 0, "chdir: " << Config.coredump_dir << ": " << xstrerror());
62e76326 949 }
b6a2f15e 950 }
62e76326 951
02e8115e 952 /* If we don't have coredump_dir or couldn't cd there, report current dir */
4a504376 953 if (getcwd(pathbuf, MAXPATHLEN)) {
bf8fe701 954 debugs(0, 1, "Current Directory is " << pathbuf);
4a504376 955 } else {
bf8fe701 956 debugs(50, 0, "WARNING: Can't find current directory, getcwd: " << xstrerror());
4a504376 957 }
b6a2f15e 958}
959
b8d8561b 960static void
9b7292ce 961mainInitialize(void)
962{
efd900cb 963 /* chroot if configured to run inside chroot */
62e76326 964
64b0a10d 965 if (Config.chroot_dir && (chroot(Config.chroot_dir) != 0 || chdir("/") != 0)) {
62e76326 966 fatal("failed to chroot");
efd900cb 967 }
62e76326 968
1758c627 969 if (opt_catch_signals) {
62e76326 970 squid_signal(SIGSEGV, death, SA_NODEFER | SA_RESETHAND);
971 squid_signal(SIGBUS, death, SA_NODEFER | SA_RESETHAND);
44f99671 972 }
62e76326 973
30a4f2a8 974 squid_signal(SIGPIPE, SIG_IGN, SA_RESTART);
975 squid_signal(SIGCHLD, sig_child, SA_NODEFER | SA_RESTART);
44f99671 976
85407535 977 setEffectiveUser();
62e76326 978
30a4f2a8 979 if (icpPortNumOverride != 1)
62e76326 980 Config.Port.icp = (u_short) icpPortNumOverride;
30a4f2a8 981
62493678 982 _db_init(Debug::cache_log, Debug::debugOptions);
62e76326 983
62493678 984 fd_open(fileno(debug_log), FD_LOG, Debug::cache_log);
62e76326 985
71a17702 986#if MEM_GEN_TRACE
62e76326 987
71a17702 988 log_trace_init("/tmp/squid.alloc");
62e76326 989
71a17702 990#endif
62e76326 991
bf8fe701 992 debugs(1, 0, "Starting Squid Cache version " << version_string << " for " << CONFIG_HOST_TYPE << "...");
62e76326 993
be266cb2 994#if _SQUID_WINDOWS_
b293c4d8 995 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
bf8fe701 996 debugs(1, 0, "Running as " << WIN32_Service_name << " Windows System Service on " << WIN32_OS_string);
997 debugs(1, 0, "Service command line is: " << WIN32_Service_Command_Line);
b293c4d8 998 } else
bf8fe701 999 debugs(1, 0, "Running on " << WIN32_OS_string);
b293c4d8 1000#endif
1001
36584579 1002 debugs(1, 1, "Process ID " << getpid());
095ec2b1
AR
1003
1004 debugs(1, 1, "Process Roles:" << ProcessRoles());
1005
f3f0f563 1006 setSystemLimits();
bf8fe701 1007 debugs(1, 1, "With " << Squid_MaxFD << " file descriptors available");
5f3f8d0e 1008
6c1962dd 1009#ifdef _SQUID_MSWIN_
1010
bf8fe701 1011 debugs(1, 1, "With " << _getmaxstdio() << " CRT stdio descriptors available");
6c1962dd 1012
1013 if (WIN32_Socks_initialized)
bf8fe701 1014 debugs(1, 1, "Windows sockets initialized");
6c1962dd 1015
babd1fd5 1016 if (WIN32_OS_version > _WIN_OS_WINNT) {
26ac0430 1017 WIN32_IpAddrChangeMonitorInit();
babd1fd5 1018 }
1019
6c1962dd 1020#endif
1021
9f75c559 1022 if (!configured_once)
62e76326 1023 disk_init(); /* disk_init must go before ipcache_init() */
1024
5f3f8d0e 1025 ipcache_init();
62e76326 1026
f88bb09c 1027 fqdncache_init();
62e76326 1028
0e70aa1e 1029 parseEtcHosts();
62e76326 1030
3c573763 1031#if USE_DNSSERVERS
62e76326 1032
74addf6c 1033 dnsInit();
62e76326 1034
3c573763 1035#else
62e76326 1036
7b724b86 1037 idnsInit();
62e76326 1038
eb824054 1039#endif
62e76326 1040
74addf6c 1041 redirectInit();
2f1431ea 1042#if USE_AUTH
5817ee13 1043 authenticateInit(&Auth::TheConfig);
2f1431ea 1044#endif
d9572179 1045 externalAclInit();
62e76326 1046
2ac76861 1047 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
62e76326 1048
2246b732 1049 httpReplyInitModule(); /* must go before accepting replies */
62e76326 1050
9b312a19 1051 errorInitialize();
62e76326 1052
7a2f978b 1053 accessLogInit();
62e76326 1054
e1381638 1055#if ICAP_CLIENT
3ff65596
AR
1056 icapLogOpen();
1057#endif
1058
3898f57f 1059#if USE_IDENT
4daaf3cb 1060 Ident::Init();
3898f57f 1061#endif
4daaf3cb 1062
59ad6d31 1063#if SQUID_SNMP
62e76326 1064
5e14bf6d 1065 snmpInit();
62e76326 1066
5e14bf6d 1067#endif
30a4f2a8 1068#if MALLOC_DBG
62e76326 1069
5f3f8d0e 1070 malloc_debug(0, malloc_debug_level);
62e76326 1071
5f3f8d0e 1072#endif
1073
dbe4fd8e 1074 if (!configured_once) {
a3d0a19d 1075#if USE_UNLINKD
62e76326 1076 unlinkdInit();
1077#endif
1078
1079 urlInitialize();
62e76326 1080 statInit();
1081 storeInit();
1082 mainSetCwd();
1083 /* after this point we want to see the mallinfo() output */
1084 do_mallinfo = 1;
1085 mimeInit(Config.mimeTablePathname);
62e76326 1086 refreshInit();
9a0a18de 1087#if USE_DELAY_POOLS
62e76326 1088 DelayPools::Init();
0d7e5d78 1089#endif
62e76326 1090
b6b6f466 1091 FwdState::initModule();
62ee09ca 1092 /* register the modules in the cache manager menus */
62ee09ca 1093
a08f1b5a 1094 cbdataRegisterWithCacheManager();
62ee09ca 1095 /* These use separate calls so that the comm loops can eventually
1096 * coexist.
1097 */
62ee09ca 1098
15b3c0d7 1099 eventInit();
610ee341 1100
26ac0430 1101 // TODO: pconn is a good candidate for new-style registration
6852be71 1102 // PconnModule::GetInstance()->registerWithCacheManager();
26ac0430 1103 // moved to PconnModule::PconnModule()
5f3f8d0e 1104 }
62e76326 1105
7de94c8c 1106 if (IamPrimaryProcess()) {
1f38f50a 1107#if USE_WCCP
5667a628 1108 wccpInit();
62e76326 1109
0b0cfcf2 1110#endif
1111#if USE_WCCPv2
1112
5667a628 1113 wccp2Init();
0b0cfcf2 1114
1f38f50a 1115#endif
7de94c8c 1116 }
62e76326 1117
2285407f 1118 serverConnectionsOpen();
62e76326 1119
3ee2b4f8 1120 neighbors_init();
fc68f6b1 1121
5f5e883f 1122 // neighborsRegisterWithCacheManager(); //moved to neighbors_init()
62e76326 1123
efd900cb 1124 if (Config.chroot_dir)
62e76326 1125 no_suid();
1126
dbe4fd8e 1127 if (!configured_once)
62e76326 1128 writePidFile(); /* write PID file */
0a5b9b32 1129
7e7a0442 1130#ifdef _SQUID_LINUX_THREADS_
62e76326 1131
e3175d1f 1132 squid_signal(SIGQUIT, rotate_logs, SA_RESTART);
62e76326 1133
e3175d1f 1134 squid_signal(SIGTRAP, sigusr2_handle, SA_RESTART);
62e76326 1135
e3175d1f 1136#else
62e76326 1137
30a4f2a8 1138 squid_signal(SIGUSR1, rotate_logs, SA_RESTART);
62e76326 1139
30a4f2a8 1140 squid_signal(SIGUSR2, sigusr2_handle, SA_RESTART);
62e76326 1141
9fc0b4b8 1142#endif
62e76326 1143
30a4f2a8 1144 squid_signal(SIGHUP, reconfigure, SA_RESTART);
62e76326 1145
30a4f2a8 1146 squid_signal(SIGTERM, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
62e76326 1147
30a4f2a8 1148 squid_signal(SIGINT, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
62e76326 1149
ae1feb30 1150#ifdef SIGTTIN
1151
1152 squid_signal(SIGTTIN, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
1153
1154#endif
1155
58a39dc9 1156 memCheckInit();
62e76326 1157
57afc994
AR
1158#if USE_LOADABLE_MODULES
1159 LoadableModulesConfigure(Config.loadable_module_names);
1160#endif
1161
8f361c50
AR
1162#if USE_ADAPTATION
1163 bool enableAdaptation = false;
1164
1165 // We can remove this dependency on specific adaptation mechanisms
1166 // if we create a generic Registry of such mechanisms. Should we?
b958cb0f 1167#if ICAP_CLIENT
26cc52cb
AR
1168 Adaptation::Icap::TheConfig.finalize();
1169 enableAdaptation = Adaptation::Icap::TheConfig.onoff || enableAdaptation;
6e5db507
AR
1170#endif
1171#if USE_ECAP
574b508c
AR
1172 Adaptation::Ecap::TheConfig.finalize(); // must be after we load modules
1173 enableAdaptation = Adaptation::Ecap::TheConfig.onoff || enableAdaptation;
b958cb0f 1174#endif
8f361c50
AR
1175 // must be the last adaptation-related finalize
1176 Adaptation::Config::Finalize(enableAdaptation);
b958cb0f
AR
1177#endif
1178
79039294
AR
1179#if USE_SQUID_ESI
1180 Esi::Init();
1181#endif
b958cb0f 1182
9a0a18de 1183#if USE_DELAY_POOLS
b4cd430a
CT
1184 Config.ClientDelay.finalize();
1185#endif
1186
bf8fe701 1187 debugs(1, 1, "Ready to serve requests.");
62e76326 1188
dbe4fd8e 1189 if (!configured_once) {
c8f4eac4 1190 eventAdd("storeMaintain", Store::Maintain, NULL, 1.0, 1);
62e76326 1191
1192 if (Config.onoff.announce)
1193 eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
1194
1195 eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
1196
1197 eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 15.0, 1);
1198
88bfe092 1199#if USE_XPROF_STATS
62e76326 1200
1201 eventAdd("cpuProfiling", xprof_event, NULL, 1.0, 1);
1202
88bfe092 1203#endif
62e76326 1204
1205 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools, NULL, 15.0, 1);
4d7add01 1206 }
62e76326 1207
dbe4fd8e 1208 configured_once = 1;
4d64d74a 1209}
1210
c842329d 1211/// unsafe main routine -- may throw
f3f3e961 1212int SquidMain(int argc, char **argv);
c842329d 1213/// unsafe main routine wrapper to catch exceptions
6e5db507
AR
1214static int SquidMainSafe(int argc, char **argv);
1215
6c1962dd 1216#if USE_WIN32_SERVICE
1217/* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1218extern "C" void WINAPI
e1381638 1219SquidWinSvcMain(int argc, char **argv)
18631119
AJ
1220{
1221 SquidMainSafe(argc, argv);
1222}
6c1962dd 1223#else
b8d8561b 1224int
1225main(int argc, char **argv)
6e5db507 1226{
18631119 1227 return SquidMainSafe(argc, argv);
6e5db507 1228}
18631119 1229#endif
6e5db507
AR
1230
1231static int
1232SquidMainSafe(int argc, char **argv)
1233{
1234 try {
1235 return SquidMain(argc, argv);
26ac0430 1236 } catch (const std::exception &e) {
f5f9e44c 1237 debugs(0,0, "dying from an unhandled exception: " << e.what());
26ac0430
AJ
1238 throw;
1239 } catch (...) {
f5f9e44c 1240 debugs(0,0, "dying from an unhandled exception.");
26ac0430
AJ
1241 throw;
1242 }
1243 return -1; // not reached
6e5db507
AR
1244}
1245
d4a3e179
AR
1246/// computes name and ID for the current kid process
1247static void
1248ConfigureCurrentKid(const char *processName)
1249{
5667a628 1250 // kids are marked with parenthesis around their process names
d4a3e179
AR
1251 if (processName && processName[0] == '(') {
1252 if (const char *idStart = strrchr(processName, '-')) {
1253 KidIdentifier = atoi(idStart + 1);
9de6c973
AR
1254 const size_t nameLen = idStart - (processName + 1);
1255 assert(nameLen < sizeof(TheKidName));
1256 xstrncpy(TheKidName, processName + 1, nameLen + 1);
095ec2b1
AR
1257 if (!strcmp(TheKidName, "squid-coord"))
1258 TheProcessKind = pkCoordinator;
1259 else
1260 if (!strcmp(TheKidName, "squid"))
1261 TheProcessKind = pkWorker;
1262 else
1263 if (!strcmp(TheKidName, "squid-disk"))
1264 TheProcessKind = pkDisker;
1265 else
1266 TheProcessKind = pkOther; // including coordinator
d4a3e179 1267 }
2664c457 1268 } else {
9de6c973 1269 xstrncpy(TheKidName, APP_SHORTNAME, sizeof(TheKidName));
2664c457 1270 KidIdentifier = 0;
d4a3e179 1271 }
d4a3e179
AR
1272}
1273
f3f3e961 1274int
6e5db507 1275SquidMain(int argc, char **argv)
9b7292ce 1276{
d4a3e179 1277 ConfigureCurrentKid(argv[0]);
007d775d 1278
be266cb2 1279#if _SQUID_WINDOWS_
a0aa9e74 1280 int WIN32_init_err;
1281#endif
4d64d74a 1282
a4ba1105 1283#if HAVE_SBRK
62e76326 1284
9b7292ce 1285 sbrk_start = sbrk(0);
a4ba1105 1286#endif
1287
fb6a61d1 1288 Debug::parseOptions(NULL);
9b7292ce 1289 debug_log = stderr;
62e76326 1290
b9269882 1291#if defined(SQUID_MAXFD_LIMIT)
1292
1293 if (SQUID_MAXFD_LIMIT < Squid_MaxFD)
1294 Squid_MaxFD = SQUID_MAXFD_LIMIT;
1295
1296#endif
399e85ea 1297
be266cb2 1298#if _SQUID_WINDOWS_
a0aa9e74 1299 if ((WIN32_init_err = WIN32_Subsystem_Init(&argc, &argv)))
1300 return WIN32_init_err;
0e6d05ef 1301#endif
1302
9b7292ce 1303 /* call mallopt() before anything else */
0b29fe44 1304#if HAVE_MALLOPT
7328e889 1305#ifdef M_GRAIN
9b7292ce 1306 /* Round up all sizes to a multiple of this */
1307 mallopt(M_GRAIN, 16);
62e76326 1308
7328e889 1309#endif
1310#ifdef M_MXFAST
9b7292ce 1311 /* biggest size that is considered a small block */
1312 mallopt(M_MXFAST, 256);
62e76326 1313
7328e889 1314#endif
1315#ifdef M_NBLKS
9b7292ce 1316 /* allocate this many small blocks at once */
1317 mallopt(M_NLBLKS, 32);
62e76326 1318
7328e889 1319#endif
1320#endif /* HAVE_MALLOPT */
1321
9b7292ce 1322 squid_srandom(time(NULL));
4d64d74a 1323
9b7292ce 1324 getCurrentTime();
62e76326 1325
9b7292ce 1326 squid_start = current_time;
62e76326 1327
9b7292ce 1328 failure_notify = fatal_dump;
4d64d74a 1329
6c1962dd 1330#if USE_WIN32_SERVICE
1331
9b7292ce 1332 WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
6c1962dd 1333
1334#endif
1335
9b7292ce 1336 mainParseOptions(argc, argv);
4d64d74a 1337
9aae6be3 1338 if (opt_parse_cfg_only) {
26ac0430 1339 Debug::parseOptions("ALL,1");
9aae6be3 1340 }
1341
6c1962dd 1342#if USE_WIN32_SERVICE
1343
26ac0430 1344 if (opt_install_service) {
9b7292ce 1345 WIN32_InstallService();
a0aa9e74 1346 return 0;
9b7292ce 1347 }
6c1962dd 1348
26ac0430 1349 if (opt_remove_service) {
9b7292ce 1350 WIN32_RemoveService();
a0aa9e74 1351 return 0;
9b7292ce 1352 }
6c1962dd 1353
26ac0430 1354 if (opt_command_line) {
9b7292ce 1355 WIN32_SetServiceCommandLine();
a0aa9e74 1356 return 0;
9b7292ce 1357 }
6c1962dd 1358
1359#endif
1360
9b7292ce 1361 /* parse configuration file
1362 * note: in "normal" case this used to be called from mainInitialize() */
1363 {
1364 int parse_err;
62e76326 1365
9b7292ce 1366 if (!ConfigFile)
1367 ConfigFile = xstrdup(DefaultConfigFile);
62e76326 1368
9b7292ce 1369 assert(!configured_once);
62e76326 1370
9b7292ce 1371 Mem::Init();
62e76326 1372
9b7292ce 1373 storeFsInit(); /* required for config parsing */
62e76326 1374
7b5b7ba8 1375 /* TODO: call the FS::Clean() in shutdown to do Fs cleanups */
af6a12ee 1376 Fs::Init();
7b5b7ba8 1377
b9ae18aa 1378 /* May not be needed for parsing, have not audited for such */
1379 DiskIOModule::SetupAllModules();
1380
59b2d47f 1381 /* Shouldn't be needed for config parsing, but have not audited for such */
1382 StoreFileSystem::SetupAllFs();
1383
c8f4eac4 1384 /* we may want the parsing process to set this up in the future */
1385 Store::Root(new StoreController);
2f1431ea 1386#if USE_AUTH
ccd8a22a 1387 Auth::Init(); /* required for config parsing */
2f1431ea 1388#endif
055421ee
AJ
1389 Ip::ProbeTransport(); // determine IPv4 or IPv6 capabilities before parsing.
1390
dd9b1081 1391 parse_err = parseConfigFile(ConfigFile);
62e76326 1392
97244680 1393 Mem::Report();
26ac0430 1394
18631119 1395 if (opt_parse_cfg_only || parse_err > 0)
9b7292ce 1396 return parse_err;
9b7292ce 1397 }
c642c141 1398 setUmask(Config.umask);
9b7292ce 1399 if (-1 == opt_send_signal)
1400 if (checkRunningPid())
205d7c3b 1401 exit(0);
e13ee7ad 1402
9bc73deb 1403#if TEST_ACCESS
62e76326 1404
95564b0d 1405 comm_init();
62e76326 1406
9b7292ce 1407 mainInitialize();
62e76326 1408
9b7292ce 1409 test_access();
62e76326 1410
9b7292ce 1411 return 0;
62e76326 1412
9bc73deb 1413#endif
1414
9b7292ce 1415 /* send signal to running copy and exit */
26ac0430 1416 if (opt_send_signal != -1) {
9b7292ce 1417 /* chroot if configured to run inside chroot */
62e76326 1418
a572d8be 1419 if (Config.chroot_dir) {
1420 if (chroot(Config.chroot_dir))
1421 fatal("failed to chroot");
1422
1423 no_suid();
1424 } else {
1425 leave_suid();
9b7292ce 1426 }
62e76326 1427
9b7292ce 1428 sendSignal();
1429 /* NOTREACHED */
1430 }
62e76326 1431
6d57128b
AR
1432 debugs(1,2, HERE << "Doing post-config initialization\n");
1433 ActivateRegistered(rrAfterConfig);
1434 // TODO: find a place to call DeactivateRegistered(rrAfterConfig);
9487bae9 1435
2ae5c85f
AJ
1436 if (!opt_no_daemon && Config.workers > 0)
1437 watch_child(argv);
1438
26ac0430 1439 if (opt_create_swap_dirs) {
9b7292ce 1440 /* chroot if configured to run inside chroot */
0e657244 1441
9b7292ce 1442 if (Config.chroot_dir && chroot(Config.chroot_dir)) {
1443 fatal("failed to chroot");
1444 }
62e76326 1445
9b7292ce 1446 setEffectiveUser();
bf8fe701 1447 debugs(0, 0, "Creating Swap Directories");
c8f4eac4 1448 Store::Root().create();
6c1962dd 1449
9b7292ce 1450 return 0;
9b7292ce 1451 }
62e76326 1452
96c2bb61
AR
1453 if (IamPrimaryProcess())
1454 CpuAffinityCheck();
1455 CpuAffinityInit();
1456
95564b0d 1457 setMaxFD();
1458
1459 /* init comm module */
1460 comm_init();
62e76326 1461
26ac0430 1462 if (opt_no_daemon) {
9b7292ce 1463 /* we have to init fdstat here. */
1464 fd_open(0, FD_LOG, "stdin");
1465 fd_open(1, FD_LOG, "stdout");
1466 fd_open(2, FD_LOG, "stderr");
1467 }
62e76326 1468
6c1962dd 1469#if USE_WIN32_SERVICE
1470
9b7292ce 1471 WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
6c1962dd 1472
1473#endif
1474
9b7292ce 1475 mainInitialize();
4d64d74a 1476
6c1962dd 1477#if USE_WIN32_SERVICE
1478
9b7292ce 1479 WIN32_svcstatusupdate(SERVICE_RUNNING, 0);
6c1962dd 1480
1481#endif
1482
9b7292ce 1483 /* main loop */
a553a5a3 1484 EventLoop mainLoop;
62e76326 1485
9688b0ae 1486 SignalEngine signalEngine(mainLoop);
6c1962dd 1487
9688b0ae 1488 mainLoop.registerEngine(&signalEngine);
62e76326 1489
8ff3fa2e 1490 /* TODO: stop requiring the singleton here */
1491 mainLoop.registerEngine(EventScheduler::GetInstance());
62e76326 1492
8ff3fa2e 1493 StoreRootEngine store_engine;
615f9581 1494
8ff3fa2e 1495 mainLoop.registerEngine(&store_engine);
a774fd3f 1496
8ff3fa2e 1497 CommSelectEngine comm_engine;
1498
8ff3fa2e 1499 mainLoop.registerEngine(&comm_engine);
1500
bef81ea5 1501 mainLoop.setPrimaryEngine(&comm_engine);
1502
8ff3fa2e 1503 /* use the standard time service */
1504 TimeEngine time_engine;
1505
1506 mainLoop.setTimeService(&time_engine);
1507
7de94c8c 1508 if (IamCoordinatorProcess())
4299f876 1509 AsyncJob::Start(Ipc::Coordinator::Instance());
095ec2b1 1510 else if (UsingSmp() && (IamWorkerProcess() || IamDiskProcess()))
4299f876 1511 AsyncJob::Start(new Ipc::Strand);
10cefb7b 1512
48d54e4d
AJ
1513 /* at this point we are finished the synchronous startup. */
1514 starting_up = 0;
1515
8ff3fa2e 1516 mainLoop.run();
1517
1518 if (mainLoop.errcount == 10)
1519 fatal_dump("Event loop exited with failure.");
1520
1521 /* shutdown squid now */
1522 SquidShutdown();
62e76326 1523
9b7292ce 1524 /* NOTREACHED */
9b7292ce 1525 return 0;
090089c4 1526}
7690e8eb 1527
b8d8561b 1528static void
0673c0ba 1529sendSignal(void)
7690e8eb 1530{
ff8d0ea6 1531 pid_t pid;
fedac7e5 1532 debug_log = stderr;
258ac4d7 1533
1534 if (strcmp(Config.pidFilename, "none") == 0) {
bf8fe701 1535 debugs(0, 1, "No pid_filename specified. Trusting you know what you are doing.");
258ac4d7 1536 }
1537
fedac7e5 1538 pid = readPidFile();
62e76326 1539
fedac7e5 1540 if (pid > 1) {
6c1962dd 1541#if USE_WIN32_SERVICE
1542
1543 if (opt_signal_service) {
1544 WIN32_sendSignal(opt_send_signal);
1545 exit(0);
1546 } else
1547#ifdef _SQUID_MSWIN_
1548 {
7dbca7a4 1549 fprintf(stderr, "%s: ERROR: Could not send ", APP_SHORTNAME);
6c1962dd 1550 fprintf(stderr, "signal to Squid Service:\n");
1551 fprintf(stderr, "missing -n command line switch.\n");
1552 exit(1);
1553 }
1554
1555 /* NOTREACHED */
1556#endif
1557
1558#endif
1559
62e76326 1560 if (kill(pid, opt_send_signal) &&
1561 /* ignore permissions if just running check */
1562 !(opt_send_signal == 0 && errno == EPERM)) {
7dbca7a4 1563 fprintf(stderr, "%s: ERROR: Could not send ", APP_SHORTNAME);
62e76326 1564 fprintf(stderr, "signal %d to process %d: %s\n",
1565 opt_send_signal, (int) pid, xstrerror());
1566 exit(1);
1567 }
fedac7e5 1568 } else {
205d7c3b 1569 if (opt_send_signal != SIGTERM) {
e08d498f 1570 fprintf(stderr, "%s: ERROR: No running copy\n", APP_SHORTNAME);
205d7c3b
AJ
1571 exit(1);
1572 } else {
e08d498f 1573 fprintf(stderr, "%s: No running copy\n", APP_SHORTNAME);
205d7c3b
AJ
1574 exit(0);
1575 }
7690e8eb 1576 }
62e76326 1577
fedac7e5 1578 /* signal successfully sent */
1579 exit(0);
1580}
f95b8144 1581
a50bfe93 1582#ifndef _SQUID_MSWIN_
e18d7fdc 1583/*
1584 * This function is run when Squid is in daemon mode, just
1585 * before the parent forks and starts up the child process.
1586 * It can be used for admin-specific tasks, such as notifying
1587 * someone that Squid is (re)started.
1588 */
1589static void
1590mainStartScript(const char *prog)
1591{
ef364f64 1592 char script[MAXPATHLEN];
e18d7fdc 1593 char *t;
1594 size_t sl = 0;
1595 pid_t cpid;
1596 pid_t rpid;
1597 xstrncpy(script, prog, MAXPATHLEN);
62e76326 1598
e18d7fdc 1599 if ((t = strrchr(script, '/'))) {
62e76326 1600 *(++t) = '\0';
1601 sl = strlen(script);
e18d7fdc 1602 }
62e76326 1603
e18d7fdc 1604 xstrncpy(&script[sl], squid_start_script, MAXPATHLEN - sl);
62e76326 1605
e18d7fdc 1606 if ((cpid = fork()) == 0) {
62e76326 1607 /* child */
f75662c9 1608 execl(script, squid_start_script, (char *)NULL);
482aa790 1609 _exit(-1);
e18d7fdc 1610 } else {
62e76326 1611 do {
e18d7fdc 1612#ifdef _SQUID_NEXT_
62e76326 1613 union wait status;
007d775d 1614 rpid = wait4(cpid, &status, 0, NULL);
e18d7fdc 1615#else
62e76326 1616
1617 int status;
007d775d 1618 rpid = waitpid(cpid, &status, 0);
e18d7fdc 1619#endif
62e76326 1620
1621 } while (rpid != cpid);
e18d7fdc 1622 }
1623}
1624
a50bfe93 1625#endif /* _SQUID_MSWIN_ */
1626
efd900cb 1627static int
1628checkRunningPid(void)
1629{
b81949b9 1630 // master process must start alone, but its kids processes may co-exist
7de94c8c 1631 if (!IamMasterProcess())
b81949b9
AR
1632 return 0;
1633
efd900cb 1634 pid_t pid;
e0077312 1635
1636 if (!debug_log)
1637 debug_log = stderr;
1638
efd900cb 1639 pid = readPidFile();
62e76326 1640
efd900cb 1641 if (pid < 2)
62e76326 1642 return 0;
1643
efd900cb 1644 if (kill(pid, 0) < 0)
62e76326 1645 return 0;
1646
cb7a4fcb 1647 debugs(0, 0, "Squid is already running! Process ID " << pid);
62e76326 1648
efd900cb 1649 return 1;
1650}
1651
f95b8144 1652static void
bbe199dc 1653watch_child(char *argv[])
f95b8144 1654{
a50bfe93 1655#ifndef _SQUID_MSWIN_
f95b8144 1656 char *prog;
f95b8144 1657#ifdef _SQUID_NEXT_
62e76326 1658
f95b8144 1659 union wait status;
1660#else
62e76326 1661
f95b8144 1662 int status;
1663#endif
62e76326 1664
e3a3b845 1665 pid_t pid;
c99c5397 1666#ifdef TIOCNOTTY
1667
54f742e7 1668 int i;
c99c5397 1669#endif
1670
742724a4 1671 int nullfd;
62e76326 1672
7de94c8c 1673 if (!IamMasterProcess())
62e76326 1674 return;
1675
7dbca7a4 1676 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
62e76326 1677
54f742e7 1678 if ((pid = fork()) < 0)
62e76326 1679 syslog(LOG_ALERT, "fork failed: %s", xstrerror());
54f742e7 1680 else if (pid > 0)
62e76326 1681 exit(0);
1682
54f742e7 1683 if (setsid() < 0)
62e76326 1684 syslog(LOG_ALERT, "setsid failed: %s", xstrerror());
1685
efd900cb 1686 closelog();
62e76326 1687
54f742e7 1688#ifdef TIOCNOTTY
62e76326 1689
c4aefe96 1690 if ((i = open("/dev/tty", O_RDWR | O_TEXT)) >= 0) {
62e76326 1691 ioctl(i, TIOCNOTTY, NULL);
1692 close(i);
54f742e7 1693 }
62e76326 1694
54f742e7 1695#endif
b05490a8 1696
7f6ffd15 1697 /*
1698 * RBCOLLINS - if cygwin stackdumps when squid is run without
1699 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1700 * 1.1.3. execvp had a bit overflow error in a loop..
1701 */
742724a4 1702 /* Connect stdio to /dev/null in daemon mode */
4da086c4 1703 nullfd = open(_PATH_DEVNULL, O_RDWR | O_TEXT);
62e76326 1704
e4a1325e 1705 if (nullfd < 0)
4da086c4 1706 fatalf(_PATH_DEVNULL " %s\n", xstrerror());
e4a1325e 1707
742724a4 1708 dup2(nullfd, 0);
62e76326 1709
62493678 1710 if (Debug::log_stderr < 0) {
62e76326 1711 dup2(nullfd, 1);
1712 dup2(nullfd, 2);
742724a4 1713 }
62e76326 1714
ca4b9ee6
DK
1715 // handle shutdown notifications from kids
1716 squid_signal(SIGUSR1, sig_shutdown, SA_RESTART);
1717
13aeac35
AR
1718 if (Config.workers > 128) {
1719 syslog(LOG_ALERT, "Suspiciously high workers value: %d",
5667a628 1720 Config.workers);
007d775d 1721 // but we keep going in hope that user knows best
5667a628 1722 }
095ec2b1
AR
1723 TheKids.init();
1724
f1eaa254 1725syslog(LOG_NOTICE, "XXX: will start %d kids", (int)TheKids.count());
007d775d
AR
1726
1727 // keep [re]starting kids until it is time to quit
f95b8144 1728 for (;;) {
62e76326 1729 mainStartScript(argv[0]);
1730
007d775d 1731 // start each kid that needs to be [re]started; once
10cefb7b 1732 for (int i = TheKids.count() - 1; i >= 0; --i) {
007d775d 1733 Kid& kid = TheKids.get(i);
ca4b9ee6 1734 if (!kid.shouldRestart())
007d775d
AR
1735 continue;
1736
1737 if ((pid = fork()) == 0) {
1738 /* child */
1739 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
bc91a636 1740 prog = argv[0];
007d775d
AR
1741 argv[0] = const_cast<char*>(kid.name().termedBuf());
1742 execvp(prog, argv);
1743 syslog(LOG_ALERT, "execvp failed: %s", xstrerror());
1744 }
1745
1746 kid.start(pid);
095ec2b1
AR
1747 syslog(LOG_NOTICE, "Squid Parent: %s process %d started",
1748 kid.name().termedBuf(), pid);
62e76326 1749 }
1750
1751 /* parent */
7dbca7a4 1752 openlog(APP_SHORTNAME, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
62e76326 1753
62e76326 1754 squid_signal(SIGINT, SIG_IGN, SA_RESTART);
1755
f95b8144 1756#ifdef _SQUID_NEXT_
62e76326 1757
1758 pid = wait3(&status, 0, NULL);
1759
f95b8144 1760#else
62e76326 1761
1762 pid = waitpid(-1, &status, 0);
1763
007d775d 1764#endif
86b91dcd 1765 // Loop to collect all stopped kids before we go to sleep below.
5667a628 1766 do {
007d775d
AR
1767 Kid* kid = TheKids.find(pid);
1768 if (kid) {
1769 kid->stop(status);
1770 if (kid->calledExit()) {
1771 syslog(LOG_NOTICE,
095ec2b1
AR
1772 "Squid Parent: %s process %d exited with status %d",
1773 kid->name().termedBuf(),
5667a628 1774 kid->getPid(), kid->exitStatus());
007d775d
AR
1775 } else if (kid->signaled()) {
1776 syslog(LOG_NOTICE,
095ec2b1
AR
1777 "Squid Parent: %s process %d exited due to signal %d with status %d",
1778 kid->name().termedBuf(),
5667a628 1779 kid->getPid(), kid->termSignal(), kid->exitStatus());
007d775d 1780 } else {
095ec2b1
AR
1781 syslog(LOG_NOTICE, "Squid Parent: %s process %d exited",
1782 kid->name().termedBuf(), kid->getPid());
007d775d 1783 }
ca4b9ee6 1784 if (kid->hopeless()) {
1a98557c 1785 syslog(LOG_NOTICE, "Squid Parent: %s process %d will not"
ca4b9ee6 1786 " be restarted due to repeated, frequent failures",
1a98557c 1787 kid->name().termedBuf(), kid->getPid());
ca4b9ee6 1788 }
007d775d
AR
1789 } else {
1790 syslog(LOG_NOTICE, "Squid Parent: unknown child process %d exited", pid);
1791 }
1792#ifdef _SQUID_NEXT_
1793 } while ((pid = wait3(&status, WNOHANG, NULL)) > 0);
1794#else
5667a628
AR
1795 }
1796 while ((pid = waitpid(-1, &status, WNOHANG)) > 0);
62e76326 1797#endif
1798
ca4b9ee6
DK
1799 if (!TheKids.someRunning() && !TheKids.shouldRestartSome()) {
1800 if (TheKids.someSignaled(SIGINT) || TheKids.someSignaled(SIGTERM)) {
1801 syslog(LOG_ALERT, "Exiting due to unexpected forced shutdown");
1802 exit(1);
1803 }
62e76326 1804
ca4b9ee6
DK
1805 if (TheKids.allHopeless()) {
1806 syslog(LOG_ALERT, "Exiting due to repeated, frequent failures");
1807 exit(1);
1808 }
62e76326 1809
007d775d
AR
1810 exit(0);
1811 }
06a0fbd3 1812
62e76326 1813 squid_signal(SIGINT, SIG_DFL, SA_RESTART);
1814 sleep(3);
f95b8144 1815 }
62e76326 1816
bbe199dc 1817 /* NOTREACHED */
a50bfe93 1818#endif /* _SQUID_MSWIN_ */
a572d8be 1819
f95b8144 1820}
fff6ad65 1821
9ec1a1dc 1822static void
8ff3fa2e 1823SquidShutdown()
fff6ad65 1824{
d71e4674
AR
1825 /* XXX: This function is called after the main loop has quit, which
1826 * means that no AsyncCalls would be called, including close handlers.
1827 * TODO: We need to close/shut/free everything that needs calls before
1828 * exiting the loop.
26ac0430 1829 */
d71e4674 1830
6c1962dd 1831#if USE_WIN32_SERVICE
1832 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
1833#endif
1834
bf8fe701 1835 debugs(1, 1, "Shutting down...");
95a83c22 1836#if USE_DNSSERVERS
1837
1838 dnsShutdown();
1839#else
1840
1841 idnsShutdown();
1842#endif
95d2589c
CT
1843#if USE_SSL_CRTD
1844 Ssl::Helper::GetInstance()->Shutdown();
1845#endif
95a83c22 1846 redirectShutdown();
1847 externalAclShutdown();
d723bf6b 1848 icpConnectionClose();
1849#if USE_HTCP
62e76326 1850
d723bf6b 1851 htcpSocketClose();
1852#endif
59ad6d31 1853#if SQUID_SNMP
62e76326 1854
d723bf6b 1855 snmpConnectionClose();
320e9f36 1856#endif
eb824054 1857#if USE_WCCP
62e76326 1858
320e9f36 1859 wccpConnectionClose();
d723bf6b 1860#endif
0b0cfcf2 1861#if USE_WCCPv2
1862
1863 wccp2ConnectionClose();
1864#endif
62e76326 1865
fff6ad65 1866 releaseServerSockets();
d723bf6b 1867 commCloseAllSockets();
79039294
AR
1868
1869#if USE_SQUID_ESI
1870 Esi::Clean();
1871#endif
1872
9a0a18de 1873#if USE_DELAY_POOLS
b67e2c8c 1874 DelayPools::FreePools();
515ec4dc 1875#endif
2f1431ea 1876#if USE_AUTH
0bcb6908 1877 authenticateReset();
2f1431ea 1878#endif
6c1962dd 1879#if USE_WIN32_SERVICE
1880
1881 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
1882#endif
62e76326 1883
c8f4eac4 1884 Store::Root().sync(); /* Flush pending object writes/unlinks */
4d075ba0 1885#if USE_UNLINKD
1886
1887 unlinkdClose(); /* after sync/flush */
1888#endif
fc68f6b1 1889
fff6ad65 1890 storeDirWriteCleanLogs(0);
1891 PrintRusage();
1892 dumpMallocStats();
c8f4eac4 1893 Store::Root().sync(); /* Flush log writes */
fff6ad65 1894 storeLogClose();
1895 accessLogClose();
c8f4eac4 1896 Store::Root().sync(); /* Flush log close */
59b2d47f 1897 StoreFileSystem::FreeAllFs();
b9ae18aa 1898 DiskIOModule::FreeAllModules();
afec404b 1899#if LEAK_CHECK_MODE && 0 /* doesn't work at the moment */
62e76326 1900
fff6ad65 1901 configFreeMemory();
1902 storeFreeMemory();
33ab18e8 1903 /*stmemFreeMemory(); */
fff6ad65 1904 netdbFreeMemory();
1905 ipcacheFreeMemory();
1906 fqdncacheFreeMemory();
1907 asnFreeMemory();
26a369ba 1908 clientdbFreeMemory();
7021844c 1909 httpHeaderCleanModule();
d2db411c 1910 statFreeMemory();
f1fc2a8d 1911 eventFreeMemory();
c68e9c6b 1912 mimeFreeMemory();
1913 errorClean();
fff6ad65 1914#endif
26a369ba 1915#if !XMALLOC_TRACE
62e76326 1916
54f742e7 1917 if (opt_no_daemon) {
62e76326 1918 file_close(0);
1919 file_close(1);
1920 file_close(2);
54f742e7 1921 }
62e76326 1922
33ab18e8 1923#endif
fff6ad65 1924 fdDumpOpen();
62e76326 1925
236d1779 1926 comm_exit();
62e76326 1927
ddb43c58 1928 memClean();
62e76326 1929
33ab18e8 1930#if XMALLOC_TRACE
62e76326 1931
26a369ba 1932 xmalloc_find_leaks();
62e76326 1933
bf8fe701 1934 debugs(1, 0, "Memory used after shutdown: " << xmalloc_total);
62e76326 1935
33ab18e8 1936#endif
36a97e19 1937#if MEM_GEN_TRACE
62e76326 1938
399e85ea 1939 log_trace_done();
62e76326 1940
36a97e19 1941#endif
62e76326 1942
7de94c8c 1943 if (IamPrimaryProcess()) {
a2c48c98
AR
1944 if (Config.pidFilename && strcmp(Config.pidFilename, "none") != 0) {
1945 enter_suid();
1946 safeunlink(Config.pidFilename, 0);
1947 leave_suid();
1948 }
ab50ee9e 1949 }
62e76326 1950
bf8fe701 1951 debugs(1, 1, "Squid Cache (Version " << version_string << "): Exiting normally.");
62e76326 1952
0cfa98cb 1953 /*
1954 * DPW 2006-10-23
1955 * We used to fclose(debug_log) here if it was set, but then
1956 * we forgot to set it to NULL. That caused some coredumps
1957 * because exit() ends up calling a bunch of destructors and
1958 * such. So rather than forcing the debug_log to close, we'll
1959 * leave it open so that those destructors can write some
1960 * debugging if necessary. The file will be closed anyway when
1961 * the process truly exits.
1962 */
62e76326 1963
ae1feb30 1964 exit(shutdown_status);
fff6ad65 1965}
bef81ea5 1966