2 * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
9 /* Inspired by previous work by Romeo Anghelache & Eric Stern. */
15 #include "SquidConfig.h"
20 #if !defined(_MSWSOCK_)
24 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
29 /* forward declarations */
30 static void WIN32_Exit(void);
31 static unsigned int GetOSVersion();
32 void WIN32_svcstatusupdate(DWORD
, DWORD
);
33 void WINAPI
WIN32_svcHandler(DWORD
);
34 extern "C" void WINAPI
SquidWinSvcMain(DWORD
, char **);
37 static void WIN32_Abort(int);
38 static int WIN32_StoreKey(const char *, DWORD
, unsigned char *, int);
39 static int WIN32_create_key(void);
40 static void WIN32_build_argv (char *);
43 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
44 void Squid_Win32InvalidParameterHandler(const wchar_t*, const wchar_t*, const wchar_t*, unsigned int, uintptr_t);
46 static int Win32SockInit(void);
47 static void Win32SockCleanup(void);
48 SQUIDCEXTERN LPCRITICAL_SECTION dbg_mutex
;
49 void WIN32_ExceptionHandlerCleanup(void);
50 static int s_iInitCount
= 0;
51 static HANDLE NotifyAddrChange_thread
= INVALID_HANDLE_VALUE
;
53 #undef NotifyAddrChange
54 typedef DWORD(WINAPI
* PFNotifyAddrChange
) (OUT PHANDLE
, IN LPOVERLAPPED
);
55 #define NOTIFYADDRCHANGE "NotifyAddrChange"
58 static SERVICE_STATUS svcStatus
;
59 static SERVICE_STATUS_HANDLE svcHandle
;
60 static int WIN32_argc
;
61 static char ** WIN32_argv
;
62 static char * WIN32_module_name
;
64 #define VENDOR "squid-cache.org"
65 static char VENDORString
[] = VENDOR
;
66 #define SOFTWARENAME PACKAGE_NAME
67 static char SOFTWARENAMEString
[] = SOFTWARENAME
;
68 #define SOFTWARE "SOFTWARE"
69 static char SOFTWAREString
[] = SOFTWARE
;
70 #define COMMANDLINE "CommandLine"
71 #define CONFIGFILE "ConfigFile"
72 #undef ChangeServiceConfig2
73 typedef BOOL (WINAPI
* PFChangeServiceConfig2
) (SC_HANDLE
, DWORD
, LPVOID
);
75 #define CHANGESERVICECONFIG2 "ChangeServiceConfig2W"
77 #define CHANGESERVICECONFIG2 "ChangeServiceConfig2A"
79 static SC_ACTION Squid_SCAction
[] = { { SC_ACTION_RESTART
, 60000 } };
80 static char Squid_ServiceDescriptionString
[] = SOFTWARENAME
" " VERSION
" WWW Proxy Server";
81 static SERVICE_DESCRIPTION Squid_ServiceDescription
= { Squid_ServiceDescriptionString
};
82 static SERVICE_FAILURE_ACTIONS Squid_ServiceFailureActions
= { INFINITE
, NULL
, NULL
, 1, Squid_SCAction
};
83 static char REGKEY
[256] = SOFTWARE
"\\" VENDOR
"\\" SOFTWARENAME
"\\";
84 static char *keys
[] = {
85 SOFTWAREString
, /* key[0] */
86 VENDORString
, /* key[1] */
87 SOFTWARENAMEString
, /* key[2] */
92 static int Squid_Aborting
= 0;
95 /* ====================================================================== */
97 /* ====================================================================== */
101 WIN32_create_key(void)
109 hKey
= HKEY_LOCAL_MACHINE
;
113 /* Walk the tree, creating at each stage if necessary */
115 while (keys
[index
]) {
116 unsigned long result
;
117 rv
= RegCreateKeyEx(hKey
, keys
[index
], /* subkey */
120 REG_OPTION_NON_VOLATILE
, KEY_WRITE
, NULL
, &hKeyNext
, &result
);
122 if (rv
!= ERROR_SUCCESS
) {
123 fprintf(stderr
, "RegCreateKeyEx(%s),%d\n", keys
[index
], (int) rv
);
127 /* Close the old key */
128 rv
= RegCloseKey(hKey
);
130 if (rv
!= ERROR_SUCCESS
) {
131 fprintf(stderr
, "RegCloseKey %d\n", (int) rv
);
134 /* Keep error status from RegCreateKeyEx, if any */
147 if (keys
[index
] == NULL
) {
148 /* Close the final key we opened, if we walked the entire
151 rv
= RegCloseKey(hKey
);
153 if (rv
!= ERROR_SUCCESS
) {
154 fprintf(stderr
, "RegCloseKey %d\n", (int) rv
);
157 /* Keep error status from RegCreateKeyEx, if any */
167 WIN32_StoreKey(const char *key
, DWORD type
, unsigned char *value
,
174 rv
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REGKEY
, 0, KEY_WRITE
, &hKey
);
176 if (rv
== ERROR_FILE_NOT_FOUND
) {
177 /* Key could not be opened -- try to create it
180 if (WIN32_create_key() < 0) {
181 /* Creation failed (error already reported) */
185 /* Now it has been created we should be able to open it
187 rv
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REGKEY
, 0, KEY_WRITE
, &hKey
);
189 if (rv
== ERROR_FILE_NOT_FOUND
) {
190 fprintf(stderr
, "Registry does not contain key %s after creation\n",
196 if (rv
!= ERROR_SUCCESS
) {
197 fprintf(stderr
, "RegOpenKeyEx HKLM\\%s, %d\n", REGKEY
, (int) rv
);
201 /* Now set the value and data */
202 rv
= RegSetValueEx(hKey
, key
, /* value key name */
205 value
, /* value data */
206 (DWORD
) value_size
); /* for size of "value" */
208 retval
= 0; /* Return value */
210 if (rv
!= ERROR_SUCCESS
) {
211 fprintf(stderr
, "RegQueryValueEx(key %s),%d\n", key
, (int) rv
);
214 fprintf(stderr
, "Registry stored HKLM\\%s\\%s value %s\n",
217 type
== REG_SZ
? value
: (unsigned char *) "(not displayable)");
220 /* Make sure we close the key even if there was an error storing
223 rv
= RegCloseKey(hKey
);
225 if (rv
!= ERROR_SUCCESS
) {
226 fprintf(stderr
, "RegCloseKey HKLM\\%s, %d\n", REGKEY
, (int) rv
);
229 /* Keep error status from RegQueryValueEx, if any */
237 /* Build argv, argc from string passed from Windows. */
238 static void WIN32_build_argv(char *cmd
)
244 WIN32_argv
= (char **) xmalloc ((WIN32_argc
+1) * sizeof (char *));
245 WIN32_argv
[0]=xstrdup(WIN32_module_name
);
246 /* Scan command line until there is nothing left. */
251 if (xisspace(*cmd
)) {
256 /* Found the beginning of an argument. */
260 ++cmd
; /* Skip over this character */
262 if (xisspace(*cmd
)) /* End of argument if space */
267 *cmd
++ = '\0'; /* Terminate `word' */
269 /* See if we need to allocate more space for argv */
270 if (WIN32_argc
>= argvlen
) {
271 argvlen
= WIN32_argc
+ 1;
272 WIN32_argv
= (char **) xrealloc (WIN32_argv
, (1 + argvlen
) * sizeof (char *));
275 /* Add word to argv file. */
276 WIN32_argv
[WIN32_argc
++] = word
;
279 WIN32_argv
[WIN32_argc
] = NULL
;
282 #endif /* USE_WIN32_SERVICE */
287 OSVERSIONINFOEX osvi
;
288 BOOL bOsVersionInfoEx
;
290 safe_free(WIN32_OS_string
);
291 memset(&osvi
, '\0', sizeof(OSVERSIONINFOEX
));
292 /* Try calling GetVersionEx using the OSVERSIONINFOEX structure.
293 * If that fails, try using the OSVERSIONINFO structure.
296 osvi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOEX
);
298 if (!(bOsVersionInfoEx
= GetVersionEx((OSVERSIONINFO
*) & osvi
))) {
299 osvi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
300 if (!GetVersionEx((OSVERSIONINFO
*) & osvi
))
303 switch (osvi
.dwPlatformId
) {
304 case VER_PLATFORM_WIN32_NT
:
305 if (osvi
.dwMajorVersion
<= 4) {
306 WIN32_OS_string
= xstrdup("Windows NT");
307 return _WIN_OS_WINNT
;
309 if ((osvi
.dwMajorVersion
== 5) && (osvi
.dwMinorVersion
== 0)) {
310 WIN32_OS_string
= xstrdup("Windows 2000");
311 return _WIN_OS_WIN2K
;
313 if ((osvi
.dwMajorVersion
== 5) && (osvi
.dwMinorVersion
== 1)) {
314 WIN32_OS_string
= xstrdup("Windows XP");
315 return _WIN_OS_WINXP
;
317 if ((osvi
.dwMajorVersion
== 5) && (osvi
.dwMinorVersion
== 2)) {
318 WIN32_OS_string
= xstrdup("Windows Server 2003");
319 return _WIN_OS_WINNET
;
321 if ((osvi
.dwMajorVersion
== 6) && (osvi
.dwMinorVersion
== 0)) {
322 if (osvi
.wProductType
== VER_NT_WORKSTATION
)
323 WIN32_OS_string
= xstrdup("Windows Vista");
325 WIN32_OS_string
= xstrdup("Windows Server 2008");
326 return _WIN_OS_WINLON
;
328 if ((osvi
.dwMajorVersion
== 6) && (osvi
.dwMinorVersion
== 1)) {
329 if (osvi
.wProductType
== VER_NT_WORKSTATION
)
330 WIN32_OS_string
= xstrdup("Windows 7");
332 WIN32_OS_string
= xstrdup("Windows Server 2008 R2");
335 if (((osvi
.dwMajorVersion
> 6)) || ((osvi
.dwMajorVersion
== 6) && (osvi
.dwMinorVersion
> 1))) {
336 if (osvi
.wProductType
== VER_NT_WORKSTATION
)
337 WIN32_OS_string
= xstrdup("Unknown Windows version, assuming Windows 7 capabilities");
339 WIN32_OS_string
= xstrdup("Unknown Windows version, assuming Windows Server 2008 R2 capabilities");
343 case VER_PLATFORM_WIN32_WINDOWS
:
344 if ((osvi
.dwMajorVersion
== 4) && (osvi
.dwMinorVersion
== 0)) {
345 WIN32_OS_string
= xstrdup("Windows 95");
346 return _WIN_OS_WIN95
;
348 if ((osvi
.dwMajorVersion
== 4) && (osvi
.dwMinorVersion
== 10)) {
349 WIN32_OS_string
= xstrdup("Windows 98");
350 return _WIN_OS_WIN98
;
352 if ((osvi
.dwMajorVersion
== 4) && (osvi
.dwMinorVersion
== 90)) {
353 WIN32_OS_string
= xstrdup("Windows Me");
354 return _WIN_OS_WINME
;
357 case VER_PLATFORM_WIN32s
:
358 WIN32_OS_string
= xstrdup("Windows 3.1 with WIN32S");
359 return _WIN_OS_WIN32S
;
365 WIN32_OS_string
= xstrdup("Unknown Windows system");
366 return _WIN_OS_UNKNOWN
;
369 /* ====================================================================== */
370 /* PUBLIC FUNCTIONS */
371 /* ====================================================================== */
373 #if USE_WIN32_SERVICE
377 svcStatus
.dwWin32ExitCode
= ERROR_SERVICE_SPECIFIC_ERROR
;
378 svcStatus
.dwServiceSpecificExitCode
= 1;
385 WIN32_IpAddrChangeMonitorExit()
387 DWORD status
= ERROR_SUCCESS
;
389 if (NotifyAddrChange_thread
!= INVALID_HANDLE_VALUE
) {
390 TerminateThread(NotifyAddrChange_thread
, status
);
391 CloseHandle(NotifyAddrChange_thread
);
399 #if USE_WIN32_SERVICE
401 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
402 if (!Squid_Aborting
) {
403 svcStatus
.dwCurrentState
= SERVICE_STOPPED
;
404 SetServiceStatus(svcHandle
, &svcStatus
);
410 DeleteCriticalSection(dbg_mutex
);
412 WIN32_ExceptionHandlerCleanup();
413 WIN32_IpAddrChangeMonitorExit();
418 WIN32_IpAddrChangeMonitor(LPVOID lpParam
)
421 HMODULE IPHLPAPIHandle
;
422 PFNotifyAddrChange NotifyAddrChange
;
424 if ((IPHLPAPIHandle
= GetModuleHandle("IPHLPAPI")) == NULL
)
425 IPHLPAPIHandle
= LoadLibrary("IPHLPAPI");
426 NotifyAddrChange
= (PFNotifyAddrChange
) GetProcAddress(IPHLPAPIHandle
, NOTIFYADDRCHANGE
);
429 Result
= NotifyAddrChange(NULL
, NULL
);
430 if (Result
!= NO_ERROR
) {
431 debugs(1, DBG_IMPORTANT
, "NotifyAddrChange error " << Result
);
434 debugs(1, DBG_IMPORTANT
, "Notification of IP address change received, requesting Squid reconfiguration ...");
441 WIN32_IpAddrChangeMonitorInit()
443 DWORD status
= ERROR_SUCCESS
;
444 DWORD threadID
= 0, ThrdParam
= 0;
446 if ((WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) && (Config
.onoff
.WIN32_IpAddrChangeMonitor
)) {
447 NotifyAddrChange_thread
= CreateThread(NULL
, 0, WIN32_IpAddrChangeMonitor
,
448 &ThrdParam
, 0, &threadID
);
449 if (NotifyAddrChange_thread
== NULL
) {
450 status
= GetLastError();
451 NotifyAddrChange_thread
= INVALID_HANDLE_VALUE
;
452 debugs(1, DBG_IMPORTANT
, "Failed to start IP monitor thread.");
454 debugs(1, 2, "Starting IP monitor thread [" << threadID
<< "] ...");
459 int WIN32_Subsystem_Init(int * argc
, char *** argv
)
461 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
462 _invalid_parameter_handler oldHandler
, newHandler
;
465 WIN32_OS_version
= GetOSVersion();
467 if ((WIN32_OS_version
== _WIN_OS_UNKNOWN
) || (WIN32_OS_version
== _WIN_OS_WIN32S
))
470 if (atexit(WIN32_Exit
) != 0)
473 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
475 newHandler
= Squid_Win32InvalidParameterHandler
;
477 oldHandler
= _set_invalid_parameter_handler(newHandler
);
479 _CrtSetReportMode(_CRT_ASSERT
, 0);
482 #if USE_WIN32_SERVICE
484 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
488 if (signal(SIGABRT
, WIN32_Abort
) == SIG_ERR
)
491 /* Register the service Handler function */
492 svcHandle
= RegisterServiceCtrlHandler(service_name
.c_str(), WIN32_svcHandler
);
497 /* Set Process work dir to directory cointaining squid.exe */
498 GetModuleFileName(NULL
, path
, 512);
500 WIN32_module_name
=xstrdup(path
);
502 path
[strlen(path
) - 10] = '\0';
504 if (SetCurrentDirectory(path
) == 0)
507 safe_free(ConfigFile
);
509 /* get config file from Windows Registry */
510 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REGKEY
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
514 Result
= RegQueryValueEx(hndKey
, CONFIGFILE
, NULL
, &Type
, NULL
, &Size
);
516 if (Result
== ERROR_SUCCESS
&& Size
) {
517 ConfigFile
= static_cast<char *>(xmalloc(Size
));
518 RegQueryValueEx(hndKey
, CONFIGFILE
, NULL
, &Type
, (unsigned char *)ConfigFile
, &Size
);
520 ConfigFile
= xstrdup(DefaultConfigFile
);
526 Result
= RegQueryValueEx(hndKey
, COMMANDLINE
, NULL
, &Type
, NULL
, &Size
);
528 if (Result
== ERROR_SUCCESS
&& Size
) {
529 WIN32_Service_Command_Line
= static_cast<char *>(xmalloc(Size
));
530 RegQueryValueEx(hndKey
, COMMANDLINE
, NULL
, &Type
, (unsigned char *)WIN32_Service_Command_Line
, &Size
);
532 WIN32_Service_Command_Line
= xstrdup("");
536 ConfigFile
= xstrdup(DefaultConfigFile
);
537 WIN32_Service_Command_Line
= xstrdup("");
540 WIN32_build_argv(WIN32_Service_Command_Line
);
543 /* Set Service Status to SERVICE_START_PENDING */
544 svcStatus
.dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
545 svcStatus
.dwCurrentState
= SERVICE_START_PENDING
;
546 svcStatus
.dwControlsAccepted
=
547 SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_SHUTDOWN
;
548 svcStatus
.dwWin32ExitCode
= 0;
549 svcStatus
.dwServiceSpecificExitCode
= 0;
550 svcStatus
.dwCheckPoint
= 0;
551 svcStatus
.dwWaitHint
= 10000;
552 SetServiceStatus(svcHandle
, &svcStatus
);
554 _setmaxstdio(Squid_MaxFD
);
558 #endif /* USE_WIN32_SERVICE */
559 if (Win32SockInit() < 0)
565 #if USE_WIN32_SERVICE
567 WIN32_svcstatusupdate(DWORD svcstate
, DWORD WaitHint
)
569 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
570 ++svcStatus
.dwCheckPoint
;
571 svcStatus
.dwWaitHint
= WaitHint
;
572 svcStatus
.dwCurrentState
= svcstate
;
573 SetServiceStatus(svcHandle
, &svcStatus
);
578 WIN32_svcHandler(DWORD Opcode
)
584 case _WIN_SQUID_SERVICE_CONTROL_STOP
:
586 case _WIN_SQUID_SERVICE_CONTROL_SHUTDOWN
:
587 /* Do whatever it takes to stop here. */
588 svcStatus
.dwWin32ExitCode
= 0;
589 svcStatus
.dwCurrentState
= SERVICE_STOP_PENDING
;
590 svcStatus
.dwCheckPoint
= 0;
591 svcStatus
.dwWaitHint
= 10000;
594 if (!SetServiceStatus(svcHandle
, &svcStatus
)) {
595 status
= GetLastError();
596 debugs(1, DBG_IMPORTANT
, "SetServiceStatus error " << status
);
599 debugs(1, DBG_IMPORTANT
, "Leaving Squid service");
602 case _WIN_SQUID_SERVICE_CONTROL_INTERROGATE
:
603 /* Fall through to send current status. */
605 if (!SetServiceStatus(svcHandle
, &svcStatus
)) {
606 status
= GetLastError();
607 debugs(1, DBG_IMPORTANT
, "SetServiceStatus error " << status
);
612 case _WIN_SQUID_SERVICE_CONTROL_ROTATE
:
613 rotate_logs(SIGUSR1
);
616 case _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE
:
620 case _WIN_SQUID_SERVICE_CONTROL_DEBUG
:
621 sigusr2_handle(SIGUSR2
);
624 case _WIN_SQUID_SERVICE_CONTROL_INTERRUPT
:
625 /* Do whatever it takes to stop here. */
626 svcStatus
.dwWin32ExitCode
= 0;
627 svcStatus
.dwCurrentState
= SERVICE_STOP_PENDING
;
628 svcStatus
.dwCheckPoint
= 0;
629 svcStatus
.dwWaitHint
= 10000;
632 if (!SetServiceStatus(svcHandle
, &svcStatus
)) {
633 status
= GetLastError();
634 debugs(1, DBG_IMPORTANT
, "SetServiceStatus error " << status
);
637 debugs(1, DBG_IMPORTANT
, "Leaving Squid service");
641 debugs(1, DBG_IMPORTANT
, "Unrecognized opcode " << Opcode
);
648 WIN32_RemoveService()
650 SC_HANDLE schService
;
651 SC_HANDLE schSCManager
;
653 if (service_name
.isEmpty())
654 service_name
= SBuf(APP_SHORTNAME
);
656 const char *service
= service_name
.c_str();
657 strcat(REGKEY
, service
);
659 keys
[4] = const_cast<char*>(service
);
661 schSCManager
= OpenSCManager(NULL
, /* machine (NULL == local) */
662 NULL
, /* database (NULL == default) */
663 SC_MANAGER_ALL_ACCESS
/* access required */
667 fprintf(stderr
, "OpenSCManager failed\n");
669 schService
= OpenService(schSCManager
, service
, SERVICE_ALL_ACCESS
);
671 if (schService
== NULL
)
672 fprintf(stderr
, "OpenService failed\n");
674 /* Could not open the service */
676 /* try to stop the service */
678 if (ControlService(schService
, _WIN_SQUID_SERVICE_CONTROL_STOP
,
682 while (QueryServiceStatus(schService
, &svcStatus
)) {
683 if (svcStatus
.dwCurrentState
== SERVICE_STOP_PENDING
)
690 /* now remove the service */
691 if (DeleteService(schService
) == 0)
692 fprintf(stderr
, "DeleteService failed.\n");
694 printf("Service " SQUIDSBUFPH
" deleted successfully.\n", SQUIDSBUFPRINT(service_name
));
696 CloseServiceHandle(schService
);
699 CloseServiceHandle(schSCManager
);
704 WIN32_SetServiceCommandLine()
706 if (service_name
.isEmpty())
707 service_name
= SBuf(APP_SHORTNAME
);
709 const char *service
= service_name
.c_str();
710 strcat(REGKEY
, service
);
712 keys
[4] = const_cast<char*>(service
);
714 /* Now store the Service Command Line in the registry */
715 WIN32_StoreKey(COMMANDLINE
, REG_SZ
, (unsigned char *) WIN32_Command_Line
, strlen(WIN32_Command_Line
) + 1);
719 WIN32_InstallService()
721 SC_HANDLE schService
;
722 SC_HANDLE schSCManager
;
723 char ServicePath
[512];
727 if (service_name
.isEmpty())
728 service_name
= SBuf(APP_SHORTNAME
);
730 const char *service
= service_name
.c_str();
731 strcat(REGKEY
, service
);
733 keys
[4] = const_cast<char*>(service
);
735 if ((lenpath
= GetModuleFileName(NULL
, ServicePath
, 512)) == 0) {
736 fprintf(stderr
, "Can't get executable path\n");
740 snprintf(szPath
, sizeof(szPath
), "%s %s:" SQUIDSBUFPH
, ServicePath
, _WIN_SQUID_SERVICE_OPTION
, SQUIDSBUFPRINT(service_name
));
741 schSCManager
= OpenSCManager(NULL
, /* machine (NULL == local) */
742 NULL
, /* database (NULL == default) */
743 SC_MANAGER_ALL_ACCESS
/* access required */
747 fprintf(stderr
, "OpenSCManager failed\n");
750 schService
= CreateService(schSCManager
, /* SCManager database */
751 service
, /* name of service */
752 service
, /* name to display */
753 SERVICE_ALL_ACCESS
, /* desired access */
754 SERVICE_WIN32_OWN_PROCESS
, /* service type */
755 SERVICE_AUTO_START
, /* start type */
756 SERVICE_ERROR_NORMAL
, /* error control type */
757 (const char *) szPath
, /* service's binary */
758 NULL
, /* no load ordering group */
759 NULL
, /* no tag identifier */
760 "Tcpip\0AFD\0", /* dependencies */
761 NULL
, /* LocalSystem account */
762 NULL
); /* no password */
765 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
766 HMODULE ADVAPI32Handle
;
767 PFChangeServiceConfig2 ChangeServiceConfig2
;
768 DWORD dwInfoLevel
= SERVICE_CONFIG_DESCRIPTION
;
770 ADVAPI32Handle
= GetModuleHandle("advapi32");
771 ChangeServiceConfig2
= (PFChangeServiceConfig2
) GetProcAddress(ADVAPI32Handle
, CHANGESERVICECONFIG2
);
772 ChangeServiceConfig2(schService
, dwInfoLevel
, &Squid_ServiceDescription
);
773 dwInfoLevel
= SERVICE_CONFIG_FAILURE_ACTIONS
;
774 ChangeServiceConfig2(schService
, dwInfoLevel
, &Squid_ServiceFailureActions
);
777 CloseServiceHandle(schService
);
778 /* Now store the config file location in the registry */
781 ConfigFile
= xstrdup(DefaultConfigFile
);
783 WIN32_StoreKey(CONFIGFILE
, REG_SZ
, (unsigned char *) ConfigFile
, strlen(ConfigFile
) + 1);
785 printf("Squid Cache version %s for %s\n", version_string
, CONFIG_HOST_TYPE
);
786 printf("installed successfully as " SQUIDSBUFPH
" Windows System Service.\n", SQUIDSBUFPRINT(service_name
));
787 printf("To run, start it from the Services Applet of Control Panel.\n");
788 printf("Don't forget to edit squid.conf before starting it.\n\n");
790 fprintf(stderr
, "CreateService failed\n");
794 CloseServiceHandle(schSCManager
);
799 WIN32_sendSignal(int WIN32_signal
)
801 SERVICE_STATUS ssStatus
;
802 DWORD fdwAccess
, fdwControl
;
803 SC_HANDLE schService
;
804 SC_HANDLE schSCManager
;
806 if (service_name
.isEmpty())
807 service_name
= SBuf(APP_SHORTNAME
);
809 schSCManager
= OpenSCManager(NULL
, /* machine (NULL == local) */
810 NULL
, /* database (NULL == default) */
811 SC_MANAGER_ALL_ACCESS
/* access required */
815 fprintf(stderr
, "OpenSCManager failed\n");
819 /* The required service object access depends on the control. */
820 switch (WIN32_signal
) {
822 case 0: /* SIGNULL */
823 fdwAccess
= SERVICE_INTERROGATE
;
824 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_INTERROGATE
;
828 fdwAccess
= SERVICE_USER_DEFINED_CONTROL
;
829 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_ROTATE
;
833 fdwAccess
= SERVICE_USER_DEFINED_CONTROL
;
834 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_DEBUG
;
838 fdwAccess
= SERVICE_USER_DEFINED_CONTROL
;
839 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE
;
843 fdwAccess
= SERVICE_STOP
;
844 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_STOP
;
850 fdwAccess
= SERVICE_USER_DEFINED_CONTROL
;
851 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_INTERRUPT
;
858 /* Open a handle to the service. */
859 schService
= OpenService(schSCManager
, /* SCManager database */
860 service_name
.c_str(), /* name of service */
861 fdwAccess
); /* specify access */
863 if (schService
== NULL
) {
864 fprintf(stderr
, "%s: ERROR: Could not open Service " SQUIDSBUFPH
"\n", APP_SHORTNAME
, SQUIDSBUFPRINT(service_name
));
867 /* Send a control value to the service. */
869 if (!ControlService(schService
, /* handle of service */
870 fdwControl
, /* control value to send */
871 &ssStatus
)) { /* address of status info */
872 fprintf(stderr
, "%s: ERROR: Could not Control Service " SQUIDSBUFPH
"\n",
873 APP_SHORTNAME
, SQUIDSBUFPRINT(service_name
));
876 /* Print the service status. */
877 printf("\nStatus of " SQUIDSBUFPH
" Service:\n", SQUIDSBUFPRINT(service_name
));
878 printf(" Service Type: 0x%lx\n", ssStatus
.dwServiceType
);
879 printf(" Current State: 0x%lx\n", ssStatus
.dwCurrentState
);
880 printf(" Controls Accepted: 0x%lx\n", ssStatus
.dwControlsAccepted
);
881 printf(" Exit Code: %ld\n", ssStatus
.dwWin32ExitCode
);
882 printf(" Service Specific Exit Code: %ld\n",
883 ssStatus
.dwServiceSpecificExitCode
);
884 printf(" Check Point: %ld\n", ssStatus
.dwCheckPoint
);
885 printf(" Wait Hint: %ld\n", ssStatus
.dwWaitHint
);
888 CloseServiceHandle(schService
);
891 CloseServiceHandle(schSCManager
);
894 int WIN32_StartService(int argc
, char **argv
)
896 SERVICE_TABLE_ENTRY DispatchTable
[] = {
897 {NULL
, SquidWinSvcMain
},
901 char stderr_path
[256];
903 strcpy(stderr_path
, argv
[0]);
904 strcat(stderr_path
,".log");
905 freopen(stderr_path
, "w", stderr
);
906 setmode(fileno(stderr
), O_TEXT
);
907 WIN32_run_mode
= _WIN_SQUID_RUN_MODE_SERVICE
;
909 if (!(c
=strchr(argv
[1],':'))) {
910 fprintf(stderr
, "Bad Service Parameter: %s\n", argv
[1]);
914 service_name
= SBuf(c
+1);
915 const char *service
= service_name
.c_str();
916 DispatchTable
[0].lpServiceName
= const_cast<char*>(service
);
917 strcat(REGKEY
, service
);
918 keys
[4] = const_cast<char*>(service
);
920 if (!StartServiceCtrlDispatcher(DispatchTable
)) {
921 fprintf(stderr
, "StartServiceCtrlDispatcher error = %ld\n", GetLastError());
928 #endif /* USE_WIN32_SERVICE */
930 static int Win32SockInit(void)
932 int iVersionRequested
;
935 int optlen
= sizeof(opt
);
937 if (s_iInitCount
> 0) {
940 } else if (s_iInitCount
< 0)
941 return (s_iInitCount
);
943 /* s_iInitCount == 0. Do the initailization */
944 iVersionRequested
= MAKEWORD(2, 0);
946 err
= WSAStartup((WORD
) iVersionRequested
, &wsaData
);
950 return (s_iInitCount
);
953 if (LOBYTE(wsaData
.wVersion
) != 2 ||
954 HIBYTE(wsaData
.wVersion
) != 0) {
957 return (s_iInitCount
);
960 if (WIN32_OS_version
!=_WIN_OS_WINNT
) {
961 if (::getsockopt(INVALID_SOCKET
, SOL_SOCKET
, SO_OPENTYPE
, (char *)&opt
, &optlen
)) {
964 return (s_iInitCount
);
966 opt
= opt
| SO_SYNCHRONOUS_NONALERT
;
968 if (::setsockopt(INVALID_SOCKET
, SOL_SOCKET
, SO_OPENTYPE
, (char *) &opt
, optlen
)) {
971 return (s_iInitCount
);
976 WIN32_Socks_initialized
= 1;
978 return (s_iInitCount
);
981 static void Win32SockCleanup(void)
983 if (--s_iInitCount
== 0)
989 void Squid_Win32InvalidParameterHandler(const wchar_t* expression
, const wchar_t* function
, const wchar_t* file
, unsigned int line
, uintptr_t pReserved
)