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

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors