3 * $Id: win32.cc,v 1.24 2006/09/09 15:29:59 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.
40 #include "squid_windows.h"
50 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
56 static unsigned int GetOSVersion();
57 void WIN32_svcstatusupdate(DWORD
, DWORD
);
58 void WINAPI
WIN32_svcHandler(DWORD
);
60 static int WIN32_StoreKey(const char *, DWORD
, unsigned char *, int);
61 static int WIN32_create_key(void);
62 static void WIN32_build_argv (char *);
64 extern "C" void WINAPI
SquidWinSvcMain(DWORD
, char **);
66 #if defined(_SQUID_MSWIN_)
67 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
68 void Squid_Win32InvalidParameterHandler(const wchar_t*, const wchar_t*, const wchar_t*, unsigned int, uintptr_t);
70 static int Win32SockInit(void);
71 static void Win32SockCleanup(void);
72 SQUIDCEXTERN LPCRITICAL_SECTION dbg_mutex
;
73 void WIN32_ExceptionHandlerCleanup(void);
74 static LPTOP_LEVEL_EXCEPTION_FILTER Win32_Old_ExceptionHandler
= NULL
;
75 static int s_iInitCount
= 0;
78 static int Squid_Aborting
= 0;
81 static SERVICE_STATUS svcStatus
;
82 static SERVICE_STATUS_HANDLE svcHandle
;
83 static int WIN32_argc
;
84 static char ** WIN32_argv
;
85 static char * WIN32_module_name
;
88 static char VENDORString
[] = VENDOR
;
89 #define SOFTWARENAME "Squid"
90 static char SOFTWARENAMEString
[] = SOFTWARENAME
;
91 #define WIN32_VERSION "3.0"
92 static char WIN32_VERSIONString
[] = WIN32_VERSION
;
93 #define SOFTWARE "SOFTWARE"
94 static char SOFTWAREString
[] = SOFTWARE
;
95 #define COMMANDLINE "CommandLine"
96 #define CONFIGFILE "ConfigFile"
97 #undef ChangeServiceConfig2
98 typedef BOOL (WINAPI
* PFChangeServiceConfig2
) (SC_HANDLE
, DWORD
, LPVOID
);
100 #define CHANGESERVICECONFIG2 "ChangeServiceConfig2W"
102 #define CHANGESERVICECONFIG2 "ChangeServiceConfig2A"
104 static SC_ACTION Squid_SCAction
[] = { { SC_ACTION_RESTART
, 60000 } };
105 static char Squid_ServiceDescriptionString
[] = SOFTWARENAME
" " VERSION
" WWW Proxy Server";
106 static SERVICE_DESCRIPTION Squid_ServiceDescription
= { Squid_ServiceDescriptionString
};
107 static SERVICE_FAILURE_ACTIONS Squid_ServiceFailureActions
= { INFINITE
, NULL
, NULL
, 1, Squid_SCAction
};
108 static char REGKEY
[256]=SOFTWARE
"\\"VENDOR
"\\"SOFTWARENAME
"\\"WIN32_VERSION
"\\";
109 static char *keys
[] = {
110 SOFTWAREString
, /* key[0] */
111 VENDORString
, /* key[1] */
112 SOFTWARENAMEString
, /* key[2] */
113 WIN32_VERSIONString
, /* key[3] */
119 /* ====================================================================== */
120 /* LOCAL FUNCTIONS */
121 /* ====================================================================== */
123 #if USE_WIN32_SERVICE
125 WIN32_create_key(void)
133 hKey
= HKEY_LOCAL_MACHINE
;
137 /* Walk the tree, creating at each stage if necessary */
139 while (keys
[index
]) {
140 unsigned long result
;
141 rv
= RegCreateKeyEx(hKey
, keys
[index
], /* subkey */
144 REG_OPTION_NON_VOLATILE
, KEY_WRITE
, NULL
, &hKeyNext
, &result
);
146 if (rv
!= ERROR_SUCCESS
) {
147 fprintf(stderr
, "RegCreateKeyEx(%s),%d\n", keys
[index
], (int) rv
);
151 /* Close the old key */
152 rv
= RegCloseKey(hKey
);
154 if (rv
!= ERROR_SUCCESS
) {
155 fprintf(stderr
, "RegCloseKey %d\n", (int) rv
);
158 /* Keep error status from RegCreateKeyEx, if any */
171 if (keys
[index
] == NULL
) {
172 /* Close the final key we opened, if we walked the entire
175 rv
= RegCloseKey(hKey
);
177 if (rv
!= ERROR_SUCCESS
) {
178 fprintf(stderr
, "RegCloseKey %d\n", (int) rv
);
181 /* Keep error status from RegCreateKeyEx, if any */
191 WIN32_StoreKey(const char *key
, DWORD type
, unsigned char *value
,
198 rv
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REGKEY
, 0, KEY_WRITE
, &hKey
);
200 if (rv
== ERROR_FILE_NOT_FOUND
) {
201 /* Key could not be opened -- try to create it
204 if (WIN32_create_key() < 0) {
205 /* Creation failed (error already reported) */
209 /* Now it has been created we should be able to open it
211 rv
= RegOpenKeyEx(HKEY_LOCAL_MACHINE
, REGKEY
, 0, KEY_WRITE
, &hKey
);
213 if (rv
== ERROR_FILE_NOT_FOUND
) {
214 fprintf(stderr
, "Registry does not contain key %s after creation\n",
220 if (rv
!= ERROR_SUCCESS
) {
221 fprintf(stderr
, "RegOpenKeyEx HKLM\\%s, %d\n", REGKEY
, (int) rv
);
225 /* Now set the value and data */
226 rv
= RegSetValueEx(hKey
, key
, /* value key name */
229 value
, /* value data */
230 (DWORD
) value_size
); /* for size of "value" */
232 retval
= 0; /* Return value */
234 if (rv
!= ERROR_SUCCESS
) {
235 fprintf(stderr
, "RegQueryValueEx(key %s),%d\n", key
, (int) rv
);
238 fprintf(stderr
, "Registry stored HKLM\\%s\\%s value %s\n",
241 type
== REG_SZ
? value
: (unsigned char *) "(not displayable)");
244 /* Make sure we close the key even if there was an error storing
247 rv
= RegCloseKey(hKey
);
249 if (rv
!= ERROR_SUCCESS
) {
250 fprintf(stderr
, "RegCloseKey HKLM\\%s, %d\n", REGKEY
, (int) rv
);
253 /* Keep error status from RegQueryValueEx, if any */
261 /* Build argv, argc from string passed from Windows. */
262 static void WIN32_build_argv(char *cmd
)
268 WIN32_argv
= (char **) xmalloc ((WIN32_argc
+1) * sizeof (char *));
269 WIN32_argv
[0]=xstrdup(WIN32_module_name
);
270 /* Scan command line until there is nothing left. */
275 if (xisspace(*cmd
)) {
280 /* Found the beginning of an argument. */
284 cmd
++; /* Skip over this character */
286 if (xisspace(*cmd
)) /* End of argument if space */
291 *cmd
++ = '\0'; /* Terminate `word' */
293 /* See if we need to allocate more space for argv */
294 if (WIN32_argc
>= argvlen
) {
295 argvlen
= WIN32_argc
+ 1;
296 WIN32_argv
= (char **) xrealloc (WIN32_argv
, (1 + argvlen
) * sizeof (char *));
299 /* Add word to argv file. */
300 WIN32_argv
[WIN32_argc
++] = word
;
303 WIN32_argv
[WIN32_argc
] = NULL
;
306 #endif /* USE_WIN32_SERVICE */
313 safe_free(WIN32_OS_string
);
314 memset(&osvi
, '\0', sizeof(OSVERSIONINFO
));
315 osvi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFO
);
316 GetVersionEx((OSVERSIONINFO
*) & osvi
);
318 switch (osvi
.dwPlatformId
) {
320 case VER_PLATFORM_WIN32_NT
:
322 if (osvi
.dwMajorVersion
<= 4) {
323 WIN32_OS_string
= xstrdup("Windows NT");
324 return _WIN_OS_WINNT
;
327 if ((osvi
.dwMajorVersion
== 5) && (osvi
.dwMinorVersion
== 0)) {
328 WIN32_OS_string
= xstrdup("Windows 2000");
329 return _WIN_OS_WIN2K
;
332 if ((osvi
.dwMajorVersion
== 5) && (osvi
.dwMinorVersion
== 1)) {
333 WIN32_OS_string
= xstrdup("Windows XP");
334 return _WIN_OS_WINXP
;
337 if ((osvi
.dwMajorVersion
== 5) && (osvi
.dwMinorVersion
== 2)) {
338 WIN32_OS_string
= xstrdup("Windows Server 2003");
339 return _WIN_OS_WINNET
;
342 if ((osvi
.dwMajorVersion
== 6) && (osvi
.dwMinorVersion
== 0)) {
343 WIN32_OS_string
= xstrdup("Windows code name \"Longhorn\"");
344 return _WIN_OS_WINLON
;
349 case VER_PLATFORM_WIN32_WINDOWS
:
351 if ((osvi
.dwMajorVersion
== 4) && (osvi
.dwMinorVersion
== 0)) {
352 WIN32_OS_string
= xstrdup("Windows 95");
353 return _WIN_OS_WIN95
;
356 if ((osvi
.dwMajorVersion
== 4) && (osvi
.dwMinorVersion
== 10)) {
357 WIN32_OS_string
= xstrdup("Windows 98");
358 return _WIN_OS_WIN98
;
361 if ((osvi
.dwMajorVersion
== 4) && (osvi
.dwMinorVersion
== 90)) {
362 WIN32_OS_string
= xstrdup("Windows Me");
363 return _WIN_OS_WINME
;
368 case VER_PLATFORM_WIN32s
:
369 WIN32_OS_string
= xstrdup("Windows 3.1 with WIN32S");
370 return _WIN_OS_WIN32S
;
377 WIN32_OS_string
= xstrdup("Unknown Windows system");
378 return _WIN_OS_UNKNOWN
;
381 /* ====================================================================== */
382 /* PUBLIC FUNCTIONS */
383 /* ====================================================================== */
388 #if USE_WIN32_SERVICE
389 svcStatus
.dwWin32ExitCode
= ERROR_SERVICE_SPECIFIC_ERROR
;
390 svcStatus
.dwServiceSpecificExitCode
= 1;
403 #if USE_WIN32_SERVICE
405 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
406 if (!Squid_Aborting
) {
407 svcStatus
.dwCurrentState
= SERVICE_STOPPED
;
408 SetServiceStatus(svcHandle
, &svcStatus
);
415 DeleteCriticalSection(dbg_mutex
);
417 WIN32_ExceptionHandlerCleanup();
424 int WIN32_Subsystem_Init(int * argc
, char *** argv
)
426 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
427 _invalid_parameter_handler oldHandler
, newHandler
;
430 WIN32_OS_version
= GetOSVersion();
432 if ((WIN32_OS_version
== _WIN_OS_UNKNOWN
) || (WIN32_OS_version
== _WIN_OS_WIN32S
))
435 if (atexit(WIN32_Exit
) != 0)
438 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
440 newHandler
= Squid_Win32InvalidParameterHandler
;
442 oldHandler
= _set_invalid_parameter_handler(newHandler
);
444 _CrtSetReportMode(_CRT_ASSERT
, 0);
447 #if USE_WIN32_SERVICE
449 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
453 if (signal(SIGABRT
, WIN32_Abort
) == SIG_ERR
)
456 /* Register the service Handler function */
458 RegisterServiceCtrlHandler(WIN32_Service_name
,
464 /* Set Process work dir to directory cointaining squid.exe */
465 GetModuleFileName(NULL
, path
, 512);
467 WIN32_module_name
=xstrdup(path
);
469 path
[strlen(path
) - 10] = '\0';
471 if (SetCurrentDirectory(path
) == 0)
474 safe_free(ConfigFile
);
476 /* get config file from Windows Registry */
477 if (RegOpenKey(HKEY_LOCAL_MACHINE
, REGKEY
, &hndKey
) == ERROR_SUCCESS
) {
482 RegQueryValueEx(hndKey
, CONFIGFILE
, NULL
, &Type
, NULL
, &Size
);
484 if (Result
== ERROR_SUCCESS
&& Size
) {
485 ConfigFile
= static_cast<char *>(xmalloc(Size
));
486 RegQueryValueEx(hndKey
, CONFIGFILE
, NULL
, &Type
, (unsigned char *)ConfigFile
,
489 ConfigFile
= xstrdup(DefaultConfigFile
);
496 RegQueryValueEx(hndKey
, COMMANDLINE
, NULL
, &Type
, NULL
, &Size
);
498 if (Result
== ERROR_SUCCESS
&& Size
) {
499 WIN32_Service_Command_Line
= static_cast<char *>(xmalloc(Size
));
500 RegQueryValueEx(hndKey
, COMMANDLINE
, NULL
, &Type
, (unsigned char *)WIN32_Service_Command_Line
,
503 WIN32_Service_Command_Line
= xstrdup("");
507 ConfigFile
= xstrdup(DefaultConfigFile
);
508 WIN32_Service_Command_Line
= xstrdup("");
511 WIN32_build_argv(WIN32_Service_Command_Line
);
514 /* Set Service Status to SERVICE_START_PENDING */
515 svcStatus
.dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
516 svcStatus
.dwCurrentState
= SERVICE_START_PENDING
;
517 svcStatus
.dwControlsAccepted
=
518 SERVICE_ACCEPT_STOP
| SERVICE_ACCEPT_SHUTDOWN
;
519 svcStatus
.dwWin32ExitCode
= 0;
520 svcStatus
.dwServiceSpecificExitCode
= 0;
521 svcStatus
.dwCheckPoint
= 0;
522 svcStatus
.dwWaitHint
= 10000;
523 SetServiceStatus(svcHandle
, &svcStatus
);
526 _setmaxstdio(Squid_MaxFD
);
530 #endif /* USE_WIN32_SERVICE */
532 if (Win32SockInit() < 0)
540 #if USE_WIN32_SERVICE
542 WIN32_svcstatusupdate(DWORD svcstate
, DWORD WaitHint
)
544 if (WIN32_run_mode
== _WIN_SQUID_RUN_MODE_SERVICE
) {
545 svcStatus
.dwCheckPoint
++;
546 svcStatus
.dwWaitHint
= WaitHint
;
547 svcStatus
.dwCurrentState
= svcstate
;
548 SetServiceStatus(svcHandle
, &svcStatus
);
553 WIN32_svcHandler(DWORD Opcode
)
559 case _WIN_SQUID_SERVICE_CONTROL_STOP
:
561 case _WIN_SQUID_SERVICE_CONTROL_SHUTDOWN
:
562 /* Do whatever it takes to stop here. */
563 svcStatus
.dwWin32ExitCode
= 0;
564 svcStatus
.dwCurrentState
= SERVICE_STOP_PENDING
;
565 svcStatus
.dwCheckPoint
= 0;
566 svcStatus
.dwWaitHint
= 10000;
569 if (!SetServiceStatus(svcHandle
, &svcStatus
)) {
570 status
= GetLastError();
571 debug(1, 1) ("SetServiceStatus error %ld\n", status
);
574 debug(1, 1) ("Leaving Squid service\n");
577 case _WIN_SQUID_SERVICE_CONTROL_INTERROGATE
:
578 /* Fall through to send current status. */
580 if (!SetServiceStatus(svcHandle
, &svcStatus
)) {
581 status
= GetLastError();
582 debug(1, 1) ("SetServiceStatus error %ld\n", status
);
587 case _WIN_SQUID_SERVICE_CONTROL_ROTATE
:
588 rotate_logs(SIGUSR1
);
591 case _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE
:
595 case _WIN_SQUID_SERVICE_CONTROL_DEBUG
:
596 sigusr2_handle(SIGUSR2
);
599 case _WIN_SQUID_SERVICE_CONTROL_INTERRUPT
:
600 /* Do whatever it takes to stop here. */
601 svcStatus
.dwWin32ExitCode
= 0;
602 svcStatus
.dwCurrentState
= SERVICE_STOP_PENDING
;
603 svcStatus
.dwCheckPoint
= 0;
604 svcStatus
.dwWaitHint
= 10000;
607 if (!SetServiceStatus(svcHandle
, &svcStatus
)) {
608 status
= GetLastError();
609 debug(1, 1) ("SetServiceStatus error %ld\n", status
);
612 debug(1, 1) ("Leaving Squid service\n");
616 debug(1, 1) ("Unrecognized opcode %ld\n", Opcode
);
623 WIN32_RemoveService()
625 SC_HANDLE schService
;
626 SC_HANDLE schSCManager
;
628 if (!WIN32_Service_name
)
629 WIN32_Service_name
= xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME
);
631 strcat(REGKEY
, WIN32_Service_name
);
633 keys
[4] = WIN32_Service_name
;
635 schSCManager
= OpenSCManager(NULL
, /* machine (NULL == local) */
636 NULL
, /* database (NULL == default) */
637 SC_MANAGER_ALL_ACCESS
/* access required */
641 fprintf(stderr
, "OpenSCManager failed\n");
643 schService
= OpenService(schSCManager
, WIN32_Service_name
, SERVICE_ALL_ACCESS
);
645 if (schService
== NULL
)
646 fprintf(stderr
, "OpenService failed\n");
648 /* Could not open the service */
650 /* try to stop the service */
652 if (ControlService(schService
, _WIN_SQUID_SERVICE_CONTROL_STOP
,
656 while (QueryServiceStatus(schService
, &svcStatus
)) {
657 if (svcStatus
.dwCurrentState
== SERVICE_STOP_PENDING
)
664 /* now remove the service */
665 if (DeleteService(schService
) == 0)
666 fprintf(stderr
, "DeleteService failed.\n");
668 printf("Service %s deleted successfully.\n",
671 CloseServiceHandle(schService
);
674 CloseServiceHandle(schSCManager
);
679 WIN32_SetServiceCommandLine()
681 if (!WIN32_Service_name
)
682 WIN32_Service_name
= xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME
);
684 strcat(REGKEY
, WIN32_Service_name
);
686 keys
[4] = WIN32_Service_name
;
688 /* Now store the Service Command Line in the registry */
689 WIN32_StoreKey(COMMANDLINE
, REG_SZ
, (unsigned char *) WIN32_Command_Line
, strlen(WIN32_Command_Line
) + 1);
693 WIN32_InstallService()
695 SC_HANDLE schService
;
696 SC_HANDLE schSCManager
;
697 char ServicePath
[512];
701 if (!WIN32_Service_name
)
702 WIN32_Service_name
= xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME
);
704 strcat(REGKEY
, WIN32_Service_name
);
706 keys
[4] = WIN32_Service_name
;
708 if ((lenpath
= GetModuleFileName(NULL
, ServicePath
, 512)) == 0) {
709 fprintf(stderr
, "Can't get executable path\n");
713 snprintf(szPath
, sizeof(szPath
), "%s %s:%s", ServicePath
, _WIN_SQUID_SERVICE_OPTION
, WIN32_Service_name
);
714 schSCManager
= OpenSCManager(NULL
, /* machine (NULL == local) */
715 NULL
, /* database (NULL == default) */
716 SC_MANAGER_ALL_ACCESS
/* access required */
720 fprintf(stderr
, "OpenSCManager failed\n");
723 schService
= CreateService(schSCManager
, /* SCManager database */
724 WIN32_Service_name
, /* name of service */
725 WIN32_Service_name
, /* name to display */
726 SERVICE_ALL_ACCESS
, /* desired access */
727 SERVICE_WIN32_OWN_PROCESS
, /* service type */
728 SERVICE_AUTO_START
, /* start type */
729 SERVICE_ERROR_NORMAL
, /* error control type */
730 (const char *) szPath
, /* service's binary */
731 NULL
, /* no load ordering group */
732 NULL
, /* no tag identifier */
733 "Tcpip\0AFD\0", /* dependencies */
734 NULL
, /* LocalSystem account */
735 NULL
); /* no password */
738 if (WIN32_OS_version
> _WIN_OS_WINNT
) {
739 HMODULE ADVAPI32Handle
;
740 PFChangeServiceConfig2 ChangeServiceConfig2
;
741 DWORD dwInfoLevel
= SERVICE_CONFIG_DESCRIPTION
;
743 ADVAPI32Handle
= GetModuleHandle("advapi32");
744 ChangeServiceConfig2
= (PFChangeServiceConfig2
) GetProcAddress(ADVAPI32Handle
, CHANGESERVICECONFIG2
);
745 ChangeServiceConfig2(schService
, dwInfoLevel
, &Squid_ServiceDescription
);
746 dwInfoLevel
= SERVICE_CONFIG_FAILURE_ACTIONS
;
747 ChangeServiceConfig2(schService
, dwInfoLevel
, &Squid_ServiceFailureActions
);
750 CloseServiceHandle(schService
);
751 /* Now store the config file location in the registry */
754 ConfigFile
= xstrdup(DefaultConfigFile
);
756 WIN32_StoreKey(CONFIGFILE
, REG_SZ
, (unsigned char *) ConfigFile
, strlen(ConfigFile
) + 1);
758 printf("Squid Cache version %s for %s\n", version_string
,
761 printf("installed successfully as %s Windows System Service.\n",
765 ("To run, start it from the Services Applet of Control Panel.\n");
767 printf("Don't forget to edit squid.conf before starting it.\n\n");
769 fprintf(stderr
, "CreateService failed\n");
773 CloseServiceHandle(schSCManager
);
778 WIN32_sendSignal(int WIN32_signal
)
780 SERVICE_STATUS ssStatus
;
781 DWORD fdwAccess
, fdwControl
;
782 SC_HANDLE schService
;
783 SC_HANDLE schSCManager
;
785 if (!WIN32_Service_name
)
786 WIN32_Service_name
= xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME
);
788 schSCManager
= OpenSCManager(NULL
, /* machine (NULL == local) */
789 NULL
, /* database (NULL == default) */
790 SC_MANAGER_ALL_ACCESS
/* access required */
794 fprintf(stderr
, "OpenSCManager failed\n");
798 /* The required service object access depends on the control. */
799 switch (WIN32_signal
) {
801 case 0: /* SIGNULL */
802 fdwAccess
= SERVICE_INTERROGATE
;
803 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_INTERROGATE
;
807 fdwAccess
= SERVICE_USER_DEFINED_CONTROL
;
808 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_ROTATE
;
812 fdwAccess
= SERVICE_USER_DEFINED_CONTROL
;
813 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_DEBUG
;
817 fdwAccess
= SERVICE_USER_DEFINED_CONTROL
;
818 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE
;
822 fdwAccess
= SERVICE_STOP
;
823 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_STOP
;
829 fdwAccess
= SERVICE_USER_DEFINED_CONTROL
;
830 fdwControl
= _WIN_SQUID_SERVICE_CONTROL_INTERRUPT
;
837 /* Open a handle to the service. */
838 schService
= OpenService(schSCManager
, /* SCManager database */
839 WIN32_Service_name
, /* name of service */
840 fdwAccess
); /* specify access */
842 if (schService
== NULL
) {
843 fprintf(stderr
, "%s: ERROR: Could not open Service %s\n", appname
,
847 /* Send a control value to the service. */
849 if (!ControlService(schService
, /* handle of service */
850 fdwControl
, /* control value to send */
851 &ssStatus
)) { /* address of status info */
852 fprintf(stderr
, "%s: ERROR: Could not Control Service %s\n",
853 appname
, WIN32_Service_name
);
856 /* Print the service status. */
857 printf("\nStatus of %s Service:\n", WIN32_Service_name
);
858 printf(" Service Type: 0x%lx\n", ssStatus
.dwServiceType
);
859 printf(" Current State: 0x%lx\n", ssStatus
.dwCurrentState
);
860 printf(" Controls Accepted: 0x%lx\n", ssStatus
.dwControlsAccepted
);
861 printf(" Exit Code: %ld\n", ssStatus
.dwWin32ExitCode
);
862 printf(" Service Specific Exit Code: %ld\n",
863 ssStatus
.dwServiceSpecificExitCode
);
864 printf(" Check Point: %ld\n", ssStatus
.dwCheckPoint
);
865 printf(" Wait Hint: %ld\n", ssStatus
.dwWaitHint
);
868 CloseServiceHandle(schService
);
871 CloseServiceHandle(schSCManager
);
874 int main(int argc
, char **argv
)
876 SERVICE_TABLE_ENTRY DispatchTable
[] = {
877 {NULL
, SquidWinSvcMain
},
881 char stderr_path
[256];
883 if ((argc
== 2) && strstr(argv
[1], _WIN_SQUID_SERVICE_OPTION
)) {
884 strcpy(stderr_path
, argv
[0]);
885 strcat(stderr_path
,".log");
886 freopen(stderr_path
, "w", stderr
);
887 setmode(fileno(stderr
), O_TEXT
);
888 WIN32_run_mode
= _WIN_SQUID_RUN_MODE_SERVICE
;
891 if (!(c
=strchr(argv
[1],':'))) {
892 fprintf(stderr
, "Bad Service Parameter: %s\n", argv
[1]);
896 WIN32_Service_name
= xstrdup(c
+1);
897 DispatchTable
[0].lpServiceName
=WIN32_Service_name
;
898 strcat(REGKEY
, WIN32_Service_name
);
899 keys
[4] = WIN32_Service_name
;
901 if (!StartServiceCtrlDispatcher(DispatchTable
)) {
902 fprintf(stderr
, "StartServiceCtrlDispatcher error = %ld\n",
907 WIN32_run_mode
= _WIN_SQUID_RUN_MODE_INTERACTIVE
;
914 return SquidMain(argc
, argv
);
920 #endif /* USE_WIN32_SERVICE */
922 #if defined(_SQUID_MSWIN_)
923 int WIN32_pipe(int handles
[2])
928 struct sockaddr_in serv_addr
;
929 int len
= sizeof(serv_addr
);
930 u_short handle1_port
;
932 handles
[0] = handles
[1] = -1;
934 statCounter
.syscalls
.sock
.sockets
++;
936 if ((new_socket
= socket(AF_INET
, SOCK_STREAM
, IPPROTO_TCP
)) < 0)
939 memset((void *) &serv_addr
, 0, sizeof(serv_addr
));
941 serv_addr
.sin_family
= AF_INET
;
943 serv_addr
.sin_port
= htons(0);
945 serv_addr
.sin_addr
= local_addr
;
947 if (bind(new_socket
, (SOCKADDR
*) & serv_addr
, len
) < 0 ||
948 listen(new_socket
, 1) < 0 || getsockname(new_socket
, (SOCKADDR
*) & serv_addr
, &len
) < 0 ||
949 (handles
[1] = socket(PF_INET
, SOCK_STREAM
, 0)) < 0) {
950 closesocket(new_socket
);
954 handle1_port
= ntohs(serv_addr
.sin_port
);
956 if (connect(handles
[1], (SOCKADDR
*) & serv_addr
, len
) < 0 ||
957 (handles
[0] = accept(new_socket
, (SOCKADDR
*) & serv_addr
, &len
)) < 0) {
958 closesocket(handles
[1]);
960 closesocket(new_socket
);
964 closesocket(new_socket
);
966 F
= &fd_table
[handles
[0]];
967 F
->local_addr
= local_addr
;
968 F
->local_port
= ntohs(serv_addr
.sin_port
);
970 F
= &fd_table
[handles
[1]];
971 F
->local_addr
= local_addr
;
972 xstrncpy(F
->ipaddr
, inet_ntoa(local_addr
), 16);
973 F
->remote_port
= handle1_port
;
978 int WIN32_getrusage(int who
, struct rusage
*usage
)
982 if ((WIN32_OS_version
== _WIN_OS_WINNT
) || (WIN32_OS_version
== _WIN_OS_WIN2K
)
983 || (WIN32_OS_version
== _WIN_OS_WINXP
) || (WIN32_OS_version
== _WIN_OS_WINNET
))
985 /* On Windows NT/2000 call PSAPI.DLL for process Memory */
986 /* informations -- Guido Serassio */
988 PROCESS_MEMORY_COUNTERS pmc
;
989 hProcess
= OpenProcess(PROCESS_QUERY_INFORMATION
|
991 FALSE
, GetCurrentProcessId());
993 /* Microsoft CRT doesn't have getrusage function, */
994 /* so we get process CPU time information from PSAPI.DLL. */
995 FILETIME ftCreate
, ftExit
, ftKernel
, ftUser
;
997 if (GetProcessTimes(hProcess
, &ftCreate
, &ftExit
, &ftKernel
, &ftUser
)) {
998 int64_t tUser64
= (*(int64_t *)&ftUser
/ 10);
999 int64_t tKernel64
= (*(int64_t *)&ftKernel
/ 10);
1000 usage
->ru_utime
.tv_sec
=(long)(tUser64
/ 1000000);
1001 usage
->ru_stime
.tv_sec
=(long)(tKernel64
/ 1000000);
1002 usage
->ru_utime
.tv_usec
=(long)(tUser64
% 1000000);
1003 usage
->ru_stime
.tv_usec
=(long)(tKernel64
% 1000000);
1005 CloseHandle( hProcess
);
1010 if (GetProcessMemoryInfo( hProcess
, &pmc
, sizeof(pmc
))) {
1011 usage
->ru_maxrss
=(DWORD
)(pmc
.WorkingSetSize
/ getpagesize());
1012 usage
->ru_majflt
=pmc
.PageFaultCount
;
1014 CloseHandle( hProcess
);
1018 CloseHandle( hProcess
);
1025 static int Win32SockInit(void)
1027 int iVersionRequested
;
1030 int optlen
= sizeof(opt
);
1032 if (s_iInitCount
> 0) {
1035 } else if (s_iInitCount
< 0)
1036 return (s_iInitCount
);
1038 /* s_iInitCount == 0. Do the initailization */
1039 iVersionRequested
= MAKEWORD(2, 0);
1041 err
= WSAStartup((WORD
) iVersionRequested
, &wsaData
);
1045 return (s_iInitCount
);
1048 if (LOBYTE(wsaData
.wVersion
) != 2 ||
1049 HIBYTE(wsaData
.wVersion
) != 0) {
1052 return (s_iInitCount
);
1055 if (WIN32_OS_version
!=_WIN_OS_WINNT
) {
1056 if (::getsockopt(INVALID_SOCKET
, SOL_SOCKET
, SO_OPENTYPE
, (char *)&opt
, &optlen
)) {
1059 return (s_iInitCount
);
1061 opt
= opt
| SO_SYNCHRONOUS_NONALERT
;
1063 if (::setsockopt(INVALID_SOCKET
, SOL_SOCKET
, SO_OPENTYPE
, (char *) &opt
, optlen
)) {
1066 return (s_iInitCount
);
1071 WIN32_Socks_initialized
= 1;
1073 return (s_iInitCount
);
1076 static void Win32SockCleanup(void)
1078 if (--s_iInitCount
== 0)
1084 int Win32__WSAFDIsSet(int fd
, fd_set FAR
* set
1087 fde
*F
= &fd_table
[fd
];
1088 SOCKET s
= F
->win32
.handle
;
1090 return __WSAFDIsSet(s
, set
1094 void Squid_Win32InvalidParameterHandler(const wchar_t* expression
, const wchar_t* function
, const wchar_t* file
, unsigned int line
, uintptr_t pReserved
)
1099 LONG CALLBACK
WIN32_ExceptionHandler(EXCEPTION_POINTERS
* ep
)
1101 EXCEPTION_RECORD
* er
;
1103 er
= ep
->ExceptionRecord
;
1105 switch (er
->ExceptionCode
) {
1107 case EXCEPTION_ACCESS_VIOLATION
:
1111 case EXCEPTION_DATATYPE_MISALIGNMENT
:
1113 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED
:
1115 case EXCEPTION_IN_PAGE_ERROR
:
1123 return EXCEPTION_CONTINUE_SEARCH
;
1127 void WIN32_ExceptionHandlerInit()
1129 #if !defined(_DEBUG)
1131 if (Win32_Old_ExceptionHandler
== NULL
)
1132 Win32_Old_ExceptionHandler
= SetUnhandledExceptionFilter(WIN32_ExceptionHandler
);
1137 void WIN32_ExceptionHandlerCleanup()
1139 if (Win32_Old_ExceptionHandler
!= NULL
)
1140 SetUnhandledExceptionFilter(Win32_Old_ExceptionHandler
);
1143 #endif /* SQUID_MSWIN_ */