diff options
Diffstat (limited to '')
-rw-r--r-- | bin/named/win32/ntservice.c | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/bin/named/win32/ntservice.c b/bin/named/win32/ntservice.c new file mode 100644 index 0000000..5c5c40f --- /dev/null +++ b/bin/named/win32/ntservice.c @@ -0,0 +1,190 @@ +/* + * Copyright (C) Internet Systems Consortium, Inc. ("ISC") + * + * SPDX-License-Identifier: MPL-2.0 + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + * + * See the COPYRIGHT file distributed with this work for additional + * information regarding copyright ownership. + */ + +#include <stdio.h> + +#include <isc/app.h> +#include <isc/commandline.h> +#include <isc/log.h> +#include <isc/print.h> +#include <isc/string.h> + +#include <named/globals.h> +#include <named/main.h> +#include <named/ntservice.h> +#include <named/server.h> + +/* Handle to SCM for updating service status */ +static SERVICE_STATUS_HANDLE hServiceStatus = 0; +static BOOL foreground = FALSE; +static char ConsoleTitle[128]; + +/* + * Forward declarations + */ +static int +bindmain_service_wrapper(int argc, char *argv[]); +void +ServiceControl(DWORD dwCtrlCode); +int +bindmain(int, char *[]); /* From main.c */ + +/* + * Initialize the ISC library running as a Windows Service before calling + * bindmain() + */ +static int +bindmain_service_wrapper(int argc, char *argv[]) { + return (isc_lib_ntservice(bindmain, argc, argv)); +} + +/* + * Initialize the Service by registering it. + */ +void +ntservice_init(void) { + if (!foreground) { + /* Register handler with the SCM */ + hServiceStatus = RegisterServiceCtrlHandler( + BIND_SERVICE_NAME, (LPHANDLER_FUNCTION)ServiceControl); + if (!hServiceStatus) { + named_main_earlyfatal("could not register service " + "control handler"); + } + UpdateSCM(SERVICE_RUNNING); + } else { + strlcpy(ConsoleTitle, "BIND Version ", sizeof(ConsoleTitle)); + strlcat(ConsoleTitle, VERSION, sizeof(ConsoleTitle)); + SetConsoleTitle(ConsoleTitle); + } +} + +void +ntservice_shutdown(void) { + UpdateSCM(SERVICE_STOPPED); +} + +/* + * Routine to check if this is a service or a foreground program + */ +BOOL +ntservice_isservice(void) { + return (!foreground); +} + +/* + * ServiceControl(): Handles requests from the SCM and passes them on + * to named. + */ +void +ServiceControl(DWORD dwCtrlCode) { + /* Handle the requested control code */ + switch (dwCtrlCode) { + case SERVICE_CONTROL_INTERROGATE: + UpdateSCM(0); + break; + + case SERVICE_CONTROL_SHUTDOWN: + case SERVICE_CONTROL_STOP: + named_server_flushonshutdown(named_g_server, true); + isc_app_shutdown(); + UpdateSCM(SERVICE_STOP_PENDING); + break; + default: + break; + } +} + +/* + * Tell the Service Control Manager the state of the service. + */ +void +UpdateSCM(DWORD state) { + SERVICE_STATUS ss; + static DWORD dwState = SERVICE_STOPPED; + + if (hServiceStatus) { + if (state) { + dwState = state; + } + + memset(&ss, 0, sizeof(SERVICE_STATUS)); + ss.dwServiceType |= SERVICE_WIN32_OWN_PROCESS; + ss.dwCurrentState = dwState; + ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | + SERVICE_ACCEPT_SHUTDOWN; + ss.dwCheckPoint = 0; + ss.dwServiceSpecificExitCode = 0; + ss.dwWin32ExitCode = NO_ERROR; + ss.dwWaitHint = dwState == SERVICE_STOP_PENDING ? 10000 : 1000; + + if (!SetServiceStatus(hServiceStatus, &ss)) { + ss.dwCurrentState = SERVICE_STOPPED; + SetServiceStatus(hServiceStatus, &ss); + } + } +} + +/* unhook main */ + +#undef main + +/* + * This is the entry point for the executable + * We can now call bindmain() explicitly or via StartServiceCtrlDispatcher() + * as we need to. + */ +int +main(int argc, char *argv[]) { + int rc, ch; + + /* Command line users should put -f in the options. */ + isc_commandline_errprint = false; + while ((ch = isc_commandline_parse(argc, argv, NAMED_MAIN_ARGS)) != -1) + { + switch (ch) { + case 'f': + case 'g': + case 'v': + case 'V': + foreground = TRUE; + break; + default: + break; + } + } + isc_commandline_reset = true; + + if (foreground) { + /* run in console window */ + exit(bindmain(argc, argv)); + } else { + /* Start up as service */ + char *SERVICE_NAME = BIND_SERVICE_NAME; + + SERVICE_TABLE_ENTRY dispatchTable[] = { + { TEXT(SERVICE_NAME), + (LPSERVICE_MAIN_FUNCTION)bindmain_service_wrapper }, + { NULL, NULL } + }; + + rc = StartServiceCtrlDispatcher(dispatchTable); + if (!rc) { + fprintf(stderr, "Use -f to run from the command " + "line.\n"); + /* will be 1063 when launched as a console app */ + exit(GetLastError()); + } + } + exit(0); +} |