windows_service.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2023 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* Inspired by previous work by Romeo Anghelache & Eric Stern. */
10 
11 #include "squid.h"
12 #include "debug/Stream.h"
13 #include "globals.h"
14 #include "protos.h"
15 #include "SquidConfig.h"
16 #include "tools.h"
17 #include "windows_service.h"
18 
19 #if _SQUID_WINDOWS_
20 #if !defined(_MSWSOCK_)
21 #include <mswsock.h>
22 #endif
23 #include <process.h>
24 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
25 #include <crtdbg.h>
26 #endif
27 #endif
28 
29 /* forward declarations */
30 static void WIN32_Exit(void);
31 static unsigned int GetOSVersion();
32 void WIN32_svcstatusupdate(DWORD, DWORD);
33 void WINAPI WIN32_svcHandler(DWORD);
34 extern "C" void WINAPI SquidWinSvcMain(DWORD, char **);
35 
36 #if USE_WIN32_SERVICE
37 static void WIN32_Abort(int);
38 static int WIN32_StoreKey(const char *, DWORD, unsigned char *, int);
39 static int WIN32_create_key(void);
40 static void WIN32_build_argv (char *);
41 #endif
42 
43 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
44 void Squid_Win32InvalidParameterHandler(const wchar_t*, const wchar_t*, const wchar_t*, unsigned int, uintptr_t);
45 #endif
46 static int Win32SockInit(void);
47 static void Win32SockCleanup(void);
48 SQUIDCEXTERN LPCRITICAL_SECTION dbg_mutex;
50 static int s_iInitCount = 0;
51 static HANDLE NotifyAddrChange_thread = INVALID_HANDLE_VALUE;
52 
53 #undef NotifyAddrChange
54 typedef DWORD(WINAPI * PFNotifyAddrChange) (OUT PHANDLE, IN LPOVERLAPPED);
55 #define NOTIFYADDRCHANGE "NotifyAddrChange"
56 
57 #if USE_WIN32_SERVICE
58 static SERVICE_STATUS svcStatus;
59 static SERVICE_STATUS_HANDLE svcHandle;
60 static int WIN32_argc;
61 static char ** WIN32_argv;
62 static char * WIN32_module_name;
63 
64 #define VENDOR "squid-cache.org"
65 static char VENDORString[] = VENDOR;
66 #define SOFTWARENAME PACKAGE_NAME
68 #define SOFTWARE "SOFTWARE"
69 static char SOFTWAREString[] = SOFTWARE;
70 #define COMMANDLINE "CommandLine"
71 #define CONFIGFILE "ConfigFile"
72 #undef ChangeServiceConfig2
73 typedef BOOL (WINAPI * PFChangeServiceConfig2) (SC_HANDLE, DWORD, LPVOID);
74 #ifdef UNICODE
75 #define CHANGESERVICECONFIG2 "ChangeServiceConfig2W"
76 #else
77 #define CHANGESERVICECONFIG2 "ChangeServiceConfig2A"
78 #endif
79 static SC_ACTION Squid_SCAction[] = { { SC_ACTION_RESTART, 60000 } };
80 static char Squid_ServiceDescriptionString[] = SOFTWARENAME " " VERSION " WWW Proxy Server";
82 static SERVICE_FAILURE_ACTIONS Squid_ServiceFailureActions = { INFINITE, nullptr, nullptr, 1, Squid_SCAction };
83 static char REGKEY[256] = SOFTWARE "\\" VENDOR "\\" SOFTWARENAME "\\";
84 static char *keys[] = {
85  SOFTWAREString, /* key[0] */
86  VENDORString, /* key[1] */
87  SOFTWARENAMEString, /* key[2] */
88  nullptr, /* key[3] */
89  NULL /* key[4] */
90 };
91 
92 static int Squid_Aborting = 0;
93 #endif
94 
95 /* ====================================================================== */
96 /* LOCAL FUNCTIONS */
97 /* ====================================================================== */
98 
99 #if USE_WIN32_SERVICE
100 static int
102 {
103  int index;
104  HKEY hKey;
105  HKEY hKeyNext;
106  int retval;
107  LONG rv;
108 
109  hKey = HKEY_LOCAL_MACHINE;
110  index = 0;
111  retval = 0;
112 
113  /* Walk the tree, creating at each stage if necessary */
114 
115  while (keys[index]) {
116  unsigned long result;
117  rv = RegCreateKeyEx(hKey, keys[index], /* subkey */
118  0, /* reserved */
119  nullptr, /* class */
120  REG_OPTION_NON_VOLATILE, KEY_WRITE, nullptr, &hKeyNext, &result);
121 
122  if (rv != ERROR_SUCCESS) {
123  fprintf(stderr, "RegCreateKeyEx(%s),%d\n", keys[index], (int) rv);
124  retval = -4;
125  }
126 
127  /* Close the old key */
128  rv = RegCloseKey(hKey);
129 
130  if (rv != ERROR_SUCCESS) {
131  fprintf(stderr, "RegCloseKey %d\n", (int) rv);
132 
133  if (retval == 0) {
134  /* Keep error status from RegCreateKeyEx, if any */
135  retval = -4;
136  }
137  }
138 
139  if (retval) {
140  break;
141  }
142 
143  hKey = hKeyNext;
144  ++index;
145  }
146 
147  if (keys[index] == NULL) {
148  /* Close the final key we opened, if we walked the entire
149  * tree
150  */
151  rv = RegCloseKey(hKey);
152 
153  if (rv != ERROR_SUCCESS) {
154  fprintf(stderr, "RegCloseKey %d\n", (int) rv);
155 
156  if (retval == 0) {
157  /* Keep error status from RegCreateKeyEx, if any */
158  retval = -4;
159  }
160  }
161  }
162 
163  return retval;
164 }
165 
166 static int
167 WIN32_StoreKey(const char *key, DWORD type, unsigned char *value,
168  int value_size)
169 {
170  LONG rv;
171  HKEY hKey;
172  int retval;
173 
174  rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_WRITE, &hKey);
175 
176  if (rv == ERROR_FILE_NOT_FOUND) {
177  /* Key could not be opened -- try to create it
178  */
179 
180  if (WIN32_create_key() < 0) {
181  /* Creation failed (error already reported) */
182  return -4;
183  }
184 
185  /* Now it has been created we should be able to open it
186  */
187  rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_WRITE, &hKey);
188 
189  if (rv == ERROR_FILE_NOT_FOUND) {
190  fprintf(stderr, "Registry does not contain key %s after creation\n",
191  REGKEY);
192  return -1;
193  }
194  }
195 
196  if (rv != ERROR_SUCCESS) {
197  fprintf(stderr, "RegOpenKeyEx HKLM\\%s, %d\n", REGKEY, (int) rv);
198  return -4;
199  }
200 
201  /* Now set the value and data */
202  rv = RegSetValueEx(hKey, key, /* value key name */
203  0, /* reserved */
204  type, /* type */
205  value, /* value data */
206  (DWORD) value_size); /* for size of "value" */
207 
208  retval = 0; /* Return value */
209 
210  if (rv != ERROR_SUCCESS) {
211  fprintf(stderr, "RegQueryValueEx(key %s),%d\n", key, (int) rv);
212  retval = -4;
213  } else {
214  fprintf(stderr, "Registry stored HKLM\\%s\\%s value %s\n",
215  REGKEY,
216  key,
217  type == REG_SZ ? value : (unsigned char *) "(not displayable)");
218  }
219 
220  /* Make sure we close the key even if there was an error storing
221  * the data
222  */
223  rv = RegCloseKey(hKey);
224 
225  if (rv != ERROR_SUCCESS) {
226  fprintf(stderr, "RegCloseKey HKLM\\%s, %d\n", REGKEY, (int) rv);
227 
228  if (retval == 0) {
229  /* Keep error status from RegQueryValueEx, if any */
230  retval = -4;
231  }
232  }
233 
234  return retval;
235 }
236 
237 /* Build argv, argc from string passed from Windows. */
238 static void WIN32_build_argv(char *cmd)
239 {
240  int argvlen = 0;
241  char *word;
242 
243  WIN32_argc = 1;
244  WIN32_argv = (char **) xmalloc ((WIN32_argc+1) * sizeof (char *));
246  /* Scan command line until there is nothing left. */
247 
248  while (*cmd) {
249  /* Ignore spaces */
250 
251  if (xisspace(*cmd)) {
252  ++cmd;
253  continue;
254  }
255 
256  /* Found the beginning of an argument. */
257  word = cmd;
258 
259  while (*cmd) {
260  ++cmd; /* Skip over this character */
261 
262  if (xisspace(*cmd)) /* End of argument if space */
263  break;
264  }
265 
266  if (*cmd)
267  *cmd++ = '\0'; /* Terminate `word' */
268 
269  /* See if we need to allocate more space for argv */
270  if (WIN32_argc >= argvlen) {
271  argvlen = WIN32_argc + 1;
272  WIN32_argv = (char **) xrealloc (WIN32_argv, (1 + argvlen) * sizeof (char *));
273  }
274 
275  /* Add word to argv file. */
276  WIN32_argv[WIN32_argc++] = word;
277  }
278 
279  WIN32_argv[WIN32_argc] = nullptr;
280 }
281 
282 #endif /* USE_WIN32_SERVICE */
283 
284 static unsigned int
286 {
287  OSVERSIONINFOEX osvi;
288  BOOL bOsVersionInfoEx;
289 
290  safe_free(WIN32_OS_string);
291  memset(&osvi, '\0', sizeof(OSVERSIONINFOEX));
292  /* Try calling GetVersionEx using the OSVERSIONINFOEX structure.
293  * If that fails, try using the OSVERSIONINFO structure.
294  */
295 
296  osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
297 
298  if (!(bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) & osvi))) {
299  osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
300  if (!GetVersionEx((OSVERSIONINFO *) & osvi))
301  goto GetVerError;
302  }
303  switch (osvi.dwPlatformId) {
304  case VER_PLATFORM_WIN32_NT:
305  if (osvi.dwMajorVersion <= 4) {
306  WIN32_OS_string = xstrdup("Windows NT");
307  return _WIN_OS_WINNT;
308  }
309  if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 0)) {
310  WIN32_OS_string = xstrdup("Windows 2000");
311  return _WIN_OS_WIN2K;
312  }
313  if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 1)) {
314  WIN32_OS_string = xstrdup("Windows XP");
315  return _WIN_OS_WINXP;
316  }
317  if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 2)) {
318  WIN32_OS_string = xstrdup("Windows Server 2003");
319  return _WIN_OS_WINNET;
320  }
321  if ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 0)) {
322  if (osvi.wProductType == VER_NT_WORKSTATION)
323  WIN32_OS_string = xstrdup("Windows Vista");
324  else
325  WIN32_OS_string = xstrdup("Windows Server 2008");
326  return _WIN_OS_WINLON;
327  }
328  if ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 1)) {
329  if (osvi.wProductType == VER_NT_WORKSTATION)
330  WIN32_OS_string = xstrdup("Windows 7");
331  else
332  WIN32_OS_string = xstrdup("Windows Server 2008 R2");
333  return _WIN_OS_WIN7;
334  }
335  if (((osvi.dwMajorVersion > 6)) || ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion > 1))) {
336  if (osvi.wProductType == VER_NT_WORKSTATION)
337  WIN32_OS_string = xstrdup("Unknown Windows version, assuming Windows 7 capabilities");
338  else
339  WIN32_OS_string = xstrdup("Unknown Windows version, assuming Windows Server 2008 R2 capabilities");
340  return _WIN_OS_WIN7;
341  }
342  break;
343  case VER_PLATFORM_WIN32_WINDOWS:
344  if ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 0)) {
345  WIN32_OS_string = xstrdup("Windows 95");
346  return _WIN_OS_WIN95;
347  }
348  if ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 10)) {
349  WIN32_OS_string = xstrdup("Windows 98");
350  return _WIN_OS_WIN98;
351  }
352  if ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 90)) {
353  WIN32_OS_string = xstrdup("Windows Me");
354  return _WIN_OS_WINME;
355  }
356  break;
357  case VER_PLATFORM_WIN32s:
358  WIN32_OS_string = xstrdup("Windows 3.1 with WIN32S");
359  return _WIN_OS_WIN32S;
360  break;
361  default:
362  break;
363  }
364 GetVerError:
365  WIN32_OS_string = xstrdup("Unknown Windows system");
366  return _WIN_OS_UNKNOWN;
367 }
368 
369 /* ====================================================================== */
370 /* PUBLIC FUNCTIONS */
371 /* ====================================================================== */
372 
373 #if USE_WIN32_SERVICE
374 void
375 WIN32_Abort(int sig)
376 {
377  svcStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
378  svcStatus.dwServiceSpecificExitCode = 1;
379  Squid_Aborting = 1;
380  WIN32_Exit();
381 }
382 #endif
383 
384 void
386 {
387  DWORD status = ERROR_SUCCESS;
388 
389  if (NotifyAddrChange_thread != INVALID_HANDLE_VALUE) {
390  TerminateThread(NotifyAddrChange_thread, status);
391  CloseHandle(NotifyAddrChange_thread);
392  }
393 }
394 
395 void
397 {
399 #if USE_WIN32_SERVICE
400 
401  if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
402  if (!Squid_Aborting) {
403  svcStatus.dwCurrentState = SERVICE_STOPPED;
404  SetServiceStatus(svcHandle, &svcStatus);
405  }
406  }
407 
408 #endif
409  if (dbg_mutex)
410  DeleteCriticalSection(dbg_mutex);
411 
414  _exit(0);
415 }
416 
417 static DWORD WINAPI
419 {
420  DWORD Result;
421  HMODULE IPHLPAPIHandle;
422  PFNotifyAddrChange NotifyAddrChange;
423 
424  if ((IPHLPAPIHandle = GetModuleHandle("IPHLPAPI")) == NULL)
425  IPHLPAPIHandle = LoadLibrary("IPHLPAPI");
426  NotifyAddrChange = (PFNotifyAddrChange) GetProcAddress(IPHLPAPIHandle, NOTIFYADDRCHANGE);
427 
428  while (1) {
429  Result = NotifyAddrChange(nullptr, nullptr);
430  if (Result != NO_ERROR) {
431  debugs(1, DBG_IMPORTANT, "ERROR: NotifyAddrChange error " << Result);
432  return 1;
433  }
434  debugs(1, DBG_IMPORTANT, "Notification of IP address change received, requesting Squid reconfiguration ...");
435  reconfigure(SIGHUP);
436  }
437  return 0;
438 }
439 
440 DWORD
442 {
443  DWORD status = ERROR_SUCCESS;
444  DWORD threadID = 0, ThrdParam = 0;
445 
446  if ((WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) && (Config.onoff.WIN32_IpAddrChangeMonitor)) {
447  NotifyAddrChange_thread = CreateThread(nullptr, 0, WIN32_IpAddrChangeMonitor,
448  &ThrdParam, 0, &threadID);
449  if (NotifyAddrChange_thread == NULL) {
450  status = GetLastError();
451  NotifyAddrChange_thread = INVALID_HANDLE_VALUE;
452  debugs(1, DBG_IMPORTANT, "ERROR: Failed to start IP monitor thread.");
453  } else
454  debugs(1, 2, "Starting IP monitor thread [" << threadID << "] ...");
455  }
456  return status;
457 }
458 
459 int WIN32_Subsystem_Init(int * argc, char *** argv)
460 {
461 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
462  _invalid_parameter_handler oldHandler, newHandler;
463 #endif
464 
465  WIN32_OS_version = GetOSVersion();
466 
467  if ((WIN32_OS_version == _WIN_OS_UNKNOWN) || (WIN32_OS_version == _WIN_OS_WIN32S))
468  return 1;
469 
470  if (atexit(WIN32_Exit) != 0)
471  return 1;
472 
473 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
474 
476 
477  oldHandler = _set_invalid_parameter_handler(newHandler);
478 
479  _CrtSetReportMode(_CRT_ASSERT, 0);
480 
481 #endif
482 #if USE_WIN32_SERVICE
483 
484  if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
485  char path[512];
486  HKEY hndKey;
487 
488  if (signal(SIGABRT, WIN32_Abort) == SIG_ERR)
489  return 1;
490 
491  /* Register the service Handler function */
492  svcHandle = RegisterServiceCtrlHandler(service_name.c_str(), WIN32_svcHandler);
493 
494  if (svcHandle == 0)
495  return 1;
496 
497  /* Set Process work dir to directory containing squid.exe */
498  GetModuleFileName(nullptr, path, 512);
499 
501 
502  path[strlen(path) - 10] = '\0';
503 
504  if (SetCurrentDirectory(path) == 0)
505  return 1;
506 
508 
509  /* get config file from Windows Registry */
510  if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_QUERY_VALUE, &hndKey) == ERROR_SUCCESS) {
511  DWORD Type = 0;
512  DWORD Size = 0;
513  LONG Result;
514  Result = RegQueryValueEx(hndKey, CONFIGFILE, nullptr, &Type, nullptr, &Size);
515 
516  if (Result == ERROR_SUCCESS && Size) {
517  ConfigFile = static_cast<char *>(xmalloc(Size));
518  RegQueryValueEx(hndKey, CONFIGFILE, nullptr, &Type, (unsigned char *)ConfigFile, &Size);
519  } else
520  ConfigFile = xstrdup(DEFAULT_CONFIG_FILE);
521 
522  Size = 0;
523 
524  Type = 0;
525 
526  Result = RegQueryValueEx(hndKey, COMMANDLINE, nullptr, &Type, nullptr, &Size);
527 
528  if (Result == ERROR_SUCCESS && Size) {
529  WIN32_Service_Command_Line = static_cast<char *>(xmalloc(Size));
530  RegQueryValueEx(hndKey, COMMANDLINE, nullptr, &Type, (unsigned char *)WIN32_Service_Command_Line, &Size);
531  } else
532  WIN32_Service_Command_Line = xstrdup("");
533 
534  RegCloseKey(hndKey);
535  } else {
536  ConfigFile = xstrdup(DEFAULT_CONFIG_FILE);
537  WIN32_Service_Command_Line = xstrdup("");
538  }
539 
540  WIN32_build_argv(WIN32_Service_Command_Line);
541  *argc = WIN32_argc;
542  *argv = WIN32_argv;
543  /* Set Service Status to SERVICE_START_PENDING */
544  svcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
545  svcStatus.dwCurrentState = SERVICE_START_PENDING;
546  svcStatus.dwControlsAccepted =
547  SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
548  svcStatus.dwWin32ExitCode = 0;
549  svcStatus.dwServiceSpecificExitCode = 0;
550  svcStatus.dwCheckPoint = 0;
551  svcStatus.dwWaitHint = 10000;
552  SetServiceStatus(svcHandle, &svcStatus);
553 
554  _setmaxstdio(Squid_MaxFD);
555 
556  }
557 
558 #endif /* USE_WIN32_SERVICE */
559  if (Win32SockInit() < 0)
560  return 1;
561 
562  return 0;
563 }
564 
565 #if USE_WIN32_SERVICE
566 void
567 WIN32_svcstatusupdate(DWORD svcstate, DWORD WaitHint)
568 {
569  if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
570  ++svcStatus.dwCheckPoint;
571  svcStatus.dwWaitHint = WaitHint;
572  svcStatus.dwCurrentState = svcstate;
573  SetServiceStatus(svcHandle, &svcStatus);
574  }
575 }
576 
577 VOID WINAPI
578 WIN32_svcHandler(DWORD Opcode)
579 {
580  DWORD status;
581 
582  switch (Opcode) {
583 
584  case _WIN_SQUID_SERVICE_CONTROL_STOP:
585 
586  case _WIN_SQUID_SERVICE_CONTROL_SHUTDOWN:
587  /* Do whatever it takes to stop here. */
588  svcStatus.dwWin32ExitCode = 0;
589  svcStatus.dwCurrentState = SERVICE_STOP_PENDING;
590  svcStatus.dwCheckPoint = 0;
591  svcStatus.dwWaitHint = 10000;
592  shut_down(SIGTERM);
593 
594  if (!SetServiceStatus(svcHandle, &svcStatus)) {
595  status = GetLastError();
596  debugs(1, DBG_IMPORTANT, "ERROR: SetServiceStatus error " << status);
597  }
598 
599  debugs(1, DBG_IMPORTANT, "Leaving Squid service");
600  return;
601 
602  case _WIN_SQUID_SERVICE_CONTROL_INTERROGATE:
603  /* Fall through to send current status. */
604 
605  if (!SetServiceStatus(svcHandle, &svcStatus)) {
606  status = GetLastError();
607  debugs(1, DBG_IMPORTANT, "ERROR: SetServiceStatus error " << status);
608  }
609 
610  break;
611 
612  case _WIN_SQUID_SERVICE_CONTROL_ROTATE:
613  rotate_logs(SIGUSR1);
614  break;
615 
616  case _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE:
617  reconfigure(SIGHUP);
618  break;
619 
620  case _WIN_SQUID_SERVICE_CONTROL_DEBUG:
621  sigusr2_handle(SIGUSR2);
622  break;
623 
624  case _WIN_SQUID_SERVICE_CONTROL_INTERRUPT:
625  /* Do whatever it takes to stop here. */
626  svcStatus.dwWin32ExitCode = 0;
627  svcStatus.dwCurrentState = SERVICE_STOP_PENDING;
628  svcStatus.dwCheckPoint = 0;
629  svcStatus.dwWaitHint = 10000;
630  shut_down(SIGINT);
631 
632  if (!SetServiceStatus(svcHandle, &svcStatus)) {
633  status = GetLastError();
634  debugs(1, DBG_IMPORTANT, "ERROR: SetServiceStatus error " << status);
635  }
636 
637  debugs(1, DBG_IMPORTANT, "Leaving Squid service");
638  break;
639 
640  default:
641  debugs(1, DBG_IMPORTANT, "Unrecognized opcode " << Opcode);
642  }
643 
644  return;
645 }
646 
647 void
649 {
650  SC_HANDLE schService;
651  SC_HANDLE schSCManager;
652 
653  if (service_name.isEmpty())
655 
656  const char *service = service_name.c_str();
657  strcat(REGKEY, service);
658 
659  keys[4] = const_cast<char*>(service);
660 
661  schSCManager = OpenSCManager(nullptr, /* machine (NULL == local) */
662  nullptr, /* database (NULL == default) */
663  SC_MANAGER_ALL_ACCESS /* access required */
664  );
665 
666  if (!schSCManager)
667  fprintf(stderr, "OpenSCManager failed\n");
668  else {
669  schService = OpenService(schSCManager, service, SERVICE_ALL_ACCESS);
670 
671  if (schService == NULL)
672  fprintf(stderr, "OpenService failed\n");
673 
674  /* Could not open the service */
675  else {
676  /* try to stop the service */
677 
678  if (ControlService(schService, _WIN_SQUID_SERVICE_CONTROL_STOP,
679  &svcStatus)) {
680  sleep(1);
681 
682  while (QueryServiceStatus(schService, &svcStatus)) {
683  if (svcStatus.dwCurrentState == SERVICE_STOP_PENDING)
684  sleep(1);
685  else
686  break;
687  }
688  }
689 
690  /* now remove the service */
691  if (DeleteService(schService) == 0)
692  fprintf(stderr, "DeleteService failed.\n");
693  else
694  printf("Service " SQUIDSBUFPH " deleted successfully.\n", SQUIDSBUFPRINT(service_name));
695 
696  CloseServiceHandle(schService);
697  }
698 
699  CloseServiceHandle(schSCManager);
700  }
701 }
702 
703 void
705 {
706  if (service_name.isEmpty())
708 
709  const char *service = service_name.c_str();
710  strcat(REGKEY, service);
711 
712  keys[4] = const_cast<char*>(service);
713 
714  /* Now store the Service Command Line in the registry */
715  WIN32_StoreKey(COMMANDLINE, REG_SZ, (unsigned char *) WIN32_Command_Line, strlen(WIN32_Command_Line) + 1);
716 }
717 
718 void
720 {
721  SC_HANDLE schService;
722  SC_HANDLE schSCManager;
723  char ServicePath[512];
724  char szPath[512];
725  int lenpath;
726 
727  if (service_name.isEmpty())
729 
730  const char *service = service_name.c_str();
731  strcat(REGKEY, service);
732 
733  keys[4] = const_cast<char*>(service);
734 
735  if ((lenpath = GetModuleFileName(nullptr, ServicePath, 512)) == 0) {
736  fprintf(stderr, "Can't get executable path\n");
737  exit(EXIT_FAILURE);
738  }
739 
740  snprintf(szPath, sizeof(szPath), "%s %s:" SQUIDSBUFPH, ServicePath, _WIN_SQUID_SERVICE_OPTION, SQUIDSBUFPRINT(service_name));
741  schSCManager = OpenSCManager(nullptr, /* machine (NULL == local) */
742  nullptr, /* database (NULL == default) */
743  SC_MANAGER_ALL_ACCESS /* access required */
744  );
745 
746  if (!schSCManager) {
747  fprintf(stderr, "OpenSCManager failed\n");
748  exit(EXIT_FAILURE);
749  } else {
750  schService = CreateService(schSCManager, /* SCManager database */
751  service, /* name of service */
752  service, /* name to display */
753  SERVICE_ALL_ACCESS, /* desired access */
754  SERVICE_WIN32_OWN_PROCESS, /* service type */
755  SERVICE_AUTO_START, /* start type */
756  SERVICE_ERROR_NORMAL, /* error control type */
757  (const char *) szPath, /* service's binary */
758  nullptr, /* no load ordering group */
759  nullptr, /* no tag identifier */
760  "Tcpip\0AFD\0", /* dependencies */
761  nullptr, /* LocalSystem account */
762  nullptr); /* no password */
763 
764  if (schService) {
765  if (WIN32_OS_version > _WIN_OS_WINNT) {
766  HMODULE ADVAPI32Handle;
767  PFChangeServiceConfig2 ChangeServiceConfig2;
768  DWORD dwInfoLevel = SERVICE_CONFIG_DESCRIPTION;
769 
770  ADVAPI32Handle = GetModuleHandle("advapi32");
771  ChangeServiceConfig2 = (PFChangeServiceConfig2) GetProcAddress(ADVAPI32Handle, CHANGESERVICECONFIG2);
772  ChangeServiceConfig2(schService, dwInfoLevel, &Squid_ServiceDescription);
773  dwInfoLevel = SERVICE_CONFIG_FAILURE_ACTIONS;
774  ChangeServiceConfig2(schService, dwInfoLevel, &Squid_ServiceFailureActions);
775  }
776 
777  CloseServiceHandle(schService);
778  /* Now store the config file location in the registry */
779 
780  if (!ConfigFile)
781  ConfigFile = xstrdup(DEFAULT_CONFIG_FILE);
782 
783  WIN32_StoreKey(CONFIGFILE, REG_SZ, (unsigned char *) ConfigFile, strlen(ConfigFile) + 1);
784 
785  printf("Squid Cache version %s for %s\n", version_string, CONFIG_HOST_TYPE);
786  printf("installed successfully as " SQUIDSBUFPH " Windows System Service.\n", SQUIDSBUFPRINT(service_name));
787  printf("To run, start it from the Services Applet of Control Panel.\n");
788  printf("Don't forget to edit squid.conf before starting it.\n\n");
789  } else {
790  fprintf(stderr, "CreateService failed\n");
791  exit(EXIT_FAILURE);
792  }
793 
794  CloseServiceHandle(schSCManager);
795  }
796 }
797 
798 void
799 WIN32_sendSignal(int WIN32_signal)
800 {
801  SERVICE_STATUS ssStatus;
802  DWORD fdwAccess, fdwControl;
803  SC_HANDLE schService;
804  SC_HANDLE schSCManager;
805 
806  if (service_name.isEmpty())
808 
809  schSCManager = OpenSCManager(nullptr, /* machine (NULL == local) */
810  nullptr, /* database (NULL == default) */
811  SC_MANAGER_ALL_ACCESS /* access required */
812  );
813 
814  if (!schSCManager) {
815  fprintf(stderr, "OpenSCManager failed\n");
816  exit(EXIT_FAILURE);
817  }
818 
819  /* The required service object access depends on the control. */
820  switch (WIN32_signal) {
821 
822  case 0: /* SIGNULL */
823  fdwAccess = SERVICE_INTERROGATE;
824  fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERROGATE;
825  break;
826 
827  case SIGUSR1:
828  fdwAccess = SERVICE_USER_DEFINED_CONTROL;
829  fdwControl = _WIN_SQUID_SERVICE_CONTROL_ROTATE;
830  break;
831 
832  case SIGUSR2:
833  fdwAccess = SERVICE_USER_DEFINED_CONTROL;
834  fdwControl = _WIN_SQUID_SERVICE_CONTROL_DEBUG;
835  break;
836 
837  case SIGHUP:
838  fdwAccess = SERVICE_USER_DEFINED_CONTROL;
839  fdwControl = _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE;
840  break;
841 
842  case SIGTERM:
843  fdwAccess = SERVICE_STOP;
844  fdwControl = _WIN_SQUID_SERVICE_CONTROL_STOP;
845  break;
846 
847  case SIGINT:
848 
849  case SIGKILL:
850  fdwAccess = SERVICE_USER_DEFINED_CONTROL;
851  fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERRUPT;
852  break;
853 
854  default:
855  exit(EXIT_FAILURE);
856  }
857 
858  /* Open a handle to the service. */
859  schService = OpenService(schSCManager, /* SCManager database */
860  service_name.c_str(), /* name of service */
861  fdwAccess); /* specify access */
862 
863  if (schService == NULL) {
864  fprintf(stderr, "%s: ERROR: Could not open Service " SQUIDSBUFPH "\n", APP_SHORTNAME, SQUIDSBUFPRINT(service_name));
865  exit(EXIT_FAILURE);
866  } else {
867  /* Send a control value to the service. */
868 
869  if (!ControlService(schService, /* handle of service */
870  fdwControl, /* control value to send */
871  &ssStatus)) { /* address of status info */
872  fprintf(stderr, "%s: ERROR: Could not Control Service " SQUIDSBUFPH "\n",
874  exit(EXIT_FAILURE);
875  } else {
876  /* Print the service status. */
877  printf("\nStatus of " SQUIDSBUFPH " Service:\n", SQUIDSBUFPRINT(service_name));
878  printf(" Service Type: 0x%lx\n", ssStatus.dwServiceType);
879  printf(" Current State: 0x%lx\n", ssStatus.dwCurrentState);
880  printf(" Controls Accepted: 0x%lx\n", ssStatus.dwControlsAccepted);
881  printf(" Exit Code: %ld\n", ssStatus.dwWin32ExitCode);
882  printf(" Service Specific Exit Code: %ld\n",
883  ssStatus.dwServiceSpecificExitCode);
884  printf(" Check Point: %ld\n", ssStatus.dwCheckPoint);
885  printf(" Wait Hint: %ld\n", ssStatus.dwWaitHint);
886  }
887 
888  CloseServiceHandle(schService);
889  }
890 
891  CloseServiceHandle(schSCManager);
892 }
893 
894 int WIN32_StartService(int argc, char **argv)
895 {
896  SERVICE_TABLE_ENTRY DispatchTable[] = {
897  {nullptr, SquidWinSvcMain},
898  {nullptr, nullptr}
899  };
900  char *c;
901  char stderr_path[256];
902 
903  strcpy(stderr_path, argv[0]);
904  strcat(stderr_path,".log");
905  freopen(stderr_path, "w", stderr);
906  setmode(fileno(stderr), O_TEXT);
907  WIN32_run_mode = _WIN_SQUID_RUN_MODE_SERVICE;
908 
909  if (!(c=strchr(argv[1],':'))) {
910  fprintf(stderr, "Bad Service Parameter: %s\n", argv[1]);
911  return 1;
912  }
913 
914  service_name = SBuf(c+1);
915  const char *service = service_name.c_str();
916  DispatchTable[0].lpServiceName = const_cast<char*>(service);
917  strcat(REGKEY, service);
918  keys[4] = const_cast<char*>(service);
919 
920  if (!StartServiceCtrlDispatcher(DispatchTable)) {
921  fprintf(stderr, "StartServiceCtrlDispatcher error = %ld\n", GetLastError());
922  return 1;
923  }
924 
925  return 0;
926 }
927 
928 #endif /* USE_WIN32_SERVICE */
929 
930 static int Win32SockInit(void)
931 {
932  int iVersionRequested;
933  WSADATA wsaData;
934  int err, opt;
935  int optlen = sizeof(opt);
936 
937  if (s_iInitCount > 0) {
938  ++s_iInitCount;
939  return (0);
940  } else if (s_iInitCount < 0)
941  return (s_iInitCount);
942 
943  /* s_iInitCount == 0. Do the initialization */
944  iVersionRequested = MAKEWORD(2, 0);
945 
946  err = WSAStartup((WORD) iVersionRequested, &wsaData);
947 
948  if (err) {
949  s_iInitCount = -1;
950  return (s_iInitCount);
951  }
952 
953  if (LOBYTE(wsaData.wVersion) != 2 ||
954  HIBYTE(wsaData.wVersion) != 0) {
955  s_iInitCount = -2;
956  WSACleanup();
957  return (s_iInitCount);
958  }
959 
960  if (WIN32_OS_version !=_WIN_OS_WINNT) {
961  if (::getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&opt, &optlen)) {
962  s_iInitCount = -3;
963  WSACleanup();
964  return (s_iInitCount);
965  } else {
966  opt = opt | SO_SYNCHRONOUS_NONALERT;
967 
968  if (::setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, optlen)) {
969  s_iInitCount = -3;
970  WSACleanup();
971  return (s_iInitCount);
972  }
973  }
974  }
975 
976  WIN32_Socks_initialized = 1;
977  ++s_iInitCount;
978  return (s_iInitCount);
979 }
980 
981 static void Win32SockCleanup(void)
982 {
983  if (--s_iInitCount == 0)
984  WSACleanup();
985 
986  return;
987 }
988 
989 void Squid_Win32InvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved)
990 {
991  return;
992 }
993 
static SC_ACTION Squid_SCAction[]
void WIN32_sendSignal(int WIN32_signal)
#define SOFTWARENAME
static void WIN32_Exit(void)
static HANDLE NotifyAddrChange_thread
void WIN32_SetServiceCommandLine()
#define xmalloc
#define CONFIGFILE
int WIN32_StartService(int argc, char **argv)
void rotate_logs(int sig)
Definition: main.cc:698
bool isEmpty() const
Definition: SBuf.h:435
int WIN32_IpAddrChangeMonitor
Definition: SquidConfig.h:334
SQUIDCEXTERN LPCRITICAL_SECTION dbg_mutex
#define O_TEXT
Definition: defines.h:131
DWORD(WINAPI * PFNotifyAddrChange)(OUT PHANDLE, IN LPOVERLAPPED)
Definition: SBuf.h:93
static int Win32SockInit(void)
static char REGKEY[256]
#define xstrdup
unsigned short WORD
Definition: smblib-priv.h:145
SBuf service_name(APP_SHORTNAME)
struct SquidConfig::@97 onoff
DWORD WIN32_IpAddrChangeMonitorInit()
static int WIN32_argc
static SERVICE_STATUS_HANDLE svcHandle
void WIN32_InstallService()
#define NOTIFYADDRCHANGE
#define APP_SHORTNAME
Definition: version.h:22
static char Squid_ServiceDescriptionString[]
#define VENDOR
const char * version_string
static SERVICE_DESCRIPTION Squid_ServiceDescription
static DWORD WINAPI WIN32_IpAddrChangeMonitor(LPVOID lpParam)
void sigusr2_handle(int sig)
Definition: tools.cc:433
#define NULL
Definition: types.h:145
static int Squid_Aborting
#define SQUIDSBUFPRINT(s)
Definition: SBuf.h:32
static char * keys[]
#define SQUIDCEXTERN
Definition: squid.h:21
static int s_iInitCount
void WIN32_ExceptionHandlerCleanup(void)
static unsigned int GetOSVersion()
static int WIN32_StoreKey(const char *, DWORD, unsigned char *, int)
static SERVICE_STATUS svcStatus
#define safe_free(x)
Definition: xalloc.h:73
Definition: cf_gen.cc:108
const char * c_str()
Definition: SBuf.cc:516
static char VENDORString[]
int Squid_MaxFD
void reconfigure(int sig)
Definition: main.cc:712
void WINAPI SquidWinSvcMain(DWORD, char **)
static int WIN32_create_key(void)
static char * WIN32_module_name
static void WIN32_build_argv(char *)
void WINAPI WIN32_svcHandler(DWORD)
static SERVICE_FAILURE_ACTIONS Squid_ServiceFailureActions
char * ConfigFile
void WIN32_RemoveService()
#define SOFTWARE
void WIN32_IpAddrChangeMonitorExit()
static void Win32SockCleanup(void)
#define DBG_IMPORTANT
Definition: Stream.h:38
static void WIN32_Abort(int)
void Squid_Win32InvalidParameterHandler(const wchar_t *expression, const wchar_t *function, const wchar_t *file, unsigned int line, uintptr_t pReserved)
#define COMMANDLINE
static char SOFTWAREString[]
void WIN32_svcstatusupdate(DWORD, DWORD)
#define xisspace(x)
Definition: xis.h:15
#define VERSION
BOOL(WINAPI * PFChangeServiceConfig2)(SC_HANDLE, DWORD, LPVOID)
static char SOFTWARENAMEString[]
void * xrealloc(void *s, size_t sz)
Definition: xalloc.cc:126
#define BOOL
Definition: std-includes.h:38
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:192
int WIN32_Subsystem_Init(int *argc, char ***argv)
static char ** WIN32_argv
#define SQUIDSBUFPH
Definition: SBuf.h:31
#define CHANGESERVICECONFIG2
class SquidConfig Config
Definition: SquidConfig.cc:12
void shut_down(int sig)
Definition: main.cc:753

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors