/* * $Id: win32.c,v 1.17.2.4 2009/09/16 21:09:05 hno Exp $ * * Windows support * AUTHOR: Guido Serassio * inspired by previous work by Romeo Anghelache & Eric Stern. * * SQUID Web Proxy Cache http://www.squid-cache.org/ * ---------------------------------------------------------- * * Squid is the result of efforts by numerous individuals from * the Internet community; see the CONTRIBUTORS file for full * details. Many organizations have provided support for Squid's * development; see the SPONSORS file for full details. Squid is * Copyrighted (C) 2001 by the Regents of the University of * California; see the COPYRIGHT file for full details. Squid * incorporates software developed and/or copyrighted by other * sources; see the CREDITS file for full details. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. * */ #define WIN32_C #include "squid.h" /* This code compiles only Cygwin & native Windows Port */ #ifdef _SQUID_WIN32_ #include #ifdef _SQUID_MSWIN_ #if HAVE_WIN32_PSAPI #include #endif #ifndef _MSWSOCK_ #include #endif #include #endif static unsigned int GetOSVersion(); void WIN32_svcstatusupdate(DWORD, DWORD); void WINAPI WIN32_svcHandler(DWORD); #if USE_WIN32_SERVICE static int WIN32_StoreKey(const char *, DWORD, unsigned char *, int); static int WIN32_create_key(void); static void WIN32_build_argv(char *); #endif /* USE_WIN32_SERVICE */ void WINAPI SquidWinSvcMain(DWORD, char **); #if defined(_SQUID_MSWIN_) static int Win32SockInit(void); static void Win32SockCleanup(void); extern LPCRITICAL_SECTION dbg_mutex; void WIN32_ExceptionHandlerCleanup(void); static LPTOP_LEVEL_EXCEPTION_FILTER Win32_Old_ExceptionHandler = NULL; #endif /* _SQUID_MSWIN_ */ #if USE_WIN32_SERVICE static SERVICE_STATUS svcStatus; static SERVICE_STATUS_HANDLE svcHandle; static int WIN32_argc; static char **WIN32_argv; static char *WIN32_module_name; #endif /* USE_WIN32_SERVICE */ static int Squid_Aborting = 0; #define VENDOR "GNU" #define SOFTWARENAME "Squid" #define WIN32_VERSION "2.6" #define COMMANDLINE "CommandLine" #define CONFIGFILE "ConfigFile" #undef ChangeServiceConfig2 typedef BOOL(WINAPI * PFChangeServiceConfig2) (SC_HANDLE, DWORD, LPVOID); #ifdef UNICODE #define CHANGESERVICECONFIG2 "ChangeServiceConfig2W" #else #define CHANGESERVICECONFIG2 "ChangeServiceConfig2A" #endif #if USE_WIN32_SERVICE static SC_ACTION Squid_SCAction[] = { {SC_ACTION_RESTART, 60000}}; static SERVICE_DESCRIPTION Squid_ServiceDescription = {SOFTWARENAME " " VERSION " " PACKAGE_NAME}; static SERVICE_FAILURE_ACTIONS Squid_ServiceFailureActions = {INFINITE, NULL, NULL, 1, Squid_SCAction}; static char REGKEY[256] = "SOFTWARE\\" VENDOR "\\" SOFTWARENAME "\\" WIN32_VERSION "\\"; static char *keys[] = { "SOFTWARE", /* key[0] */ VENDOR, /* key[1] */ SOFTWARENAME, /* key[2] */ WIN32_VERSION, /* key[3] */ NULL, /* key[4] */ NULL /* key[5] */ }; #endif /* USE_WIN32_SERVICE */ /* ====================================================================== */ /* LOCAL FUNCTIONS */ /* ====================================================================== */ #if USE_WIN32_SERVICE static int WIN32_create_key(void) { int index; HKEY hKey; HKEY hKeyNext; int retval; LONG rv; hKey = HKEY_LOCAL_MACHINE; index = 0; retval = 0; /* Walk the tree, creating at each stage if necessary */ while (keys[index]) { unsigned long result; rv = RegCreateKeyEx(hKey, keys[index], /* subkey */ 0, /* reserved */ NULL, /* class */ REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKeyNext, &result); if (rv != ERROR_SUCCESS) { fprintf(stderr, "RegCreateKeyEx(%s),%d\n", keys[index], (int) rv); retval = -4; } /* Close the old key */ rv = RegCloseKey(hKey); if (rv != ERROR_SUCCESS) { fprintf(stderr, "RegCloseKey %d\n", (int) rv); if (retval == 0) { /* Keep error status from RegCreateKeyEx, if any */ retval = -4; } } if (retval) { break; } hKey = hKeyNext; index++; } if (keys[index] == NULL) { /* Close the final key we opened, if we walked the entire * tree */ rv = RegCloseKey(hKey); if (rv != ERROR_SUCCESS) { fprintf(stderr, "RegCloseKey %d\n", (int) rv); if (retval == 0) { /* Keep error status from RegCreateKeyEx, if any */ retval = -4; } } } return retval; } static int WIN32_StoreKey(const char *key, DWORD type, unsigned char *value, int value_size) { LONG rv; HKEY hKey; int retval; rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_WRITE, &hKey); if (rv == ERROR_FILE_NOT_FOUND) { /* Key could not be opened -- try to create it */ if (WIN32_create_key() < 0) { /* Creation failed (error already reported) */ return -4; } /* Now it has been created we should be able to open it */ rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_WRITE, &hKey); if (rv == ERROR_FILE_NOT_FOUND) { fprintf(stderr, "Registry does not contain key %s after creation\n", REGKEY); return -1; } } if (rv != ERROR_SUCCESS) { fprintf(stderr, "RegOpenKeyEx HKLM\\%s, %d\n", REGKEY, (int) rv); return -4; } /* Now set the value and data */ rv = RegSetValueEx(hKey, key, /* value key name */ 0, /* reserved */ type, /* type */ value, /* value data */ (DWORD) value_size); /* for size of "value" */ retval = 0; /* Return value */ if (rv != ERROR_SUCCESS) { fprintf(stderr, "RegQueryValueEx(key %s),%d\n", key, (int) rv); retval = -4; } else { fprintf(stderr, "Registry stored HKLM\\%s\\%s value %s\n", REGKEY, key, type == REG_SZ ? value : (unsigned char *) "(not displayable)"); } /* Make sure we close the key even if there was an error storing * the data */ rv = RegCloseKey(hKey); if (rv != ERROR_SUCCESS) { fprintf(stderr, "RegCloseKey HKLM\\%s, %d\n", REGKEY, (int) rv); if (retval == 0) { /* Keep error status from RegQueryValueEx, if any */ retval = -4; } } return retval; } #endif /* USE_WIN32_SERVICE */ static unsigned int GetOSVersion() { OSVERSIONINFOEX osvi; BOOL bOsVersionInfoEx; safe_free(WIN32_OS_string); memset(&osvi, '\0', sizeof(OSVERSIONINFOEX)); /* Try calling GetVersionEx using the OSVERSIONINFOEX structure. * If that fails, try using the OSVERSIONINFO structure. */ osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if (!(bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) & osvi))) { osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); if (!GetVersionEx((OSVERSIONINFO *) & osvi)) goto GetVerError; } switch (osvi.dwPlatformId) { case VER_PLATFORM_WIN32_NT: if (osvi.dwMajorVersion <= 4) { WIN32_OS_string = xstrdup("Windows NT"); return _WIN_OS_WINNT; } if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 0)) { WIN32_OS_string = xstrdup("Windows 2000"); return _WIN_OS_WIN2K; } if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 1)) { WIN32_OS_string = xstrdup("Windows XP"); return _WIN_OS_WINXP; } if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 2)) { WIN32_OS_string = xstrdup("Windows Server 2003"); return _WIN_OS_WINNET; } if ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 0)) { if (osvi.wProductType == VER_NT_WORKSTATION) WIN32_OS_string = xstrdup("Windows Vista"); else WIN32_OS_string = xstrdup("Windows Server 2008"); return _WIN_OS_WINLON; } if ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 1)) { if (osvi.wProductType == VER_NT_WORKSTATION) WIN32_OS_string = xstrdup("Windows 7"); else WIN32_OS_string = xstrdup("Windows Server 2008 R2"); return _WIN_OS_WIN7; } if (((osvi.dwMajorVersion > 6)) || ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion > 1))) { if (osvi.wProductType == VER_NT_WORKSTATION) WIN32_OS_string = xstrdup("Unknown Windows version, assuming Windows 7 capabilities"); else WIN32_OS_string = xstrdup("Unknown Windows version, assuming Windows Server 2008 R2 capabilities"); return _WIN_OS_WIN7; } break; case VER_PLATFORM_WIN32_WINDOWS: if ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 0)) { WIN32_OS_string = xstrdup("Windows 95"); return _WIN_OS_WIN95; } if ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 10)) { WIN32_OS_string = xstrdup("Windows 98"); return _WIN_OS_WIN98; } if ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 90)) { WIN32_OS_string = xstrdup("Windows Me"); return _WIN_OS_WINME; } break; case VER_PLATFORM_WIN32s: WIN32_OS_string = xstrdup("Windows 3.1 with WIN32S"); return _WIN_OS_WIN32S; break; default: break; } GetVerError: WIN32_OS_string = xstrdup("Unknown Windows system"); return _WIN_OS_UNKNOWN; } #if USE_WIN32_SERVICE /* Build argv, argc from string passed from Windows. */ static void WIN32_build_argv(char *cmd) { int argvlen = 0; char *word; WIN32_argc = 1; WIN32_argv = (char **) xmalloc((WIN32_argc + 1) * sizeof(char *)); WIN32_argv[0] = xstrdup(WIN32_module_name); /* Scan command line until there is nothing left. */ while (*cmd) { /* Ignore spaces */ if (xisspace(*cmd)) { cmd++; continue; } /* Found the beginning of an argument. */ word = cmd; while (*cmd) { cmd++; /* Skip over this character */ if (xisspace(*cmd)) /* End of argument if space */ break; } if (*cmd) *cmd++ = '\0'; /* Terminate `word' */ /* See if we need to allocate more space for argv */ if (WIN32_argc >= argvlen) { argvlen = WIN32_argc + 1; WIN32_argv = (char **) xrealloc(WIN32_argv, (1 + argvlen) * sizeof(char *)); } /* Add word to argv file. */ WIN32_argv[WIN32_argc++] = word; } WIN32_argv[WIN32_argc] = NULL; } #endif /* ====================================================================== */ /* PUBLIC FUNCTIONS */ /* ====================================================================== */ void WIN32_Abort(int sig) { #if USE_WIN32_SERVICE svcStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; svcStatus.dwServiceSpecificExitCode = 1; #endif Squid_Aborting = 1; WIN32_Exit(); } void WIN32_Exit() { #ifdef _SQUID_MSWIN_ Win32SockCleanup(); #endif #if USE_WIN32_SERVICE if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) { if (!Squid_Aborting) { svcStatus.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(svcHandle, &svcStatus); } } #endif #ifdef _SQUID_MSWIN_ if (dbg_mutex) DeleteCriticalSection(dbg_mutex); WIN32_ExceptionHandlerCleanup(); #endif _exit(0); } int WIN32_Subsystem_Init(int *argc, char ***argv) { WIN32_OS_version = GetOSVersion(); if ((WIN32_OS_version == _WIN_OS_UNKNOWN) || (WIN32_OS_version == _WIN_OS_WIN32S)) return 1; if (atexit(WIN32_Exit) != 0) return 1; #if USE_WIN32_SERVICE if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) { char path[512]; HKEY hndKey; if (signal(SIGABRT, WIN32_Abort) == SIG_ERR) return 1; /* Register the service Handler function */ svcHandle = RegisterServiceCtrlHandler(WIN32_Service_name, WIN32_svcHandler); if (svcHandle == 0) return 1; /* Set Process work dir to directory cointaining squid.exe */ GetModuleFileName(NULL, path, 512); WIN32_module_name = xstrdup(path); path[strlen(path) - 10] = '\0'; if (SetCurrentDirectory(path) == 0) return 1; safe_free(ConfigFile); /* get config file from Windows Registry */ if (RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY, &hndKey) == ERROR_SUCCESS) { DWORD Type = 0; DWORD Size = 0; LONG Result; Result = RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, NULL, &Size); if (Result == ERROR_SUCCESS && Size) { ConfigFile = xmalloc(Size); RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, ConfigFile, &Size); } else ConfigFile = xstrdup(DefaultConfigFile); Size = 0; Type = 0; Result = RegQueryValueEx(hndKey, COMMANDLINE, NULL, &Type, NULL, &Size); if (Result == ERROR_SUCCESS && Size) { WIN32_Service_Command_Line = xmalloc(Size); RegQueryValueEx(hndKey, COMMANDLINE, NULL, &Type, WIN32_Service_Command_Line, &Size); } else WIN32_Service_Command_Line = xstrdup(""); RegCloseKey(hndKey); } else { ConfigFile = xstrdup(DefaultConfigFile); WIN32_Service_Command_Line = xstrdup(""); } WIN32_build_argv(WIN32_Service_Command_Line); *argc = WIN32_argc; *argv = WIN32_argv; /* Set Service Status to SERVICE_START_PENDING */ svcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; svcStatus.dwCurrentState = SERVICE_START_PENDING; svcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; svcStatus.dwWin32ExitCode = 0; svcStatus.dwServiceSpecificExitCode = 0; svcStatus.dwCheckPoint = 0; svcStatus.dwWaitHint = 10000; SetServiceStatus(svcHandle, &svcStatus); #ifdef _SQUID_MSWIN_ _setmaxstdio(Squid_MaxFD); #endif } #endif #ifdef _SQUID_MSWIN_ if (Win32SockInit() < 0) return 1; #endif return 0; } #if USE_WIN32_SERVICE void WIN32_svcstatusupdate(DWORD svcstate, DWORD WaitHint) { if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) { svcStatus.dwCheckPoint++; svcStatus.dwWaitHint = WaitHint; svcStatus.dwCurrentState = svcstate; SetServiceStatus(svcHandle, &svcStatus); } } VOID WINAPI WIN32_svcHandler(DWORD Opcode) { DWORD status; switch (Opcode) { case _WIN_SQUID_SERVICE_CONTROL_STOP: case _WIN_SQUID_SERVICE_CONTROL_SHUTDOWN: /* Do whatever it takes to stop here. */ svcStatus.dwWin32ExitCode = 0; svcStatus.dwCurrentState = SERVICE_STOP_PENDING; svcStatus.dwCheckPoint = 0; svcStatus.dwWaitHint = 10000; shut_down(SIGTERM); if (!SetServiceStatus(svcHandle, &svcStatus)) { status = GetLastError(); debug(1, 1) ("SetServiceStatus error %ld\n", status); } debug(1, 1) ("Leaving Squid service\n"); return; case _WIN_SQUID_SERVICE_CONTROL_INTERROGATE: /* Fall through to send current status. */ if (!SetServiceStatus(svcHandle, &svcStatus)) { status = GetLastError(); debug(1, 1) ("SetServiceStatus error %ld\n", status); } break; case _WIN_SQUID_SERVICE_CONTROL_ROTATE: rotate_logs(SIGUSR1); break; case _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE: reconfigure(SIGHUP); break; case _WIN_SQUID_SERVICE_CONTROL_DEBUG: sigusr2_handle(SIGUSR2); break; case _WIN_SQUID_SERVICE_CONTROL_INTERRUPT: /* Do whatever it takes to stop here. */ svcStatus.dwWin32ExitCode = 0; svcStatus.dwCurrentState = SERVICE_STOP_PENDING; svcStatus.dwCheckPoint = 0; svcStatus.dwWaitHint = 10000; shut_down(SIGINT); if (!SetServiceStatus(svcHandle, &svcStatus)) { status = GetLastError(); debug(1, 1) ("SetServiceStatus error %ld\n", status); } debug(1, 1) ("Leaving Squid service\n"); break; default: debug(1, 1) ("Unrecognized opcode %ld\n", Opcode); } return; } void WIN32_RemoveService() { SC_HANDLE schService; SC_HANDLE schSCManager; if (!WIN32_Service_name) WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME); strcat(REGKEY, WIN32_Service_name); keys[4] = WIN32_Service_name; schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */ NULL, /* database (NULL == default) */ SC_MANAGER_ALL_ACCESS /* access required */ ); if (!schSCManager) fprintf(stderr, "OpenSCManager failed\n"); else { schService = OpenService(schSCManager, WIN32_Service_name, SERVICE_ALL_ACCESS); if (schService == NULL) fprintf(stderr, "OpenService failed\n"); /* Could not open the service */ else { /* try to stop the service */ if (ControlService(schService, _WIN_SQUID_SERVICE_CONTROL_STOP, &svcStatus)) { sleep(1); while (QueryServiceStatus(schService, &svcStatus)) { if (svcStatus.dwCurrentState == SERVICE_STOP_PENDING) sleep(1); else break; } } /* now remove the service */ if (DeleteService(schService) == 0) fprintf(stderr, "DeleteService failed.\n"); else printf("Service %s deleted successfully.\n", WIN32_Service_name); CloseServiceHandle(schService); } CloseServiceHandle(schSCManager); } } void WIN32_SetServiceCommandLine() { if (!WIN32_Service_name) WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME); strcat(REGKEY, WIN32_Service_name); keys[4] = WIN32_Service_name; /* Now store the Service Command Line in the registry */ WIN32_StoreKey(COMMANDLINE, REG_SZ, (unsigned char *) WIN32_Command_Line, strlen(WIN32_Command_Line) + 1); } void WIN32_InstallService() { SC_HANDLE schService; SC_HANDLE schSCManager; char ServicePath[512]; char szPath[512]; int lenpath; if (!WIN32_Service_name) WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME); strcat(REGKEY, WIN32_Service_name); keys[4] = WIN32_Service_name; if ((lenpath = GetModuleFileName(NULL, ServicePath, 512)) == 0) { fprintf(stderr, "Can't get executable path\n"); exit(1); } snprintf(szPath, sizeof(szPath), "%s %s:%s", ServicePath, _WIN_SQUID_SERVICE_OPTION, WIN32_Service_name); schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */ NULL, /* database (NULL == default) */ SC_MANAGER_ALL_ACCESS /* access required */ ); if (!schSCManager) { fprintf(stderr, "OpenSCManager failed\n"); exit(1); } else { schService = CreateService(schSCManager, /* SCManager database */ WIN32_Service_name, /* name of service */ WIN32_Service_name, /* name to display */ SERVICE_ALL_ACCESS, /* desired access */ SERVICE_WIN32_OWN_PROCESS, /* service type */ SERVICE_AUTO_START, /* start type */ SERVICE_ERROR_NORMAL, /* error control type */ (const char *) szPath, /* service's binary */ NULL, /* no load ordering group */ NULL, /* no tag identifier */ "Tcpip\0AFD\0", /* dependencies */ NULL, /* LocalSystem account */ NULL); /* no password */ if (schService) { if (WIN32_OS_version > _WIN_OS_WINNT) { HMODULE ADVAPI32Handle; PFChangeServiceConfig2 ChangeServiceConfig2; DWORD dwInfoLevel = SERVICE_CONFIG_DESCRIPTION; ADVAPI32Handle = GetModuleHandle("advapi32"); ChangeServiceConfig2 = (PFChangeServiceConfig2) GetProcAddress(ADVAPI32Handle, CHANGESERVICECONFIG2); ChangeServiceConfig2(schService, dwInfoLevel, &Squid_ServiceDescription); dwInfoLevel = SERVICE_CONFIG_FAILURE_ACTIONS; ChangeServiceConfig2(schService, dwInfoLevel, &Squid_ServiceFailureActions); } CloseServiceHandle(schService); /* Now store the config file location in the registry */ if (!ConfigFile) ConfigFile = xstrdup(DefaultConfigFile); WIN32_StoreKey(CONFIGFILE, REG_SZ, (unsigned char *) ConfigFile, strlen(ConfigFile) + 1); printf("Squid Cache version %s for %s\n", version_string, CONFIG_HOST_TYPE); printf("installed successfully as %s Windows System Service.\n", WIN32_Service_name); printf ("To run, start it from the Services Applet of Control Panel.\n"); printf("Don't forget to edit squid.conf before starting it.\n\n"); } else { fprintf(stderr, "CreateService failed\n"); exit(1); } CloseServiceHandle(schSCManager); } } void WIN32_sendSignal(int WIN32_signal) { SERVICE_STATUS ssStatus; DWORD fdwAccess, fdwControl; SC_HANDLE schService; SC_HANDLE schSCManager; if (!WIN32_Service_name) WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME); schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */ NULL, /* database (NULL == default) */ SC_MANAGER_ALL_ACCESS /* access required */ ); if (!schSCManager) { fprintf(stderr, "OpenSCManager failed\n"); exit(1); } /* The required service object access depends on the control. */ switch (WIN32_signal) { case 0: /* SIGNULL */ fdwAccess = SERVICE_INTERROGATE; fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERROGATE; break; case SIGUSR1: fdwAccess = SERVICE_USER_DEFINED_CONTROL; fdwControl = _WIN_SQUID_SERVICE_CONTROL_ROTATE; break; case SIGUSR2: fdwAccess = SERVICE_USER_DEFINED_CONTROL; fdwControl = _WIN_SQUID_SERVICE_CONTROL_DEBUG; break; case SIGHUP: fdwAccess = SERVICE_USER_DEFINED_CONTROL; fdwControl = _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE; break; case SIGTERM: fdwAccess = SERVICE_STOP; fdwControl = _WIN_SQUID_SERVICE_CONTROL_STOP; break; case SIGINT: case SIGKILL: fdwAccess = SERVICE_USER_DEFINED_CONTROL; fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERRUPT; break; default: exit(1); } /* Open a handle to the service. */ schService = OpenService(schSCManager, /* SCManager database */ WIN32_Service_name, /* name of service */ fdwAccess); /* specify access */ if (schService == NULL) { fprintf(stderr, "%s: ERROR: Could not open Service %s\n", appname, WIN32_Service_name); exit(1); } else { /* Send a control value to the service. */ if (!ControlService(schService, /* handle of service */ fdwControl, /* control value to send */ &ssStatus)) { /* address of status info */ fprintf(stderr, "%s: ERROR: Could not Control Service %s\n", appname, WIN32_Service_name); exit(1); } else { /* Print the service status. */ printf("\nStatus of %s Service:\n", WIN32_Service_name); printf(" Service Type: 0x%lx\n", ssStatus.dwServiceType); printf(" Current State: 0x%lx\n", ssStatus.dwCurrentState); printf(" Controls Accepted: 0x%lx\n", ssStatus.dwControlsAccepted); printf(" Exit Code: %ld\n", ssStatus.dwWin32ExitCode); printf(" Service Specific Exit Code: %ld\n", ssStatus.dwServiceSpecificExitCode); printf(" Check Point: %ld\n", ssStatus.dwCheckPoint); printf(" Wait Hint: %ld\n", ssStatus.dwWaitHint); } CloseServiceHandle(schService); } CloseServiceHandle(schSCManager); } int main(int argc, char **argv) { SERVICE_TABLE_ENTRY DispatchTable[] = { {NULL, SquidWinSvcMain}, {NULL, NULL} }; char *c; char stderr_path[256]; if ((argc == 2) && strstr(argv[1], _WIN_SQUID_SERVICE_OPTION)) { strcpy(stderr_path, argv[0]); strcat(stderr_path, ".log"); freopen(stderr_path, "w", stderr); setmode(fileno(stderr), O_TEXT); WIN32_run_mode = _WIN_SQUID_RUN_MODE_SERVICE; if (!(c = strchr(argv[1], ':'))) { fprintf(stderr, "Bad Service Parameter: %s\n", argv[1]); return 1; } WIN32_Service_name = xstrdup(c + 1); DispatchTable[0].lpServiceName = WIN32_Service_name; strcat(REGKEY, WIN32_Service_name); keys[4] = WIN32_Service_name; if (!StartServiceCtrlDispatcher(DispatchTable)) { fprintf(stderr, "StartServiceCtrlDispatcher error = %ld\n", GetLastError()); return 1; } } else { WIN32_run_mode = _WIN_SQUID_RUN_MODE_INTERACTIVE; #ifdef _SQUID_MSWIN_ opt_no_daemon = 1; #endif return SquidMain(argc, argv); } return 0; } #endif #if defined(_SQUID_MSWIN_) static int s_iInitCount = 0; int WIN32_pipe(int handles[2]) { int new_socket; fde *F = NULL; struct sockaddr_in serv_addr; int len = sizeof(serv_addr); u_short handle1_port; handles[0] = handles[1] = -1; statCounter.syscalls.sock.sockets++; if ((new_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) return -1; memset((void *) &serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family = AF_INET; serv_addr.sin_port = htons(0); serv_addr.sin_addr = local_addr; if (bind(new_socket, (SOCKADDR *) & serv_addr, len) < 0 || listen(new_socket, 1) < 0 || getsockname(new_socket, (SOCKADDR *) & serv_addr, &len) < 0 || (handles[1] = socket(PF_INET, SOCK_STREAM, 0)) < 0) { closesocket(new_socket); return -1; } handle1_port = ntohs(serv_addr.sin_port); if (connect(handles[1], (SOCKADDR *) & serv_addr, len) < 0 || (handles[0] = accept(new_socket, (SOCKADDR *) & serv_addr, &len)) < 0) { closesocket(handles[1]); handles[1] = -1; closesocket(new_socket); return -1; } closesocket(new_socket); F = &fd_table[handles[0]]; F->local_addr = local_addr; F->local_port = ntohs(serv_addr.sin_port); F = &fd_table[handles[1]]; F->local_addr = local_addr; xstrncpy(F->ipaddr, inet_ntoa(local_addr), 16); F->remote_port = handle1_port; return 0; } int WIN32_getrusage(int who, struct rusage *usage) { #if HAVE_WIN32_PSAPI if (WIN32_OS_version >= _WIN_OS_WINNT) { /* On Windows NT and later call PSAPI.DLL for process Memory */ /* informations -- Guido Serassio */ HANDLE hProcess; PROCESS_MEMORY_COUNTERS pmc; hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, GetCurrentProcessId()); { /* Microsoft CRT doesn't have getrusage function, */ /* so we get process CPU time information from PSAPI.DLL. */ FILETIME ftCreate, ftExit, ftKernel, ftUser; if (GetProcessTimes(hProcess, &ftCreate, &ftExit, &ftKernel, &ftUser)) { PFILETIME p_ftUser = &ftUser; PFILETIME p_ftKernel = &ftKernel; int64_t tUser64 = (*(int64_t *) p_ftUser / 10); int64_t tKernel64 = (*(int64_t *) p_ftKernel / 10); usage->ru_utime.tv_sec = (long) (tUser64 / 1000000); usage->ru_stime.tv_sec = (long) (tKernel64 / 1000000); usage->ru_utime.tv_usec = (long) (tUser64 % 1000000); usage->ru_stime.tv_usec = (long) (tKernel64 % 1000000); } else { CloseHandle(hProcess); return -1; } } if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) { usage->ru_maxrss = (DWORD) (pmc.WorkingSetSize / getpagesize()); usage->ru_majflt = pmc.PageFaultCount; } else { CloseHandle(hProcess); return -1; } CloseHandle(hProcess); } #endif return 0; } static int Win32SockInit(void) { int iVersionRequested; WSADATA wsaData; int err, opt; int optlen = sizeof(opt); if (s_iInitCount > 0) { s_iInitCount++; return (0); } else if (s_iInitCount < 0) return (s_iInitCount); /* s_iInitCount == 0. Do the initailization */ iVersionRequested = MAKEWORD(2, 0); err = WSAStartup((WORD) iVersionRequested, &wsaData); if (err) { s_iInitCount = -1; return (s_iInitCount); } if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 0) { s_iInitCount = -2; WSACleanup(); return (s_iInitCount); } if (WIN32_OS_version != _WIN_OS_WINNT) { if (getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, &optlen)) { s_iInitCount = -3; WSACleanup(); return (s_iInitCount); } else { opt = opt | SO_SYNCHRONOUS_NONALERT; if (setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, optlen)) { s_iInitCount = -3; WSACleanup(); return (s_iInitCount); } } } WIN32_Socks_initialized = 1; s_iInitCount++; return (s_iInitCount); } static void Win32SockCleanup(void) { if (--s_iInitCount == 0) WSACleanup(); return; } LONG CALLBACK WIN32_ExceptionHandler(EXCEPTION_POINTERS * ep) { EXCEPTION_RECORD *er; er = ep->ExceptionRecord; switch (er->ExceptionCode) { case EXCEPTION_ACCESS_VIOLATION: raise(SIGSEGV); break; case EXCEPTION_DATATYPE_MISALIGNMENT: case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: case EXCEPTION_IN_PAGE_ERROR: death(SIGBUS); break; default: break; } return EXCEPTION_CONTINUE_SEARCH; } void WIN32_ExceptionHandlerInit() { #if !defined(_DEBUG) if (Win32_Old_ExceptionHandler == NULL) Win32_Old_ExceptionHandler = SetUnhandledExceptionFilter(WIN32_ExceptionHandler); #endif } void WIN32_ExceptionHandlerCleanup() { if (Win32_Old_ExceptionHandler != NULL) SetUnhandledExceptionFilter(Win32_Old_ExceptionHandler); } #endif /* _SQUID_MSWIN_ */ #endif /* _SQUID_WIN32_ */