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