]> git.ipfire.org Git - thirdparty/squid.git/blob - src/WinSvc.cc
Completed protos.h split and code refactoring
[thirdparty/squid.git] / src / WinSvc.cc
1 /*
2 * Windows support
3 * AUTHOR: Guido Serassio <serassio@squid-cache.org>
4 * inspired by previous work by Romeo Anghelache & Eric Stern.
5 *
6 * SQUID Web Proxy Cache http://www.squid-cache.org/
7 * ----------------------------------------------------------
8 *
9 * Squid is the result of efforts by numerous individuals from
10 * the Internet community; see the CONTRIBUTORS file for full
11 * details. Many organizations have provided support for Squid's
12 * development; see the SPONSORS file for full details. Squid is
13 * Copyrighted (C) 2001 by the Regents of the University of
14 * California; see the COPYRIGHT file for full details. Squid
15 * incorporates software developed and/or copyrighted by other
16 * sources; see the CREDITS file for full details.
17 *
18 * This program is free software; you can redistribute it and/or modify
19 * it under the terms of the GNU General Public License as published by
20 * the Free Software Foundation; either version 2 of the License, or
21 * (at your option) any later version.
22 *
23 * This program is distributed in the hope that it will be useful,
24 * but WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 * GNU General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program; if not, write to the Free Software
30 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
31 *
32 */
33
34 #include "squid.h"
35 #include "protos.h"
36 #include "squid_windows.h"
37
38 #if _SQUID_MSWIN_
39 #ifndef _MSWSOCK_
40 #include <mswsock.h>
41 #endif
42 #include <process.h>
43 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
44 #include <crtdbg.h>
45 #endif
46 #endif
47
48 /* forward declarations */
49 static void WIN32_Exit(void);
50 static void WIN32_Abort(int);
51
52 static unsigned int GetOSVersion();
53 void WIN32_svcstatusupdate(DWORD, DWORD);
54 void WINAPI WIN32_svcHandler(DWORD);
55 #if USE_WIN32_SERVICE
56 static int WIN32_StoreKey(const char *, DWORD, unsigned char *, int);
57 static int WIN32_create_key(void);
58 static void WIN32_build_argv (char *);
59 #endif
60 extern "C" void WINAPI SquidWinSvcMain(DWORD, char **);
61
62 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
63 void Squid_Win32InvalidParameterHandler(const wchar_t*, const wchar_t*, const wchar_t*, unsigned int, uintptr_t);
64 #endif
65 static int Win32SockInit(void);
66 static void Win32SockCleanup(void);
67 SQUIDCEXTERN LPCRITICAL_SECTION dbg_mutex;
68 void WIN32_ExceptionHandlerCleanup(void);
69 static int s_iInitCount = 0;
70 static HANDLE NotifyAddrChange_thread = INVALID_HANDLE_VALUE;
71
72 static int Squid_Aborting = 0;
73
74 #undef NotifyAddrChange
75 typedef DWORD(WINAPI * PFNotifyAddrChange) (OUT PHANDLE, IN LPOVERLAPPED);
76 #define NOTIFYADDRCHANGE "NotifyAddrChange"
77
78 #if USE_WIN32_SERVICE
79 static SERVICE_STATUS svcStatus;
80 static SERVICE_STATUS_HANDLE svcHandle;
81 static int WIN32_argc;
82 static char ** WIN32_argv;
83 static char * WIN32_module_name;
84
85 #define VENDOR "squid-cache.org"
86 static char VENDORString[] = VENDOR;
87 #define SOFTWARENAME PACKAGE_NAME
88 static char SOFTWARENAMEString[] = SOFTWARENAME;
89 #define SOFTWARE "SOFTWARE"
90 static char SOFTWAREString[] = SOFTWARE;
91 #define COMMANDLINE "CommandLine"
92 #define CONFIGFILE "ConfigFile"
93 #undef ChangeServiceConfig2
94 typedef BOOL (WINAPI * PFChangeServiceConfig2) (SC_HANDLE, DWORD, LPVOID);
95 #ifdef UNICODE
96 #define CHANGESERVICECONFIG2 "ChangeServiceConfig2W"
97 #else
98 #define CHANGESERVICECONFIG2 "ChangeServiceConfig2A"
99 #endif
100 static SC_ACTION Squid_SCAction[] = { { SC_ACTION_RESTART, 60000 } };
101 static char Squid_ServiceDescriptionString[] = SOFTWARENAME " " VERSION " WWW Proxy Server";
102 static SERVICE_DESCRIPTION Squid_ServiceDescription = { Squid_ServiceDescriptionString };
103 static SERVICE_FAILURE_ACTIONS Squid_ServiceFailureActions = { INFINITE, NULL, NULL, 1, Squid_SCAction };
104 static char REGKEY[256]=SOFTWARE"\\"VENDOR"\\"SOFTWARENAME"\\";
105 static char *keys[] = {
106 SOFTWAREString, /* key[0] */
107 VENDORString, /* key[1] */
108 SOFTWARENAMEString, /* key[2] */
109 NULL, /* key[3] */
110 NULL /* key[4] */
111 };
112 #endif
113
114 /* ====================================================================== */
115 /* LOCAL FUNCTIONS */
116 /* ====================================================================== */
117
118 #if USE_WIN32_SERVICE
119 static int
120 WIN32_create_key(void)
121 {
122 int index;
123 HKEY hKey;
124 HKEY hKeyNext;
125 int retval;
126 LONG rv;
127
128 hKey = HKEY_LOCAL_MACHINE;
129 index = 0;
130 retval = 0;
131
132 /* Walk the tree, creating at each stage if necessary */
133
134 while (keys[index]) {
135 unsigned long result;
136 rv = RegCreateKeyEx(hKey, keys[index], /* subkey */
137 0, /* reserved */
138 NULL, /* class */
139 REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKeyNext, &result);
140
141 if (rv != ERROR_SUCCESS) {
142 fprintf(stderr, "RegCreateKeyEx(%s),%d\n", keys[index], (int) rv);
143 retval = -4;
144 }
145
146 /* Close the old key */
147 rv = RegCloseKey(hKey);
148
149 if (rv != ERROR_SUCCESS) {
150 fprintf(stderr, "RegCloseKey %d\n", (int) rv);
151
152 if (retval == 0) {
153 /* Keep error status from RegCreateKeyEx, if any */
154 retval = -4;
155 }
156 }
157
158 if (retval) {
159 break;
160 }
161
162 hKey = hKeyNext;
163 ++index;
164 }
165
166 if (keys[index] == NULL) {
167 /* Close the final key we opened, if we walked the entire
168 * tree
169 */
170 rv = RegCloseKey(hKey);
171
172 if (rv != ERROR_SUCCESS) {
173 fprintf(stderr, "RegCloseKey %d\n", (int) rv);
174
175 if (retval == 0) {
176 /* Keep error status from RegCreateKeyEx, if any */
177 retval = -4;
178 }
179 }
180 }
181
182 return retval;
183 }
184
185 static int
186 WIN32_StoreKey(const char *key, DWORD type, unsigned char *value,
187 int value_size)
188 {
189 LONG rv;
190 HKEY hKey;
191 int retval;
192
193 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_WRITE, &hKey);
194
195 if (rv == ERROR_FILE_NOT_FOUND) {
196 /* Key could not be opened -- try to create it
197 */
198
199 if (WIN32_create_key() < 0) {
200 /* Creation failed (error already reported) */
201 return -4;
202 }
203
204 /* Now it has been created we should be able to open it
205 */
206 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_WRITE, &hKey);
207
208 if (rv == ERROR_FILE_NOT_FOUND) {
209 fprintf(stderr, "Registry does not contain key %s after creation\n",
210 REGKEY);
211 return -1;
212 }
213 }
214
215 if (rv != ERROR_SUCCESS) {
216 fprintf(stderr, "RegOpenKeyEx HKLM\\%s, %d\n", REGKEY, (int) rv);
217 return -4;
218 }
219
220 /* Now set the value and data */
221 rv = RegSetValueEx(hKey, key, /* value key name */
222 0, /* reserved */
223 type, /* type */
224 value, /* value data */
225 (DWORD) value_size); /* for size of "value" */
226
227 retval = 0; /* Return value */
228
229 if (rv != ERROR_SUCCESS) {
230 fprintf(stderr, "RegQueryValueEx(key %s),%d\n", key, (int) rv);
231 retval = -4;
232 } else {
233 fprintf(stderr, "Registry stored HKLM\\%s\\%s value %s\n",
234 REGKEY,
235 key,
236 type == REG_SZ ? value : (unsigned char *) "(not displayable)");
237 }
238
239 /* Make sure we close the key even if there was an error storing
240 * the data
241 */
242 rv = RegCloseKey(hKey);
243
244 if (rv != ERROR_SUCCESS) {
245 fprintf(stderr, "RegCloseKey HKLM\\%s, %d\n", REGKEY, (int) rv);
246
247 if (retval == 0) {
248 /* Keep error status from RegQueryValueEx, if any */
249 retval = -4;
250 }
251 }
252
253 return retval;
254 }
255
256 /* Build argv, argc from string passed from Windows. */
257 static void WIN32_build_argv(char *cmd)
258 {
259 int argvlen = 0;
260 char *word;
261
262 WIN32_argc = 1;
263 WIN32_argv = (char **) xmalloc ((WIN32_argc+1) * sizeof (char *));
264 WIN32_argv[0]=xstrdup(WIN32_module_name);
265 /* Scan command line until there is nothing left. */
266
267 while (*cmd) {
268 /* Ignore spaces */
269
270 if (xisspace(*cmd)) {
271 ++cmd;
272 continue;
273 }
274
275 /* Found the beginning of an argument. */
276 word = cmd;
277
278 while (*cmd) {
279 ++cmd; /* Skip over this character */
280
281 if (xisspace(*cmd)) /* End of argument if space */
282 break;
283 }
284
285 if (*cmd)
286 *cmd++ = '\0'; /* Terminate `word' */
287
288 /* See if we need to allocate more space for argv */
289 if (WIN32_argc >= argvlen) {
290 argvlen = WIN32_argc + 1;
291 WIN32_argv = (char **) xrealloc (WIN32_argv, (1 + argvlen) * sizeof (char *));
292 }
293
294 /* Add word to argv file. */
295 WIN32_argv[WIN32_argc++] = word;
296 }
297
298 WIN32_argv[WIN32_argc] = NULL;
299 }
300
301 #endif /* USE_WIN32_SERVICE */
302
303 static unsigned int
304 GetOSVersion()
305 {
306 OSVERSIONINFOEX osvi;
307 BOOL bOsVersionInfoEx;
308
309 safe_free(WIN32_OS_string);
310 memset(&osvi, '\0', sizeof(OSVERSIONINFOEX));
311 /* Try calling GetVersionEx using the OSVERSIONINFOEX structure.
312 * If that fails, try using the OSVERSIONINFO structure.
313 */
314
315 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
316
317 if (!(bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) & osvi))) {
318 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
319 if (!GetVersionEx((OSVERSIONINFO *) & osvi))
320 goto GetVerError;
321 }
322 switch (osvi.dwPlatformId) {
323 case VER_PLATFORM_WIN32_NT:
324 if (osvi.dwMajorVersion <= 4) {
325 WIN32_OS_string = xstrdup("Windows NT");
326 return _WIN_OS_WINNT;
327 }
328 if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 0)) {
329 WIN32_OS_string = xstrdup("Windows 2000");
330 return _WIN_OS_WIN2K;
331 }
332 if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 1)) {
333 WIN32_OS_string = xstrdup("Windows XP");
334 return _WIN_OS_WINXP;
335 }
336 if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 2)) {
337 WIN32_OS_string = xstrdup("Windows Server 2003");
338 return _WIN_OS_WINNET;
339 }
340 if ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 0)) {
341 if (osvi.wProductType == VER_NT_WORKSTATION)
342 WIN32_OS_string = xstrdup("Windows Vista");
343 else
344 WIN32_OS_string = xstrdup("Windows Server 2008");
345 return _WIN_OS_WINLON;
346 }
347 if ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 1)) {
348 if (osvi.wProductType == VER_NT_WORKSTATION)
349 WIN32_OS_string = xstrdup("Windows 7");
350 else
351 WIN32_OS_string = xstrdup("Windows Server 2008 R2");
352 return _WIN_OS_WIN7;
353 }
354 if (((osvi.dwMajorVersion > 6)) || ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion > 1))) {
355 if (osvi.wProductType == VER_NT_WORKSTATION)
356 WIN32_OS_string = xstrdup("Unknown Windows version, assuming Windows 7 capabilities");
357 else
358 WIN32_OS_string = xstrdup("Unknown Windows version, assuming Windows Server 2008 R2 capabilities");
359 return _WIN_OS_WIN7;
360 }
361 break;
362 case VER_PLATFORM_WIN32_WINDOWS:
363 if ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 0)) {
364 WIN32_OS_string = xstrdup("Windows 95");
365 return _WIN_OS_WIN95;
366 }
367 if ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 10)) {
368 WIN32_OS_string = xstrdup("Windows 98");
369 return _WIN_OS_WIN98;
370 }
371 if ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 90)) {
372 WIN32_OS_string = xstrdup("Windows Me");
373 return _WIN_OS_WINME;
374 }
375 break;
376 case VER_PLATFORM_WIN32s:
377 WIN32_OS_string = xstrdup("Windows 3.1 with WIN32S");
378 return _WIN_OS_WIN32S;
379 break;
380 default:
381 break;
382 }
383 GetVerError:
384 WIN32_OS_string = xstrdup("Unknown Windows system");
385 return _WIN_OS_UNKNOWN;
386 }
387
388 /* ====================================================================== */
389 /* PUBLIC FUNCTIONS */
390 /* ====================================================================== */
391
392 void
393 WIN32_Abort(int sig)
394 {
395 #if USE_WIN32_SERVICE
396 svcStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
397 svcStatus.dwServiceSpecificExitCode = 1;
398 #endif
399
400 Squid_Aborting = 1;
401 WIN32_Exit();
402 }
403
404 void
405 WIN32_IpAddrChangeMonitorExit()
406 {
407 DWORD status = ERROR_SUCCESS;
408
409 if (NotifyAddrChange_thread != INVALID_HANDLE_VALUE) {
410 TerminateThread(NotifyAddrChange_thread, status);
411 CloseHandle(NotifyAddrChange_thread);
412 }
413 }
414
415 void
416 WIN32_Exit()
417 {
418 Win32SockCleanup();
419 #if USE_WIN32_SERVICE
420
421 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
422 if (!Squid_Aborting) {
423 svcStatus.dwCurrentState = SERVICE_STOPPED;
424 SetServiceStatus(svcHandle, &svcStatus);
425 }
426 }
427
428 #endif
429 if (dbg_mutex)
430 DeleteCriticalSection(dbg_mutex);
431
432 WIN32_ExceptionHandlerCleanup();
433 WIN32_IpAddrChangeMonitorExit();
434 _exit(0);
435 }
436
437 static DWORD WINAPI
438 WIN32_IpAddrChangeMonitor(LPVOID lpParam)
439 {
440 DWORD Result;
441 HMODULE IPHLPAPIHandle;
442 PFNotifyAddrChange NotifyAddrChange;
443
444 if ((IPHLPAPIHandle = GetModuleHandle("IPHLPAPI")) == NULL)
445 IPHLPAPIHandle = LoadLibrary("IPHLPAPI");
446 NotifyAddrChange = (PFNotifyAddrChange) GetProcAddress(IPHLPAPIHandle, NOTIFYADDRCHANGE);
447
448 while (1) {
449 Result = NotifyAddrChange(NULL, NULL);
450 if (Result != NO_ERROR) {
451 debugs(1, DBG_IMPORTANT, "NotifyAddrChange error " << Result);
452 return 1;
453 }
454 debugs(1, DBG_IMPORTANT, "Notification of IP address change received, requesting Squid reconfiguration ...");
455 reconfigure(SIGHUP);
456 }
457 return 0;
458 }
459
460 DWORD
461 WIN32_IpAddrChangeMonitorInit()
462 {
463 DWORD status = ERROR_SUCCESS;
464 DWORD threadID = 0, ThrdParam = 0;
465
466 if ((WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) && (Config.onoff.WIN32_IpAddrChangeMonitor)) {
467 NotifyAddrChange_thread = CreateThread(NULL, 0, WIN32_IpAddrChangeMonitor,
468 &ThrdParam, 0, &threadID);
469 if (NotifyAddrChange_thread == NULL) {
470 status = GetLastError();
471 NotifyAddrChange_thread = INVALID_HANDLE_VALUE;
472 debugs(1, DBG_IMPORTANT, "Failed to start IP monitor thread.");
473 } else
474 debugs(1, 2, "Starting IP monitor thread [" << threadID << "] ...");
475 }
476 return status;
477 }
478
479 int WIN32_Subsystem_Init(int * argc, char *** argv)
480 {
481 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
482 _invalid_parameter_handler oldHandler, newHandler;
483 #endif
484
485 WIN32_OS_version = GetOSVersion();
486
487 if ((WIN32_OS_version == _WIN_OS_UNKNOWN) || (WIN32_OS_version == _WIN_OS_WIN32S))
488 return 1;
489
490 if (atexit(WIN32_Exit) != 0)
491 return 1;
492
493 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
494
495 newHandler = Squid_Win32InvalidParameterHandler;
496
497 oldHandler = _set_invalid_parameter_handler(newHandler);
498
499 _CrtSetReportMode(_CRT_ASSERT, 0);
500
501 #endif
502 #if USE_WIN32_SERVICE
503
504 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
505 char path[512];
506 HKEY hndKey;
507
508 if (signal(SIGABRT, WIN32_Abort) == SIG_ERR)
509 return 1;
510
511 /* Register the service Handler function */
512 svcHandle = RegisterServiceCtrlHandler(WIN32_Service_name, WIN32_svcHandler);
513
514 if (svcHandle == 0)
515 return 1;
516
517 /* Set Process work dir to directory cointaining squid.exe */
518 GetModuleFileName(NULL, path, 512);
519
520 WIN32_module_name=xstrdup(path);
521
522 path[strlen(path) - 10] = '\0';
523
524 if (SetCurrentDirectory(path) == 0)
525 return 1;
526
527 safe_free(ConfigFile);
528
529 /* get config file from Windows Registry */
530 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_QUERY_VALUE, &hndKey) == ERROR_SUCCESS) {
531 DWORD Type = 0;
532 DWORD Size = 0;
533 LONG Result;
534 Result = RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, NULL, &Size);
535
536 if (Result == ERROR_SUCCESS && Size) {
537 ConfigFile = static_cast<char *>(xmalloc(Size));
538 RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, (unsigned char *)ConfigFile, &Size);
539 } else
540 ConfigFile = xstrdup(DefaultConfigFile);
541
542 Size = 0;
543
544 Type = 0;
545
546 Result = RegQueryValueEx(hndKey, COMMANDLINE, NULL, &Type, NULL, &Size);
547
548 if (Result == ERROR_SUCCESS && Size) {
549 WIN32_Service_Command_Line = static_cast<char *>(xmalloc(Size));
550 RegQueryValueEx(hndKey, COMMANDLINE, NULL, &Type, (unsigned char *)WIN32_Service_Command_Line, &Size);
551 } else
552 WIN32_Service_Command_Line = xstrdup("");
553
554 RegCloseKey(hndKey);
555 } else {
556 ConfigFile = xstrdup(DefaultConfigFile);
557 WIN32_Service_Command_Line = xstrdup("");
558 }
559
560 WIN32_build_argv(WIN32_Service_Command_Line);
561 *argc = WIN32_argc;
562 *argv = WIN32_argv;
563 /* Set Service Status to SERVICE_START_PENDING */
564 svcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
565 svcStatus.dwCurrentState = SERVICE_START_PENDING;
566 svcStatus.dwControlsAccepted =
567 SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
568 svcStatus.dwWin32ExitCode = 0;
569 svcStatus.dwServiceSpecificExitCode = 0;
570 svcStatus.dwCheckPoint = 0;
571 svcStatus.dwWaitHint = 10000;
572 SetServiceStatus(svcHandle, &svcStatus);
573
574 _setmaxstdio(Squid_MaxFD);
575
576 }
577
578 #endif /* USE_WIN32_SERVICE */
579 if (Win32SockInit() < 0)
580 return 1;
581
582 return 0;
583 }
584
585 #if USE_WIN32_SERVICE
586 void
587 WIN32_svcstatusupdate(DWORD svcstate, DWORD WaitHint)
588 {
589 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
590 ++svcStatus.dwCheckPoint;
591 svcStatus.dwWaitHint = WaitHint;
592 svcStatus.dwCurrentState = svcstate;
593 SetServiceStatus(svcHandle, &svcStatus);
594 }
595 }
596
597 VOID WINAPI
598 WIN32_svcHandler(DWORD Opcode)
599 {
600 DWORD status;
601
602 switch (Opcode) {
603
604 case _WIN_SQUID_SERVICE_CONTROL_STOP:
605
606 case _WIN_SQUID_SERVICE_CONTROL_SHUTDOWN:
607 /* Do whatever it takes to stop here. */
608 svcStatus.dwWin32ExitCode = 0;
609 svcStatus.dwCurrentState = SERVICE_STOP_PENDING;
610 svcStatus.dwCheckPoint = 0;
611 svcStatus.dwWaitHint = 10000;
612 shut_down(SIGTERM);
613
614 if (!SetServiceStatus(svcHandle, &svcStatus)) {
615 status = GetLastError();
616 debugs(1, DBG_IMPORTANT, "SetServiceStatus error " << status);
617 }
618
619 debugs(1, DBG_IMPORTANT, "Leaving Squid service");
620 return;
621
622 case _WIN_SQUID_SERVICE_CONTROL_INTERROGATE:
623 /* Fall through to send current status. */
624
625 if (!SetServiceStatus(svcHandle, &svcStatus)) {
626 status = GetLastError();
627 debugs(1, DBG_IMPORTANT, "SetServiceStatus error " << status);
628 }
629
630 break;
631
632 case _WIN_SQUID_SERVICE_CONTROL_ROTATE:
633 rotate_logs(SIGUSR1);
634 break;
635
636 case _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE:
637 reconfigure(SIGHUP);
638 break;
639
640 case _WIN_SQUID_SERVICE_CONTROL_DEBUG:
641 sigusr2_handle(SIGUSR2);
642 break;
643
644 case _WIN_SQUID_SERVICE_CONTROL_INTERRUPT:
645 /* Do whatever it takes to stop here. */
646 svcStatus.dwWin32ExitCode = 0;
647 svcStatus.dwCurrentState = SERVICE_STOP_PENDING;
648 svcStatus.dwCheckPoint = 0;
649 svcStatus.dwWaitHint = 10000;
650 shut_down(SIGINT);
651
652 if (!SetServiceStatus(svcHandle, &svcStatus)) {
653 status = GetLastError();
654 debugs(1, DBG_IMPORTANT, "SetServiceStatus error " << status);
655 }
656
657 debugs(1, DBG_IMPORTANT, "Leaving Squid service");
658 break;
659
660 default:
661 debugs(1, DBG_IMPORTANT, "Unrecognized opcode " << Opcode);
662 }
663
664 return;
665 }
666
667 void
668 WIN32_RemoveService()
669 {
670 SC_HANDLE schService;
671 SC_HANDLE schSCManager;
672
673 if (!WIN32_Service_name)
674 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
675
676 strcat(REGKEY, WIN32_Service_name);
677
678 keys[4] = WIN32_Service_name;
679
680 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
681 NULL, /* database (NULL == default) */
682 SC_MANAGER_ALL_ACCESS /* access required */
683 );
684
685 if (!schSCManager)
686 fprintf(stderr, "OpenSCManager failed\n");
687 else {
688 schService = OpenService(schSCManager, WIN32_Service_name, SERVICE_ALL_ACCESS);
689
690 if (schService == NULL)
691 fprintf(stderr, "OpenService failed\n");
692
693 /* Could not open the service */
694 else {
695 /* try to stop the service */
696
697 if (ControlService(schService, _WIN_SQUID_SERVICE_CONTROL_STOP,
698 &svcStatus)) {
699 sleep(1);
700
701 while (QueryServiceStatus(schService, &svcStatus)) {
702 if (svcStatus.dwCurrentState == SERVICE_STOP_PENDING)
703 sleep(1);
704 else
705 break;
706 }
707 }
708
709 /* now remove the service */
710 if (DeleteService(schService) == 0)
711 fprintf(stderr, "DeleteService failed.\n");
712 else
713 printf("Service %s deleted successfully.\n",
714 WIN32_Service_name);
715
716 CloseServiceHandle(schService);
717 }
718
719 CloseServiceHandle(schSCManager);
720 }
721 }
722
723 void
724 WIN32_SetServiceCommandLine()
725 {
726 if (!WIN32_Service_name)
727 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
728
729 strcat(REGKEY, WIN32_Service_name);
730
731 keys[4] = WIN32_Service_name;
732
733 /* Now store the Service Command Line in the registry */
734 WIN32_StoreKey(COMMANDLINE, REG_SZ, (unsigned char *) WIN32_Command_Line, strlen(WIN32_Command_Line) + 1);
735 }
736
737 void
738 WIN32_InstallService()
739 {
740 SC_HANDLE schService;
741 SC_HANDLE schSCManager;
742 char ServicePath[512];
743 char szPath[512];
744 int lenpath;
745
746 if (!WIN32_Service_name)
747 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
748
749 strcat(REGKEY, WIN32_Service_name);
750
751 keys[4] = WIN32_Service_name;
752
753 if ((lenpath = GetModuleFileName(NULL, ServicePath, 512)) == 0) {
754 fprintf(stderr, "Can't get executable path\n");
755 exit(1);
756 }
757
758 snprintf(szPath, sizeof(szPath), "%s %s:%s", ServicePath, _WIN_SQUID_SERVICE_OPTION, WIN32_Service_name);
759 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
760 NULL, /* database (NULL == default) */
761 SC_MANAGER_ALL_ACCESS /* access required */
762 );
763
764 if (!schSCManager) {
765 fprintf(stderr, "OpenSCManager failed\n");
766 exit(1);
767 } else {
768 schService = CreateService(schSCManager, /* SCManager database */
769 WIN32_Service_name, /* name of service */
770 WIN32_Service_name, /* name to display */
771 SERVICE_ALL_ACCESS, /* desired access */
772 SERVICE_WIN32_OWN_PROCESS, /* service type */
773 SERVICE_AUTO_START, /* start type */
774 SERVICE_ERROR_NORMAL, /* error control type */
775 (const char *) szPath, /* service's binary */
776 NULL, /* no load ordering group */
777 NULL, /* no tag identifier */
778 "Tcpip\0AFD\0", /* dependencies */
779 NULL, /* LocalSystem account */
780 NULL); /* no password */
781
782 if (schService) {
783 if (WIN32_OS_version > _WIN_OS_WINNT) {
784 HMODULE ADVAPI32Handle;
785 PFChangeServiceConfig2 ChangeServiceConfig2;
786 DWORD dwInfoLevel = SERVICE_CONFIG_DESCRIPTION;
787
788 ADVAPI32Handle = GetModuleHandle("advapi32");
789 ChangeServiceConfig2 = (PFChangeServiceConfig2) GetProcAddress(ADVAPI32Handle, CHANGESERVICECONFIG2);
790 ChangeServiceConfig2(schService, dwInfoLevel, &Squid_ServiceDescription);
791 dwInfoLevel = SERVICE_CONFIG_FAILURE_ACTIONS;
792 ChangeServiceConfig2(schService, dwInfoLevel, &Squid_ServiceFailureActions);
793 }
794
795 CloseServiceHandle(schService);
796 /* Now store the config file location in the registry */
797
798 if (!ConfigFile)
799 ConfigFile = xstrdup(DefaultConfigFile);
800
801 WIN32_StoreKey(CONFIGFILE, REG_SZ, (unsigned char *) ConfigFile, strlen(ConfigFile) + 1);
802
803 printf("Squid Cache version %s for %s\n", version_string,
804 CONFIG_HOST_TYPE);
805
806 printf("installed successfully as %s Windows System Service.\n",
807 WIN32_Service_name);
808
809 printf
810 ("To run, start it from the Services Applet of Control Panel.\n");
811
812 printf("Don't forget to edit squid.conf before starting it.\n\n");
813 } else {
814 fprintf(stderr, "CreateService failed\n");
815 exit(1);
816 }
817
818 CloseServiceHandle(schSCManager);
819 }
820 }
821
822 void
823 WIN32_sendSignal(int WIN32_signal)
824 {
825 SERVICE_STATUS ssStatus;
826 DWORD fdwAccess, fdwControl;
827 SC_HANDLE schService;
828 SC_HANDLE schSCManager;
829
830 if (!WIN32_Service_name)
831 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
832
833 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
834 NULL, /* database (NULL == default) */
835 SC_MANAGER_ALL_ACCESS /* access required */
836 );
837
838 if (!schSCManager) {
839 fprintf(stderr, "OpenSCManager failed\n");
840 exit(1);
841 }
842
843 /* The required service object access depends on the control. */
844 switch (WIN32_signal) {
845
846 case 0: /* SIGNULL */
847 fdwAccess = SERVICE_INTERROGATE;
848 fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERROGATE;
849 break;
850
851 case SIGUSR1:
852 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
853 fdwControl = _WIN_SQUID_SERVICE_CONTROL_ROTATE;
854 break;
855
856 case SIGUSR2:
857 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
858 fdwControl = _WIN_SQUID_SERVICE_CONTROL_DEBUG;
859 break;
860
861 case SIGHUP:
862 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
863 fdwControl = _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE;
864 break;
865
866 case SIGTERM:
867 fdwAccess = SERVICE_STOP;
868 fdwControl = _WIN_SQUID_SERVICE_CONTROL_STOP;
869 break;
870
871 case SIGINT:
872
873 case SIGKILL:
874 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
875 fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERRUPT;
876 break;
877
878 default:
879 exit(1);
880 }
881
882 /* Open a handle to the service. */
883 schService = OpenService(schSCManager, /* SCManager database */
884 WIN32_Service_name, /* name of service */
885 fdwAccess); /* specify access */
886
887 if (schService == NULL) {
888 fprintf(stderr, "%s: ERROR: Could not open Service %s\n", APP_SHORTNAME,
889 WIN32_Service_name);
890 exit(1);
891 } else {
892 /* Send a control value to the service. */
893
894 if (!ControlService(schService, /* handle of service */
895 fdwControl, /* control value to send */
896 &ssStatus)) { /* address of status info */
897 fprintf(stderr, "%s: ERROR: Could not Control Service %s\n",
898 APP_SHORTNAME, WIN32_Service_name);
899 exit(1);
900 } else {
901 /* Print the service status. */
902 printf("\nStatus of %s Service:\n", WIN32_Service_name);
903 printf(" Service Type: 0x%lx\n", ssStatus.dwServiceType);
904 printf(" Current State: 0x%lx\n", ssStatus.dwCurrentState);
905 printf(" Controls Accepted: 0x%lx\n", ssStatus.dwControlsAccepted);
906 printf(" Exit Code: %ld\n", ssStatus.dwWin32ExitCode);
907 printf(" Service Specific Exit Code: %ld\n",
908 ssStatus.dwServiceSpecificExitCode);
909 printf(" Check Point: %ld\n", ssStatus.dwCheckPoint);
910 printf(" Wait Hint: %ld\n", ssStatus.dwWaitHint);
911 }
912
913 CloseServiceHandle(schService);
914 }
915
916 CloseServiceHandle(schSCManager);
917 }
918
919 int main(int argc, char **argv)
920 {
921 SERVICE_TABLE_ENTRY DispatchTable[] = {
922 {NULL, SquidWinSvcMain},
923 {NULL, NULL}
924 };
925 char *c;
926 char stderr_path[256];
927
928 if ((argc == 2) && strstr(argv[1], _WIN_SQUID_SERVICE_OPTION)) {
929 strcpy(stderr_path, argv[0]);
930 strcat(stderr_path,".log");
931 freopen(stderr_path, "w", stderr);
932 setmode(fileno(stderr), O_TEXT);
933 WIN32_run_mode = _WIN_SQUID_RUN_MODE_SERVICE;
934
935 if (!(c=strchr(argv[1],':'))) {
936 fprintf(stderr, "Bad Service Parameter: %s\n", argv[1]);
937 return 1;
938 }
939
940 WIN32_Service_name = xstrdup(c+1);
941 DispatchTable[0].lpServiceName=WIN32_Service_name;
942 strcat(REGKEY, WIN32_Service_name);
943 keys[4] = WIN32_Service_name;
944
945 if (!StartServiceCtrlDispatcher(DispatchTable)) {
946 fprintf(stderr, "StartServiceCtrlDispatcher error = %ld\n",
947 GetLastError());
948 return 1;
949 }
950 } else {
951 WIN32_run_mode = _WIN_SQUID_RUN_MODE_INTERACTIVE;
952 opt_no_daemon = 1;
953
954 return SquidMain(argc, argv);
955 }
956
957 return 0;
958 }
959
960 #endif /* USE_WIN32_SERVICE */
961
962 static int Win32SockInit(void)
963 {
964 int iVersionRequested;
965 WSADATA wsaData;
966 int err, opt;
967 int optlen = sizeof(opt);
968
969 if (s_iInitCount > 0) {
970 ++s_iInitCount;
971 return (0);
972 } else if (s_iInitCount < 0)
973 return (s_iInitCount);
974
975 /* s_iInitCount == 0. Do the initailization */
976 iVersionRequested = MAKEWORD(2, 0);
977
978 err = WSAStartup((WORD) iVersionRequested, &wsaData);
979
980 if (err) {
981 s_iInitCount = -1;
982 return (s_iInitCount);
983 }
984
985 if (LOBYTE(wsaData.wVersion) != 2 ||
986 HIBYTE(wsaData.wVersion) != 0) {
987 s_iInitCount = -2;
988 WSACleanup();
989 return (s_iInitCount);
990 }
991
992 if (WIN32_OS_version !=_WIN_OS_WINNT) {
993 if (::getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&opt, &optlen)) {
994 s_iInitCount = -3;
995 WSACleanup();
996 return (s_iInitCount);
997 } else {
998 opt = opt | SO_SYNCHRONOUS_NONALERT;
999
1000 if (::setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, optlen)) {
1001 s_iInitCount = -3;
1002 WSACleanup();
1003 return (s_iInitCount);
1004 }
1005 }
1006 }
1007
1008 WIN32_Socks_initialized = 1;
1009 ++s_iInitCount;
1010 return (s_iInitCount);
1011 }
1012
1013 static void Win32SockCleanup(void)
1014 {
1015 if (--s_iInitCount == 0)
1016 WSACleanup();
1017
1018 return;
1019 }
1020
1021 void Squid_Win32InvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved)
1022 {
1023 return;
1024 }