]> git.ipfire.org Git - thirdparty/squid.git/blob - src/win32.cc
Updated Windows related copyrigth notice
[thirdparty/squid.git] / src / win32.cc
1
2 /*
3 * $Id: win32.cc,v 1.24 2006/09/09 15:29:59 serassio Exp $
4 *
5 * Windows support
6 * AUTHOR: Guido Serassio <serassio@squid-cache.org>
7 * inspired by previous work by Romeo Anghelache & Eric Stern.
8 *
9 * SQUID Web Proxy Cache http://www.squid-cache.org/
10 * ----------------------------------------------------------
11 *
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.
20 *
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.
25 *
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.
30 *
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.
34 *
35 */
36
37 #define WIN32_C
38
39 #include "squid.h"
40 #include "squid_windows.h"
41
42 #ifdef _SQUID_MSWIN_
43 #if HAVE_WIN32_PSAPI
44 #include <psapi.h>
45 #endif
46 #ifndef _MSWSOCK_
47 #include <mswsock.h>
48 #endif
49 #include <process.h>
50 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
51 #include <crtdbg.h>
52 #endif
53 #endif
54 #include <fde.h>
55
56 static unsigned int GetOSVersion();
57 void WIN32_svcstatusupdate(DWORD, DWORD);
58 void WINAPI WIN32_svcHandler(DWORD);
59 #if USE_WIN32_SERVICE
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 *);
63 #endif
64 extern "C" void WINAPI SquidWinSvcMain(DWORD, char **);
65
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);
69 #endif
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;
76 #endif
77
78 static int Squid_Aborting = 0;
79
80 #if USE_WIN32_SERVICE
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;
86
87 #define VENDOR "GNU"
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);
99 #ifdef UNICODE
100 #define CHANGESERVICECONFIG2 "ChangeServiceConfig2W"
101 #else
102 #define CHANGESERVICECONFIG2 "ChangeServiceConfig2A"
103 #endif
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] */
114 NULL, /* key[4] */
115 NULL /* key[5] */
116 };
117 #endif
118
119 /* ====================================================================== */
120 /* LOCAL FUNCTIONS */
121 /* ====================================================================== */
122
123 #if USE_WIN32_SERVICE
124 static int
125 WIN32_create_key(void)
126 {
127 int index;
128 HKEY hKey;
129 HKEY hKeyNext;
130 int retval;
131 LONG rv;
132
133 hKey = HKEY_LOCAL_MACHINE;
134 index = 0;
135 retval = 0;
136
137 /* Walk the tree, creating at each stage if necessary */
138
139 while (keys[index]) {
140 unsigned long result;
141 rv = RegCreateKeyEx(hKey, keys[index], /* subkey */
142 0, /* reserved */
143 NULL, /* class */
144 REG_OPTION_NON_VOLATILE, KEY_WRITE, NULL, &hKeyNext, &result);
145
146 if (rv != ERROR_SUCCESS) {
147 fprintf(stderr, "RegCreateKeyEx(%s),%d\n", keys[index], (int) rv);
148 retval = -4;
149 }
150
151 /* Close the old key */
152 rv = RegCloseKey(hKey);
153
154 if (rv != ERROR_SUCCESS) {
155 fprintf(stderr, "RegCloseKey %d\n", (int) rv);
156
157 if (retval == 0) {
158 /* Keep error status from RegCreateKeyEx, if any */
159 retval = -4;
160 }
161 }
162
163 if (retval) {
164 break;
165 }
166
167 hKey = hKeyNext;
168 index++;
169 }
170
171 if (keys[index] == NULL) {
172 /* Close the final key we opened, if we walked the entire
173 * tree
174 */
175 rv = RegCloseKey(hKey);
176
177 if (rv != ERROR_SUCCESS) {
178 fprintf(stderr, "RegCloseKey %d\n", (int) rv);
179
180 if (retval == 0) {
181 /* Keep error status from RegCreateKeyEx, if any */
182 retval = -4;
183 }
184 }
185 }
186
187 return retval;
188 }
189
190 static int
191 WIN32_StoreKey(const char *key, DWORD type, unsigned char *value,
192 int value_size)
193 {
194 LONG rv;
195 HKEY hKey;
196 int retval;
197
198 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_WRITE, &hKey);
199
200 if (rv == ERROR_FILE_NOT_FOUND) {
201 /* Key could not be opened -- try to create it
202 */
203
204 if (WIN32_create_key() < 0) {
205 /* Creation failed (error already reported) */
206 return -4;
207 }
208
209 /* Now it has been created we should be able to open it
210 */
211 rv = RegOpenKeyEx(HKEY_LOCAL_MACHINE, REGKEY, 0, KEY_WRITE, &hKey);
212
213 if (rv == ERROR_FILE_NOT_FOUND) {
214 fprintf(stderr, "Registry does not contain key %s after creation\n",
215 REGKEY);
216 return -1;
217 }
218 }
219
220 if (rv != ERROR_SUCCESS) {
221 fprintf(stderr, "RegOpenKeyEx HKLM\\%s, %d\n", REGKEY, (int) rv);
222 return -4;
223 }
224
225 /* Now set the value and data */
226 rv = RegSetValueEx(hKey, key, /* value key name */
227 0, /* reserved */
228 type, /* type */
229 value, /* value data */
230 (DWORD) value_size); /* for size of "value" */
231
232 retval = 0; /* Return value */
233
234 if (rv != ERROR_SUCCESS) {
235 fprintf(stderr, "RegQueryValueEx(key %s),%d\n", key, (int) rv);
236 retval = -4;
237 } else {
238 fprintf(stderr, "Registry stored HKLM\\%s\\%s value %s\n",
239 REGKEY,
240 key,
241 type == REG_SZ ? value : (unsigned char *) "(not displayable)");
242 }
243
244 /* Make sure we close the key even if there was an error storing
245 * the data
246 */
247 rv = RegCloseKey(hKey);
248
249 if (rv != ERROR_SUCCESS) {
250 fprintf(stderr, "RegCloseKey HKLM\\%s, %d\n", REGKEY, (int) rv);
251
252 if (retval == 0) {
253 /* Keep error status from RegQueryValueEx, if any */
254 retval = -4;
255 }
256 }
257
258 return retval;
259 }
260
261 /* Build argv, argc from string passed from Windows. */
262 static void WIN32_build_argv(char *cmd)
263 {
264 int argvlen = 0;
265 char *word;
266
267 WIN32_argc = 1;
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. */
271
272 while (*cmd) {
273 /* Ignore spaces */
274
275 if (xisspace(*cmd)) {
276 cmd++;
277 continue;
278 }
279
280 /* Found the beginning of an argument. */
281 word = cmd;
282
283 while (*cmd) {
284 cmd++; /* Skip over this character */
285
286 if (xisspace(*cmd)) /* End of argument if space */
287 break;
288 }
289
290 if (*cmd)
291 *cmd++ = '\0'; /* Terminate `word' */
292
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 *));
297 }
298
299 /* Add word to argv file. */
300 WIN32_argv[WIN32_argc++] = word;
301 }
302
303 WIN32_argv[WIN32_argc] = NULL;
304 }
305
306 #endif /* USE_WIN32_SERVICE */
307
308 static unsigned int
309 GetOSVersion()
310 {
311 OSVERSIONINFO osvi;
312
313 safe_free(WIN32_OS_string);
314 memset(&osvi, '\0', sizeof(OSVERSIONINFO));
315 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
316 GetVersionEx((OSVERSIONINFO *) & osvi);
317
318 switch (osvi.dwPlatformId) {
319
320 case VER_PLATFORM_WIN32_NT:
321
322 if (osvi.dwMajorVersion <= 4) {
323 WIN32_OS_string = xstrdup("Windows NT");
324 return _WIN_OS_WINNT;
325 }
326
327 if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 0)) {
328 WIN32_OS_string = xstrdup("Windows 2000");
329 return _WIN_OS_WIN2K;
330 }
331
332 if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 1)) {
333 WIN32_OS_string = xstrdup("Windows XP");
334 return _WIN_OS_WINXP;
335 }
336
337 if ((osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion == 2)) {
338 WIN32_OS_string = xstrdup("Windows Server 2003");
339 return _WIN_OS_WINNET;
340 }
341
342 if ((osvi.dwMajorVersion == 6) && (osvi.dwMinorVersion == 0)) {
343 WIN32_OS_string = xstrdup("Windows code name \"Longhorn\"");
344 return _WIN_OS_WINLON;
345 }
346
347 break;
348
349 case VER_PLATFORM_WIN32_WINDOWS:
350
351 if ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 0)) {
352 WIN32_OS_string = xstrdup("Windows 95");
353 return _WIN_OS_WIN95;
354 }
355
356 if ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 10)) {
357 WIN32_OS_string = xstrdup("Windows 98");
358 return _WIN_OS_WIN98;
359 }
360
361 if ((osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion == 90)) {
362 WIN32_OS_string = xstrdup("Windows Me");
363 return _WIN_OS_WINME;
364 }
365
366 break;
367
368 case VER_PLATFORM_WIN32s:
369 WIN32_OS_string = xstrdup("Windows 3.1 with WIN32S");
370 return _WIN_OS_WIN32S;
371 break;
372
373 default:
374 break;
375 }
376
377 WIN32_OS_string = xstrdup("Unknown Windows system");
378 return _WIN_OS_UNKNOWN;
379 }
380
381 /* ====================================================================== */
382 /* PUBLIC FUNCTIONS */
383 /* ====================================================================== */
384
385 void
386 WIN32_Abort(int sig)
387 {
388 #if USE_WIN32_SERVICE
389 svcStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
390 svcStatus.dwServiceSpecificExitCode = 1;
391 #endif
392
393 Squid_Aborting = 1;
394 WIN32_Exit();
395 }
396
397 void
398 WIN32_Exit()
399 {
400 #ifdef _SQUID_MSWIN_
401 Win32SockCleanup();
402 #endif
403 #if USE_WIN32_SERVICE
404
405 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
406 if (!Squid_Aborting) {
407 svcStatus.dwCurrentState = SERVICE_STOPPED;
408 SetServiceStatus(svcHandle, &svcStatus);
409 }
410 }
411
412 #endif
413 #ifdef _SQUID_MSWIN_
414 if (dbg_mutex)
415 DeleteCriticalSection(dbg_mutex);
416
417 WIN32_ExceptionHandlerCleanup();
418
419 #endif
420
421 _exit(0);
422 }
423
424 int WIN32_Subsystem_Init(int * argc, char *** argv)
425 {
426 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
427 _invalid_parameter_handler oldHandler, newHandler;
428 #endif
429
430 WIN32_OS_version = GetOSVersion();
431
432 if ((WIN32_OS_version == _WIN_OS_UNKNOWN) || (WIN32_OS_version == _WIN_OS_WIN32S))
433 return 1;
434
435 if (atexit(WIN32_Exit) != 0)
436 return 1;
437
438 #if defined(_MSC_VER) /* Microsoft C Compiler ONLY */
439
440 newHandler = Squid_Win32InvalidParameterHandler;
441
442 oldHandler = _set_invalid_parameter_handler(newHandler);
443
444 _CrtSetReportMode(_CRT_ASSERT, 0);
445
446 #endif
447 #if USE_WIN32_SERVICE
448
449 if (WIN32_run_mode == _WIN_SQUID_RUN_MODE_SERVICE) {
450 char path[512];
451 HKEY hndKey;
452
453 if (signal(SIGABRT, WIN32_Abort) == SIG_ERR)
454 return 1;
455
456 /* Register the service Handler function */
457 svcHandle =
458 RegisterServiceCtrlHandler(WIN32_Service_name,
459 WIN32_svcHandler);
460
461 if (svcHandle == 0)
462 return 1;
463
464 /* Set Process work dir to directory cointaining squid.exe */
465 GetModuleFileName(NULL, path, 512);
466
467 WIN32_module_name=xstrdup(path);
468
469 path[strlen(path) - 10] = '\0';
470
471 if (SetCurrentDirectory(path) == 0)
472 return 1;
473
474 safe_free(ConfigFile);
475
476 /* get config file from Windows Registry */
477 if (RegOpenKey(HKEY_LOCAL_MACHINE, REGKEY, &hndKey) == ERROR_SUCCESS) {
478 DWORD Type = 0;
479 DWORD Size = 0;
480 LONG Result;
481 Result =
482 RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, NULL, &Size);
483
484 if (Result == ERROR_SUCCESS && Size) {
485 ConfigFile = static_cast<char *>(xmalloc(Size));
486 RegQueryValueEx(hndKey, CONFIGFILE, NULL, &Type, (unsigned char *)ConfigFile,
487 &Size);
488 } else
489 ConfigFile = xstrdup(DefaultConfigFile);
490
491 Size = 0;
492
493 Type = 0;
494
495 Result =
496 RegQueryValueEx(hndKey, COMMANDLINE, NULL, &Type, NULL, &Size);
497
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,
501 &Size);
502 } else
503 WIN32_Service_Command_Line = xstrdup("");
504
505 RegCloseKey(hndKey);
506 } else {
507 ConfigFile = xstrdup(DefaultConfigFile);
508 WIN32_Service_Command_Line = xstrdup("");
509 }
510
511 WIN32_build_argv(WIN32_Service_Command_Line);
512 *argc = WIN32_argc;
513 *argv = WIN32_argv;
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);
524 #ifdef _SQUID_MSWIN_
525
526 _setmaxstdio(Squid_MaxFD);
527 #endif
528 }
529
530 #endif /* USE_WIN32_SERVICE */
531 #ifdef _SQUID_MSWIN_
532 if (Win32SockInit() < 0)
533 return 1;
534
535 #endif
536
537 return 0;
538 }
539
540 #if USE_WIN32_SERVICE
541 void
542 WIN32_svcstatusupdate(DWORD svcstate, DWORD WaitHint)
543 {
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);
549 }
550 }
551
552 VOID WINAPI
553 WIN32_svcHandler(DWORD Opcode)
554 {
555 DWORD status;
556
557 switch (Opcode) {
558
559 case _WIN_SQUID_SERVICE_CONTROL_STOP:
560
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;
567 shut_down(SIGTERM);
568
569 if (!SetServiceStatus(svcHandle, &svcStatus)) {
570 status = GetLastError();
571 debug(1, 1) ("SetServiceStatus error %ld\n", status);
572 }
573
574 debug(1, 1) ("Leaving Squid service\n");
575 return;
576
577 case _WIN_SQUID_SERVICE_CONTROL_INTERROGATE:
578 /* Fall through to send current status. */
579
580 if (!SetServiceStatus(svcHandle, &svcStatus)) {
581 status = GetLastError();
582 debug(1, 1) ("SetServiceStatus error %ld\n", status);
583 }
584
585 break;
586
587 case _WIN_SQUID_SERVICE_CONTROL_ROTATE:
588 rotate_logs(SIGUSR1);
589 break;
590
591 case _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE:
592 reconfigure(SIGHUP);
593 break;
594
595 case _WIN_SQUID_SERVICE_CONTROL_DEBUG:
596 sigusr2_handle(SIGUSR2);
597 break;
598
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;
605 shut_down(SIGINT);
606
607 if (!SetServiceStatus(svcHandle, &svcStatus)) {
608 status = GetLastError();
609 debug(1, 1) ("SetServiceStatus error %ld\n", status);
610 }
611
612 debug(1, 1) ("Leaving Squid service\n");
613 break;
614
615 default:
616 debug(1, 1) ("Unrecognized opcode %ld\n", Opcode);
617 }
618
619 return;
620 }
621
622 void
623 WIN32_RemoveService()
624 {
625 SC_HANDLE schService;
626 SC_HANDLE schSCManager;
627
628 if (!WIN32_Service_name)
629 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
630
631 strcat(REGKEY, WIN32_Service_name);
632
633 keys[4] = WIN32_Service_name;
634
635 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
636 NULL, /* database (NULL == default) */
637 SC_MANAGER_ALL_ACCESS /* access required */
638 );
639
640 if (!schSCManager)
641 fprintf(stderr, "OpenSCManager failed\n");
642 else {
643 schService = OpenService(schSCManager, WIN32_Service_name, SERVICE_ALL_ACCESS);
644
645 if (schService == NULL)
646 fprintf(stderr, "OpenService failed\n");
647
648 /* Could not open the service */
649 else {
650 /* try to stop the service */
651
652 if (ControlService(schService, _WIN_SQUID_SERVICE_CONTROL_STOP,
653 &svcStatus)) {
654 sleep(1);
655
656 while (QueryServiceStatus(schService, &svcStatus)) {
657 if (svcStatus.dwCurrentState == SERVICE_STOP_PENDING)
658 sleep(1);
659 else
660 break;
661 }
662 }
663
664 /* now remove the service */
665 if (DeleteService(schService) == 0)
666 fprintf(stderr, "DeleteService failed.\n");
667 else
668 printf("Service %s deleted successfully.\n",
669 WIN32_Service_name);
670
671 CloseServiceHandle(schService);
672 }
673
674 CloseServiceHandle(schSCManager);
675 }
676 }
677
678 void
679 WIN32_SetServiceCommandLine()
680 {
681 if (!WIN32_Service_name)
682 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
683
684 strcat(REGKEY, WIN32_Service_name);
685
686 keys[4] = WIN32_Service_name;
687
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);
690 }
691
692 void
693 WIN32_InstallService()
694 {
695 SC_HANDLE schService;
696 SC_HANDLE schSCManager;
697 char ServicePath[512];
698 char szPath[512];
699 int lenpath;
700
701 if (!WIN32_Service_name)
702 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
703
704 strcat(REGKEY, WIN32_Service_name);
705
706 keys[4] = WIN32_Service_name;
707
708 if ((lenpath = GetModuleFileName(NULL, ServicePath, 512)) == 0) {
709 fprintf(stderr, "Can't get executable path\n");
710 exit(1);
711 }
712
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 */
717 );
718
719 if (!schSCManager) {
720 fprintf(stderr, "OpenSCManager failed\n");
721 exit(1);
722 } else {
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 */
736
737 if (schService) {
738 if (WIN32_OS_version > _WIN_OS_WINNT) {
739 HMODULE ADVAPI32Handle;
740 PFChangeServiceConfig2 ChangeServiceConfig2;
741 DWORD dwInfoLevel = SERVICE_CONFIG_DESCRIPTION;
742
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);
748 }
749
750 CloseServiceHandle(schService);
751 /* Now store the config file location in the registry */
752
753 if (!ConfigFile)
754 ConfigFile = xstrdup(DefaultConfigFile);
755
756 WIN32_StoreKey(CONFIGFILE, REG_SZ, (unsigned char *) ConfigFile, strlen(ConfigFile) + 1);
757
758 printf("Squid Cache version %s for %s\n", version_string,
759 CONFIG_HOST_TYPE);
760
761 printf("installed successfully as %s Windows System Service.\n",
762 WIN32_Service_name);
763
764 printf
765 ("To run, start it from the Services Applet of Control Panel.\n");
766
767 printf("Don't forget to edit squid.conf before starting it.\n\n");
768 } else {
769 fprintf(stderr, "CreateService failed\n");
770 exit(1);
771 }
772
773 CloseServiceHandle(schSCManager);
774 }
775 }
776
777 void
778 WIN32_sendSignal(int WIN32_signal)
779 {
780 SERVICE_STATUS ssStatus;
781 DWORD fdwAccess, fdwControl;
782 SC_HANDLE schService;
783 SC_HANDLE schSCManager;
784
785 if (!WIN32_Service_name)
786 WIN32_Service_name = xstrdup(_WIN_SQUID_DEFAULT_SERVICE_NAME);
787
788 schSCManager = OpenSCManager(NULL, /* machine (NULL == local) */
789 NULL, /* database (NULL == default) */
790 SC_MANAGER_ALL_ACCESS /* access required */
791 );
792
793 if (!schSCManager) {
794 fprintf(stderr, "OpenSCManager failed\n");
795 exit(1);
796 }
797
798 /* The required service object access depends on the control. */
799 switch (WIN32_signal) {
800
801 case 0: /* SIGNULL */
802 fdwAccess = SERVICE_INTERROGATE;
803 fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERROGATE;
804 break;
805
806 case SIGUSR1:
807 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
808 fdwControl = _WIN_SQUID_SERVICE_CONTROL_ROTATE;
809 break;
810
811 case SIGUSR2:
812 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
813 fdwControl = _WIN_SQUID_SERVICE_CONTROL_DEBUG;
814 break;
815
816 case SIGHUP:
817 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
818 fdwControl = _WIN_SQUID_SERVICE_CONTROL_RECONFIGURE;
819 break;
820
821 case SIGTERM:
822 fdwAccess = SERVICE_STOP;
823 fdwControl = _WIN_SQUID_SERVICE_CONTROL_STOP;
824 break;
825
826 case SIGINT:
827
828 case SIGKILL:
829 fdwAccess = SERVICE_USER_DEFINED_CONTROL;
830 fdwControl = _WIN_SQUID_SERVICE_CONTROL_INTERRUPT;
831 break;
832
833 default:
834 exit(1);
835 }
836
837 /* Open a handle to the service. */
838 schService = OpenService(schSCManager, /* SCManager database */
839 WIN32_Service_name, /* name of service */
840 fdwAccess); /* specify access */
841
842 if (schService == NULL) {
843 fprintf(stderr, "%s: ERROR: Could not open Service %s\n", appname,
844 WIN32_Service_name);
845 exit(1);
846 } else {
847 /* Send a control value to the service. */
848
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);
854 exit(1);
855 } else {
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);
866 }
867
868 CloseServiceHandle(schService);
869 }
870
871 CloseServiceHandle(schSCManager);
872 }
873
874 int main(int argc, char **argv)
875 {
876 SERVICE_TABLE_ENTRY DispatchTable[] = {
877 {NULL, SquidWinSvcMain},
878 {NULL, NULL}
879 };
880 char *c;
881 char stderr_path[256];
882
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;
889 opt_no_daemon = 1;
890
891 if (!(c=strchr(argv[1],':'))) {
892 fprintf(stderr, "Bad Service Parameter: %s\n", argv[1]);
893 return 1;
894 }
895
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;
900
901 if (!StartServiceCtrlDispatcher(DispatchTable)) {
902 fprintf(stderr, "StartServiceCtrlDispatcher error = %ld\n",
903 GetLastError());
904 return 1;
905 }
906 } else {
907 WIN32_run_mode = _WIN_SQUID_RUN_MODE_INTERACTIVE;
908 #ifdef _SQUID_MSWIN_
909
910 opt_no_daemon = 1;
911
912 #endif
913
914 return SquidMain(argc, argv);
915 }
916
917 return 0;
918 }
919
920 #endif /* USE_WIN32_SERVICE */
921
922 #if defined(_SQUID_MSWIN_)
923 int WIN32_pipe(int handles[2])
924 {
925 int new_socket;
926 fde *F = NULL;
927
928 struct sockaddr_in serv_addr;
929 int len = sizeof(serv_addr);
930 u_short handle1_port;
931
932 handles[0] = handles[1] = -1;
933
934 statCounter.syscalls.sock.sockets++;
935
936 if ((new_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
937 return -1;
938
939 memset((void *) &serv_addr, 0, sizeof(serv_addr));
940
941 serv_addr.sin_family = AF_INET;
942
943 serv_addr.sin_port = htons(0);
944
945 serv_addr.sin_addr = local_addr;
946
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);
951 return -1;
952 }
953
954 handle1_port = ntohs(serv_addr.sin_port);
955
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]);
959 handles[1] = -1;
960 closesocket(new_socket);
961 return -1;
962 }
963
964 closesocket(new_socket);
965
966 F = &fd_table[handles[0]];
967 F->local_addr = local_addr;
968 F->local_port = ntohs(serv_addr.sin_port);
969
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;
974
975 return 0;
976 }
977
978 int WIN32_getrusage(int who, struct rusage *usage)
979 {
980 #if HAVE_WIN32_PSAPI
981
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))
984 {
985 /* On Windows NT/2000 call PSAPI.DLL for process Memory */
986 /* informations -- Guido Serassio */
987 HANDLE hProcess;
988 PROCESS_MEMORY_COUNTERS pmc;
989 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION |
990 PROCESS_VM_READ,
991 FALSE, GetCurrentProcessId());
992 {
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;
996
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);
1004 } else {
1005 CloseHandle( hProcess );
1006 return -1;
1007 }
1008 }
1009
1010 if (GetProcessMemoryInfo( hProcess, &pmc, sizeof(pmc))) {
1011 usage->ru_maxrss=(DWORD)(pmc.WorkingSetSize / getpagesize());
1012 usage->ru_majflt=pmc.PageFaultCount;
1013 } else {
1014 CloseHandle( hProcess );
1015 return -1;
1016 }
1017
1018 CloseHandle( hProcess );
1019 }
1020
1021 #endif
1022 return 0;
1023 }
1024
1025 static int Win32SockInit(void)
1026 {
1027 int iVersionRequested;
1028 WSADATA wsaData;
1029 int err, opt;
1030 int optlen = sizeof(opt);
1031
1032 if (s_iInitCount > 0) {
1033 s_iInitCount++;
1034 return (0);
1035 } else if (s_iInitCount < 0)
1036 return (s_iInitCount);
1037
1038 /* s_iInitCount == 0. Do the initailization */
1039 iVersionRequested = MAKEWORD(2, 0);
1040
1041 err = WSAStartup((WORD) iVersionRequested, &wsaData);
1042
1043 if (err) {
1044 s_iInitCount = -1;
1045 return (s_iInitCount);
1046 }
1047
1048 if (LOBYTE(wsaData.wVersion) != 2 ||
1049 HIBYTE(wsaData.wVersion) != 0) {
1050 s_iInitCount = -2;
1051 WSACleanup();
1052 return (s_iInitCount);
1053 }
1054
1055 if (WIN32_OS_version !=_WIN_OS_WINNT) {
1056 if (::getsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *)&opt, &optlen)) {
1057 s_iInitCount = -3;
1058 WSACleanup();
1059 return (s_iInitCount);
1060 } else {
1061 opt = opt | SO_SYNCHRONOUS_NONALERT;
1062
1063 if (::setsockopt(INVALID_SOCKET, SOL_SOCKET, SO_OPENTYPE, (char *) &opt, optlen)) {
1064 s_iInitCount = -3;
1065 WSACleanup();
1066 return (s_iInitCount);
1067 }
1068 }
1069 }
1070
1071 WIN32_Socks_initialized = 1;
1072 s_iInitCount++;
1073 return (s_iInitCount);
1074 }
1075
1076 static void Win32SockCleanup(void)
1077 {
1078 if (--s_iInitCount == 0)
1079 WSACleanup();
1080
1081 return;
1082 }
1083
1084 int Win32__WSAFDIsSet(int fd, fd_set FAR * set
1085 )
1086 {
1087 fde *F = &fd_table[fd];
1088 SOCKET s = F->win32.handle;
1089
1090 return __WSAFDIsSet(s, set
1091 );
1092 }
1093
1094 void Squid_Win32InvalidParameterHandler(const wchar_t* expression, const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t pReserved)
1095 {
1096 return;
1097 }
1098
1099 LONG CALLBACK WIN32_ExceptionHandler(EXCEPTION_POINTERS* ep)
1100 {
1101 EXCEPTION_RECORD* er;
1102
1103 er = ep->ExceptionRecord;
1104
1105 switch (er->ExceptionCode) {
1106
1107 case EXCEPTION_ACCESS_VIOLATION:
1108 raise(SIGSEGV);
1109 break;
1110
1111 case EXCEPTION_DATATYPE_MISALIGNMENT:
1112
1113 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
1114
1115 case EXCEPTION_IN_PAGE_ERROR:
1116 death(SIGBUS);
1117 break;
1118
1119 default:
1120 break;
1121 }
1122
1123 return EXCEPTION_CONTINUE_SEARCH;
1124 }
1125
1126
1127 void WIN32_ExceptionHandlerInit()
1128 {
1129 #if !defined(_DEBUG)
1130
1131 if (Win32_Old_ExceptionHandler == NULL)
1132 Win32_Old_ExceptionHandler = SetUnhandledExceptionFilter(WIN32_ExceptionHandler);
1133
1134 #endif
1135 }
1136
1137 void WIN32_ExceptionHandlerCleanup()
1138 {
1139 if (Win32_Old_ExceptionHandler != NULL)
1140 SetUnhandledExceptionFilter(Win32_Old_ExceptionHandler);
1141 }
1142
1143 #endif /* SQUID_MSWIN_ */