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