3 * $Id: WinSvc.cc,v 1.6 2008/02/17 19:30:12 serassio Exp $
6 * AUTHOR: Guido Serassio <serassio@squid-cache.org>
7 * inspired by previous work by Romeo Anghelache & Eric Stern.
9 * SQUID Web Proxy Cache http://www.squid-cache.org/
10 * ----------------------------------------------------------
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.
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.
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.
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.
38 #include "squid_windows.h"
45 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
50 static unsigned int GetOSVersion();
51 void WIN32_svcstatusupdate(DWORD
, DWORD
);
52 void WINAPI
WIN32_svcHandler(DWORD
);
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 *);
58 extern "C" void WINAPI
SquidWinSvcMain(DWORD
, char **);
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);
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_ */
72 static int Squid_Aborting
= 0;
74 #undef NotifyAddrChange
75 typedef DWORD(WINAPI
* PFNotifyAddrChange
) (OUT PHANDLE
, IN LPOVERLAPPED
);
76 #define NOTIFYADDRCHANGE "NotifyAddrChange"
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
;
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
);
98 #define CHANGESERVICECONFIG2 "ChangeServiceConfig2W"
100 #define CHANGESERVICECONFIG2 "ChangeServiceConfig2A"
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] */
117 /* ====================================================================== */
118 /* LOCAL FUNCTIONS */
119 /* ====================================================================== */
121 #if USE_WIN32_SERVICE
123 WIN32_create_key(void)
131 hKey
= HKEY_LOCAL_MACHINE
;
135 /* Walk the tree, creating at each stage if necessary */
137 while (keys
[index
]) {
138 unsigned long result
;
139 rv
= RegCreateKeyEx(hKey
, keys
[index
], /* subkey */
142 REG_OPTION_NON_VOLATILE
, KEY_WRITE
, NULL
, &hKeyNext
, &result
);
144 if (rv
!= ERROR_SUCCESS
) {
145 fprintf(stderr
, "RegCreateKeyEx(%s),%d\n", keys
[index
], (int) rv
);
149 /* Close the old key */
150 rv
= RegCloseKey(hKey
);
152 if (rv
!= ERROR_SUCCESS
) {
153 fprintf(stderr
, "RegCloseKey %d\n", (int) rv
);
156 /* Keep error status from RegCreateKeyEx, if any */
169 if (keys
[index
] == NULL
) {
170 /* Close the final key we opened, if we walked the entire
173 rv
= RegCloseKey(hKey
);
175 if (rv
!= ERROR_SUCCESS
) {
176 fprintf(stderr
, "RegCloseKey %d\n", (int) rv
);
179 /* Keep error status from RegCreateKeyEx, if any */
189 WIN32_StoreKey(const char *key
, DWORD type
, unsigned char *value
,
196 rv
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REGKEY
, 0, KEY_WRITE
, &hKey
);
198 if (rv
== ERROR_FILE_NOT_FOUND
) {
199 /* Key could not be opened -- try to create it
202 if (WIN32_create_key() < 0) {
203 /* Creation failed (error already reported) */
207 /* Now it has been created we should be able to open it
209 rv
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REGKEY
, 0, KEY_WRITE
, &hKey
);
211 if (rv
== ERROR_FILE_NOT_FOUND
) {
212 fprintf(stderr
, "Registry does not contain key %s after creation\n",
218 if (rv
!= ERROR_SUCCESS
) {
219 fprintf(stderr
, "RegOpenKeyEx HKLM\\%s, %d\n", REGKEY
, (int) rv
);
223 /* Now set the value and data */
224 rv
= RegSetValueEx(hKey
, key
, /* value key name */
227 value
, /* value data */
228 (DWORD
) value_size
); /* for size of "value" */
230 retval
= 0; /* Return value */
232 if (rv
!= ERROR_SUCCESS
) {
233 fprintf(stderr
, "RegQueryValueEx(key %s),%d\n", key
, (int) rv
);
236 fprintf(stderr
, "Registry stored HKLM\\%s\\%s value %s\n",
239 type
== REG_SZ
? value
: (unsigned char *) "(not displayable)");
242 /* Make sure we close the key even if there was an error storing
245 rv
= RegCloseKey(hKey
);
247 if (rv
!= ERROR_SUCCESS
) {
248 fprintf(stderr
, "RegCloseKey HKLM\\%s, %d\n", REGKEY
, (int) rv
);
251 /* Keep error status from RegQueryValueEx, if any */
259 /* Build argv, argc from string passed from Windows. */
260 static void WIN32_build_argv(char *cmd
)
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. */
273 if (xisspace(*cmd
)) {
278 /* Found the beginning of an argument. */
282 cmd
++; /* Skip over this character */
284 if (xisspace(*cmd
)) /* End of argument if space */
289 *cmd
++ = '\0'; /* Terminate `word' */
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 *));
297 /* Add word to argv file. */
298 WIN32_argv
[WIN32_argc
++] = word
;
301 WIN32_argv
[WIN32_argc
] = NULL
;
304 #endif /* USE_WIN32_SERVICE */
309 OSVERSIONINFOEX osvi
;
310 BOOL bOsVersionInfoEx
;
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.
318 osvi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOEX
);
320 if (!(bOsVersionInfoEx
= GetVersionEx((OSVERSIONINFO
*) & osvi
))) {
321 osvi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
322 if (!GetVersionEx((OSVERSIONINFO
*) & osvi
))
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
;
331 if ((osvi
.dwMajorVersion
== 5) && (osvi
.dwMinorVersion
== 0)) {
332 WIN32_OS_string
= xstrdup("Windows 2000");
333 return _WIN_OS_WIN2K
;
335 if ((osvi
.dwMajorVersion
== 5) && (osvi
.dwMinorVersion
== 1)) {
336 WIN32_OS_string
= xstrdup("Windows XP");
337 return _WIN_OS_WINXP
;
339 if ((osvi
.dwMajorVersion
== 5) && (osvi
.dwMinorVersion
== 2)) {
340 WIN32_OS_string
= xstrdup("Windows Server 2003");
341 return _WIN_OS_WINNET
;
343 if ((osvi
.dwMajorVersion
== 6) && (osvi
.dwMinorVersion
== 0)) {
344 if (osvi
.wProductType
== VER_NT_WORKSTATION
)
345 WIN32_OS_string
= xstrdup("Windows Vista");
347 WIN32_OS_string
= xstrdup("Windows Server 2008");
348 return _WIN_OS_WINLON
;
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
;
356 if ((osvi
.dwMajorVersion
== 4) && (osvi
.dwMinorVersion
== 10)) {
357 WIN32_OS_string
= xstrdup("Windows 98");
358 return _WIN_OS_WIN98
;
360 if ((osvi
.dwMajorVersion
== 4) && (osvi
.dwMinorVersion
== 90)) {
361 WIN32_OS_string
= xstrdup("Windows Me");
362 return _WIN_OS_WINME
;
365 case VER_PLATFORM_WIN32s
:
366 WIN32_OS_string
= xstrdup("Windows 3.1 with WIN32S");
367 return _WIN_OS_WIN32S
;
373 WIN32_OS_string
= xstrdup("Unknown Windows system");
374 return _WIN_OS_UNKNOWN
;
377 /* ====================================================================== */
378 /* PUBLIC FUNCTIONS */
379 /* ====================================================================== */
384 #if USE_WIN32_SERVICE
385 svcStatus
.dwWin32ExitCode
= ERROR_SERVICE_SPECIFIC_ERROR
;
386 svcStatus
.dwServiceSpecificExitCode
= 1;
395 WIN32_IpAddrChangeMonitorExit()
397 DWORD status
= ERROR_SUCCESS
;
399 if (NotifyAddrChange_thread
!= INVALID_HANDLE_VALUE
) {
400 TerminateThread(NotifyAddrChange_thread
, status
);
401 CloseHandle(NotifyAddrChange_thread
);
412 #if USE_WIN32_SERVICE
414 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
415 if (!Squid_Aborting
) {
416 svcStatus
.dwCurrentState
= SERVICE_STOPPED
;
417 SetServiceStatus(svcHandle
, &svcStatus
);
424 DeleteCriticalSection(dbg_mutex
);
426 WIN32_ExceptionHandlerCleanup();
427 WIN32_IpAddrChangeMonitorExit();
436 WIN32_IpAddrChangeMonitor(LPVOID lpParam
)
439 HMODULE IPHLPAPIHandle
;
440 PFNotifyAddrChange NotifyAddrChange
;
442 if ((IPHLPAPIHandle
= GetModuleHandle("IPHLPAPI")) == NULL
)
443 IPHLPAPIHandle
= LoadLibrary("IPHLPAPI");
444 NotifyAddrChange
= (PFNotifyAddrChange
) GetProcAddress(IPHLPAPIHandle
, NOTIFYADDRCHANGE
);
447 Result
= NotifyAddrChange(NULL
, NULL
);
448 if (Result
!= NO_ERROR
) {
449 debugs(1, 1, "NotifyAddrChange error " << Result
);
452 debugs(1, 1, "Notification of IP address change received, requesting Squid reconfiguration ...");
459 WIN32_IpAddrChangeMonitorInit()
461 DWORD status
= ERROR_SUCCESS
;
462 DWORD threadID
= 0, ThrdParam
= 0;
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.");
472 debugs(1, 2, "Starting IP monitor thread [" << threadID
<< "] ...");
476 #endif /* _SQUID_MSWIN_ */
478 int WIN32_Subsystem_Init(int * argc
, char *** argv
)
480 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
481 _invalid_parameter_handler oldHandler
, newHandler
;
484 WIN32_OS_version
= GetOSVersion();
486 if ((WIN32_OS_version
== _WIN_OS_UNKNOWN
) || (WIN32_OS_version
== _WIN_OS_WIN32S
))
489 if (atexit(WIN32_Exit
) != 0)
492 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
494 newHandler
= Squid_Win32InvalidParameterHandler
;
496 oldHandler
= _set_invalid_parameter_handler(newHandler
);
498 _CrtSetReportMode(_CRT_ASSERT
, 0);
501 #if USE_WIN32_SERVICE
503 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
507 if (signal(SIGABRT
, WIN32_Abort
) == SIG_ERR
)
510 /* Register the service Handler function */
512 RegisterServiceCtrlHandler(WIN32_Service_name
,
518 /* Set Process work dir to directory cointaining squid.exe */
519 GetModuleFileName(NULL
, path
, 512);
521 WIN32_module_name
=xstrdup(path
);
523 path
[strlen(path
) - 10] = '\0';
525 if (SetCurrentDirectory(path
) == 0)
528 safe_free(ConfigFile
);
530 /* get config file from Windows Registry */
531 if (RegOpenKey(HKEY_LOCAL_MACHINE
, REGKEY
, &hndKey
) == ERROR_SUCCESS
) {
536 RegQueryValueEx(hndKey
, CONFIGFILE
, NULL
, &Type
, NULL
, &Size
);
538 if (Result
== ERROR_SUCCESS
&& Size
) {
539 ConfigFile
= static_cast<char *>(xmalloc(Size
));
540 RegQueryValueEx(hndKey
, CONFIGFILE
, NULL
, &Type
, (unsigned char *)ConfigFile
,
543 ConfigFile
= xstrdup(DefaultConfigFile
);
550 RegQueryValueEx(hndKey
, COMMANDLINE
, NULL
, &Type
, NULL
, &Size
);
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
,
557 WIN32_Service_Command_Line
= xstrdup("");
561 ConfigFile
= xstrdup(DefaultConfigFile
);
562 WIN32_Service_Command_Line
= xstrdup("");
565 WIN32_build_argv(WIN32_Service_Command_Line
);
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
);
580 _setmaxstdio(Squid_MaxFD
);
585 #endif /* USE_WIN32_SERVICE */
587 if (Win32SockInit() < 0)
595 #if USE_WIN32_SERVICE
597 WIN32_svcstatusupdate(DWORD svcstate
, DWORD WaitHint
)
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
);
608 WIN32_svcHandler(DWORD Opcode
)
614 case _WIN_SQUID_SERVICE_CONTROL_STOP
:
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;
624 if (!SetServiceStatus(svcHandle
, &svcStatus
)) {
625 status
= GetLastError();
626 debugs(1, 1, "SetServiceStatus error " << status
);
629 debugs(1, 1, "Leaving Squid service");
632 case _WIN_SQUID_SERVICE_CONTROL_INTERROGATE
:
633 /* Fall through to send current status. */
635 if (!SetServiceStatus(svcHandle
, &svcStatus
)) {
636 status
= GetLastError();
637 debugs(1, 1, "SetServiceStatus error " << status
);
642 case _WIN_SQUID_SERVICE_CONTROL_ROTATE
:
643 rotate_logs(SIGUSR1
);
646 case _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE
:
650 case _WIN_SQUID_SERVICE_CONTROL_DEBUG
:
651 sigusr2_handle(SIGUSR2
);
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;
662 if (!SetServiceStatus(svcHandle
, &svcStatus
)) {
663 status
= GetLastError();
664 debugs(1, 1, "SetServiceStatus error " << status
);
667 debugs(1, 1, "Leaving Squid service");
671 debugs(1, 1, "Unrecognized opcode " << Opcode
);
678 WIN32_RemoveService()
680 SC_HANDLE schService
;
681 SC_HANDLE schSCManager
;
683 if (!WIN32_Service_name
)
684 WIN32_Service_name
= xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME
);
686 strcat(REGKEY
, WIN32_Service_name
);
688 keys
[4] = WIN32_Service_name
;
690 schSCManager
= OpenSCManager(NULL
, /* machine (NULL == local) */
691 NULL
, /* database (NULL == default) */
692 SC_MANAGER_ALL_ACCESS
/* access required */
696 fprintf(stderr
, "OpenSCManager failed\n");
698 schService
= OpenService(schSCManager
, WIN32_Service_name
, SERVICE_ALL_ACCESS
);
700 if (schService
== NULL
)
701 fprintf(stderr
, "OpenService failed\n");
703 /* Could not open the service */
705 /* try to stop the service */
707 if (ControlService(schService
, _WIN_SQUID_SERVICE_CONTROL_STOP
,
711 while (QueryServiceStatus(schService
, &svcStatus
)) {
712 if (svcStatus
.dwCurrentState
== SERVICE_STOP_PENDING
)
719 /* now remove the service */
720 if (DeleteService(schService
) == 0)
721 fprintf(stderr
, "DeleteService failed.\n");
723 printf("Service %s deleted successfully.\n",
726 CloseServiceHandle(schService
);
729 CloseServiceHandle(schSCManager
);
734 WIN32_SetServiceCommandLine()
736 if (!WIN32_Service_name
)
737 WIN32_Service_name
= xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME
);
739 strcat(REGKEY
, WIN32_Service_name
);
741 keys
[4] = WIN32_Service_name
;
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);
748 WIN32_InstallService()
750 SC_HANDLE schService
;
751 SC_HANDLE schSCManager
;
752 char ServicePath
[512];
756 if (!WIN32_Service_name
)
757 WIN32_Service_name
= xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME
);
759 strcat(REGKEY
, WIN32_Service_name
);
761 keys
[4] = WIN32_Service_name
;
763 if ((lenpath
= GetModuleFileName(NULL
, ServicePath
, 512)) == 0) {
764 fprintf(stderr
, "Can't get executable path\n");
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 */
775 fprintf(stderr
, "OpenSCManager failed\n");
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 */
793 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
794 HMODULE ADVAPI32Handle
;
795 PFChangeServiceConfig2 ChangeServiceConfig2
;
796 DWORD dwInfoLevel
= SERVICE_CONFIG_DESCRIPTION
;
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
);
805 CloseServiceHandle(schService
);
806 /* Now store the config file location in the registry */
809 ConfigFile
= xstrdup(DefaultConfigFile
);
811 WIN32_StoreKey(CONFIGFILE
, REG_SZ
, (unsigned char *) ConfigFile
, strlen(ConfigFile
) + 1);
813 printf("Squid Cache version %s for %s\n", version_string
,
816 printf("installed successfully as %s Windows System Service.\n",
820 ("To run, start it from the Services Applet of Control Panel.\n");
822 printf("Don't forget to edit squid.conf before starting it.\n\n");
824 fprintf(stderr
, "CreateService failed\n");
828 CloseServiceHandle(schSCManager
);
833 WIN32_sendSignal(int WIN32_signal
)
835 SERVICE_STATUS ssStatus
;
836 DWORD fdwAccess
, fdwControl
;
837 SC_HANDLE schService
;
838 SC_HANDLE schSCManager
;
840 if (!WIN32_Service_name
)
841 WIN32_Service_name
= xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME
);
843 schSCManager
= OpenSCManager(NULL
, /* machine (NULL == local) */
844 NULL
, /* database (NULL == default) */
845 SC_MANAGER_ALL_ACCESS
/* access required */
849 fprintf(stderr
, "OpenSCManager failed\n");
853 /* The required service object access depends on the control. */
854 switch (WIN32_signal
) {
856 case 0: /* SIGNULL */
857 fdwAccess
= SERVICE_INTERROGATE
;
858 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_INTERROGATE
;
862 fdwAccess
= SERVICE_USER_DEFINED_CONTROL
;
863 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_ROTATE
;
867 fdwAccess
= SERVICE_USER_DEFINED_CONTROL
;
868 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_DEBUG
;
872 fdwAccess
= SERVICE_USER_DEFINED_CONTROL
;
873 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE
;
877 fdwAccess
= SERVICE_STOP
;
878 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_STOP
;
884 fdwAccess
= SERVICE_USER_DEFINED_CONTROL
;
885 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_INTERRUPT
;
892 /* Open a handle to the service. */
893 schService
= OpenService(schSCManager
, /* SCManager database */
894 WIN32_Service_name
, /* name of service */
895 fdwAccess
); /* specify access */
897 if (schService
== NULL
) {
898 fprintf(stderr
, "%s: ERROR: Could not open Service %s\n", APP_SHORTNAME
,
902 /* Send a control value to the service. */
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 APP_SHORTNAME
, WIN32_Service_name
);
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
);
923 CloseServiceHandle(schService
);
926 CloseServiceHandle(schSCManager
);
929 int main(int argc
, char **argv
)
931 SERVICE_TABLE_ENTRY DispatchTable
[] = {
932 {NULL
, SquidWinSvcMain
},
936 char stderr_path
[256];
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
;
945 if (!(c
=strchr(argv
[1],':'))) {
946 fprintf(stderr
, "Bad Service Parameter: %s\n", argv
[1]);
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
;
955 if (!StartServiceCtrlDispatcher(DispatchTable
)) {
956 fprintf(stderr
, "StartServiceCtrlDispatcher error = %ld\n",
961 WIN32_run_mode
= _WIN_SQUID_RUN_MODE_INTERACTIVE
;
968 return SquidMain(argc
, argv
);
974 #endif /* USE_WIN32_SERVICE */
976 #if defined(_SQUID_MSWIN_)
977 static int Win32SockInit(void)
979 int iVersionRequested
;
982 int optlen
= sizeof(opt
);
984 if (s_iInitCount
> 0) {
987 } else if (s_iInitCount
< 0)
988 return (s_iInitCount
);
990 /* s_iInitCount == 0. Do the initailization */
991 iVersionRequested
= MAKEWORD(2, 0);
993 err
= WSAStartup((WORD
) iVersionRequested
, &wsaData
);
997 return (s_iInitCount
);
1000 if (LOBYTE(wsaData
.wVersion
) != 2 ||
1001 HIBYTE(wsaData
.wVersion
) != 0) {
1004 return (s_iInitCount
);
1007 if (WIN32_OS_version
!=_WIN_OS_WINNT
) {
1008 if (::getsockopt(INVALID_SOCKET
, SOL_SOCKET
, SO_OPENTYPE
, (char *)&opt
, &optlen
)) {
1011 return (s_iInitCount
);
1013 opt
= opt
| SO_SYNCHRONOUS_NONALERT
;
1015 if (::setsockopt(INVALID_SOCKET
, SOL_SOCKET
, SO_OPENTYPE
, (char *) &opt
, optlen
)) {
1018 return (s_iInitCount
);
1023 WIN32_Socks_initialized
= 1;
1025 return (s_iInitCount
);
1028 static void Win32SockCleanup(void)
1030 if (--s_iInitCount
== 0)
1036 void Squid_Win32InvalidParameterHandler(const wchar_t* expression
, const wchar_t* function
, const wchar_t* file
, unsigned int line
, uintptr_t pReserved
)
1041 #endif /* SQUID_MSWIN_ */