]> git.ipfire.org Git - thirdparty/squid.git/blob - src/WinSvc.cc
SourceFormat enforcement
[thirdparty/squid.git] / src / WinSvc.cc
1
2 /*
3 * $Id$
4 *
5 * Windows support
6 * AUTHOR: Guido Serassio <serassio@squid-cache.org>
7 * inspired by previous work by Romeo Anghelache & Eric Stern.
8 *
9 * SQUID Web Proxy Cache http://www.squid-cache.org/
10 * ----------------------------------------------------------
11 *
12 * Squid is the result of efforts by numerous individuals from
13 * the Internet community; see the CONTRIBUTORS file for full
14 * details. Many organizations have provided support for Squid's
15 * development; see the SPONSORS file for full details. Squid is
16 * Copyrighted (C) 2001 by the Regents of the University of
17 * California; see the COPYRIGHT file for full details. Squid
18 * incorporates software developed and/or copyrighted by other
19 * sources; see the CREDITS file for full details.
20 *
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 *
31 * You should have received a copy of the GNU General Public License
32 * along with this program; if not, write to the Free Software
33 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
34 *
35 */
36
37 #include "squid.h"
38 #include "squid_windows.h"
39
40 #ifdef _SQUID_MSWIN_
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 static unsigned int GetOSVersion();
51 void WIN32_svcstatusupdate(DWORD, DWORD);
52 void WINAPI WIN32_svcHandler(DWORD);
53 #if USE_WIN32_SERVICE
54 static int WIN32_StoreKey(const char *, DWORD, unsigned char *, int);
55 static int WIN32_create_key(void);
56 static void WIN32_build_argv (char *);
57 #endif
58 extern "C" void WINAPI SquidWinSvcMain(DWORD, char **);
59
60 #if defined(_SQUID_MSWIN_)
61 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
62 void Squid_Win32InvalidParameterHandler(const wchar_t*, const wchar_t*, const wchar_t*, unsigned int, uintptr_t);
63 #endif
64 static int Win32SockInit(void);
65 static void Win32SockCleanup(void);
66 SQUIDCEXTERN LPCRITICAL_SECTION dbg_mutex;
67 void WIN32_ExceptionHandlerCleanup(void);
68 static int s_iInitCount = 0;
69 static HANDLE NotifyAddrChange_thread = INVALID_HANDLE_VALUE;
70 #endif /* _SQUID_MSWIN_ */
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 #ifdef _SQUID_MSWIN_
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 #endif
416
417 void
418 WIN32_Exit()
419 {
420 #ifdef _SQUID_MSWIN_
421 Win32SockCleanup();
422 #endif
423 #if USE_WIN32_SERVICE
424
425 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
426 if (!Squid_Aborting) {
427 svcStatus.dwCurrentState = SERVICE_STOPPED;
428 SetServiceStatus(svcHandle, &svcStatus);
429 }
430 }
431
432 #endif
433 #ifdef _SQUID_MSWIN_
434 if (dbg_mutex)
435 DeleteCriticalSection(dbg_mutex);
436
437 WIN32_ExceptionHandlerCleanup();
438 WIN32_IpAddrChangeMonitorExit();
439
440 #endif
441
442 _exit(0);
443 }
444
445 #ifdef _SQUID_MSWIN_
446 static DWORD WINAPI
447 WIN32_IpAddrChangeMonitor(LPVOID lpParam)
448 {
449 DWORD Result;
450 HMODULE IPHLPAPIHandle;
451 PFNotifyAddrChange NotifyAddrChange;
452
453 if ((IPHLPAPIHandle = GetModuleHandle("IPHLPAPI")) == NULL)
454 IPHLPAPIHandle = LoadLibrary("IPHLPAPI");
455 NotifyAddrChange = (PFNotifyAddrChange) GetProcAddress(IPHLPAPIHandle, NOTIFYADDRCHANGE);
456
457 while (1) {
458 Result = NotifyAddrChange(NULL, NULL);
459 if (Result != NO_ERROR) {
460 debugs(1, 1, "NotifyAddrChange error " << Result);
461 return 1;
462 }
463 debugs(1, 1, "Notification of IP address change received, requesting Squid reconfiguration ...");
464 reconfigure(SIGHUP);
465 }
466 return 0;
467 }
468
469 DWORD
470 WIN32_IpAddrChangeMonitorInit()
471 {
472 DWORD status = ERROR_SUCCESS;
473 DWORD threadID = 0, ThrdParam = 0;
474
475 if ((WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) && (Config.onoff.WIN32_IpAddrChangeMonitor)) {
476 NotifyAddrChange_thread = CreateThread(NULL, 0, WIN32_IpAddrChangeMonitor,
477 &ThrdParam, 0, &threadID);
478 if (NotifyAddrChange_thread == NULL) {
479 status = GetLastError();
480 NotifyAddrChange_thread = INVALID_HANDLE_VALUE;
481 debugs(1, 1, "Failed to start IP monitor thread.");
482 } else
483 debugs(1, 2, "Starting IP monitor thread [" << threadID << "] ...");
484 }
485 return status;
486 }
487 #endif /* _SQUID_MSWIN_ */
488
489 int WIN32_Subsystem_Init(int * argc, char *** argv)
490 {
491 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
492 _invalid_parameter_handler oldHandler, newHandler;
493 #endif
494
495 WIN32_OS_version = GetOSVersion();
496
497 if ((WIN32_OS_version == _WIN_OS_UNKNOWN) || (WIN32_OS_version == _WIN_OS_WIN32S))
498 return 1;
499
500 if (atexit(WIN32_Exit) != 0)
501 return 1;
502
503 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
504
505 newHandler = Squid_Win32InvalidParameterHandler;
506
507 oldHandler = _set_invalid_parameter_handler(newHandler);
508
509 _CrtSetReportMode(_CRT_ASSERT, 0);
510
511 #endif
512 #if USE_WIN32_SERVICE
513
514 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
515 char path[512];
516 HKEY hndKey;
517
518 if (signal(SIGABRT, WIN32_Abort) == SIG_ERR)
519 return 1;
520
521 /* Register the service Handler function */
522 svcHandle = RegisterServiceCtrlHandler(WIN32_Service_name, WIN32_svcHandler);
523
524 if (svcHandle == 0)
525 return 1;
526
527 /* Set Process work dir to directory cointaining squid.exe */
528 GetModuleFileName(NULL, path, 512);
529
530 WIN32_module_name=xstrdup(path);
531
532 path[strlen(path) - 10] = '\0';
533
534 if (SetCurrentDirectory(path) == 0)
535 return 1;
536
537 safe_free(ConfigFile);
538
539 /* get config file from Windows Registry */
540 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_QUERY_VALUE, &hndKey) == ERROR_SUCCESS) {
541 DWORD Type = 0;
542 DWORD Size = 0;
543 LONG Result;
544 Result = RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, NULL, &Size);
545
546 if (Result == ERROR_SUCCESS && Size) {
547 ConfigFile = static_cast<char *>(xmalloc(Size));
548 RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, (unsigned char *)ConfigFile, &Size);
549 } else
550 ConfigFile = xstrdup(DefaultConfigFile);
551
552 Size = 0;
553
554 Type = 0;
555
556 Result = RegQueryValueEx(hndKey, COMMANDLINE, NULL, &Type, NULL, &Size);
557
558 if (Result == ERROR_SUCCESS && Size) {
559 WIN32_Service_Command_Line = static_cast<char *>(xmalloc(Size));
560 RegQueryValueEx(hndKey, COMMANDLINE, NULL, &Type, (unsigned char *)WIN32_Service_Command_Line, &Size);
561 } else
562 WIN32_Service_Command_Line = xstrdup("");
563
564 RegCloseKey(hndKey);
565 } else {
566 ConfigFile = xstrdup(DefaultConfigFile);
567 WIN32_Service_Command_Line = xstrdup("");
568 }
569
570 WIN32_build_argv(WIN32_Service_Command_Line);
571 *argc = WIN32_argc;
572 *argv = WIN32_argv;
573 /* Set Service Status to SERVICE_START_PENDING */
574 svcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
575 svcStatus.dwCurrentState = SERVICE_START_PENDING;
576 svcStatus.dwControlsAccepted =
577 SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
578 svcStatus.dwWin32ExitCode = 0;
579 svcStatus.dwServiceSpecificExitCode = 0;
580 svcStatus.dwCheckPoint = 0;
581 svcStatus.dwWaitHint = 10000;
582 SetServiceStatus(svcHandle, &svcStatus);
583 #ifdef _SQUID_MSWIN_
584
585 _setmaxstdio(Squid_MaxFD);
586 #endif
587
588 }
589
590 #endif /* USE_WIN32_SERVICE */
591 #ifdef _SQUID_MSWIN_
592 if (Win32SockInit() < 0)
593 return 1;
594
595 #endif
596
597 return 0;
598 }
599
600 #if USE_WIN32_SERVICE
601 void
602 WIN32_svcstatusupdate(DWORD svcstate, DWORD WaitHint)
603 {
604 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
605 svcStatus.dwCheckPoint++;
606 svcStatus.dwWaitHint = WaitHint;
607 svcStatus.dwCurrentState = svcstate;
608 SetServiceStatus(svcHandle, &svcStatus);
609 }
610 }
611
612 VOID WINAPI
613 WIN32_svcHandler(DWORD Opcode)
614 {
615 DWORD status;
616
617 switch (Opcode) {
618
619 case _WIN_SQUID_SERVICE_CONTROL_STOP:
620
621 case _WIN_SQUID_SERVICE_CONTROL_SHUTDOWN:
622 /* Do whatever it takes to stop here. */
623 svcStatus.dwWin32ExitCode = 0;
624 svcStatus.dwCurrentState = SERVICE_STOP_PENDING;
625 svcStatus.dwCheckPoint = 0;
626 svcStatus.dwWaitHint = 10000;
627 shut_down(SIGTERM);
628
629 if (!SetServiceStatus(svcHandle, &svcStatus)) {
630 status = GetLastError();
631 debugs(1, 1, "SetServiceStatus error " << status);
632 }
633
634 debugs(1, 1, "Leaving Squid service");
635 return;
636
637 case _WIN_SQUID_SERVICE_CONTROL_INTERROGATE:
638 /* Fall through to send current status. */
639
640 if (!SetServiceStatus(svcHandle, &svcStatus)) {
641 status = GetLastError();
642 debugs(1, 1, "SetServiceStatus error " << status);
643 }
644
645 break;
646
647 case _WIN_SQUID_SERVICE_CONTROL_ROTATE:
648 rotate_logs(SIGUSR1);
649 break;
650
651 case _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE:
652 reconfigure(SIGHUP);
653 break;
654
655 case _WIN_SQUID_SERVICE_CONTROL_DEBUG:
656 sigusr2_handle(SIGUSR2);
657 break;
658
659 case _WIN_SQUID_SERVICE_CONTROL_INTERRUPT:
660 /* Do whatever it takes to stop here. */
661 svcStatus.dwWin32ExitCode = 0;
662 svcStatus.dwCurrentState = SERVICE_STOP_PENDING;
663 svcStatus.dwCheckPoint = 0;
664 svcStatus.dwWaitHint = 10000;
665 shut_down(SIGINT);
666
667 if (!SetServiceStatus(svcHandle, &svcStatus)) {
668 status = GetLastError();
669 debugs(1, 1, "SetServiceStatus error " << status);
670 }
671
672 debugs(1, 1, "Leaving Squid service");
673 break;
674
675 default:
676 debugs(1, 1, "Unrecognized opcode " << Opcode);
677 }
678
679 return;
680 }
681
682 void
683 WIN32_RemoveService()
684 {
685 SC_HANDLE schService;
686 SC_HANDLE schSCManager;
687
688 if (!WIN32_Service_name)
689 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
690
691 strcat(REGKEY, WIN32_Service_name);
692
693 keys[4] = WIN32_Service_name;
694
695 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
696 NULL, /* database (NULL == default) */
697 SC_MANAGER_ALL_ACCESS /* access required */
698 );
699
700 if (!schSCManager)
701 fprintf(stderr, "OpenSCManager failed\n");
702 else {
703 schService = OpenService(schSCManager, WIN32_Service_name, SERVICE_ALL_ACCESS);
704
705 if (schService == NULL)
706 fprintf(stderr, "OpenService failed\n");
707
708 /* Could not open the service */
709 else {
710 /* try to stop the service */
711
712 if (ControlService(schService, _WIN_SQUID_SERVICE_CONTROL_STOP,
713 &svcStatus)) {
714 sleep(1);
715
716 while (QueryServiceStatus(schService, &svcStatus)) {
717 if (svcStatus.dwCurrentState == SERVICE_STOP_PENDING)
718 sleep(1);
719 else
720 break;
721 }
722 }
723
724 /* now remove the service */
725 if (DeleteService(schService) == 0)
726 fprintf(stderr, "DeleteService failed.\n");
727 else
728 printf("Service %s deleted successfully.\n",
729 WIN32_Service_name);
730
731 CloseServiceHandle(schService);
732 }
733
734 CloseServiceHandle(schSCManager);
735 }
736 }
737
738 void
739 WIN32_SetServiceCommandLine()
740 {
741 if (!WIN32_Service_name)
742 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
743
744 strcat(REGKEY, WIN32_Service_name);
745
746 keys[4] = WIN32_Service_name;
747
748 /* Now store the Service Command Line in the registry */
749 WIN32_StoreKey(COMMANDLINE, REG_SZ, (unsigned char *) WIN32_Command_Line, strlen(WIN32_Command_Line) + 1);
750 }
751
752 void
753 WIN32_InstallService()
754 {
755 SC_HANDLE schService;
756 SC_HANDLE schSCManager;
757 char ServicePath[512];
758 char szPath[512];
759 int lenpath;
760
761 if (!WIN32_Service_name)
762 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
763
764 strcat(REGKEY, WIN32_Service_name);
765
766 keys[4] = WIN32_Service_name;
767
768 if ((lenpath = GetModuleFileName(NULL, ServicePath, 512)) == 0) {
769 fprintf(stderr, "Can't get executable path\n");
770 exit(1);
771 }
772
773 snprintf(szPath, sizeof(szPath), "%s %s:%s", ServicePath, _WIN_SQUID_SERVICE_OPTION, WIN32_Service_name);
774 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
775 NULL, /* database (NULL == default) */
776 SC_MANAGER_ALL_ACCESS /* access required */
777 );
778
779 if (!schSCManager) {
780 fprintf(stderr, "OpenSCManager failed\n");
781 exit(1);
782 } else {
783 schService = CreateService(schSCManager, /* SCManager database */
784 WIN32_Service_name, /* name of service */
785 WIN32_Service_name, /* name to display */
786 SERVICE_ALL_ACCESS, /* desired access */
787 SERVICE_WIN32_OWN_PROCESS, /* service type */
788 SERVICE_AUTO_START, /* start type */
789 SERVICE_ERROR_NORMAL, /* error control type */
790 (const char *) szPath, /* service's binary */
791 NULL, /* no load ordering group */
792 NULL, /* no tag identifier */
793 "Tcpip\0AFD\0", /* dependencies */
794 NULL, /* LocalSystem account */
795 NULL); /* no password */
796
797 if (schService) {
798 if (WIN32_OS_version > _WIN_OS_WINNT) {
799 HMODULE ADVAPI32Handle;
800 PFChangeServiceConfig2 ChangeServiceConfig2;
801 DWORD dwInfoLevel = SERVICE_CONFIG_DESCRIPTION;
802
803 ADVAPI32Handle = GetModuleHandle("advapi32");
804 ChangeServiceConfig2 = (PFChangeServiceConfig2) GetProcAddress(ADVAPI32Handle, CHANGESERVICECONFIG2);
805 ChangeServiceConfig2(schService, dwInfoLevel, &Squid_ServiceDescription);
806 dwInfoLevel = SERVICE_CONFIG_FAILURE_ACTIONS;
807 ChangeServiceConfig2(schService, dwInfoLevel, &Squid_ServiceFailureActions);
808 }
809
810 CloseServiceHandle(schService);
811 /* Now store the config file location in the registry */
812
813 if (!ConfigFile)
814 ConfigFile = xstrdup(DefaultConfigFile);
815
816 WIN32_StoreKey(CONFIGFILE, REG_SZ, (unsigned char *) ConfigFile, strlen(ConfigFile) + 1);
817
818 printf("Squid Cache version %s for %s\n", version_string,
819 CONFIG_HOST_TYPE);
820
821 printf("installed successfully as %s Windows System Service.\n",
822 WIN32_Service_name);
823
824 printf
825 ("To run, start it from the Services Applet of Control Panel.\n");
826
827 printf("Don't forget to edit squid.conf before starting it.\n\n");
828 } else {
829 fprintf(stderr, "CreateService failed\n");
830 exit(1);
831 }
832
833 CloseServiceHandle(schSCManager);
834 }
835 }
836
837 void
838 WIN32_sendSignal(int WIN32_signal)
839 {
840 SERVICE_STATUS ssStatus;
841 DWORD fdwAccess, fdwControl;
842 SC_HANDLE schService;
843 SC_HANDLE schSCManager;
844
845 if (!WIN32_Service_name)
846 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
847
848 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
849 NULL, /* database (NULL == default) */
850 SC_MANAGER_ALL_ACCESS /* access required */
851 );
852
853 if (!schSCManager) {
854 fprintf(stderr, "OpenSCManager failed\n");
855 exit(1);
856 }
857
858 /* The required service object access depends on the control. */
859 switch (WIN32_signal) {
860
861 case 0: /* SIGNULL */
862 fdwAccess = SERVICE_INTERROGATE;
863 fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERROGATE;
864 break;
865
866 case SIGUSR1:
867 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
868 fdwControl = _WIN_SQUID_SERVICE_CONTROL_ROTATE;
869 break;
870
871 case SIGUSR2:
872 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
873 fdwControl = _WIN_SQUID_SERVICE_CONTROL_DEBUG;
874 break;
875
876 case SIGHUP:
877 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
878 fdwControl = _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE;
879 break;
880
881 case SIGTERM:
882 fdwAccess = SERVICE_STOP;
883 fdwControl = _WIN_SQUID_SERVICE_CONTROL_STOP;
884 break;
885
886 case SIGINT:
887
888 case SIGKILL:
889 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
890 fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERRUPT;
891 break;
892
893 default:
894 exit(1);
895 }
896
897 /* Open a handle to the service. */
898 schService = OpenService(schSCManager, /* SCManager database */
899 WIN32_Service_name, /* name of service */
900 fdwAccess); /* specify access */
901
902 if (schService == NULL) {
903 fprintf(stderr, "%s: ERROR: Could not open Service %s\n", APP_SHORTNAME,
904 WIN32_Service_name);
905 exit(1);
906 } else {
907 /* Send a control value to the service. */
908
909 if (!ControlService(schService, /* handle of service */
910 fdwControl, /* control value to send */
911 &ssStatus)) { /* address of status info */
912 fprintf(stderr, "%s: ERROR: Could not Control Service %s\n",
913 APP_SHORTNAME, WIN32_Service_name);
914 exit(1);
915 } else {
916 /* Print the service status. */
917 printf("\nStatus of %s Service:\n", WIN32_Service_name);
918 printf(" Service Type: 0x%lx\n", ssStatus.dwServiceType);
919 printf(" Current State: 0x%lx\n", ssStatus.dwCurrentState);
920 printf(" Controls Accepted: 0x%lx\n", ssStatus.dwControlsAccepted);
921 printf(" Exit Code: %ld\n", ssStatus.dwWin32ExitCode);
922 printf(" Service Specific Exit Code: %ld\n",
923 ssStatus.dwServiceSpecificExitCode);
924 printf(" Check Point: %ld\n", ssStatus.dwCheckPoint);
925 printf(" Wait Hint: %ld\n", ssStatus.dwWaitHint);
926 }
927
928 CloseServiceHandle(schService);
929 }
930
931 CloseServiceHandle(schSCManager);
932 }
933
934 int main(int argc, char **argv)
935 {
936 SERVICE_TABLE_ENTRY DispatchTable[] = {
937 {NULL, SquidWinSvcMain},
938 {NULL, NULL}
939 };
940 char *c;
941 char stderr_path[256];
942
943 if ((argc == 2) && strstr(argv[1], _WIN_SQUID_SERVICE_OPTION)) {
944 strcpy(stderr_path, argv[0]);
945 strcat(stderr_path,".log");
946 freopen(stderr_path, "w", stderr);
947 setmode(fileno(stderr), O_TEXT);
948 WIN32_run_mode = _WIN_SQUID_RUN_MODE_SERVICE;
949
950 if (!(c=strchr(argv[1],':'))) {
951 fprintf(stderr, "Bad Service Parameter: %s\n", argv[1]);
952 return 1;
953 }
954
955 WIN32_Service_name = xstrdup(c+1);
956 DispatchTable[0].lpServiceName=WIN32_Service_name;
957 strcat(REGKEY, WIN32_Service_name);
958 keys[4] = WIN32_Service_name;
959
960 if (!StartServiceCtrlDispatcher(DispatchTable)) {
961 fprintf(stderr, "StartServiceCtrlDispatcher error = %ld\n",
962 GetLastError());
963 return 1;
964 }
965 } else {
966 WIN32_run_mode = _WIN_SQUID_RUN_MODE_INTERACTIVE;
967 #ifdef _SQUID_MSWIN_
968
969 opt_no_daemon = 1;
970
971 #endif
972
973 return SquidMain(argc, argv);
974 }
975
976 return 0;
977 }
978
979 #endif /* USE_WIN32_SERVICE */
980
981 #if defined(_SQUID_MSWIN_)
982 static int Win32SockInit(void)
983 {
984 int iVersionRequested;
985 WSADATA wsaData;
986 int err, opt;
987 int optlen = sizeof(opt);
988
989 if (s_iInitCount > 0) {
990 s_iInitCount++;
991 return (0);
992 } else if (s_iInitCount < 0)
993 return (s_iInitCount);
994
995 /* s_iInitCount == 0. Do the initailization */
996 iVersionRequested = MAKEWORD(2, 0);
997
998 err = WSAStartup((WORD) iVersionRequested, &wsaData);
999
1000 if (err) {
1001 s_iInitCount = -1;
1002 return (s_iInitCount);
1003 }
1004
1005 if (LOBYTE(wsaData.wVersion) != 2 ||
1006 HIBYTE(wsaData.wVersion) != 0) {
1007 s_iInitCount = -2;
1008 WSACleanup();
1009 return (s_iInitCount);
1010 }
1011
1012 if (WIN32_OS_version !=_WIN_OS_WINNT) {
1013 if (::getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&opt, &optlen)) {
1014 s_iInitCount = -3;
1015 WSACleanup();
1016 return (s_iInitCount);
1017 } else {
1018 opt = opt | SO_SYNCHRONOUS_NONALERT;
1019
1020 if (::setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, optlen)) {
1021 s_iInitCount = -3;
1022 WSACleanup();
1023 return (s_iInitCount);
1024 }
1025 }
1026 }
1027
1028 WIN32_Socks_initialized = 1;
1029 s_iInitCount++;
1030 return (s_iInitCount);
1031 }
1032
1033 static void Win32SockCleanup(void)
1034 {
1035 if (--s_iInitCount == 0)
1036 WSACleanup();
1037
1038 return;
1039 }
1040
1041 void Squid_Win32InvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved)
1042 {
1043 return;
1044 }
1045
1046 #endif /* SQUID_MSWIN_ */