]> git.ipfire.org Git - thirdparty/squid.git/blame - src/WinSvc.cc
Prep for 3.3.12 and 3.4.4
[thirdparty/squid.git] / src / WinSvc.cc
CommitLineData
9c8434f6 1/*
9c8434f6 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.
26ac0430 22 *
9c8434f6 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.
26ac0430 27 *
9c8434f6 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
582c2af2 34#include "squid.h"
91d63ce7
AJ
35#include "Debug.h"
36#include "globals.h"
cf3edd6f 37#include "protos.h"
91d63ce7 38#include "SquidConfig.h"
9c8434f6 39
7aa9bb3e 40#if _SQUID_WINDOWS_
9c8434f6 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
cf3edd6f
FC
50/* forward declarations */
51static void WIN32_Exit(void);
9c8434f6 52static unsigned int GetOSVersion();
53void WIN32_svcstatusupdate(DWORD, DWORD);
54void WINAPI WIN32_svcHandler(DWORD);
91d63ce7
AJ
55extern "C" void WINAPI SquidWinSvcMain(DWORD, char **);
56
9c8434f6 57#if USE_WIN32_SERVICE
91d63ce7 58static void WIN32_Abort(int);
9c8434f6 59static int WIN32_StoreKey(const char *, DWORD, unsigned char *, int);
60static int WIN32_create_key(void);
61static void WIN32_build_argv (char *);
62#endif
9c8434f6 63
9c8434f6 64#if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
65void Squid_Win32InvalidParameterHandler(const wchar_t*, const wchar_t*, const wchar_t*, unsigned int, uintptr_t);
66#endif
67static int Win32SockInit(void);
68static void Win32SockCleanup(void);
69SQUIDCEXTERN LPCRITICAL_SECTION dbg_mutex;
70void WIN32_ExceptionHandlerCleanup(void);
71static int s_iInitCount = 0;
353942c5 72static HANDLE NotifyAddrChange_thread = INVALID_HANDLE_VALUE;
9c8434f6 73
babd1fd5 74#undef NotifyAddrChange
75typedef DWORD(WINAPI * PFNotifyAddrChange) (OUT PHANDLE, IN LPOVERLAPPED);
76#define NOTIFYADDRCHANGE "NotifyAddrChange"
9c8434f6 77
78#if USE_WIN32_SERVICE
79static SERVICE_STATUS svcStatus;
80static SERVICE_STATUS_HANDLE svcHandle;
81static int WIN32_argc;
82static char ** WIN32_argv;
83static char * WIN32_module_name;
84
d2b4d181 85#define VENDOR "squid-cache.org"
9c8434f6 86static char VENDORString[] = VENDOR;
d2b4d181 87#define SOFTWARENAME PACKAGE_NAME
9c8434f6 88static char SOFTWARENAMEString[] = SOFTWARENAME;
9c8434f6 89#define SOFTWARE "SOFTWARE"
90static char SOFTWAREString[] = SOFTWARE;
91#define COMMANDLINE "CommandLine"
92#define CONFIGFILE "ConfigFile"
93#undef ChangeServiceConfig2
94typedef BOOL (WINAPI * PFChangeServiceConfig2) (SC_HANDLE, DWORD, LPVOID);
95#ifdef UNICODE
96#define CHANGESERVICECONFIG2 "ChangeServiceConfig2W"
97#else
98#define CHANGESERVICECONFIG2 "ChangeServiceConfig2A"
99#endif
100static SC_ACTION Squid_SCAction[] = { { SC_ACTION_RESTART, 60000 } };
101static char Squid_ServiceDescriptionString[] = SOFTWARENAME " " VERSION " WWW Proxy Server";
102static SERVICE_DESCRIPTION Squid_ServiceDescription = { Squid_ServiceDescriptionString };
103static SERVICE_FAILURE_ACTIONS Squid_ServiceFailureActions = { INFINITE, NULL, NULL, 1, Squid_SCAction };
d2b4d181 104static char REGKEY[256]=SOFTWARE"\\"VENDOR"\\"SOFTWARENAME"\\";
9c8434f6 105static char *keys[] = {
26ac0430
AJ
106 SOFTWAREString, /* key[0] */
107 VENDORString, /* key[1] */
108 SOFTWARENAMEString, /* key[2] */
d2b4d181
GS
109 NULL, /* key[3] */
110 NULL /* key[4] */
26ac0430 111};
91d63ce7
AJ
112
113static int Squid_Aborting = 0;
9c8434f6 114#endif
115
116/* ====================================================================== */
117/* LOCAL FUNCTIONS */
118/* ====================================================================== */
119
120#if USE_WIN32_SERVICE
121static int
122WIN32_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;
14942edd 165 ++index;
9c8434f6 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
187static int
188WIN32_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. */
259static 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)) {
14942edd 273 ++cmd;
9c8434f6 274 continue;
275 }
276
277 /* Found the beginning of an argument. */
278 word = cmd;
279
280 while (*cmd) {
14942edd 281 ++cmd; /* Skip over this character */
9c8434f6 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
305static unsigned int
306GetOSVersion()
307{
cda5938d 308 OSVERSIONINFOEX osvi;
309 BOOL bOsVersionInfoEx;
9c8434f6 310
311 safe_free(WIN32_OS_string);
cda5938d 312 memset(&osvi, '\0', sizeof(OSVERSIONINFOEX));
313 /* Try calling GetVersionEx using the OSVERSIONINFOEX structure.
314 * If that fails, try using the OSVERSIONINFO structure.
315 */
9c8434f6 316
cda5938d 317 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
9c8434f6 318
cda5938d 319 if (!(bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) & osvi))) {
26ac0430
AJ
320 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
321 if (!GetVersionEx((OSVERSIONINFO *) & osvi))
322 goto GetVerError;
cda5938d 323 }
324 switch (osvi.dwPlatformId) {
9c8434f6 325 case VER_PLATFORM_WIN32_NT:
26ac0430
AJ
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 }
af6a12ee
AJ
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 }
26ac0430 363 break;
9c8434f6 364 case VER_PLATFORM_WIN32_WINDOWS:
26ac0430
AJ
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;
9c8434f6 378 case VER_PLATFORM_WIN32s:
26ac0430
AJ
379 WIN32_OS_string = xstrdup("Windows 3.1 with WIN32S");
380 return _WIN_OS_WIN32S;
381 break;
9c8434f6 382 default:
26ac0430 383 break;
9c8434f6 384 }
26ac0430 385GetVerError:
9c8434f6 386 WIN32_OS_string = xstrdup("Unknown Windows system");
387 return _WIN_OS_UNKNOWN;
388}
389
390/* ====================================================================== */
391/* PUBLIC FUNCTIONS */
392/* ====================================================================== */
393
91d63ce7 394#if USE_WIN32_SERVICE
9c8434f6 395void
396WIN32_Abort(int sig)
397{
9c8434f6 398 svcStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
399 svcStatus.dwServiceSpecificExitCode = 1;
9c8434f6 400 Squid_Aborting = 1;
401 WIN32_Exit();
402}
91d63ce7 403#endif
9c8434f6 404
babd1fd5 405void
406WIN32_IpAddrChangeMonitorExit()
407{
408 DWORD status = ERROR_SUCCESS;
409
b6696974 410 if (NotifyAddrChange_thread != INVALID_HANDLE_VALUE) {
26ac0430
AJ
411 TerminateThread(NotifyAddrChange_thread, status);
412 CloseHandle(NotifyAddrChange_thread);
babd1fd5 413 }
414}
415
9c8434f6 416void
417WIN32_Exit()
418{
9c8434f6 419 Win32SockCleanup();
9c8434f6 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
9c8434f6 430 if (dbg_mutex)
431 DeleteCriticalSection(dbg_mutex);
432
433 WIN32_ExceptionHandlerCleanup();
babd1fd5 434 WIN32_IpAddrChangeMonitorExit();
9c8434f6 435 _exit(0);
436}
437
babd1fd5 438static DWORD WINAPI
439WIN32_IpAddrChangeMonitor(LPVOID lpParam)
440{
441 DWORD Result;
442 HMODULE IPHLPAPIHandle;
443 PFNotifyAddrChange NotifyAddrChange;
444
445 if ((IPHLPAPIHandle = GetModuleHandle("IPHLPAPI")) == NULL)
26ac0430 446 IPHLPAPIHandle = LoadLibrary("IPHLPAPI");
babd1fd5 447 NotifyAddrChange = (PFNotifyAddrChange) GetProcAddress(IPHLPAPIHandle, NOTIFYADDRCHANGE);
448
449 while (1) {
26ac0430
AJ
450 Result = NotifyAddrChange(NULL, NULL);
451 if (Result != NO_ERROR) {
e0236918 452 debugs(1, DBG_IMPORTANT, "NotifyAddrChange error " << Result);
26ac0430
AJ
453 return 1;
454 }
e0236918 455 debugs(1, DBG_IMPORTANT, "Notification of IP address change received, requesting Squid reconfiguration ...");
26ac0430 456 reconfigure(SIGHUP);
babd1fd5 457 }
458 return 0;
459}
460
461DWORD
462WIN32_IpAddrChangeMonitorInit()
463{
464 DWORD status = ERROR_SUCCESS;
465 DWORD threadID = 0, ThrdParam = 0;
466
b6696974 467 if ((WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) && (Config.onoff.WIN32_IpAddrChangeMonitor)) {
26ac0430
AJ
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;
e0236918 473 debugs(1, DBG_IMPORTANT, "Failed to start IP monitor thread.");
26ac0430
AJ
474 } else
475 debugs(1, 2, "Starting IP monitor thread [" << threadID << "] ...");
babd1fd5 476 }
477 return status;
478}
babd1fd5 479
9c8434f6 480int 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 */
cf2155f2 513 svcHandle = RegisterServiceCtrlHandler(service_name, WIN32_svcHandler);
9c8434f6 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 */
04f7fd38 531 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_QUERY_VALUE, &hndKey) == ERROR_SUCCESS) {
9c8434f6 532 DWORD Type = 0;
533 DWORD Size = 0;
534 LONG Result;
0dde2160 535 Result = RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, NULL, &Size);
9c8434f6 536
537 if (Result == ERROR_SUCCESS && Size) {
538 ConfigFile = static_cast<char *>(xmalloc(Size));
0dde2160 539 RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, (unsigned char *)ConfigFile, &Size);
9c8434f6 540 } else
541 ConfigFile = xstrdup(DefaultConfigFile);
542
543 Size = 0;
544
545 Type = 0;
546
0dde2160 547 Result = RegQueryValueEx(hndKey, COMMANDLINE, NULL, &Type, NULL, &Size);
9c8434f6 548
549 if (Result == ERROR_SUCCESS && Size) {
550 WIN32_Service_Command_Line = static_cast<char *>(xmalloc(Size));
0dde2160 551 RegQueryValueEx(hndKey, COMMANDLINE, NULL, &Type, (unsigned char *)WIN32_Service_Command_Line, &Size);
9c8434f6 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);
9c8434f6 574
575 _setmaxstdio(Squid_MaxFD);
9c8434f6 576
577 }
578
579#endif /* USE_WIN32_SERVICE */
9c8434f6 580 if (Win32SockInit() < 0)
581 return 1;
582
9c8434f6 583 return 0;
584}
585
586#if USE_WIN32_SERVICE
587void
588WIN32_svcstatusupdate(DWORD svcstate, DWORD WaitHint)
589{
590 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
14942edd 591 ++svcStatus.dwCheckPoint;
9c8434f6 592 svcStatus.dwWaitHint = WaitHint;
593 svcStatus.dwCurrentState = svcstate;
594 SetServiceStatus(svcHandle, &svcStatus);
595 }
596}
597
598VOID WINAPI
599WIN32_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();
e0236918 617 debugs(1, DBG_IMPORTANT, "SetServiceStatus error " << status);
9c8434f6 618 }
619
e0236918 620 debugs(1, DBG_IMPORTANT, "Leaving Squid service");
9c8434f6 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();
e0236918 628 debugs(1, DBG_IMPORTANT, "SetServiceStatus error " << status);
9c8434f6 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();
e0236918 655 debugs(1, DBG_IMPORTANT, "SetServiceStatus error " << status);
9c8434f6 656 }
657
e0236918 658 debugs(1, DBG_IMPORTANT, "Leaving Squid service");
9c8434f6 659 break;
660
661 default:
e0236918 662 debugs(1, DBG_IMPORTANT, "Unrecognized opcode " << Opcode);
9c8434f6 663 }
664
665 return;
666}
667
668void
669WIN32_RemoveService()
670{
671 SC_HANDLE schService;
672 SC_HANDLE schSCManager;
673
cf2155f2
AJ
674 if (!service_name)
675 service_name = xstrdup(APP_SHORTNAME);
9c8434f6 676
cf2155f2 677 strcat(REGKEY, service_name);
9c8434f6 678
cf2155f2 679 keys[4] = service_name;
9c8434f6 680
681 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
682 NULL, /* database (NULL == default) */
683 SC_MANAGER_ALL_ACCESS /* access required */
684 );
685
686 if (!schSCManager)
687 fprintf(stderr, "OpenSCManager failed\n");
688 else {
cf2155f2 689 schService = OpenService(schSCManager, service_name, SERVICE_ALL_ACCESS);
9c8434f6 690
691 if (schService == NULL)
692 fprintf(stderr, "OpenService failed\n");
693
694 /* Could not open the service */
695 else {
696 /* try to stop the service */
697
698 if (ControlService(schService, _WIN_SQUID_SERVICE_CONTROL_STOP,
699 &svcStatus)) {
700 sleep(1);
701
702 while (QueryServiceStatus(schService, &svcStatus)) {
703 if (svcStatus.dwCurrentState == SERVICE_STOP_PENDING)
704 sleep(1);
705 else
706 break;
707 }
708 }
709
710 /* now remove the service */
711 if (DeleteService(schService) == 0)
712 fprintf(stderr, "DeleteService failed.\n");
713 else
cf2155f2 714 printf("Service %s deleted successfully.\n", service_name);
9c8434f6 715
716 CloseServiceHandle(schService);
717 }
718
719 CloseServiceHandle(schSCManager);
720 }
721}
722
723void
724WIN32_SetServiceCommandLine()
725{
cf2155f2
AJ
726 if (!service_name)
727 service_name = xstrdup(APP_SHORTNAME);
9c8434f6 728
cf2155f2 729 strcat(REGKEY, service_name);
9c8434f6 730
cf2155f2 731 keys[4] = service_name;
9c8434f6 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
737void
738WIN32_InstallService()
739{
740 SC_HANDLE schService;
741 SC_HANDLE schSCManager;
742 char ServicePath[512];
743 char szPath[512];
744 int lenpath;
745
cf2155f2
AJ
746 if (!service_name)
747 service_name = xstrdup(APP_SHORTNAME);
9c8434f6 748
cf2155f2 749 strcat(REGKEY, service_name);
9c8434f6 750
cf2155f2 751 keys[4] = service_name;
9c8434f6 752
753 if ((lenpath = GetModuleFileName(NULL, ServicePath, 512)) == 0) {
754 fprintf(stderr, "Can't get executable path\n");
755 exit(1);
756 }
757
cf2155f2 758 snprintf(szPath, sizeof(szPath), "%s %s:%s", ServicePath, _WIN_SQUID_SERVICE_OPTION, service_name);
9c8434f6 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 */
cf2155f2
AJ
769 service_name, /* name of service */
770 service_name, /* name to display */
9c8434f6 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
cf2155f2
AJ
803 printf("Squid Cache version %s for %s\n", version_string, CONFIG_HOST_TYPE);
804 printf("installed successfully as %s Windows System Service.\n", service_name);
805 printf("To run, start it from the Services Applet of Control Panel.\n");
9c8434f6 806 printf("Don't forget to edit squid.conf before starting it.\n\n");
807 } else {
808 fprintf(stderr, "CreateService failed\n");
809 exit(1);
810 }
811
812 CloseServiceHandle(schSCManager);
813 }
814}
815
816void
817WIN32_sendSignal(int WIN32_signal)
818{
819 SERVICE_STATUS ssStatus;
820 DWORD fdwAccess, fdwControl;
821 SC_HANDLE schService;
822 SC_HANDLE schSCManager;
823
cf2155f2
AJ
824 if (!service_name)
825 service_name = xstrdup(APP_SHORTNAME);
9c8434f6 826
827 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
828 NULL, /* database (NULL == default) */
829 SC_MANAGER_ALL_ACCESS /* access required */
830 );
831
832 if (!schSCManager) {
833 fprintf(stderr, "OpenSCManager failed\n");
834 exit(1);
835 }
836
837 /* The required service object access depends on the control. */
838 switch (WIN32_signal) {
839
840 case 0: /* SIGNULL */
841 fdwAccess = SERVICE_INTERROGATE;
842 fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERROGATE;
843 break;
844
845 case SIGUSR1:
846 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
847 fdwControl = _WIN_SQUID_SERVICE_CONTROL_ROTATE;
848 break;
849
850 case SIGUSR2:
851 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
852 fdwControl = _WIN_SQUID_SERVICE_CONTROL_DEBUG;
853 break;
854
855 case SIGHUP:
856 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
857 fdwControl = _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE;
858 break;
859
860 case SIGTERM:
861 fdwAccess = SERVICE_STOP;
862 fdwControl = _WIN_SQUID_SERVICE_CONTROL_STOP;
863 break;
864
865 case SIGINT:
866
867 case SIGKILL:
868 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
869 fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERRUPT;
870 break;
871
872 default:
873 exit(1);
874 }
875
876 /* Open a handle to the service. */
877 schService = OpenService(schSCManager, /* SCManager database */
cf2155f2 878 service_name, /* name of service */
9c8434f6 879 fdwAccess); /* specify access */
880
881 if (schService == NULL) {
cf2155f2 882 fprintf(stderr, "%s: ERROR: Could not open Service %s\n", APP_SHORTNAME, service_name);
9c8434f6 883 exit(1);
884 } else {
885 /* Send a control value to the service. */
886
887 if (!ControlService(schService, /* handle of service */
888 fdwControl, /* control value to send */
889 &ssStatus)) { /* address of status info */
890 fprintf(stderr, "%s: ERROR: Could not Control Service %s\n",
cf2155f2 891 APP_SHORTNAME, service_name);
9c8434f6 892 exit(1);
893 } else {
894 /* Print the service status. */
cf2155f2 895 printf("\nStatus of %s Service:\n", service_name);
9c8434f6 896 printf(" Service Type: 0x%lx\n", ssStatus.dwServiceType);
897 printf(" Current State: 0x%lx\n", ssStatus.dwCurrentState);
898 printf(" Controls Accepted: 0x%lx\n", ssStatus.dwControlsAccepted);
899 printf(" Exit Code: %ld\n", ssStatus.dwWin32ExitCode);
900 printf(" Service Specific Exit Code: %ld\n",
901 ssStatus.dwServiceSpecificExitCode);
902 printf(" Check Point: %ld\n", ssStatus.dwCheckPoint);
903 printf(" Wait Hint: %ld\n", ssStatus.dwWaitHint);
904 }
905
906 CloseServiceHandle(schService);
907 }
908
909 CloseServiceHandle(schSCManager);
910}
911
912int main(int argc, char **argv)
913{
914 SERVICE_TABLE_ENTRY DispatchTable[] = {
26ac0430
AJ
915 {NULL, SquidWinSvcMain},
916 {NULL, NULL}
917 };
9c8434f6 918 char *c;
919 char stderr_path[256];
920
91d63ce7 921 SetErrorMode(SEM_NOGPFAULTERRORBOX);
9c8434f6 922 if ((argc == 2) && strstr(argv[1], _WIN_SQUID_SERVICE_OPTION)) {
923 strcpy(stderr_path, argv[0]);
924 strcat(stderr_path,".log");
925 freopen(stderr_path, "w", stderr);
926 setmode(fileno(stderr), O_TEXT);
927 WIN32_run_mode = _WIN_SQUID_RUN_MODE_SERVICE;
9c8434f6 928
929 if (!(c=strchr(argv[1],':'))) {
930 fprintf(stderr, "Bad Service Parameter: %s\n", argv[1]);
931 return 1;
932 }
933
cf2155f2
AJ
934 service_name = xstrdup(c+1);
935 DispatchTable[0].lpServiceName=service_name;
936 strcat(REGKEY, service_name);
937 keys[4] = service_name;
9c8434f6 938
939 if (!StartServiceCtrlDispatcher(DispatchTable)) {
940 fprintf(stderr, "StartServiceCtrlDispatcher error = %ld\n",
941 GetLastError());
942 return 1;
943 }
944 } else {
945 WIN32_run_mode = _WIN_SQUID_RUN_MODE_INTERACTIVE;
9c8434f6 946 opt_no_daemon = 1;
947
9c8434f6 948 return SquidMain(argc, argv);
949 }
950
951 return 0;
952}
953
954#endif /* USE_WIN32_SERVICE */
955
9c8434f6 956static int Win32SockInit(void)
957{
958 int iVersionRequested;
959 WSADATA wsaData;
960 int err, opt;
961 int optlen = sizeof(opt);
962
963 if (s_iInitCount > 0) {
14942edd 964 ++s_iInitCount;
9c8434f6 965 return (0);
966 } else if (s_iInitCount < 0)
967 return (s_iInitCount);
968
969 /* s_iInitCount == 0. Do the initailization */
970 iVersionRequested = MAKEWORD(2, 0);
971
972 err = WSAStartup((WORD) iVersionRequested, &wsaData);
973
974 if (err) {
975 s_iInitCount = -1;
976 return (s_iInitCount);
977 }
978
979 if (LOBYTE(wsaData.wVersion) != 2 ||
980 HIBYTE(wsaData.wVersion) != 0) {
981 s_iInitCount = -2;
982 WSACleanup();
983 return (s_iInitCount);
984 }
985
986 if (WIN32_OS_version !=_WIN_OS_WINNT) {
987 if (::getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&opt, &optlen)) {
988 s_iInitCount = -3;
989 WSACleanup();
990 return (s_iInitCount);
991 } else {
992 opt = opt | SO_SYNCHRONOUS_NONALERT;
993
994 if (::setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, optlen)) {
995 s_iInitCount = -3;
996 WSACleanup();
997 return (s_iInitCount);
998 }
999 }
1000 }
1001
1002 WIN32_Socks_initialized = 1;
14942edd 1003 ++s_iInitCount;
9c8434f6 1004 return (s_iInitCount);
1005}
1006
1007static void Win32SockCleanup(void)
1008{
1009 if (--s_iInitCount == 0)
1010 WSACleanup();
1011
1012 return;
1013}
1014
1015void Squid_Win32InvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved)
1016{
1017 return;
1018}