summaryrefslogtreecommitdiffstats
path: root/bin/named/win32/ntservice.c
diff options
context:
space:
mode:
Diffstat (limited to 'bin/named/win32/ntservice.c')
-rw-r--r--bin/named/win32/ntservice.c190
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);
+}