3 * AUTHOR: Guido Serassio <serassio@squid-cache.org>
4 * inspired by previous work by Romeo Anghelache & Eric Stern.
6 * SQUID Web Proxy Cache http://www.squid-cache.org/
7 * ----------------------------------------------------------
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.
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.
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.
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.
38 #include "SquidConfig.h"
45 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
50 /* forward declarations */
51 static void WIN32_Exit(void);
52 static unsigned int GetOSVersion();
53 void WIN32_svcstatusupdate(DWORD
, DWORD
);
54 void WINAPI
WIN32_svcHandler(DWORD
);
55 extern "C" void WINAPI
SquidWinSvcMain(DWORD
, char **);
58 static void WIN32_Abort(int);
59 static int WIN32_StoreKey(const char *, DWORD
, unsigned char *, int);
60 static int WIN32_create_key(void);
61 static void WIN32_build_argv (char *);
64 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
65 void Squid_Win32InvalidParameterHandler(const wchar_t*, const wchar_t*, const wchar_t*, unsigned int, uintptr_t);
67 static int Win32SockInit(void);
68 static void Win32SockCleanup(void);
69 SQUIDCEXTERN LPCRITICAL_SECTION dbg_mutex
;
70 void WIN32_ExceptionHandlerCleanup(void);
71 static int s_iInitCount
= 0;
72 static HANDLE NotifyAddrChange_thread
= INVALID_HANDLE_VALUE
;
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
;
85 #define VENDOR "squid-cache.org"
86 static char VENDORString
[] = VENDOR
;
87 #define SOFTWARENAME PACKAGE_NAME
88 static char SOFTWARENAMEString
[] = SOFTWARENAME
;
89 #define SOFTWARE "SOFTWARE"
90 static char SOFTWAREString
[] = SOFTWARE
;
91 #define COMMANDLINE "CommandLine"
92 #define CONFIGFILE "ConfigFile"
93 #undef ChangeServiceConfig2
94 typedef BOOL (WINAPI
* PFChangeServiceConfig2
) (SC_HANDLE
, DWORD
, LPVOID
);
96 #define CHANGESERVICECONFIG2 "ChangeServiceConfig2W"
98 #define CHANGESERVICECONFIG2 "ChangeServiceConfig2A"
100 static SC_ACTION Squid_SCAction
[] = { { SC_ACTION_RESTART
, 60000 } };
101 static char Squid_ServiceDescriptionString
[] = SOFTWARENAME
" " VERSION
" WWW Proxy Server";
102 static SERVICE_DESCRIPTION Squid_ServiceDescription
= { Squid_ServiceDescriptionString
};
103 static SERVICE_FAILURE_ACTIONS Squid_ServiceFailureActions
= { INFINITE
, NULL
, NULL
, 1, Squid_SCAction
};
104 static char REGKEY
[256]=SOFTWARE
"\\"VENDOR
"\\"SOFTWARENAME
"\\";
105 static char *keys
[] = {
106 SOFTWAREString
, /* key[0] */
107 VENDORString
, /* key[1] */
108 SOFTWARENAMEString
, /* key[2] */
113 static int Squid_Aborting
= 0;
116 /* ====================================================================== */
117 /* LOCAL FUNCTIONS */
118 /* ====================================================================== */
120 #if USE_WIN32_SERVICE
122 WIN32_create_key(void)
130 hKey
= HKEY_LOCAL_MACHINE
;
134 /* Walk the tree, creating at each stage if necessary */
136 while (keys
[index
]) {
137 unsigned long result
;
138 rv
= RegCreateKeyEx(hKey
, keys
[index
], /* subkey */
141 REG_OPTION_NON_VOLATILE
, KEY_WRITE
, NULL
, &hKeyNext
, &result
);
143 if (rv
!= ERROR_SUCCESS
) {
144 fprintf(stderr
, "RegCreateKeyEx(%s),%d\n", keys
[index
], (int) rv
);
148 /* Close the old key */
149 rv
= RegCloseKey(hKey
);
151 if (rv
!= ERROR_SUCCESS
) {
152 fprintf(stderr
, "RegCloseKey %d\n", (int) rv
);
155 /* Keep error status from RegCreateKeyEx, if any */
168 if (keys
[index
] == NULL
) {
169 /* Close the final key we opened, if we walked the entire
172 rv
= RegCloseKey(hKey
);
174 if (rv
!= ERROR_SUCCESS
) {
175 fprintf(stderr
, "RegCloseKey %d\n", (int) rv
);
178 /* Keep error status from RegCreateKeyEx, if any */
188 WIN32_StoreKey(const char *key
, DWORD type
, unsigned char *value
,
195 rv
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REGKEY
, 0, KEY_WRITE
, &hKey
);
197 if (rv
== ERROR_FILE_NOT_FOUND
) {
198 /* Key could not be opened -- try to create it
201 if (WIN32_create_key() < 0) {
202 /* Creation failed (error already reported) */
206 /* Now it has been created we should be able to open it
208 rv
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REGKEY
, 0, KEY_WRITE
, &hKey
);
210 if (rv
== ERROR_FILE_NOT_FOUND
) {
211 fprintf(stderr
, "Registry does not contain key %s after creation\n",
217 if (rv
!= ERROR_SUCCESS
) {
218 fprintf(stderr
, "RegOpenKeyEx HKLM\\%s, %d\n", REGKEY
, (int) rv
);
222 /* Now set the value and data */
223 rv
= RegSetValueEx(hKey
, key
, /* value key name */
226 value
, /* value data */
227 (DWORD
) value_size
); /* for size of "value" */
229 retval
= 0; /* Return value */
231 if (rv
!= ERROR_SUCCESS
) {
232 fprintf(stderr
, "RegQueryValueEx(key %s),%d\n", key
, (int) rv
);
235 fprintf(stderr
, "Registry stored HKLM\\%s\\%s value %s\n",
238 type
== REG_SZ
? value
: (unsigned char *) "(not displayable)");
241 /* Make sure we close the key even if there was an error storing
244 rv
= RegCloseKey(hKey
);
246 if (rv
!= ERROR_SUCCESS
) {
247 fprintf(stderr
, "RegCloseKey HKLM\\%s, %d\n", REGKEY
, (int) rv
);
250 /* Keep error status from RegQueryValueEx, if any */
258 /* Build argv, argc from string passed from Windows. */
259 static void WIN32_build_argv(char *cmd
)
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. */
272 if (xisspace(*cmd
)) {
277 /* Found the beginning of an argument. */
281 ++cmd
; /* Skip over this character */
283 if (xisspace(*cmd
)) /* End of argument if space */
288 *cmd
++ = '\0'; /* Terminate `word' */
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 *));
296 /* Add word to argv file. */
297 WIN32_argv
[WIN32_argc
++] = word
;
300 WIN32_argv
[WIN32_argc
] = NULL
;
303 #endif /* USE_WIN32_SERVICE */
308 OSVERSIONINFOEX osvi
;
309 BOOL bOsVersionInfoEx
;
311 safe_free(WIN32_OS_string
);
312 memset(&osvi
, '\0', sizeof(OSVERSIONINFOEX
));
313 /* Try calling GetVersionEx using the OSVERSIONINFOEX structure.
314 * If that fails, try using the OSVERSIONINFO structure.
317 osvi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOEX
);
319 if (!(bOsVersionInfoEx
= GetVersionEx((OSVERSIONINFO
*) & osvi
))) {
320 osvi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
321 if (!GetVersionEx((OSVERSIONINFO
*) & osvi
))
324 switch (osvi
.dwPlatformId
) {
325 case VER_PLATFORM_WIN32_NT
:
326 if (osvi
.dwMajorVersion
<= 4) {
327 WIN32_OS_string
= xstrdup("Windows NT");
328 return _WIN_OS_WINNT
;
330 if ((osvi
.dwMajorVersion
== 5) && (osvi
.dwMinorVersion
== 0)) {
331 WIN32_OS_string
= xstrdup("Windows 2000");
332 return _WIN_OS_WIN2K
;
334 if ((osvi
.dwMajorVersion
== 5) && (osvi
.dwMinorVersion
== 1)) {
335 WIN32_OS_string
= xstrdup("Windows XP");
336 return _WIN_OS_WINXP
;
338 if ((osvi
.dwMajorVersion
== 5) && (osvi
.dwMinorVersion
== 2)) {
339 WIN32_OS_string
= xstrdup("Windows Server 2003");
340 return _WIN_OS_WINNET
;
342 if ((osvi
.dwMajorVersion
== 6) && (osvi
.dwMinorVersion
== 0)) {
343 if (osvi
.wProductType
== VER_NT_WORKSTATION
)
344 WIN32_OS_string
= xstrdup("Windows Vista");
346 WIN32_OS_string
= xstrdup("Windows Server 2008");
347 return _WIN_OS_WINLON
;
349 if ((osvi
.dwMajorVersion
== 6) && (osvi
.dwMinorVersion
== 1)) {
350 if (osvi
.wProductType
== VER_NT_WORKSTATION
)
351 WIN32_OS_string
= xstrdup("Windows 7");
353 WIN32_OS_string
= xstrdup("Windows Server 2008 R2");
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");
360 WIN32_OS_string
= xstrdup("Unknown Windows version, assuming Windows Server 2008 R2 capabilities");
364 case VER_PLATFORM_WIN32_WINDOWS
:
365 if ((osvi
.dwMajorVersion
== 4) && (osvi
.dwMinorVersion
== 0)) {
366 WIN32_OS_string
= xstrdup("Windows 95");
367 return _WIN_OS_WIN95
;
369 if ((osvi
.dwMajorVersion
== 4) && (osvi
.dwMinorVersion
== 10)) {
370 WIN32_OS_string
= xstrdup("Windows 98");
371 return _WIN_OS_WIN98
;
373 if ((osvi
.dwMajorVersion
== 4) && (osvi
.dwMinorVersion
== 90)) {
374 WIN32_OS_string
= xstrdup("Windows Me");
375 return _WIN_OS_WINME
;
378 case VER_PLATFORM_WIN32s
:
379 WIN32_OS_string
= xstrdup("Windows 3.1 with WIN32S");
380 return _WIN_OS_WIN32S
;
386 WIN32_OS_string
= xstrdup("Unknown Windows system");
387 return _WIN_OS_UNKNOWN
;
390 /* ====================================================================== */
391 /* PUBLIC FUNCTIONS */
392 /* ====================================================================== */
394 #if USE_WIN32_SERVICE
398 svcStatus
.dwWin32ExitCode
= ERROR_SERVICE_SPECIFIC_ERROR
;
399 svcStatus
.dwServiceSpecificExitCode
= 1;
406 WIN32_IpAddrChangeMonitorExit()
408 DWORD status
= ERROR_SUCCESS
;
410 if (NotifyAddrChange_thread
!= INVALID_HANDLE_VALUE
) {
411 TerminateThread(NotifyAddrChange_thread
, status
);
412 CloseHandle(NotifyAddrChange_thread
);
420 #if USE_WIN32_SERVICE
422 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
423 if (!Squid_Aborting
) {
424 svcStatus
.dwCurrentState
= SERVICE_STOPPED
;
425 SetServiceStatus(svcHandle
, &svcStatus
);
431 DeleteCriticalSection(dbg_mutex
);
433 WIN32_ExceptionHandlerCleanup();
434 WIN32_IpAddrChangeMonitorExit();
439 WIN32_IpAddrChangeMonitor(LPVOID lpParam
)
442 HMODULE IPHLPAPIHandle
;
443 PFNotifyAddrChange NotifyAddrChange
;
445 if ((IPHLPAPIHandle
= GetModuleHandle("IPHLPAPI")) == NULL
)
446 IPHLPAPIHandle
= LoadLibrary("IPHLPAPI");
447 NotifyAddrChange
= (PFNotifyAddrChange
) GetProcAddress(IPHLPAPIHandle
, NOTIFYADDRCHANGE
);
450 Result
= NotifyAddrChange(NULL
, NULL
);
451 if (Result
!= NO_ERROR
) {
452 debugs(1, DBG_IMPORTANT
, "NotifyAddrChange error " << Result
);
455 debugs(1, DBG_IMPORTANT
, "Notification of IP address change received, requesting Squid reconfiguration ...");
462 WIN32_IpAddrChangeMonitorInit()
464 DWORD status
= ERROR_SUCCESS
;
465 DWORD threadID
= 0, ThrdParam
= 0;
467 if ((WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) && (Config
.onoff
.WIN32_IpAddrChangeMonitor
)) {
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
;
473 debugs(1, DBG_IMPORTANT
, "Failed to start IP monitor thread.");
475 debugs(1, 2, "Starting IP monitor thread [" << threadID
<< "] ...");
480 int WIN32_Subsystem_Init(int * argc
, char *** argv
)
482 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
483 _invalid_parameter_handler oldHandler
, newHandler
;
486 WIN32_OS_version
= GetOSVersion();
488 if ((WIN32_OS_version
== _WIN_OS_UNKNOWN
) || (WIN32_OS_version
== _WIN_OS_WIN32S
))
491 if (atexit(WIN32_Exit
) != 0)
494 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
496 newHandler
= Squid_Win32InvalidParameterHandler
;
498 oldHandler
= _set_invalid_parameter_handler(newHandler
);
500 _CrtSetReportMode(_CRT_ASSERT
, 0);
503 #if USE_WIN32_SERVICE
505 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
509 if (signal(SIGABRT
, WIN32_Abort
) == SIG_ERR
)
512 /* Register the service Handler function */
513 svcHandle
= RegisterServiceCtrlHandler(service_name
.c_str(), WIN32_svcHandler
);
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 (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REGKEY
, 0, KEY_QUERY_VALUE
, &hndKey
) == ERROR_SUCCESS
) {
535 Result
= RegQueryValueEx(hndKey
, CONFIGFILE
, NULL
, &Type
, NULL
, &Size
);
537 if (Result
== ERROR_SUCCESS
&& Size
) {
538 ConfigFile
= static_cast<char *>(xmalloc(Size
));
539 RegQueryValueEx(hndKey
, CONFIGFILE
, NULL
, &Type
, (unsigned char *)ConfigFile
, &Size
);
541 ConfigFile
= xstrdup(DefaultConfigFile
);
547 Result
= RegQueryValueEx(hndKey
, COMMANDLINE
, NULL
, &Type
, NULL
, &Size
);
549 if (Result
== ERROR_SUCCESS
&& Size
) {
550 WIN32_Service_Command_Line
= static_cast<char *>(xmalloc(Size
));
551 RegQueryValueEx(hndKey
, COMMANDLINE
, NULL
, &Type
, (unsigned char *)WIN32_Service_Command_Line
, &Size
);
553 WIN32_Service_Command_Line
= xstrdup("");
557 ConfigFile
= xstrdup(DefaultConfigFile
);
558 WIN32_Service_Command_Line
= xstrdup("");
561 WIN32_build_argv(WIN32_Service_Command_Line
);
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
);
575 _setmaxstdio(Squid_MaxFD
);
579 #endif /* USE_WIN32_SERVICE */
580 if (Win32SockInit() < 0)
586 #if USE_WIN32_SERVICE
588 WIN32_svcstatusupdate(DWORD svcstate
, DWORD WaitHint
)
590 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
591 ++svcStatus
.dwCheckPoint
;
592 svcStatus
.dwWaitHint
= WaitHint
;
593 svcStatus
.dwCurrentState
= svcstate
;
594 SetServiceStatus(svcHandle
, &svcStatus
);
599 WIN32_svcHandler(DWORD Opcode
)
605 case _WIN_SQUID_SERVICE_CONTROL_STOP
:
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;
615 if (!SetServiceStatus(svcHandle
, &svcStatus
)) {
616 status
= GetLastError();
617 debugs(1, DBG_IMPORTANT
, "SetServiceStatus error " << status
);
620 debugs(1, DBG_IMPORTANT
, "Leaving Squid service");
623 case _WIN_SQUID_SERVICE_CONTROL_INTERROGATE
:
624 /* Fall through to send current status. */
626 if (!SetServiceStatus(svcHandle
, &svcStatus
)) {
627 status
= GetLastError();
628 debugs(1, DBG_IMPORTANT
, "SetServiceStatus error " << status
);
633 case _WIN_SQUID_SERVICE_CONTROL_ROTATE
:
634 rotate_logs(SIGUSR1
);
637 case _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE
:
641 case _WIN_SQUID_SERVICE_CONTROL_DEBUG
:
642 sigusr2_handle(SIGUSR2
);
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;
653 if (!SetServiceStatus(svcHandle
, &svcStatus
)) {
654 status
= GetLastError();
655 debugs(1, DBG_IMPORTANT
, "SetServiceStatus error " << status
);
658 debugs(1, DBG_IMPORTANT
, "Leaving Squid service");
662 debugs(1, DBG_IMPORTANT
, "Unrecognized opcode " << Opcode
);
669 WIN32_RemoveService()
671 SC_HANDLE schService
;
672 SC_HANDLE schSCManager
;
674 if (service_name
.isEmpty())
675 service_name
= SBuf(APP_SHORTNAME
);
677 const char *service
= service_name
.c_str();
678 strcat(REGKEY
, service
);
682 schSCManager
= OpenSCManager(NULL
, /* machine (NULL == local) */
683 NULL
, /* database (NULL == default) */
684 SC_MANAGER_ALL_ACCESS
/* access required */
688 fprintf(stderr
, "OpenSCManager failed\n");
690 schService
= OpenService(schSCManager
, service
, SERVICE_ALL_ACCESS
);
692 if (schService
== NULL
)
693 fprintf(stderr
, "OpenService failed\n");
695 /* Could not open the service */
697 /* try to stop the service */
699 if (ControlService(schService
, _WIN_SQUID_SERVICE_CONTROL_STOP
,
703 while (QueryServiceStatus(schService
, &svcStatus
)) {
704 if (svcStatus
.dwCurrentState
== SERVICE_STOP_PENDING
)
711 /* now remove the service */
712 if (DeleteService(schService
) == 0)
713 fprintf(stderr
, "DeleteService failed.\n");
715 printf("Service " SQUIDSBUFPH
" deleted successfully.\n", SQUIDSBUFPRINT(service_name
));
717 CloseServiceHandle(schService
);
720 CloseServiceHandle(schSCManager
);
725 WIN32_SetServiceCommandLine()
727 if (service_name
.isEmpty())
728 service_name
= SBuf(APP_SHORTNAME
);
730 const char *service
= servie_name
.c_str();
731 strcat(REGKEY
, service
);
735 /* Now store the Service Command Line in the registry */
736 WIN32_StoreKey(COMMANDLINE
, REG_SZ
, (unsigned char *) WIN32_Command_Line
, strlen(WIN32_Command_Line
) + 1);
740 WIN32_InstallService()
742 SC_HANDLE schService
;
743 SC_HANDLE schSCManager
;
744 char ServicePath
[512];
748 if (service_name
.isEmpty())
749 service_name
= SBuf(APP_SHORTNAME
);
751 const char *service
= service_name
.c_str();
752 strcat(REGKEY
, service
);
756 if ((lenpath
= GetModuleFileName(NULL
, ServicePath
, 512)) == 0) {
757 fprintf(stderr
, "Can't get executable path\n");
761 snprintf(szPath
, sizeof(szPath
), "%s %s:" SQUIDSBUFPH
, ServicePath
, _WIN_SQUID_SERVICE_OPTION
, SQUIDSBUFPRINT(service_name
));
762 schSCManager
= OpenSCManager(NULL
, /* machine (NULL == local) */
763 NULL
, /* database (NULL == default) */
764 SC_MANAGER_ALL_ACCESS
/* access required */
768 fprintf(stderr
, "OpenSCManager failed\n");
771 schService
= CreateService(schSCManager
, /* SCManager database */
772 service
, /* name of service */
773 service
, /* name to display */
774 SERVICE_ALL_ACCESS
, /* desired access */
775 SERVICE_WIN32_OWN_PROCESS
, /* service type */
776 SERVICE_AUTO_START
, /* start type */
777 SERVICE_ERROR_NORMAL
, /* error control type */
778 (const char *) szPath
, /* service's binary */
779 NULL
, /* no load ordering group */
780 NULL
, /* no tag identifier */
781 "Tcpip\0AFD\0", /* dependencies */
782 NULL
, /* LocalSystem account */
783 NULL
); /* no password */
786 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
787 HMODULE ADVAPI32Handle
;
788 PFChangeServiceConfig2 ChangeServiceConfig2
;
789 DWORD dwInfoLevel
= SERVICE_CONFIG_DESCRIPTION
;
791 ADVAPI32Handle
= GetModuleHandle("advapi32");
792 ChangeServiceConfig2
= (PFChangeServiceConfig2
) GetProcAddress(ADVAPI32Handle
, CHANGESERVICECONFIG2
);
793 ChangeServiceConfig2(schService
, dwInfoLevel
, &Squid_ServiceDescription
);
794 dwInfoLevel
= SERVICE_CONFIG_FAILURE_ACTIONS
;
795 ChangeServiceConfig2(schService
, dwInfoLevel
, &Squid_ServiceFailureActions
);
798 CloseServiceHandle(schService
);
799 /* Now store the config file location in the registry */
802 ConfigFile
= xstrdup(DefaultConfigFile
);
804 WIN32_StoreKey(CONFIGFILE
, REG_SZ
, (unsigned char *) ConfigFile
, strlen(ConfigFile
) + 1);
806 printf("Squid Cache version %s for %s\n", version_string
, CONFIG_HOST_TYPE
);
807 printf("installed successfully as " SQUIDSBUFPH
" Windows System Service.\n", SQUIDSBUFPRINT(service_name
));
808 printf("To run, start it from the Services Applet of Control Panel.\n");
809 printf("Don't forget to edit squid.conf before starting it.\n\n");
811 fprintf(stderr
, "CreateService failed\n");
815 CloseServiceHandle(schSCManager
);
820 WIN32_sendSignal(int WIN32_signal
)
822 SERVICE_STATUS ssStatus
;
823 DWORD fdwAccess
, fdwControl
;
824 SC_HANDLE schService
;
825 SC_HANDLE schSCManager
;
827 if (service_name
.isEmpty())
828 service_name
= SBuf(APP_SHORTNAME
);
830 schSCManager
= OpenSCManager(NULL
, /* machine (NULL == local) */
831 NULL
, /* database (NULL == default) */
832 SC_MANAGER_ALL_ACCESS
/* access required */
836 fprintf(stderr
, "OpenSCManager failed\n");
840 /* The required service object access depends on the control. */
841 switch (WIN32_signal
) {
843 case 0: /* SIGNULL */
844 fdwAccess
= SERVICE_INTERROGATE
;
845 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_INTERROGATE
;
849 fdwAccess
= SERVICE_USER_DEFINED_CONTROL
;
850 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_ROTATE
;
854 fdwAccess
= SERVICE_USER_DEFINED_CONTROL
;
855 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_DEBUG
;
859 fdwAccess
= SERVICE_USER_DEFINED_CONTROL
;
860 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE
;
864 fdwAccess
= SERVICE_STOP
;
865 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_STOP
;
871 fdwAccess
= SERVICE_USER_DEFINED_CONTROL
;
872 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_INTERRUPT
;
879 /* Open a handle to the service. */
880 schService
= OpenService(schSCManager
, /* SCManager database */
881 service_name
.c_str(), /* name of service */
882 fdwAccess
); /* specify access */
884 if (schService
== NULL
) {
885 fprintf(stderr
, "%s: ERROR: Could not open Service " SQUIDSBUFPH
"\n", APP_SHORTNAME
, SQUIDSBUFPRINT(service_name
));
888 /* Send a control value to the service. */
890 if (!ControlService(schService
, /* handle of service */
891 fdwControl
, /* control value to send */
892 &ssStatus
)) { /* address of status info */
893 fprintf(stderr
, "%s: ERROR: Could not Control Service " SQUIDSBUFPH
"\n",
894 APP_SHORTNAME
, SQUIDSBUFPRINT(service_name
));
897 /* Print the service status. */
898 printf("\nStatus of " SQUIDSBUFPH
" Service:\n", SQUIDSBUFPRINT(service_name
));
899 printf(" Service Type: 0x%lx\n", ssStatus
.dwServiceType
);
900 printf(" Current State: 0x%lx\n", ssStatus
.dwCurrentState
);
901 printf(" Controls Accepted: 0x%lx\n", ssStatus
.dwControlsAccepted
);
902 printf(" Exit Code: %ld\n", ssStatus
.dwWin32ExitCode
);
903 printf(" Service Specific Exit Code: %ld\n",
904 ssStatus
.dwServiceSpecificExitCode
);
905 printf(" Check Point: %ld\n", ssStatus
.dwCheckPoint
);
906 printf(" Wait Hint: %ld\n", ssStatus
.dwWaitHint
);
909 CloseServiceHandle(schService
);
912 CloseServiceHandle(schSCManager
);
915 int main(int argc
, char **argv
)
917 SERVICE_TABLE_ENTRY DispatchTable
[] = {
918 {NULL
, SquidWinSvcMain
},
922 char stderr_path
[256];
924 SetErrorMode(SEM_NOGPFAULTERRORBOX
);
925 if ((argc
== 2) && strstr(argv
[1], _WIN_SQUID_SERVICE_OPTION
)) {
926 strcpy(stderr_path
, argv
[0]);
927 strcat(stderr_path
,".log");
928 freopen(stderr_path
, "w", stderr
);
929 setmode(fileno(stderr
), O_TEXT
);
930 WIN32_run_mode
= _WIN_SQUID_RUN_MODE_SERVICE
;
932 if (!(c
=strchr(argv
[1],':'))) {
933 fprintf(stderr
, "Bad Service Parameter: %s\n", argv
[1]);
937 service_name
= SBuf(c
+1);
938 const char *service
= service_name
.c_str();
939 DispatchTable
[0].lpServiceName
=service
;
940 strcat(REGKEY
, service
);
943 if (!StartServiceCtrlDispatcher(DispatchTable
)) {
944 fprintf(stderr
, "StartServiceCtrlDispatcher error = %ld\n",
949 WIN32_run_mode
= _WIN_SQUID_RUN_MODE_INTERACTIVE
;
952 return SquidMain(argc
, argv
);
958 #endif /* USE_WIN32_SERVICE */
960 static int Win32SockInit(void)
962 int iVersionRequested
;
965 int optlen
= sizeof(opt
);
967 if (s_iInitCount
> 0) {
970 } else if (s_iInitCount
< 0)
971 return (s_iInitCount
);
973 /* s_iInitCount == 0. Do the initailization */
974 iVersionRequested
= MAKEWORD(2, 0);
976 err
= WSAStartup((WORD
) iVersionRequested
, &wsaData
);
980 return (s_iInitCount
);
983 if (LOBYTE(wsaData
.wVersion
) != 2 ||
984 HIBYTE(wsaData
.wVersion
) != 0) {
987 return (s_iInitCount
);
990 if (WIN32_OS_version
!=_WIN_OS_WINNT
) {
991 if (::getsockopt(INVALID_SOCKET
, SOL_SOCKET
, SO_OPENTYPE
, (char *)&opt
, &optlen
)) {
994 return (s_iInitCount
);
996 opt
= opt
| SO_SYNCHRONOUS_NONALERT
;
998 if (::setsockopt(INVALID_SOCKET
, SOL_SOCKET
, SO_OPENTYPE
, (char *) &opt
, optlen
)) {
1001 return (s_iInitCount
);
1006 WIN32_Socks_initialized
= 1;
1008 return (s_iInitCount
);
1011 static void Win32SockCleanup(void)
1013 if (--s_iInitCount
== 0)
1019 void Squid_Win32InvalidParameterHandler(const wchar_t* expression
, const wchar_t* function
, const wchar_t* file
, unsigned int line
, uintptr_t pReserved
)