--------------------- PatchSet 2465 Date: 2001/06/02 12:32:41 Author: serassio Branch: cygwin-svc Tag: (none) Log: Windows NT Service Support - Round 3 Members: acconfig.h:1.4.10.5->1.4.10.5.2.1 configure.in:1.8.2.10->1.8.2.10.2.1 src/defines.h:1.3.22.10->1.3.22.10.2.1 src/globals.h:1.5.12.10->1.5.12.10.2.1 src/main.c:1.12.2.12->1.12.2.12.2.1 src/protos.h:1.9.2.11->1.9.2.11.2.1 src/win32.c:1.1.50.6->1.1.50.6.2.1 Index: squid/acconfig.h =================================================================== RCS file: /cvsroot/squid-sf//squid/Attic/acconfig.h,v retrieving revision 1.4.10.5 retrieving revision 1.4.10.5.2.1 diff -u -r1.4.10.5 -r1.4.10.5.2.1 --- squid/acconfig.h 27 May 2001 14:43:14 -0000 1.4.10.5 +++ squid/acconfig.h 2 Jun 2001 12:32:41 -0000 1.4.10.5.2.1 @@ -23,7 +23,7 @@ #ifndef __CONFIGURE_H__ #define __CONFIGURE_H__ @TOP@ -/* $Id: acconfig.h,v 1.4.10.5 2001/05/27 14:43:14 serassio Exp $ */ +/* $Id: acconfig.h,v 1.4.10.5.2.1 2001/06/02 12:32:41 serassio Exp $ */ /********************************* * START OF CONFIGURABLE OPTIONS * @@ -135,6 +135,11 @@ /* Define if NTLM is allowed to fail gracefully when a helper has problems */ #undef NTLM_FAIL_OPEN +/* + * Define Windows NT & Windows 2000 run service mode + */ +#undef USE_WIN32_SERVICE + /******************************** * END OF CONFIGURABLE OPTIONS * ********************************/ Index: squid/configure.in =================================================================== RCS file: /cvsroot/squid-sf//squid/configure.in,v retrieving revision 1.8.2.10 retrieving revision 1.8.2.10.2.1 diff -u -r1.8.2.10 -r1.8.2.10.2.1 --- squid/configure.in 27 May 2001 15:07:51 -0000 1.8.2.10 +++ squid/configure.in 2 Jun 2001 12:32:41 -0000 1.8.2.10.2.1 @@ -3,13 +3,13 @@ dnl dnl Duane Wessels, wessels@nlanr.net, February 1996 (autoconf v2.9) dnl -dnl $Id: configure.in,v 1.8.2.10 2001/05/27 15:07:51 serassio Exp $ +dnl $Id: configure.in,v 1.8.2.10.2.1 2001/06/02 12:32:41 serassio Exp $ dnl dnl dnl AC_INIT(src/main.c) AC_CONFIG_HEADER(include/autoconf.h) -AC_REVISION($Revision: 1.8.2.10 $)dnl +AC_REVISION($Revision: 1.8.2.10.2.1 $)dnl AC_PREFIX_DEFAULT(/usr/local/squid) AC_CONFIG_AUX_DIR(cfgaux) @@ -740,6 +740,16 @@ fi ]) +dnl Enable WIN32 Service compile mode +AC_ARG_ENABLE(win32-service, +[ --enable-win32-service Compile Squid as a WIN32 Service + Works only on Windows NT and Windows 2000 Platforms.], +[ if test "$enableval" = "yes" ; then + echo "Enabling WIN32 run service mode" + AC_DEFINE(USE_WIN32_SERVICE) + fi +]) + dnl Select auth schemes modules to build AC_ARG_ENABLE(auth, [ --enable-auth=\"list of auth scheme modules\" Index: squid/src/defines.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/defines.h,v retrieving revision 1.3.22.10 retrieving revision 1.3.22.10.2.1 diff -u -r1.3.22.10 -r1.3.22.10.2.1 --- squid/src/defines.h 6 May 2001 17:44:02 -0000 1.3.22.10 +++ squid/src/defines.h 2 Jun 2001 12:32:41 -0000 1.3.22.10.2.1 @@ -1,6 +1,6 @@ /* - * $Id: defines.h,v 1.3.22.10 2001/05/06 17:44:02 serassio Exp $ + * $Id: defines.h,v 1.3.22.10.2.1 2001/06/02 12:32:41 serassio Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -301,4 +301,15 @@ #define _WIN_OS_WIN98 3 #define _WIN_OS_WINNT 4 #define _WIN_OS_WIN2K 5 +#define _WIN_SQUID_SERVICE_CONTROL_STOP SERVICE_CONTROL_STOP +#define _WIN_SQUID_SERVICE_CONTROL_SHUTDOWN SERVICE_CONTROL_SHUTDOWN +#define _WIN_SQUID_SERVICE_CONTROL_INTERROGATE SERVICE_CONTROL_INTERROGATE +#define _WIN_SQUID_SERVICE_CONTROL_ROTATE 128 +#define _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE 129 +#define _WIN_SQUID_SERVICE_CONTROL_DEBUG 130 +#define _WIN_SQUID_SERVICE_CONTROL_INTERRUPT 131 +#define _WIN_SQUID_DEFAULT_SERVICE_NAME "SquidNT" +#define _WIN_SQUID_SERVICE_OPTION "--ntservice" +#define _WIN_SQUID_RUN_MODE_INTERACTIVE 0 +#define _WIN_SQUID_RUN_MODE_SERVICE 1 #endif Index: squid/src/globals.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/globals.h,v retrieving revision 1.5.12.10 retrieving revision 1.5.12.10.2.1 diff -u -r1.5.12.10 -r1.5.12.10.2.1 --- squid/src/globals.h 6 May 2001 17:44:02 -0000 1.5.12.10 +++ squid/src/globals.h 2 Jun 2001 12:32:41 -0000 1.5.12.10.2.1 @@ -1,6 +1,6 @@ /* - * $Id: globals.h,v 1.5.12.10 2001/05/06 17:44:02 serassio Exp $ + * $Id: globals.h,v 1.5.12.10.2.1 2001/06/02 12:32:41 serassio Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -157,4 +157,6 @@ #if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) extern unsigned int WIN32_OS_version; /* 0 */ extern char *WIN32_OS_string; +extern char *WIN32_Service_name; +extern unsigned int WIN32_run_mode; /* _WIN_SQUID_RUN_MODE_INTERACTIVE */ #endif Index: squid/src/main.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/main.c,v retrieving revision 1.12.2.12 retrieving revision 1.12.2.12.2.1 diff -u -r1.12.2.12 -r1.12.2.12.2.1 --- squid/src/main.c 21 May 2001 21:10:28 -0000 1.12.2.12 +++ squid/src/main.c 2 Jun 2001 12:32:41 -0000 1.12.2.12.2.1 @@ -1,6 +1,6 @@ /* - * $Id: main.c,v 1.12.2.12 2001/05/21 21:10:28 serassio Exp $ + * $Id: main.c,v 1.12.2.12.2.1 2001/06/02 12:32:41 serassio Exp $ * * DEBUG: section 1 Startup and Main Loop * AUTHOR: Harvest Derived @@ -35,11 +35,25 @@ #include "squid.h" +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) +#include +#include +static int opt_install_service = FALSE; +static int opt_remove_service = FALSE; +static int opt_signal_service = FALSE; +extern void WIN32_svcstatusupdate(DWORD); +void WINAPI WIN32_svcHandler(DWORD); +#endif + /* for error reporting from xmalloc and friends */ extern void (*failure_notify) (const char *); static int opt_send_signal = -1; +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) +static int opt_no_daemon = 1; +#else static int opt_no_daemon = 0; +#endif static int opt_parse_cfg_only = 0; static int httpPortNumOverride = 1; static int icpPortNumOverride = 1; /* Want to detect "-u 0" */ @@ -53,8 +67,6 @@ static void mainRotate(void); static void mainReconfigure(void); -static SIGHDLR rotate_logs; -static SIGHDLR reconfigure; #if ALARM_UPDATES_TIME static SIGHDLR time_tick; #endif @@ -83,15 +95,27 @@ usage(void) { fprintf(stderr, +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + "Usage: %s [-dhirsvzCDFRVYX] [-f config-file] [-[au] port] [-k signal] [-n name]\n" +#else "Usage: %s [-dhsvzCDFNRVYX] [-f config-file] [-[au] port] [-k signal]\n" +#endif " -a port Specify HTTP port number (default: %d).\n" " -d level Write debugging to stderr also.\n" " -f file Use given config-file instead of\n" " %s\n" " -h Print help message.\n" +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + " -i Installs as a Windows Service (see -n option).\n" +#endif " -k reconfigure|rotate|shutdown|interrupt|kill|debug|check|parse\n" " Parse configuration file, then send signal to \n" " running copy (except -k parse) and exit.\n" +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + " -n name Specify Windows Service name to use for service operations\n" + " default is: " _WIN_SQUID_DEFAULT_SERVICE_NAME ".\n" + " -r Removes a Windows Service (see -n option).\n" +#endif " -s Enable logging to syslog.\n" " -u port Specify ICP port number (default: %d), disable with 0.\n" " -v Print version.\n" @@ -99,7 +123,9 @@ " -C Do not catch fatal signals.\n" " -D Disable initial DNS tests.\n" " -F Don't serve any requests until store is rebuilt.\n" +#if !(defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_))) " -N No daemon mode.\n" +#endif " -R Do not set REUSEADDR on port.\n" " -S Double-check swap during rebuild.\n" " -V Virtual host httpd-accelerator.\n" @@ -115,7 +141,11 @@ extern char *optarg; int c; +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + while ((c = getopt(argc, argv, "CDFRSVYXa:d:f:hik:m::n:rsu:vz?")) != -1) { +#else while ((c = getopt(argc, argv, "CDFNRSVYXa:d:f:hk:m::su:vz?")) != -1) { +#endif switch (c) { case 'C': opt_catch_signals = 0; @@ -126,9 +156,11 @@ case 'F': opt_foreground_rebuild = 1; break; +#if !(defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_))) case 'N': opt_no_daemon = 1; break; +#endif case 'R': opt_reuseaddr = 0; break; @@ -158,6 +190,11 @@ case 'h': usage(); break; +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + case 'i': + opt_install_service = TRUE; + break; +#endif case 'k': if ((int) strlen(optarg) < 1) usage(); @@ -205,6 +242,16 @@ fatal("Need to configure --enable-xmalloc-debug-trace to use -m option"); #endif } +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + case 'n': + xfree(WIN32_Service_name); + WIN32_Service_name = xstrdup(optarg); + opt_signal_service = TRUE; + break; + case 'r': + opt_remove_service = TRUE; + break; +#endif case 's': opt_syslog_enable = 1; break; @@ -215,6 +262,9 @@ break; case 'v': printf("Squid Cache: Version %s\n", version_string); +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + printf("Compiled as Windows System Service.\n"); +#endif exit(0); /* NOTREACHED */ case 'z': @@ -229,7 +279,7 @@ } /* ARGSUSED */ -static void +void rotate_logs(int sig) { do_rotate = 1; @@ -252,7 +302,7 @@ #endif /* ARGSUSED */ -static void +void reconfigure(int sig) { do_reconfigure = 1; @@ -406,6 +456,7 @@ static void setEffectiveUser(void) { +#if !(defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_))) leave_suid(); /* Run as non privilegied user */ #ifdef _SQUID_OS2_ return; @@ -417,6 +468,7 @@ debug(0, 0) ("'cache_effective_user' option in the config file.\n"); fatal("Don't run Squid as root, set 'cache_effective_user'!"); } +#endif } static void @@ -466,6 +518,12 @@ debug(1, 0) ("Starting Squid Cache version %s for %s...\n", version_string, CONFIG_HOST_TYPE); +#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) + if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) + debug(1, 0) ("Running as %s Windows System Service on %s\n", WIN32_Service_name, WIN32_OS_string); + else + debug(1, 0) ("Running on %s\n",WIN32_OS_string); +#endif debug(1, 1) ("Process ID %d\n", (int) getpid()); debug(1, 1) ("With %d file descriptors available\n", Squid_MaxFD); @@ -519,6 +577,10 @@ #if USE_WCCP wccpInit(); #endif +#if USE_SSL + if (Config.Sockaddr.https) + sslInit(Config.SSL.certificate, Config.SSL.key); +#endif serverConnectionsOpen(); if (theOutIcpConnection >= 0) { if (!Config2.Accel.on || Config.onoff.accel_with_proxy) @@ -557,14 +619,20 @@ configured_once = 1; } +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) +/* When USE_WIN32_SERVICE is defined, the main function is placed in win32.c */ +void WINAPI +SquidMain(DWORD argc, char **argv) +#else int main(int argc, char **argv) +#endif { int errcount = 0; int n; /* # of GC'd objects */ time_t loop_delay; mode_t oldmask; -#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) +#if !defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) int WIN32_init_err; #endif @@ -573,9 +641,15 @@ Squid_MaxFD = FD_SETSIZE; #if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) +#ifdef USE_WIN32_SERVICE + if (WIN32_Subsystem_Init()) + return; +/* opt_no_daemon=(WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) ? 0 : 1; */ +#else if ((WIN32_init_err = WIN32_Subsystem_Init())) return WIN32_init_err; #endif +#endif /* call mallopt() before anything else */ #if HAVE_MALLOPT @@ -615,8 +689,23 @@ squid_start = current_time; failure_notify = fatal_dump; + +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + WIN32_svcstatusupdate(SERVICE_START_PENDING); +#endif mainParseOptions(argc, argv); +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + if (opt_install_service) { + WIN32_InstallService(); + return; + } + if (opt_remove_service) { + WIN32_RemoveService(); + return; + } +#endif + /* parse configuration file * note: in "normal" case this used to be called from mainInitialize() */ { @@ -635,7 +724,11 @@ parse_err = parseConfigFile(ConfigFile); if (opt_parse_cfg_only) +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + return; +#else return parse_err; +#endif } if (-1 == opt_send_signal) if (checkRunningPid()) @@ -666,7 +759,11 @@ setEffectiveUser(); debug(0, 0) ("Creating Swap Directories\n"); storeCreateSwapDirectories(); +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + return; +#else return 0; +#endif } if (!opt_no_daemon) watch_child(argv); @@ -686,8 +783,15 @@ fd_open(1, FD_LOG, "stdout"); fd_open(2, FD_LOG, "stderr"); } +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + WIN32_svcstatusupdate(SERVICE_START_PENDING); +#endif mainInitialize(); +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + WIN32_svcstatusupdate(SERVICE_RUNNING); +#endif + /* main loop */ for (;;) { if (do_reconfigure) { @@ -705,6 +809,9 @@ do_shutdown = 0; shutting_down = 1; serverConnectionsClose(); +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + WIN32_svcstatusupdate(SERVICE_STOP_PENDING); +#endif #if USE_DNSSERVERS dnsShutdown(); #else @@ -741,7 +848,11 @@ } } /* NOTREACHED */ +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + return; +#else return 0; +#endif } static void @@ -751,6 +862,11 @@ debug_log = stderr; pid = readPidFile(); if (pid > 1) { +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + if (opt_signal_service) + WIN32_sendSignal(opt_send_signal); + else { +#endif if (kill(pid, opt_send_signal) && /* ignore permissions if just running check */ !(opt_send_signal == 0 && errno == EPERM)) { @@ -759,6 +875,9 @@ opt_send_signal, (int) pid, xstrerror()); exit(1); } +#if defined(USE_WIN32_SERVICE) && (defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)) + } +#endif } else { fprintf(stderr, "%s: ERROR: No running copy\n", appname); exit(1); @@ -1003,4 +1122,5 @@ #else exit(0); #endif + } Index: squid/src/protos.h =================================================================== RCS file: /cvsroot/squid-sf//squid/src/protos.h,v retrieving revision 1.9.2.11 retrieving revision 1.9.2.11.2.1 diff -u -r1.9.2.11 -r1.9.2.11.2.1 --- squid/src/protos.h 21 May 2001 21:10:28 -0000 1.9.2.11 +++ squid/src/protos.h 2 Jun 2001 12:32:41 -0000 1.9.2.11.2.1 @@ -1,6 +1,6 @@ /* - * $Id: protos.h,v 1.9.2.11 2001/05/21 21:10:28 serassio Exp $ + * $Id: protos.h,v 1.9.2.11.2.1 2001/06/02 12:32:41 serassio Exp $ * * * SQUID Web Proxy Cache http://www.squid-cache.org/ @@ -773,6 +773,8 @@ extern void serverConnectionsClose(void); extern void shut_down(int); +extern void rotate_logs(int); +extern void reconfigure(int); extern void start_announce(void *unused); @@ -1306,9 +1308,12 @@ /* Vary support functions */ int varyEvaluateMatch(StoreEntry * entry, request_t * req); -/* CygWin & Windows NT Port */ -/* win32.c */ +/* CygWin & Windows NT Port */ +/* win32.c */ #if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_) extern int WIN32_Subsystem_Init(); +extern void WIN32_sendSignal(int); extern void WIN32_Exit(int); +extern void WIN32_InstallService(void); +extern void WIN32_RemoveService(void); #endif Index: squid/src/win32.c =================================================================== RCS file: /cvsroot/squid-sf//squid/src/win32.c,v retrieving revision 1.1.50.6 retrieving revision 1.1.50.6.2.1 diff -u -r1.1.50.6 -r1.1.50.6.2.1 --- squid/src/win32.c 6 May 2001 17:44:02 -0000 1.1.50.6 +++ squid/src/win32.c 2 Jun 2001 12:32:41 -0000 1.1.50.6.2.1 @@ -28,11 +28,144 @@ #include static unsigned int GetOSVersion(); +void WIN32_svcstatusupdate(DWORD); +void WINAPI WIN32_svcHandler(DWORD); +static int WIN32_StoreKey(const char *, DWORD, unsigned char *, int); +static int WIN32_create_key(void); +void WINAPI SquidMain(DWORD, char **); + +static SERVICE_STATUS svcStatus; +static SERVICE_STATUS_HANDLE svcHandle; + +#define VENDOR "GNU" +#define SOFTWARE "Squid" +#define VERSION "2.5" +#define REGKEY "SOFTWARE\\" VENDOR "\\" SOFTWARE "\\" VERSION /* ====================================================================== */ /* LOCAL FUNCTIONS */ /* ====================================================================== */ +static int +WIN32_create_key(void) +{ + static char *keys[] = { "SOFTWARE", + VENDOR, + SOFTWARE, + VERSION, + NULL + }; + int index; + HKEY hKey; + HKEY hKeyNext; + int retval; + int 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) { + debug(1, 1) ("RegCreateKeyEx(%s),%d\n", keys[index], rv); + retval = -4; + } + /* Close the old key */ + rv = RegCloseKey(hKey); + if (rv != ERROR_SUCCESS) { + debug(1, 1) ("RegCloseKey %d\n", 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) { + debug(1, 1) ("RegCloseKey %d\n", 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) { + debug(1, 1) ("Registry does not contain key %s after creation", + REGKEY); + return -1; + } + } + if (rv != ERROR_SUCCESS) { + debug(1, 1) ("RegOpenKeyEx HKLM\\%s, %d\n", REGKEY, 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) { + debug(1, 1) ("RegQueryValueEx(key %s),%d\n", key, rv); + retval = -4; + } else { + debug(1, 1) ("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) { + debug(1, 1) ("RegCloseKey HKLM\\%s, %d\n", REGKEY, rv); + if (retval == 0) { + /* Keep error status from RegQueryValueEx, if any */ + retval = -4; + } + } + return retval; +} + static unsigned int GetOSVersion() { @@ -80,6 +213,14 @@ VOID WIN32_Exit(int ExitStatus) { +#ifdef USE_WIN32_SERVICE + if (ExitStatus) { + svcStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR; + svcStatus.dwServiceSpecificExitCode = 1; + } + svcStatus.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(svcHandle, &svcStatus); +#endif exit(0); } @@ -87,6 +228,329 @@ WIN32_Subsystem_Init() { WIN32_OS_version = GetOSVersion(); +#ifdef USE_WIN32_SERVICE + if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) { + char path[512]; + HKEY hndKey; + /* 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); + path[strlen(path) - 10] = '\0'; + if (SetCurrentDirectory(path) == 0) + return 1; + xfree(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, WIN32_Service_name, NULL, &Type, NULL, &Size); + if (Result == ERROR_SUCCESS && Size) { + ConfigFile = xmalloc(Size); + RegQueryValueEx(hndKey, WIN32_Service_name, NULL, &Type, ConfigFile, + &Size); + } else + ConfigFile = xstrdup(DefaultConfigFile); + RegCloseKey(hndKey); + } else { + ConfigFile = xstrdup(DefaultConfigFile); + } + /* Set Service Staus 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); + } +#endif return 0; } + +#ifdef USE_WIN32_SERVICE +void +WIN32_svcstatusupdate(DWORD svcstate) +{ + if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) { + svcStatus.dwCheckPoint++; + 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); + schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */ + NULL, /* database (NULL == default) */ + SC_MANAGER_ALL_ACCESS /* access required */ + ); + if (!schSCManager) + debug(1, 1) ("OpenSCManager failed"); + else { + schService = OpenService(schSCManager, WIN32_Service_name, SERVICE_ALL_ACCESS); + if (schService == NULL) + debug(1, 1) ("OpenService failed"); + /* Could not open the service */ + else { + /* try to stop the service */ + if (ControlService(schService, _WIN_SQUID_SERVICE_CONTROL_STOP, + &svcStatus)) { + Sleep(1000); + while (QueryServiceStatus(schService, &svcStatus)) { + if (svcStatus.dwCurrentState == SERVICE_STOP_PENDING) + Sleep(1000); + 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_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); + if ((lenpath = GetModuleFileName(NULL, ServicePath, 512)) == 0) { + debug(1, 1) ("Can't get executable path"); + 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) { + debug(1, 1) ("OpenSCManager failed"); + 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) { + CloseServiceHandle(schService); + /* Now store the config file location in the registry */ + if (!ConfigFile) + ConfigFile = xstrdup(DefaultConfigFile); + WIN32_StoreKey(WIN32_Service_name, 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 { + debug(1, 1) ("CreateService failed"); + 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) { + debug(1, 1) ("OpenSCManager failed"); + 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, SquidMain}, + {NULL, NULL} + }; + char *c; + + if ((argc == 2) && strstr(argv[1], _WIN_SQUID_SERVICE_OPTION)){ + 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; + if (!StartServiceCtrlDispatcher(DispatchTable)) { + fprintf(stderr, "StartServiceCtrlDispatcher error = %ld\n", + GetLastError()); + return 1; + } + } else { + WIN32_run_mode = _WIN_SQUID_RUN_MODE_INTERACTIVE; + SquidMain(argc, argv); + } + return 0; +} +#endif #endif