]> git.ipfire.org Git - thirdparty/squid.git/blob - src/main.cc
Forward port of WCCPv2 support and latest WCCPv1 changes from 2.6.
[thirdparty/squid.git] / src / main.cc
1
2 /*
3 * $Id: main.cc,v 1.427 2006/07/02 16:53:46 serassio Exp $
4 *
5 * DEBUG: section 1 Startup and Main Loop
6 * AUTHOR: Harvest Derived
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36 #include "squid.h"
37 #include "AccessLogEntry.h"
38 #include "authenticate.h"
39 #include "CacheManager.h"
40 #include "ConfigParser.h"
41 #include "ExternalACL.h"
42 #include "Store.h"
43 #include "ICP.h"
44 #include "HttpReply.h"
45 #include "pconn.h"
46 #include "Mem.h"
47 #include "ACLASN.h"
48 #include "ACL.h"
49 #include "htcp.h"
50 #include "StoreFileSystem.h"
51 #include "DiskIO/DiskIOModule.h"
52 #include "comm.h"
53 #if USE_EPOLL
54 #include "comm_epoll.h"
55 #endif
56 #if USE_KQUEUE
57 #include "comm_kqueue.h"
58 #endif
59 #if USE_POLL
60 #include "comm_poll.h"
61 #endif
62 #if USE_SELECT
63 #include "comm_select.h"
64 #endif
65 #if USE_SELECT_WIN32
66 #include "comm_select.h"
67 #endif
68 #include "SquidTime.h"
69 #include "SwapDir.h"
70 #include "forward.h"
71 #include "MemPool.h"
72
73 #if USE_WIN32_SERVICE
74
75 #include "squid_windows.h"
76 #include <process.h>
77
78 static int opt_install_service = FALSE;
79 static int opt_remove_service = FALSE;
80 static int opt_signal_service = FALSE;
81 static int opt_command_line = FALSE;
82 extern void WIN32_svcstatusupdate(DWORD, DWORD);
83 void WINAPI WIN32_svcHandler(DWORD);
84
85 #endif
86
87 /* for error reporting from xmalloc and friends */
88 SQUIDCEXTERN void (*failure_notify) (const char *);
89
90 static int opt_parse_cfg_only = 0;
91 static char *opt_syslog_facility = NULL;
92 static int icpPortNumOverride = 1; /* Want to detect "-u 0" */
93 static int configured_once = 0;
94 #if MALLOC_DBG
95 static int malloc_debug_level = 0;
96 #endif
97 static volatile int do_reconfigure = 0;
98 static volatile int do_rotate = 0;
99 static volatile int do_shutdown = 0;
100 static volatile int shutdown_status = 0;
101
102 static void mainRotate(void);
103 static void mainReconfigure(void);
104 static void mainInitialize(void);
105 static void usage(void);
106 static void mainParseOptions(int, char **);
107 static void sendSignal(void);
108 static void serverConnectionsOpen(void);
109 static void watch_child(char **);
110 static void setEffectiveUser(void);
111 #if MEM_GEN_TRACE
112 extern void log_trace_done();
113 extern void log_trace_init(char *);
114 #endif
115 static EVH SquidShutdown;
116 static void mainSetCwd(void);
117 static int checkRunningPid(void);
118
119 static CacheManager manager;
120
121 #ifndef _SQUID_MSWIN_
122 static const char *squid_start_script = "squid_start";
123 #endif
124
125 #if TEST_ACCESS
126 #include "test_access.c"
127 #endif
128
129 static void
130 usage(void)
131 {
132 fprintf(stderr,
133 #if USE_WIN32_SERVICE
134 "Usage: %s [-cdhirvzCDFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal] [-n name] [-O CommandLine]\n"
135 #else
136 "Usage: %s [-cdhvzCDFNRVYX] [-s | -l facility] [-f config-file] [-[au] port] [-k signal]\n"
137 #endif
138 " -a port Specify HTTP port number (default: %d).\n"
139 " -d level Write debugging to stderr also.\n"
140 " -f file Use given config-file instead of\n"
141 " %s\n"
142 " -h Print help message.\n"
143 #if USE_WIN32_SERVICE
144 " -i Installs as a Windows Service (see -n option).\n"
145 #endif
146 " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n"
147 " Parse configuration file, then send signal to \n"
148 " running copy (except -k parse) and exit.\n"
149 #if USE_WIN32_SERVICE
150 " -n name Specify Windows Service name to use for service operations\n"
151 " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME ".\n"
152 " -r Removes a Windows Service (see -n option).\n"
153 #endif
154 " -s | -l facility\n"
155 " Enable logging to syslog.\n"
156 " -u port Specify ICP port number (default: %d), disable with 0.\n"
157 " -v Print version.\n"
158 " -z Create swap directories\n"
159 " -C Do not catch fatal signals.\n"
160 " -D Disable initial DNS tests.\n"
161 " -F Don't serve any requests until store is rebuilt.\n"
162 " -N No daemon mode.\n"
163 #if USE_WIN32_SERVICE
164 " -O options\n"
165 " Set Windows Service Command line options in Registry.\n"
166 #endif
167 " -R Do not set REUSEADDR on port.\n"
168 " -S Double-check swap during rebuild.\n"
169 " -V Virtual host httpd-accelerator.\n"
170 " -X Force full debugging.\n"
171 " -Y Only return UDP_HIT or UDP_MISS_NOFETCH during fast reload.\n",
172 appname, CACHE_HTTP_PORT, DefaultConfigFile, CACHE_ICP_PORT);
173 exit(1);
174 }
175
176 static void
177 mainParseOptions(int argc, char *argv[])
178 {
179 extern char *optarg;
180 int c;
181
182 #if USE_WIN32_SERVICE
183
184 while ((c = getopt(argc, argv, "CDFNO:RSVYXa:d:f:hik:m::n:rsl:u:vz?")) != -1)
185 #else
186
187 while ((c = getopt(argc, argv, "CDFNRSVYXa:d:f:hk:m::sl:u:vz?")) != -1)
188 #endif
189
190 {
191
192 switch (c)
193 {
194
195 case 'C':
196 opt_catch_signals = 0;
197 break;
198
199 case 'D':
200 opt_dns_tests = 0;
201 break;
202
203 case 'F':
204 opt_foreground_rebuild = 1;
205 break;
206
207 case 'N':
208 opt_no_daemon = 1;
209 break;
210 #if USE_WIN32_SERVICE
211
212 case 'O':
213 opt_command_line = 1;
214 WIN32_Command_Line = xstrdup(optarg);
215 break;
216 #endif
217
218 case 'R':
219 opt_reuseaddr = 0;
220 break;
221
222 case 'S':
223 opt_store_doublecheck = 1;
224 break;
225
226 case 'V':
227
228 if (Config.Sockaddr.http)
229 Config.Sockaddr.http->vhost = 1;
230
231 #if USE_SSL
232
233 else if (Config.Sockaddr.https)
234 Config.Sockaddr.https->http.vhost = 1;
235
236 #endif
237
238 else
239 fatal("No http_port specified\n");
240
241 break;
242
243 case 'X':
244 /* force full debugging */
245 sigusr2_handle(SIGUSR2);
246
247 break;
248
249 case 'Y':
250 opt_reload_hit_only = 1;
251
252 break;
253
254 #if USE_WIN32_SERVICE
255
256 case 'i':
257 opt_install_service = TRUE;
258
259 break;
260
261 #endif
262
263 case 'a':
264 add_http_port(optarg);
265
266 break;
267
268 case 'd':
269 opt_debug_stderr = atoi(optarg);
270
271 break;
272
273 case 'f':
274 xfree(ConfigFile);
275
276 ConfigFile = xstrdup(optarg);
277
278 break;
279
280 case 'h':
281 usage();
282
283 break;
284
285 case 'k':
286 if ((int) strlen(optarg) < 1)
287 usage();
288
289 if (!strncmp(optarg, "reconfigure", strlen(optarg)))
290 opt_send_signal = SIGHUP;
291 else if (!strncmp(optarg, "rotate", strlen(optarg)))
292 #ifdef _SQUID_LINUX_THREADS_
293
294 opt_send_signal = SIGQUIT;
295
296 #else
297
298 opt_send_signal = SIGUSR1;
299
300 #endif
301
302 else if (!strncmp(optarg, "debug", strlen(optarg)))
303 #ifdef _SQUID_LINUX_THREADS_
304
305 opt_send_signal = SIGTRAP;
306
307 #else
308
309 opt_send_signal = SIGUSR2;
310
311 #endif
312
313 else if (!strncmp(optarg, "shutdown", strlen(optarg)))
314 opt_send_signal = SIGTERM;
315 else if (!strncmp(optarg, "interrupt", strlen(optarg)))
316 opt_send_signal = SIGINT;
317 else if (!strncmp(optarg, "kill", strlen(optarg)))
318 opt_send_signal = SIGKILL;
319
320 #ifdef SIGTTIN
321
322 else if (!strncmp(optarg, "restart", strlen(optarg)))
323 opt_send_signal = SIGTTIN; /* exit and restart by parent */
324
325 #endif
326
327 else if (!strncmp(optarg, "check", strlen(optarg)))
328 opt_send_signal = 0; /* SIGNULL */
329 else if (!strncmp(optarg, "parse", strlen(optarg)))
330 opt_parse_cfg_only = 1; /* parse cfg file only */
331 else
332 usage();
333
334 break;
335
336 case 'm':
337 if (optarg) {
338 if (*optarg == 'c') {
339 MemPools::GetInstance().setDefaultPoolChunking(0);
340 } else {
341 #if MALLOC_DBG
342 malloc_debug_level = atoi(optarg);
343 #else
344
345 fatal("Need to add -DMALLOC_DBG when compiling to use -mX option");
346 #endif
347
348 }
349
350 } else {
351 #if XMALLOC_TRACE
352 xmalloc_trace = !xmalloc_trace;
353 #else
354
355 fatal("Need to configure --enable-xmalloc-debug-trace to use -m option");
356 #endif
357
358 }
359
360 break;
361 /* NOTREACHED */
362
363 #if USE_WIN32_SERVICE
364
365 case 'n':
366 xfree(WIN32_Service_name);
367
368 WIN32_Service_name = xstrdup(optarg);
369
370 opt_signal_service = TRUE;
371
372 break;
373
374 case 'r':
375 opt_remove_service = TRUE;
376
377 break;
378
379 #endif
380
381 case 'l':
382 opt_syslog_facility = xstrdup(optarg);
383
384 case 's':
385 #if HAVE_SYSLOG
386
387 _db_set_syslog(opt_syslog_facility);
388
389 break;
390
391 #else
392
393 fatal("Logging to syslog not available on this platform");
394
395 /* NOTREACHED */
396 #endif
397
398 case 'u':
399 icpPortNumOverride = atoi(optarg);
400
401 if (icpPortNumOverride < 0)
402 icpPortNumOverride = 0;
403
404 break;
405
406 case 'v':
407 printf("Squid Cache: Version %s\nconfigure options: %s\n", version_string, SQUID_CONFIGURE_OPTIONS);
408
409 #if USE_WIN32_SERVICE
410
411 printf("Compiled as Windows System Service.\n");
412
413 #endif
414
415 exit(0);
416
417 /* NOTREACHED */
418
419 case 'z':
420 opt_debug_stderr = 1;
421
422 opt_create_swap_dirs = 1;
423
424 break;
425
426 case '?':
427
428 default:
429 usage();
430
431 break;
432 }
433
434 }
435 }
436
437 /* ARGSUSED */
438 void
439 rotate_logs(int sig)
440 {
441 do_rotate = 1;
442 #ifndef _SQUID_MSWIN_
443 #if !HAVE_SIGACTION
444
445 signal(sig, rotate_logs);
446 #endif
447 #endif
448 }
449
450 /* ARGSUSED */
451 void
452 reconfigure(int sig)
453 {
454 do_reconfigure = 1;
455 #ifndef _SQUID_MSWIN_
456 #if !HAVE_SIGACTION
457
458 signal(sig, reconfigure);
459 #endif
460 #endif
461 }
462
463 void
464 shut_down(int sig)
465 {
466 do_shutdown = sig == SIGINT ? -1 : 1;
467 #ifdef SIGTTIN
468
469 if (SIGTTIN == sig)
470 shutdown_status = 1;
471
472 #endif
473 #ifndef _SQUID_MSWIN_
474 #ifdef KILL_PARENT_OPT
475
476 if (getppid() > 1) {
477 debugs(1, 1, "Killing RunCache, pid " << getppid());
478
479 if (kill(getppid(), sig) < 0)
480 debugs(1, 1, "kill " << getppid() << ": " << xstrerror());
481 }
482
483 #endif
484 #if SA_RESETHAND == 0
485 signal(SIGTERM, SIG_DFL);
486
487 signal(SIGINT, SIG_DFL);
488
489 #endif
490 #endif
491 }
492
493 static void
494 serverConnectionsOpen(void)
495 {
496 clientOpenListenSockets();
497 icpConnectionsOpen();
498 #if USE_HTCP
499
500 htcpInit();
501 #endif
502 #ifdef SQUID_SNMP
503
504 snmpConnectionOpen();
505 #endif
506 #if USE_WCCP
507
508 wccpConnectionOpen();
509 #endif
510
511 #if USE_WCCPv2
512
513 wccp2ConnectionOpen();
514 #endif
515
516 clientdbInit();
517 icmpOpen();
518 netdbInit();
519 asnInit();
520 ACL::Initialize();
521 peerSelectInit();
522 #if USE_CARP
523
524 carpInit();
525 #endif
526 }
527
528 void
529 serverConnectionsClose(void)
530 {
531 assert(shutting_down || reconfiguring);
532 clientHttpConnectionsClose();
533 icpConnectionShutdown();
534 #if USE_HTCP
535
536 htcpSocketShutdown();
537 #endif
538
539 icmpClose();
540 #ifdef SQUID_SNMP
541
542 snmpConnectionShutdown();
543 #endif
544 #if USE_WCCP
545
546 wccpConnectionClose();
547 #endif
548 #if USE_WCCPv2
549
550 wccp2ConnectionClose();
551 #endif
552
553 asnFreeMemory();
554 }
555
556 static void
557 mainReconfigure(void)
558 {
559 debug(1, 1) ("Reconfiguring Squid Cache (version %s)...\n", version_string);
560 reconfiguring = 1;
561 /* Already called serverConnectionsClose and ipcacheShutdownServers() */
562 serverConnectionsClose();
563 icpConnectionClose();
564 #if USE_HTCP
565
566 htcpSocketClose();
567 #endif
568 #ifdef SQUID_SNMP
569
570 snmpConnectionClose();
571 #endif
572 #if USE_DNSSERVERS
573
574 dnsShutdown();
575 #else
576
577 idnsShutdown();
578 #endif
579
580 redirectShutdown();
581 authenticateShutdown();
582 externalAclShutdown();
583 storeDirCloseSwapLogs();
584 storeLogClose();
585 accessLogClose();
586 useragentLogClose();
587 refererCloseLog();
588 errorClean();
589 enter_suid(); /* root to read config file */
590 parseConfigFile(ConfigFile, manager);
591 setEffectiveUser();
592 _db_init(Config.Log.log, Config.debugOptions);
593 ipcache_restart(); /* clear stuck entries */
594 authenticateUserCacheRestart(); /* clear stuck ACL entries */
595 fqdncache_restart(); /* sigh, fqdncache too */
596 parseEtcHosts();
597 errorInitialize(); /* reload error pages */
598 accessLogInit();
599 storeLogOpen();
600 useragentOpenLog();
601 refererOpenLog();
602 #if USE_DNSSERVERS
603
604 dnsInit();
605 #else
606
607 idnsInit();
608 #endif
609
610 redirectInit();
611 authenticateInit(&Config.authConfiguration);
612 externalAclInit();
613 #if USE_WCCP
614
615 wccpInit();
616 #endif
617 #if USE_WCCPv2
618
619 wccp2Init();
620 #endif
621
622 serverConnectionsOpen();
623
624 if (theOutIcpConnection >= 0) {
625 neighbors_init();
626 neighborsRegisterWithCacheManager(manager);
627 }
628
629 storeDirOpenSwapLogs();
630
631 mimeInit(Config.mimeTablePathname);
632
633 writePidFile(); /* write PID file */
634
635 debug(1, 1) ("Ready to serve requests.\n");
636
637 reconfiguring = 0;
638 }
639
640 static void
641 mainRotate(void)
642 {
643 icmpClose();
644 #if USE_DNSSERVERS
645
646 dnsShutdown();
647 #endif
648
649 redirectShutdown();
650 authenticateShutdown();
651 externalAclShutdown();
652 _db_rotate_log(); /* cache.log */
653 storeDirWriteCleanLogs(1);
654 storeLogRotate(); /* store.log */
655 accessLogRotate(); /* access.log */
656 useragentRotateLog(); /* useragent.log */
657 refererRotateLog(); /* referer.log */
658 #if WIP_FWD_LOG
659
660 fwdLogRotate();
661 #endif
662
663 icmpOpen();
664 #if USE_DNSSERVERS
665
666 dnsInit();
667 #endif
668
669 redirectInit();
670 authenticateInit(&Config.authConfiguration);
671 externalAclInit();
672 }
673
674 static void
675 setEffectiveUser(void)
676 {
677 leave_suid(); /* Run as non privilegied user */
678 #ifdef _SQUID_OS2_
679
680 return;
681 #endif
682
683 if (geteuid() == 0) {
684 debug(0, 0) ("Squid is not safe to run as root! If you must\n");
685 debug(0, 0) ("start Squid as root, then you must configure\n");
686 debug(0, 0) ("it to run as a non-priveledged user with the\n");
687 debug(0, 0) ("'cache_effective_user' option in the config file.\n");
688 fatal("Don't run Squid as root, set 'cache_effective_user'!");
689 }
690 }
691
692 static void
693 mainSetCwd(void)
694 {
695 char pathbuf[MAXPATHLEN];
696
697 if (Config.coredump_dir) {
698 if (0 == strcmp("none", Config.coredump_dir)) {
699 (void) 0;
700 } else if (chdir(Config.coredump_dir) == 0) {
701 debug(0, 1) ("Set Current Directory to %s\n", Config.coredump_dir);
702 return;
703 } else {
704 debug(50, 0) ("chdir: %s: %s\n", Config.coredump_dir, xstrerror());
705 }
706 }
707
708 /* If we don't have coredump_dir or couldn't cd there, report current dir */
709 if (getcwd(pathbuf, MAXPATHLEN)) {
710 debug(0, 1) ("Current Directory is %s\n", pathbuf);
711 } else {
712 debug(50, 0) ("WARNING: Can't find current directory, getcwd: %s\n", xstrerror());
713 }
714 }
715
716 #if DELAY_POOLS
717 #include "DelayPools.h"
718 #endif
719
720 static void
721 mainInitialize(void)
722 {
723 /* chroot if configured to run inside chroot */
724
725 if (Config.chroot_dir && chroot(Config.chroot_dir)) {
726 fatal("failed to chroot");
727 }
728
729 if (opt_catch_signals) {
730 squid_signal(SIGSEGV, death, SA_NODEFER | SA_RESETHAND);
731 squid_signal(SIGBUS, death, SA_NODEFER | SA_RESETHAND);
732 }
733
734 squid_signal(SIGPIPE, SIG_IGN, SA_RESTART);
735 squid_signal(SIGCHLD, sig_child, SA_NODEFER | SA_RESTART);
736
737 setEffectiveUser();
738
739 if (icpPortNumOverride != 1)
740 Config.Port.icp = (u_short) icpPortNumOverride;
741
742 _db_init(Config.Log.log, Config.debugOptions);
743
744 fd_open(fileno(debug_log), FD_LOG, Config.Log.log);
745
746 #if MEM_GEN_TRACE
747
748 log_trace_init("/tmp/squid.alloc");
749
750 #endif
751
752 debug(1, 0) ("Starting Squid Cache version %s for %s...\n",
753 version_string,
754 CONFIG_HOST_TYPE);
755
756 #ifdef _SQUID_WIN32_
757
758 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
759 debug(1, 0) ("Running as %s Windows System Service on %s\n", WIN32_Service_name, WIN32_OS_string);
760 debug(1, 0) ("Service command line is: %s\n", WIN32_Service_Command_Line);
761 } else
762 debug(1, 0) ("Running on %s\n",WIN32_OS_string);
763
764 #endif
765
766 debugs(1, 1, "Process ID " << getpid());
767
768 debug(1, 1) ("With %d file descriptors available\n", Squid_MaxFD);
769
770 #ifdef _SQUID_MSWIN_
771
772 debug(1, 1) ("With %d CRT stdio descriptors available\n", _getmaxstdio());
773
774 if (WIN32_Socks_initialized)
775 debug(1, 1)("Windows sockets initialized\n");
776
777 #endif
778
779 if (!configured_once)
780 disk_init(); /* disk_init must go before ipcache_init() */
781
782 ipcache_init();
783
784 fqdncache_init();
785
786 parseEtcHosts();
787
788 #if USE_DNSSERVERS
789
790 dnsInit();
791
792 #else
793
794 idnsInit();
795
796 #endif
797
798 redirectInit();
799
800 authenticateInit(&Config.authConfiguration);
801
802 externalAclInit();
803
804 useragentOpenLog();
805
806 refererOpenLog();
807
808 httpHeaderInitModule(); /* must go before any header processing (e.g. the one in errorInitialize) */
809
810 httpReplyInitModule(); /* must go before accepting replies */
811
812 errorInitialize();
813
814 accessLogInit();
815
816 #if USE_IDENT
817
818 identInit();
819
820 #endif
821 #ifdef SQUID_SNMP
822
823 snmpInit();
824
825 #endif
826 #if MALLOC_DBG
827
828 malloc_debug(0, malloc_debug_level);
829
830 #endif
831
832 if (!configured_once) {
833 #if USE_UNLINKD
834 unlinkdInit();
835 #endif
836
837 urlInitialize();
838 statInit();
839 storeInit();
840 mainSetCwd();
841 /* after this point we want to see the mallinfo() output */
842 do_mallinfo = 1;
843 mimeInit(Config.mimeTablePathname);
844 refreshInit();
845 #if DELAY_POOLS
846
847 DelayPools::Init();
848 #endif
849
850 FwdState::initModule();
851 /* register the modules in the cache manager menus */
852 accessLogRegisterWithCacheManager(manager);
853 asnRegisterWithCacheManager(manager);
854 authenticateRegisterWithCacheManager(&Config.authConfiguration, manager);
855 #if USE_CARP
856
857 carpRegisterWithCacheManager(manager);
858 #endif
859
860 cbdataRegisterWithCacheManager(manager);
861 /* These use separate calls so that the comm loops can eventually
862 * coexist.
863 */
864 #ifdef USE_EPOLL
865
866 commEPollRegisterWithCacheManager(manager);
867 #endif
868 #ifdef USE_KQUEUE
869
870 commKQueueRegisterWithCacheManager(manager);
871 #endif
872 #ifdef USE_POLL
873
874 commPollRegisterWithCacheManager(manager);
875 #endif
876 #ifdef USE_SELECT
877
878 commSelectRegisterWithCacheManager(manager);
879 #endif
880
881 clientdbRegisterWithCacheManager(manager);
882 #if DELAY_POOLS
883
884 DelayPools::RegisterWithCacheManager(manager);
885 #endif
886
887 DiskIOModule::RegisterAllModulesWithCacheManager(manager);
888 #if USE_DNSSERVERS
889
890 dnsRegisterWithCacheManager(manager);
891 #endif
892
893 eventInit(manager);
894 externalAclRegisterWithCacheManager(manager);
895 fqdncacheRegisterWithCacheManager(manager);
896 FwdState::RegisterWithCacheManager(manager);
897 httpHeaderRegisterWithCacheManager(manager);
898 #if !USE_DNSSERVERS
899
900 idnsRegisterWithCacheManager(manager);
901 #endif
902
903 ipcacheRegisterWithCacheManager(manager);
904 Mem::RegisterWithCacheManager(manager);
905 netdbRegisterWitHCacheManager(manager);
906 PconnModule::GetInstance()->registerWithCacheManager(manager);
907 redirectRegisterWithCacheManager(manager);
908 refreshRegisterWithCacheManager(manager);
909 statRegisterWithCacheManager(manager);
910 storeDigestRegisterWithCacheManager(manager);
911 StoreFileSystem::RegisterAllFsWithCacheManager(manager);
912 storeRegisterWithCacheManager(manager);
913 #if DEBUGSTRINGS
914
915 StringRegistry::Instance().registerWithCacheManager(manager);
916 #endif
917
918 #if USE_XPROF_STATS
919
920 xprofRegisterWithCacheManager(manager);
921 #endif
922
923 }
924
925 #if USE_WCCP
926 wccpInit();
927
928 #endif
929 #if USE_WCCPv2
930
931 wccp2Init();
932
933 #endif
934
935 serverConnectionsOpen();
936
937 if (theOutIcpConnection >= 0) {
938 neighbors_init();
939 neighborsRegisterWithCacheManager(manager);
940 }
941
942 if (Config.chroot_dir)
943 no_suid();
944
945 if (!configured_once)
946 writePidFile(); /* write PID file */
947
948 #ifdef _SQUID_LINUX_THREADS_
949
950 squid_signal(SIGQUIT, rotate_logs, SA_RESTART);
951
952 squid_signal(SIGTRAP, sigusr2_handle, SA_RESTART);
953
954 #else
955
956 squid_signal(SIGUSR1, rotate_logs, SA_RESTART);
957
958 squid_signal(SIGUSR2, sigusr2_handle, SA_RESTART);
959
960 #endif
961
962 squid_signal(SIGHUP, reconfigure, SA_RESTART);
963
964 squid_signal(SIGTERM, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
965
966 squid_signal(SIGINT, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
967
968 #ifdef SIGTTIN
969
970 squid_signal(SIGTTIN, shut_down, SA_NODEFER | SA_RESETHAND | SA_RESTART);
971
972 #endif
973
974 memCheckInit();
975
976 debug(1, 1) ("Ready to serve requests.\n");
977
978 if (!configured_once) {
979 eventAdd("storeMaintain", Store::Maintain, NULL, 1.0, 1);
980
981 if (Config.onoff.announce)
982 eventAdd("start_announce", start_announce, NULL, 3600.0, 1);
983
984 eventAdd("ipcache_purgelru", ipcache_purgelru, NULL, 10.0, 1);
985
986 eventAdd("fqdncache_purgelru", fqdncache_purgelru, NULL, 15.0, 1);
987
988 #if USE_XPROF_STATS
989
990 eventAdd("cpuProfiling", xprof_event, NULL, 1.0, 1);
991
992 #endif
993
994 eventAdd("memPoolCleanIdlePools", Mem::CleanIdlePools, NULL, 15.0, 1);
995
996 eventAdd("commCheckHalfClosed", commCheckHalfClosed, NULL, 1.0, false);
997 }
998
999 configured_once = 1;
1000 }
1001
1002 #if USE_WIN32_SERVICE
1003 /* When USE_WIN32_SERVICE is defined, the main function is placed in win32.cc */
1004 extern "C" void WINAPI
1005 SquidWinSvcMain(int argc, char **argv)
1006 {
1007 SquidMain(argc, argv);
1008 }
1009
1010 int
1011 SquidMain(int argc, char **argv)
1012 #else
1013 int
1014 main(int argc, char **argv)
1015 #endif
1016 {
1017 int errcount = 0;
1018 mode_t oldmask;
1019 #ifdef _SQUID_WIN32_
1020
1021 int WIN32_init_err;
1022 #endif
1023
1024 #if HAVE_SBRK
1025
1026 sbrk_start = sbrk(0);
1027 #endif
1028
1029 Debug::parseOptions("ALL,1");
1030 debug_log = stderr;
1031
1032 #if defined(SQUID_MAXFD_LIMIT)
1033
1034 if (SQUID_MAXFD_LIMIT < Squid_MaxFD)
1035 Squid_MaxFD = SQUID_MAXFD_LIMIT;
1036
1037 #endif
1038
1039 #ifdef _SQUID_WIN32_
1040
1041 if ((WIN32_init_err = WIN32_Subsystem_Init(&argc, &argv)))
1042 return WIN32_init_err;
1043
1044 #endif
1045
1046 /* call mallopt() before anything else */
1047 #if HAVE_MALLOPT
1048 #ifdef M_GRAIN
1049 /* Round up all sizes to a multiple of this */
1050 mallopt(M_GRAIN, 16);
1051
1052 #endif
1053 #ifdef M_MXFAST
1054 /* biggest size that is considered a small block */
1055 mallopt(M_MXFAST, 256);
1056
1057 #endif
1058 #ifdef M_NBLKS
1059 /* allocate this many small blocks at once */
1060 mallopt(M_NLBLKS, 32);
1061
1062 #endif
1063 #endif /* HAVE_MALLOPT */
1064
1065 /*
1066 * The plan here is to set the umask to 007 (deny others for
1067 * read,write,execute), but only if the umask is not already
1068 * set. Unfortunately, there is no way to get the current
1069 * umask value without setting it.
1070 */
1071 oldmask = umask(S_IRWXO);
1072
1073 if (oldmask)
1074 umask(oldmask);
1075
1076 memset(&local_addr, '\0', sizeof(struct IN_ADDR));
1077
1078 safe_inet_addr(localhost, &local_addr);
1079
1080 memset(&any_addr, '\0', sizeof(struct IN_ADDR));
1081
1082 safe_inet_addr("0.0.0.0", &any_addr);
1083
1084 memset(&no_addr, '\0', sizeof(struct IN_ADDR));
1085
1086 safe_inet_addr("255.255.255.255", &no_addr);
1087
1088 squid_srandom(time(NULL));
1089
1090 getCurrentTime();
1091
1092 squid_start = current_time;
1093
1094 failure_notify = fatal_dump;
1095
1096 #if USE_WIN32_SERVICE
1097
1098 WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
1099
1100 #endif
1101
1102 mainParseOptions(argc, argv);
1103
1104 #if USE_WIN32_SERVICE
1105
1106 if (opt_install_service)
1107 {
1108 WIN32_InstallService();
1109 return 0;
1110 }
1111
1112 if (opt_remove_service)
1113 {
1114 WIN32_RemoveService();
1115 return 0;
1116 }
1117
1118 if (opt_command_line)
1119 {
1120 WIN32_SetServiceCommandLine();
1121 return 0;
1122 }
1123
1124 #endif
1125
1126 /* parse configuration file
1127 * note: in "normal" case this used to be called from mainInitialize() */
1128 {
1129 int parse_err;
1130
1131 if (!ConfigFile)
1132 ConfigFile = xstrdup(DefaultConfigFile);
1133
1134 assert(!configured_once);
1135
1136 Mem::Init();
1137
1138 cbdataInit();
1139
1140 storeFsInit(); /* required for config parsing */
1141
1142 /* May not be needed for parsing, have not audited for such */
1143 DiskIOModule::SetupAllModules();
1144
1145 /* Shouldn't be needed for config parsing, but have not audited for such */
1146 StoreFileSystem::SetupAllFs();
1147
1148 /* we may want the parsing process to set this up in the future */
1149 Store::Root(new StoreController);
1150
1151 parse_err = parseConfigFile(ConfigFile, manager);
1152
1153 if (opt_parse_cfg_only)
1154
1155 return parse_err;
1156 }
1157 if (-1 == opt_send_signal)
1158 if (checkRunningPid())
1159 exit(1);
1160
1161 #if TEST_ACCESS
1162
1163 comm_init();
1164
1165 comm_select_init();
1166
1167 mainInitialize();
1168
1169 test_access();
1170
1171 return 0;
1172
1173 #endif
1174
1175 /* send signal to running copy and exit */
1176 if (opt_send_signal != -1)
1177 {
1178 /* chroot if configured to run inside chroot */
1179
1180 if (Config.chroot_dir) {
1181 if (chroot(Config.chroot_dir))
1182 fatal("failed to chroot");
1183
1184 no_suid();
1185 } else {
1186 leave_suid();
1187 }
1188
1189 sendSignal();
1190 /* NOTREACHED */
1191 }
1192
1193 if (opt_create_swap_dirs)
1194 {
1195 /* chroot if configured to run inside chroot */
1196
1197 if (Config.chroot_dir && chroot(Config.chroot_dir)) {
1198 fatal("failed to chroot");
1199 }
1200
1201 setEffectiveUser();
1202 debug(0, 0) ("Creating Swap Directories\n");
1203 Store::Root().create();
1204
1205 return 0;
1206 }
1207
1208 if (!opt_no_daemon)
1209 watch_child(argv);
1210
1211 setMaxFD();
1212
1213 /* init comm module */
1214 comm_init();
1215
1216 comm_select_init();
1217
1218 if (opt_no_daemon)
1219 {
1220 /* we have to init fdstat here. */
1221 fd_open(0, FD_LOG, "stdin");
1222 fd_open(1, FD_LOG, "stdout");
1223 fd_open(2, FD_LOG, "stderr");
1224 }
1225
1226 #if USE_WIN32_SERVICE
1227
1228 WIN32_svcstatusupdate(SERVICE_START_PENDING, 10000);
1229
1230 #endif
1231
1232 mainInitialize();
1233
1234 #if USE_WIN32_SERVICE
1235
1236 WIN32_svcstatusupdate(SERVICE_RUNNING, 0);
1237
1238 #endif
1239
1240 /* main loop */
1241
1242 for (;;)
1243 {
1244 if (do_reconfigure) {
1245 mainReconfigure();
1246 do_reconfigure = 0;
1247 #if defined(_SQUID_MSWIN_) && defined(_DEBUG)
1248
1249 } else if (do_debug_trap) {
1250 do_debug_trap = 0;
1251 __asm int 3;
1252 #endif
1253
1254 } else if (do_rotate) {
1255 mainRotate();
1256 do_rotate = 0;
1257 } else if (do_shutdown) {
1258 time_t wait = do_shutdown > 0 ? (int) Config.shutdownLifetime : 0;
1259 debug(1, 1) ("Preparing for shutdown after %d requests\n",
1260 statCounter.client_http.requests);
1261 debug(1, 1) ("Waiting %d seconds for active connections to finish\n",
1262 (int) wait);
1263 do_shutdown = 0;
1264 shutting_down = 1;
1265 #if USE_WIN32_SERVICE
1266
1267 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, (wait + 1) * 1000);
1268 #endif
1269
1270 serverConnectionsClose();
1271 eventAdd("SquidShutdown", SquidShutdown, NULL, (double) (wait + 1), 1);
1272 }
1273
1274 eventRun();
1275
1276 /* Attempt any pending storedir IO
1277 * Note: the storedir is roughly a reactor of its own.
1278 */
1279 Store::Root().callback();
1280
1281 comm_calliocallback();
1282
1283 /* and again to deal with indirectly queued events
1284 * resulting from the first call. These are usually
1285 * callbacks and should be dealt with immediately.
1286 */
1287
1288 if (comm_iocallbackpending())
1289 comm_calliocallback();
1290
1291 int loop_delay = eventNextTime();
1292
1293 if (loop_delay < 0)
1294 loop_delay = 0;
1295
1296 switch (comm_select(loop_delay)) {
1297
1298 case COMM_OK:
1299 errcount = 0; /* reset if successful */
1300 break;
1301
1302 case COMM_ERROR:
1303 errcount++;
1304 debug(1, 0) ("Select loop Error. Retry %d\n", errcount);
1305
1306 if (errcount == 10)
1307 fatal_dump("Select Loop failed!");
1308
1309 break;
1310
1311 case COMM_TIMEOUT:
1312 break;
1313
1314 case COMM_SHUTDOWN:
1315 SquidShutdown(NULL);
1316
1317 break;
1318
1319 default:
1320 fatal_dump("MAIN: Internal error -- this should never happen.");
1321
1322 break;
1323 }
1324 }
1325
1326 /* NOTREACHED */
1327 return 0;
1328 }
1329
1330 static void
1331 sendSignal(void)
1332 {
1333 pid_t pid;
1334 debug_log = stderr;
1335
1336 if (strcmp(Config.pidFilename, "none") == 0) {
1337 debug(0, 1) ("No pid_filename specified. Trusting you know what you are doing.\n");
1338 }
1339
1340 pid = readPidFile();
1341
1342 if (pid > 1) {
1343 #if USE_WIN32_SERVICE
1344
1345 if (opt_signal_service) {
1346 WIN32_sendSignal(opt_send_signal);
1347 exit(0);
1348 } else
1349 #ifdef _SQUID_MSWIN_
1350 {
1351 fprintf(stderr, "%s: ERROR: Could not send ", appname);
1352 fprintf(stderr, "signal to Squid Service:\n");
1353 fprintf(stderr, "missing -n command line switch.\n");
1354 exit(1);
1355 }
1356
1357 /* NOTREACHED */
1358 #endif
1359
1360 #endif
1361
1362 if (kill(pid, opt_send_signal) &&
1363 /* ignore permissions if just running check */
1364 !(opt_send_signal == 0 && errno == EPERM)) {
1365 fprintf(stderr, "%s: ERROR: Could not send ", appname);
1366 fprintf(stderr, "signal %d to process %d: %s\n",
1367 opt_send_signal, (int) pid, xstrerror());
1368 exit(1);
1369 }
1370 } else {
1371 fprintf(stderr, "%s: ERROR: No running copy\n", appname);
1372 exit(1);
1373 }
1374
1375 /* signal successfully sent */
1376 exit(0);
1377 }
1378
1379 #ifndef _SQUID_MSWIN_
1380 /*
1381 * This function is run when Squid is in daemon mode, just
1382 * before the parent forks and starts up the child process.
1383 * It can be used for admin-specific tasks, such as notifying
1384 * someone that Squid is (re)started.
1385 */
1386 static void
1387 mainStartScript(const char *prog)
1388 {
1389 char script[SQUID_MAXPATHLEN];
1390 char *t;
1391 size_t sl = 0;
1392 pid_t cpid;
1393 pid_t rpid;
1394 xstrncpy(script, prog, MAXPATHLEN);
1395
1396 if ((t = strrchr(script, '/'))) {
1397 *(++t) = '\0';
1398 sl = strlen(script);
1399 }
1400
1401 xstrncpy(&script[sl], squid_start_script, MAXPATHLEN - sl);
1402
1403 if ((cpid = fork()) == 0) {
1404 /* child */
1405 execl(script, squid_start_script, (char *)NULL);
1406 _exit(-1);
1407 } else {
1408 do {
1409 #ifdef _SQUID_NEXT_
1410 union wait status;
1411 rpid = wait3(&status, 0, NULL);
1412 #else
1413
1414 int status;
1415 rpid = waitpid(-1, &status, 0);
1416 #endif
1417
1418 } while (rpid != cpid);
1419 }
1420 }
1421
1422 #endif /* _SQUID_MSWIN_ */
1423
1424 static int
1425 checkRunningPid(void)
1426 {
1427 pid_t pid;
1428
1429 if (!debug_log)
1430 debug_log = stderr;
1431
1432 pid = readPidFile();
1433
1434 if (pid < 2)
1435 return 0;
1436
1437 if (kill(pid, 0) < 0)
1438 return 0;
1439
1440 debugs(0, 0, "Squid is already running! Process ID " << pid);
1441
1442 return 1;
1443 }
1444
1445 static void
1446 watch_child(char *argv[])
1447 {
1448 #ifndef _SQUID_MSWIN_
1449 char *prog;
1450 int failcount = 0;
1451 time_t start;
1452 time_t stop;
1453 #ifdef _SQUID_NEXT_
1454
1455 union wait status;
1456 #else
1457
1458 int status;
1459 #endif
1460
1461 pid_t pid;
1462 #ifdef TIOCNOTTY
1463
1464 int i;
1465 #endif
1466
1467 int nullfd;
1468
1469 if (*(argv[0]) == '(')
1470 return;
1471
1472 openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
1473
1474 if ((pid = fork()) < 0)
1475 syslog(LOG_ALERT, "fork failed: %s", xstrerror());
1476 else if (pid > 0)
1477 exit(0);
1478
1479 if (setsid() < 0)
1480 syslog(LOG_ALERT, "setsid failed: %s", xstrerror());
1481
1482 closelog();
1483
1484 #ifdef TIOCNOTTY
1485
1486 if ((i = open("/dev/tty", O_RDWR | O_TEXT)) >= 0) {
1487 ioctl(i, TIOCNOTTY, NULL);
1488 close(i);
1489 }
1490
1491 #endif
1492
1493
1494 /*
1495 * RBCOLLINS - if cygwin stackdumps when squid is run without
1496 * -N, check the cygwin1.dll version, it needs to be AT LEAST
1497 * 1.1.3. execvp had a bit overflow error in a loop..
1498 */
1499 /* Connect stdio to /dev/null in daemon mode */
1500 nullfd = open("/dev/null", O_RDWR | O_TEXT);
1501
1502 if (nullfd < 0)
1503 fatalf("/dev/null: %s\n", xstrerror());
1504
1505 dup2(nullfd, 0);
1506
1507 if (opt_debug_stderr < 0) {
1508 dup2(nullfd, 1);
1509 dup2(nullfd, 2);
1510 }
1511
1512 for (;;) {
1513 mainStartScript(argv[0]);
1514
1515 if ((pid = fork()) == 0) {
1516 /* child */
1517 openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
1518 prog = xstrdup(argv[0]);
1519 argv[0] = xstrdup("(squid)");
1520 execvp(prog, argv);
1521 syslog(LOG_ALERT, "execvp failed: %s", xstrerror());
1522 }
1523
1524 /* parent */
1525 openlog(appname, LOG_PID | LOG_NDELAY | LOG_CONS, LOG_LOCAL4);
1526
1527 syslog(LOG_NOTICE, "Squid Parent: child process %d started", pid);
1528
1529 time(&start);
1530
1531 squid_signal(SIGINT, SIG_IGN, SA_RESTART);
1532
1533 #ifdef _SQUID_NEXT_
1534
1535 pid = wait3(&status, 0, NULL);
1536
1537 #else
1538
1539 pid = waitpid(-1, &status, 0);
1540
1541 #endif
1542
1543 time(&stop);
1544
1545 if (WIFEXITED(status)) {
1546 syslog(LOG_NOTICE,
1547 "Squid Parent: child process %d exited with status %d",
1548 pid, WEXITSTATUS(status));
1549 } else if (WIFSIGNALED(status)) {
1550 syslog(LOG_NOTICE,
1551 "Squid Parent: child process %d exited due to signal %d",
1552 pid, WTERMSIG(status));
1553 } else {
1554 syslog(LOG_NOTICE, "Squid Parent: child process %d exited", pid);
1555 }
1556
1557 if (stop - start < 10)
1558 failcount++;
1559 else
1560 failcount = 0;
1561
1562 if (failcount == 5) {
1563 syslog(LOG_ALERT, "Exiting due to repeated, frequent failures");
1564 exit(1);
1565 }
1566
1567 if (WIFEXITED(status))
1568 if (WEXITSTATUS(status) == 0)
1569 exit(0);
1570
1571 if (WIFSIGNALED(status)) {
1572 switch (WTERMSIG(status)) {
1573
1574 case SIGKILL:
1575 exit(0);
1576 break;
1577
1578 default:
1579 break;
1580 }
1581 }
1582
1583 squid_signal(SIGINT, SIG_DFL, SA_RESTART);
1584 sleep(3);
1585 }
1586
1587 /* NOTREACHED */
1588 #endif /* _SQUID_MSWIN_ */
1589
1590 }
1591
1592 static void
1593 SquidShutdown(void *unused)
1594 {
1595 #if USE_WIN32_SERVICE
1596 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
1597 #endif
1598
1599 debug(1, 1) ("Shutting down...\n");
1600 #if USE_DNSSERVERS
1601
1602 dnsShutdown();
1603 #else
1604
1605 idnsShutdown();
1606 #endif
1607
1608 redirectShutdown();
1609 externalAclShutdown();
1610 icpConnectionClose();
1611 #if USE_HTCP
1612
1613 htcpSocketClose();
1614 #endif
1615 #ifdef SQUID_SNMP
1616
1617 snmpConnectionClose();
1618 #endif
1619 #if USE_WCCP
1620
1621 wccpConnectionClose();
1622 #endif
1623 #if USE_WCCPv2
1624
1625 wccp2ConnectionClose();
1626 #endif
1627
1628 releaseServerSockets();
1629 commCloseAllSockets();
1630 #if DELAY_POOLS
1631
1632 DelayPools::FreePools();
1633 #endif
1634
1635 authenticateShutdown();
1636 #if USE_UNLINKD
1637
1638 unlinkdClose();
1639 #endif
1640 #if USE_WIN32_SERVICE
1641
1642 WIN32_svcstatusupdate(SERVICE_STOP_PENDING, 10000);
1643 #endif
1644
1645 Store::Root().sync(); /* Flush pending object writes/unlinks */
1646 storeDirWriteCleanLogs(0);
1647 PrintRusage();
1648 dumpMallocStats();
1649 Store::Root().sync(); /* Flush log writes */
1650 storeLogClose();
1651 accessLogClose();
1652 useragentLogClose();
1653 refererCloseLog();
1654 #if WIP_FWD_LOG
1655
1656 fwdUninit();
1657 #endif
1658
1659 Store::Root().sync(); /* Flush log close */
1660 StoreFileSystem::FreeAllFs();
1661 DiskIOModule::FreeAllModules();
1662 #if PURIFY || XMALLOC_TRACE
1663
1664 configFreeMemory();
1665 storeFreeMemory();
1666 /*stmemFreeMemory(); */
1667 netdbFreeMemory();
1668 ipcacheFreeMemory();
1669 fqdncacheFreeMemory();
1670 asnFreeMemory();
1671 clientdbFreeMemory();
1672 httpHeaderCleanModule();
1673 statFreeMemory();
1674 eventFreeMemory();
1675 mimeFreeMemory();
1676 errorClean();
1677 #endif
1678 #if !XMALLOC_TRACE
1679
1680 if (opt_no_daemon) {
1681 file_close(0);
1682 file_close(1);
1683 file_close(2);
1684 }
1685
1686 #endif
1687 fdDumpOpen();
1688
1689 fdFreeMemory();
1690
1691 memClean();
1692
1693 #if XMALLOC_TRACE
1694
1695 xmalloc_find_leaks();
1696
1697 debug(1, 0) ("Memory used after shutdown: %d\n", xmalloc_total);
1698
1699 #endif
1700 #if MEM_GEN_TRACE
1701
1702 log_trace_done();
1703
1704 #endif
1705
1706 if (Config.pidFilename && strcmp(Config.pidFilename, "none") != 0) {
1707 enter_suid();
1708 safeunlink(Config.pidFilename, 0);
1709 leave_suid();
1710 }
1711
1712 debug(1, 1) ("Squid Cache (Version %s): Exiting normally.\n",
1713 version_string);
1714
1715 if (debug_log)
1716 fclose(debug_log);
1717
1718 exit(shutdown_status);
1719 }