]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
update anchors on win.
authorWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 12 Mar 2009 16:31:57 +0000 (16:31 +0000)
committerWouter Wijngaards <wouter@nlnetlabs.nl>
Thu, 12 Mar 2009 16:31:57 +0000 (16:31 +0000)
git-svn-id: file:///svn/unbound/trunk@1524 be551aaa-1e26-0410-a405-d3ace91eadb9

13 files changed:
Makefile.in
daemon/worker.c
doc/Changelog
libunbound/libworker.c
smallapp/worker_cb.c
util/fptr_wlist.c
winrc/anchor-update.c [new file with mode: 0644]
winrc/rsrc_anchorupd.rc [new file with mode: 0644]
winrc/service.conf
winrc/setup.nsi
winrc/vista_user.manifest [new file with mode: 0644]
winrc/win_svc.c
winrc/win_svc.h

index fbea6575048a384f4661494ddcaa742036457ccd..55d7dfbd7e4906217be175d241af3f6d3170240e 100644 (file)
@@ -128,15 +128,18 @@ ifeq "$(UB_ON_WINDOWS)" "yes"
   CONTROL_OBJ+=$(BUILD)winrc/rsrc_unbound_control.o
   CHECKCONF_OBJ+=$(BUILD)winrc/rsrc_unbound_checkconf.o
 
-  WINAPPS=unbound-service-install unbound-service-remove
+  WINAPPS=unbound-service-install unbound-service-remove anchor-update
   SVCINST_SRC=winrc/unbound-service-install.c winrc/w_inst.c
   SVCINST_OBJ=$(addprefix $(BUILD),$(SVCINST_SRC:.c=.lo)) $(COMPAT_OBJ) \
        $(BUILD)winrc/rsrc_svcinst.o
   SVCUNINST_SRC=winrc/unbound-service-remove.c winrc/w_inst.c
   SVCUNINST_OBJ=$(addprefix $(BUILD),$(SVCUNINST_SRC:.c=.lo)) $(COMPAT_OBJ) \
        $(BUILD)winrc/rsrc_svcuninst.o
-  ALL_SRC:=$(sort $(ALL_SRC) $(SVCINST_SRC) $(SVCUNINST_SRC))
-  ALL_OBJ:=$(sort $(ALL_OBJ) $(SVCINST_OBJ) $(SVCUNINST_OBJ))
+  ANCHORUPD_SRC=winrc/anchor-update.c
+  ANCHORUPD_OBJ=$(addprefix $(BUILD),$(ANCHORUPD_SRC:.c=.lo)) $(COMPAT_OBJ) \
+        $(BUILD)winrc/rsrc_anchorupd.o
+  ALL_SRC:=$(sort $(ALL_SRC) $(SVCINST_SRC) $(SVCUNINST_SRC) $(ANCHORUPD_SRC))
+  ALL_OBJ:=$(sort $(ALL_OBJ) $(SVCINST_OBJ) $(SVCUNINST_OBJ) $(ANCHORUPD_OBJ))
 
 $(BUILD)%.o:      $(srcdir)/%.rc $(srcdir)/config.h
        $(INFO) Resource $<
@@ -207,6 +210,10 @@ unbound-service-remove:    $(SVCUNINST_OBJ)
        $(INFO) Link $@
        $Q$(LINK) -o $@ $(sort $(SVCUNINST_OBJ)) $(LIBS)
 
+anchor-update:  $(ANCHORUPD_OBJ) libunbound.la $(ldnslib)
+       $(INFO) Link $@
+       $Q$(LINK) -o $@ $(sort $(ANCHORUPD_OBJ)) -L. -L.libs -lunbound $(LIBS)
+
 unittest:      $(UNITTEST_OBJ) $(ldnslib)
        $(INFO) Link $@
        $Q$(LINK) -o $@ $(sort $(UNITTEST_OBJ)) $(LIBS)
index cd5490ff09a68b826ef9d8eff11f3bc477f8ac06..611781ace8803e6dc953fb4fafd03abdd0c1ede7 100644 (file)
@@ -1173,8 +1173,12 @@ worker_delete(struct worker* worker)
        comm_timer_delete(worker->stat_timer);
        daemon_remote_delete(worker->rc);
        free(worker->ports);
-       if(worker->thread_num == 0)
+       if(worker->thread_num == 0) {
                log_set_time(NULL);
+#ifdef UB_ON_WINDOWS
+               wsvc_desetup_worker(worker);
+#endif /* UB_ON_WINDOWS */
+       }
        comm_base_delete(worker->base);
        ub_randfree(worker->rndstate);
        alloc_clear(&worker->alloc);
index 67a27544682c738dcac431b90268d278625fe44b..66ffc5ae89db69e164a7bd7d0e0408f1d1f2e508 100644 (file)
@@ -2,6 +2,7 @@
        - log to App.logs on windows prints executable identity.
        - fixup tests.
        - munin plugin fix benign locking error printout.
+       - anchor-update for windows, called every 24 hours; unbound reloads.
 
 11 March 2009: Wouter
        - winsock event handler resets WSAevents after signalled.
index a68a4092d4f610775bfde1055d103937e9716fd6..63fd0082d532c394bd8af4dc9b45e32cb0c4ede2 100644 (file)
@@ -853,4 +853,10 @@ worker_win_stop_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), void*
         ATTR_UNUSED(arg)) {
         log_assert(0);
 }
-#endif
+
+void
+wsvc_cron_cb(void* ATTR_UNUSED(arg))
+{
+        log_assert(0);
+}
+#endif /* UB_ON_WINDOWS */
index a020a48ab55dd036defae5cb10dee0847aa8738d..684f3a9f359d851a2e6a0c3fb1cb85895102933a 100644 (file)
@@ -124,7 +124,13 @@ worker_win_stop_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), void*
        ATTR_UNUSED(arg)) {
        log_assert(0);
 }
-#endif
+
+void
+wsvc_cron_cb(void* ATTR_UNUSED(arg))
+{
+       log_assert(0);
+}
+#endif /* UB_ON_WINDOWS */
 
 void 
 worker_alloc_cleanup(void* ATTR_UNUSED(arg))
index 0e3742cacdfdf39a4771081ff51af4705eeba512..6bae9fb3f70daebe4164014fe503b45509bcce6f 100644 (file)
@@ -99,6 +99,9 @@ fptr_whitelist_comm_timer(void (*fptr)(void*))
        if(fptr == &pending_udp_timer_cb) return 1;
        else if(fptr == &outnet_tcptimer) return 1;
        else if(fptr == &worker_stat_timer_cb) return 1;
+#ifdef UB_ON_WINDOWS
+       else if(fptr == &wsvc_cron_cb) return 1;
+#endif
        return 0;
 }
 
diff --git a/winrc/anchor-update.c b/winrc/anchor-update.c
new file mode 100644 (file)
index 0000000..4971bc6
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * winrc/anchor-update.c - windows trust anchor update util
+ *
+ * Copyright (c) 2009, NLnet Labs. All rights reserved.
+ *
+ * This software is open source.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 
+ * Neither the name of the NLNET LABS nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * \file
+ *
+ * This file is made because contrib/update-anchor.sh does not work on
+ * windows (no shell). 
+ */
+#include "config.h"
+#include "libunbound/unbound.h"
+
+/** usage */
+static void
+usage(void)
+{
+       printf("usage: { name-of-domain filename }+ \n");
+       printf("exit codes: 0 anchors updated, 1 no changes, 2 errors.\n");
+       exit(1);
+}
+
+/** fatal exit */
+static void fatal(const char* str)
+{
+       printf("fatal error: %s\n", str);
+       exit(2);
+}
+
+/** lookup data */
+static struct ub_result*
+do_lookup(struct ub_ctx* ctx, char* domain)
+{
+       struct ub_result* result = NULL;
+       int r;
+       r = ub_resolve(ctx, domain, LDNS_RR_TYPE_DNSKEY, LDNS_RR_CLASS_IN,
+               &result);
+       if(r) {
+               printf("failed to lookup %s\n", ub_strerror(r));
+               fatal("ub_resolve failed");
+       }
+       if(!result->havedata && (result->rcode == LDNS_RCODE_SERVFAIL ||
+               result->rcode == LDNS_RCODE_REFUSED))
+               return NULL; /* probably no internet connection */
+       if(!result->havedata) fatal("result has no data");
+       if(!result->secure) fatal("result is not secure");
+       return result;
+}
+
+/** get answer into ldns rr list */
+static ldns_rr_list*
+result2answer(struct ub_result* result)
+{
+       ldns_pkt* p = NULL;
+       ldns_rr_list* a;
+       if(ldns_wire2pkt(&p, result->answer_packet, result->answer_len) 
+               != LDNS_STATUS_OK) 
+               return NULL;
+       a = ldns_pkt_answer(p);
+       ldns_pkt_set_answer(p, NULL);
+       ldns_pkt_free(p);
+       return a;
+}
+
+/** print result to file */
+static void
+do_print(struct ub_result* result, char* file)
+{
+       FILE* out;
+       ldns_rr_list* list = result2answer(result);
+       if(!list) fatal("result2answer failed");
+       
+       out = fopen(file, "w");
+       if(!out) {
+               perror(file);
+               fatal("fopen failed");
+       }
+       ldns_rr_list_print(out, list);
+       fclose(out);
+       ldns_rr_list_deep_free(list);
+}
+
+/** update domain to file */
+static int
+do_update(char* domain, char* file)
+{
+       struct ub_ctx* ctx;
+       struct ub_result* result;
+       int r;
+       printf("updating %s to %s\n", domain, file);
+       ctx = ub_ctx_create();
+       if(!ctx) fatal("ub_ctx_create failed");
+
+       if((r=ub_ctx_add_ta_file(ctx, file))) {
+               printf("%s\n", ub_strerror(r));
+               fatal("ub_ctx_add_ta_file failed");
+       }
+
+       if(!(result=do_lookup(ctx, domain))) {
+               ub_ctx_delete(ctx);
+               return 1;
+       }
+       ub_ctx_delete(ctx);
+       do_print(result, file);
+       ub_resolve_free(result);
+       return 0;
+}
+
+/** anchor update main */
+int main(int argc, char** argv)
+{
+       int retcode = 1;
+       if(argc == 1) {
+               usage();
+       }
+       argc--;
+       argv++;
+       while(argc > 0) {
+               int r = do_update(argv[0], argv[1]);
+               if(r == 0) retcode = 0;
+
+               /* next */
+               argc-=2;
+               argv+=2;
+       }
+       return retcode;
+}
diff --git a/winrc/rsrc_anchorupd.rc b/winrc/rsrc_anchorupd.rc
new file mode 100644 (file)
index 0000000..2419bfa
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+  Unbound resource file for windows.  For use with windres
+*/
+#include "winver.h"
+#include "config.h"
+
+1 ICON "winrc/combined.ico"
+
+1 VERSIONINFO
+FILEVERSION    RSRC_PACKAGE_VERSION
+PRODUCTVERSION  RSRC_PACKAGE_VERSION
+FILEFLAGSMASK  0
+FILEFLAGS      0
+FILEOS         VOS__WINDOWS32
+FILETYPE       VFT_APP
+FILESUBTYPE    0
+BEGIN
+  BLOCK "StringFileInfo"
+  BEGIN
+    BLOCK "040904E4"
+    BEGIN
+      VALUE "CompanyName",     "NLnet Labs"
+      VALUE "FileDescription", "Unbound trust anchor tool"
+      VALUE "FileVersion",     PACKAGE_VERSION
+      VALUE "InternalName",    "anchor-update"
+      VALUE "OriginalFilename",        "anchor-update.exe"
+      VALUE "ProductName",     "unbound"
+      VALUE "ProductVersion",  PACKAGE_VERSION
+      VALUE "LegalCopyright",  "(C) 2009 NLnet Labs. Source is BSD licensed."
+    END
+  END
+  BLOCK "VarFileInfo"
+  BEGIN
+    /* English(409), windows ANSI codepage (1252) */
+    VALUE "Translation", 0x409, 0x1252
+  END
+END
+
+/* vista administrator access, show UAC prompt */
+1 RT_MANIFEST "winrc/vista_user.manifest"
index 4b6b49060dd3df93acc0c5601d3d3fe8c7374cad..bda45e44745ad8376c426c898655d2667f825a45 100644 (file)
@@ -5,7 +5,7 @@ server:
        verbosity: 0
 
        # if you want to log to a file use
-       #logfile: "unbound.log"
+       logfile: "C:\unbound.log"
 
        # on Windows, this setting makes reports go into the Application log
        # found in ControlPanels - System tasks - Logs 
index baa3443b801ba169b50e5bd82e4d0b4eac917808..74755885efed0c561a9060da156a2b7c2e9904d0 100644 (file)
@@ -94,6 +94,7 @@ section "-hidden.postinstall"
        File "..\unbound-host.exe"
        File "..\unbound-service-install.exe"
        File "..\unbound-service-remove.exe"
+       File "..\anchor-update.exe"
        File "unbound-website.url"
        File "service.conf"
        File "..\doc\example.conf"
@@ -109,11 +110,15 @@ section "-hidden.postinstall"
                FileWrite $R1 "$\nserver: dlv-anchor-file: $\"$INSTDIR\dlv.isc.org.key$\"$\n"
                FileClose $R1
          done:
+               WriteRegStr HKLM "Software\Unbound" "CronAction" "$\"$INSTDIR\anchor-update.exe$\" dlv.isc.org $\"$INSTDIR\dlv.isc.org.key$\""
+       ${Else}
+               WriteRegStr HKLM "Software\Unbound" "CronAction" "$\"$INSTDIR\anchor-update.exe$\" "
        ${EndIf}
 
        # store installation folder
        WriteRegStr HKLM "Software\Unbound" "InstallLocation" "$INSTDIR"
        WriteRegStr HKLM "Software\Unbound" "ConfigFile" "$INSTDIR\service.conf"
+       WriteRegDWORD HKLM "Software\Unbound" "CronTime" 86400
 
        # uninstaller
        WriteUninstaller "uninst.exe"
@@ -169,6 +174,7 @@ section "un.Unbound"
        Delete "$INSTDIR\unbound-host.exe"
        Delete "$INSTDIR\unbound-service-install.exe"
        Delete "$INSTDIR\unbound-service-remove.exe"
+       Delete "$INSTDIR\anchor-update.exe"
        Delete "$INSTDIR\unbound-website.url"
        Delete "$INSTDIR\service.conf"
        Delete "$INSTDIR\example.conf"
diff --git a/winrc/vista_user.manifest b/winrc/vista_user.manifest
new file mode 100644 (file)
index 0000000..24f5164
--- /dev/null
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> 
+  <assemblyIdentity version="1.0.0.0"
+     processorArchitecture="X86" name="anchor-update.exe" type="win32"/> 
+  <description>Retrieve latest version of trust anchor</description> 
+  <!-- Identify the application security requirements. -->
+  <ms_asmv2:trustInfo xmlns:ms_asmv2="urn:schemas-microsoft-com:asm.v2">
+    <ms_asmv2:security>
+      <ms_asmv2:requestedPrivileges>
+        <ms_asmv2:requestedExecutionLevel
+          level="asInvoker"
+          uiAccess="false"/>
+        </ms_asmv2:requestedPrivileges>
+       </ms_asmv2:security>
+  </ms_asmv2:trustInfo>
+</assembly>
index f04fc0fdfe63eaad7b1026205aa532b4ff870ff5..c06c1f9a0c2813ee26c9a9a3b571c9e032dd900a 100644 (file)
 #include "util/winsock_event.h"
 
 /** global service status */
-SERVICE_STATUS service_status;
+static SERVICE_STATUS  service_status;
 /** global service status handle */
-SERVICE_STATUS_HANDLE service_status_handle;
+static SERVICE_STATUS_HANDLE service_status_handle;
 /** global service stop event */
-WSAEVENT service_stop_event = NULL;
+static WSAEVENT service_stop_event = NULL;
 /** event struct for stop callbacks */
-struct event service_stop_ev;
+static struct event service_stop_ev;
+/** if stop even means shutdown or restart */
+static int service_stop_shutdown = 0;
 /** config file to open. global communication to service_main() */
-char* service_cfgfile = CONFIGFILE;
+static char* service_cfgfile = CONFIGFILE;
 /** commandline verbosity. global communication to service_main() */
-int service_cmdline_verbose = 0;
+static int service_cmdline_verbose = 0;
+/** the cron callback */
+static struct comm_timer* service_cron = NULL;
+/** the cron thread */
+static ub_thread_t cron_thread = NULL;
+/** if cron has already done its quick check */
+static int cron_was_quick = 0;
 
 /**
  * Report current service status to service control manager
@@ -96,6 +104,7 @@ hdlr(DWORD ctrl)
 {
        if(ctrl == SERVICE_CONTROL_STOP) {
                report_status(SERVICE_STOP_PENDING, NO_ERROR, 0);
+               service_stop_shutdown = 1;
                /* send signal to stop */
                if(!WSASetEvent(service_stop_event))
                        log_err("Could not WSASetEvent: %s",
@@ -177,15 +186,57 @@ lookup_reg_str(const char* key, const char* name)
        return result;
 }
 
+/**
+ * Obtain registry integer (if it exists).
+ * @param key: key string
+ * @param name: name of value to fetch.
+ * @return integer value (if it exists), or 0 on error.
+ */
+static int
+lookup_reg_int(const char* key, const char* name)
+{
+       HKEY hk = NULL;
+       DWORD type = 0;
+       BYTE buf[1024];
+       DWORD len = (DWORD)sizeof(buf);
+       LONG ret;
+       int result = 0;
+       ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hk);
+       if(ret == ERROR_FILE_NOT_FOUND)
+               return 0; /* key does not exist */
+       else if(ret != ERROR_SUCCESS) {
+               reportev("RegOpenKeyEx failed");
+               return 0;
+       }
+       ret = RegQueryValueEx(hk, (LPCTSTR)name, 0, &type, buf, &len);
+       if(RegCloseKey(hk))
+               reportev("RegCloseKey");
+       if(ret == ERROR_FILE_NOT_FOUND)
+               return 0; /* name does not exist */
+       else if(ret != ERROR_SUCCESS) {
+               reportev("RegQueryValueEx failed");
+               return 0;
+       }
+       if(type == REG_SZ || type == REG_MULTI_SZ || type == REG_EXPAND_SZ) {
+               buf[sizeof(buf)-1] = 0;
+               buf[sizeof(buf)-2] = 0; /* for multi_sz */
+               result = atoi(buf);
+       } else if(type == REG_DWORD) {
+               result = *(DWORD*)buf;
+       } 
+       return result;
+}
+
 /**
  * Init service. Keeps calling status pending to tell service control
  * manager that this process is not hanging.
+ * @param r: restart, true on restart
  * @param d: daemon returned here.
  * @param c: config file returned here.
  * @return false if failed.
  */
 static int
-service_init(struct daemon** d, struct config_file** c)
+service_init(int r, struct daemon** d, struct config_file** c)
 {
        struct config_file* cfg = NULL;
        struct daemon* daemon = NULL;
@@ -198,9 +249,10 @@ service_init(struct daemon** d, struct config_file** c)
        }
 
        /* create daemon */
-       daemon = daemon_init();
+       if(r)   daemon = *d;
+       else    daemon = daemon_init();
        if(!daemon) return 0;
-       report_status(SERVICE_START_PENDING, NO_ERROR, 2800);
+       if(!r) report_status(SERVICE_START_PENDING, NO_ERROR, 2800);
 
        /* read config */
        cfg = config_create();
@@ -212,7 +264,7 @@ service_init(struct daemon** d, struct config_file** c)
                }
                log_warn("could not open config file, using defaults");
        }
-       report_status(SERVICE_START_PENDING, NO_ERROR, 2600);
+       if(!r) report_status(SERVICE_START_PENDING, NO_ERROR, 2600);
 
        verbose(VERB_QUERY, "winservice - apply settings");
        /* apply settings and init */
@@ -228,23 +280,34 @@ service_init(struct daemon** d, struct config_file** c)
                        verbose(VERB_QUERY, "chdir to %s", cfg->directory);
        }
        log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir);
-       report_status(SERVICE_START_PENDING, NO_ERROR, 2400);
+       if(!r) report_status(SERVICE_START_PENDING, NO_ERROR, 2400);
        verbose(VERB_QUERY, "winservice - apply cfg");
        daemon_apply_cfg(daemon, cfg);
        
        /* open ports */
        /* keep reporting that we are busy starting */
-       report_status(SERVICE_START_PENDING, NO_ERROR, 2200);
+       if(!r) report_status(SERVICE_START_PENDING, NO_ERROR, 2200);
        verbose(VERB_QUERY, "winservice - open ports");
        if(!daemon_open_shared_ports(daemon)) return 0;
        verbose(VERB_QUERY, "winservice - ports opened");
-       report_status(SERVICE_START_PENDING, NO_ERROR, 2000);
+       if(!r) report_status(SERVICE_START_PENDING, NO_ERROR, 2000);
 
        *d = daemon;
        *c = cfg;
        return 1;
 }
 
+/**
+ * Deinit the service
+ */
+static void
+service_deinit(struct daemon* daemon, struct config_file* cfg)
+{
+       daemon_cleanup(daemon);
+       config_delete(cfg);
+       daemon_delete(daemon);
+}
+
 /**
  * The main function for the service.
  * Called by the services API when starting unbound on windows in background.
@@ -270,7 +333,7 @@ service_main(DWORD ATTR_UNUSED(argc), LPTSTR* ATTR_UNUSED(argv))
 
        /* we are now starting up */
        report_status(SERVICE_START_PENDING, NO_ERROR, 3000);
-       if(!service_init(&daemon, &cfg)) {
+       if(!service_init(0, &daemon, &cfg)) {
                reportev("Could not service_init");
                report_status(SERVICE_STOPPED, NO_ERROR, 0);
                return;
@@ -294,16 +357,25 @@ service_main(DWORD ATTR_UNUSED(argc), LPTSTR* ATTR_UNUSED(argv))
        verbose(VERB_QUERY, "winservice - init complete");
 
        /* daemon performs work */
-       daemon_fork(daemon);
+       while(!service_stop_shutdown) {
+               daemon_fork(daemon);
+               if(!service_stop_shutdown) {
+                       daemon_cleanup(daemon);
+                       config_delete(cfg); cfg=NULL;
+                       if(!service_init(1, &daemon, &cfg)) {
+                               reportev("Could not service_init");
+                               report_status(SERVICE_STOPPED, NO_ERROR, 0);
+                               return;
+                       }
+               }
+       }
 
        /* exit */
        verbose(VERB_ALGO, "winservice - cleanup.");
        report_status(SERVICE_STOP_PENDING, NO_ERROR, 0);
-       daemon_cleanup(daemon);
-       config_delete(cfg);
-       daemon_delete(daemon);
-       (void)WSACloseEvent(service_stop_event);
+       service_deinit(daemon, cfg);
        free(service_cfgfile);
+       if(service_stop_event) (void)WSACloseEvent(service_stop_event);
        verbose(VERB_QUERY, "winservice - full stop");
        report_status(SERVICE_STOPPED, NO_ERROR, 0);
 }
@@ -315,6 +387,7 @@ service_start(const char* cfgfile, int v, int c)
        SERVICE_TABLE_ENTRY myservices[2] = {
                {SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)service_main},
                {NULL, NULL} };
+       v=4; /* DEBUG */
        verbosity=v;
        if(verbosity >= VERB_QUERY) {
                /* log to file about start sequence */
@@ -355,6 +428,90 @@ worker_win_stop_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(ev), void* arg)
         comm_base_exit(worker->base);
 }
 
+/** wait for cron process to finish */
+static void
+waitforit(PROCESS_INFORMATION* pinfo)
+{
+       DWORD ret = WaitForSingleObject(pinfo->hProcess, INFINITE);
+       verbose(VERB_ALGO, "cronaction done");
+       if(ret != WAIT_OBJECT_0) {
+               return; /* did not end successfully */
+       }
+       if(!GetExitCodeProcess(pinfo->hProcess, &ret)) {
+               log_err("GetExitCodeProcess failed");
+               return;
+       }
+       verbose(VERB_ALGO, "exit code is %d", (int)ret);
+       if(ret != 1) {
+               if(!WSASetEvent(service_stop_event))
+                       log_err("Could not WSASetEvent: %s",
+                       wsa_strerror(WSAGetLastError()));
+       }
+}
+
+/** Do the cron action and wait for result exit value */
+static void*
+win_do_cron(void* ATTR_UNUSED(arg))
+{
+       int mynum=65;
+       char* cronaction;
+       log_thread_set(&mynum);
+       cronaction = lookup_reg_str("Software\\Unbound", "CronAction");
+       if(cronaction) {
+               STARTUPINFO sinfo;
+               PROCESS_INFORMATION pinfo;
+               memset(&pinfo, 0, sizeof(pinfo));
+               memset(&sinfo, 0, sizeof(sinfo));
+               sinfo.cb = sizeof(sinfo);
+               verbose(VERB_ALGO, "cronaction: %s", cronaction);
+               if(!CreateProcess(NULL, cronaction, NULL, NULL, 0, 
+                       CREATE_NO_WINDOW, NULL, NULL, &sinfo, &pinfo))
+                       log_err("CreateProcess error");
+               else {
+                       waitforit(&pinfo);
+                       CloseHandle(pinfo.hProcess);
+                       CloseHandle(pinfo.hThread);
+               }
+               free(cronaction);
+       }
+       /* stop self */
+       CloseHandle(cron_thread);
+       cron_thread = NULL;
+       return NULL;
+}
+
+static void
+set_cron_timer()
+{
+       struct timeval tv;
+       int crontime;
+       if(cron_was_quick == 0) {
+               cron_was_quick = 1;
+               crontime = 10; /* first update 10 seconds after boot */
+       } else {
+               crontime = lookup_reg_int("Software\\Unbound", "CronTime");
+               if(crontime == 0) crontime = 60*60*24; /* 24 hours */
+       }
+       crontime = 10; /* DEBUG */
+       memset(&tv, 0, sizeof(tv));
+       tv.tv_sec = (time_t)crontime;
+       comm_timer_set(service_cron, &tv);
+}
+
+void
+wsvc_cron_cb(void* arg)
+{
+       struct worker* worker = (struct worker*)arg;
+       /* perform cronned operation */
+       verbose(VERB_ALGO, "cron timer callback");
+       if(cron_thread == NULL) {
+               /* create new thread to do it */
+               ub_thread_create(&cron_thread, win_do_cron, worker);
+       }
+       /* reschedule */
+       set_cron_timer();
+}
+
 void wsvc_setup_worker(struct worker* worker)
 {
        /* if not started with -w service, do nothing */
@@ -366,5 +523,17 @@ void wsvc_setup_worker(struct worker* worker)
                fatal_exit("could not register wsaevent");
                return;
        }
+       if(!service_cron) {
+               service_cron = comm_timer_create(worker->base, 
+                       wsvc_cron_cb, worker);
+               if(!service_cron)
+                       fatal_exit("could not create cron timer");
+               set_cron_timer();
+       }
 }
 
+void wsvc_desetup_worker(struct worker* ATTR_UNUSED(worker))
+{
+       comm_timer_delete(service_cron);
+       service_cron = NULL;
+}
index 332a5268cb1b102e18a4425f9d08cef57929e573..737658727596dc3740b15ee965960bf67b5a6a8a 100644 (file)
@@ -75,7 +75,16 @@ void wsvc_command_option(const char* wopt, const char* cfgfile, int v, int c);
  */
 void wsvc_setup_worker(struct worker* worker);
 
+/**
+ * Desetup lead worker events.
+ * @param worker: the worker
+ */
+void wsvc_desetup_worker(struct worker* worker);
+
 /** windows worker stop event callback handler */
 void worker_win_stop_cb(int fd, short ev, void* arg);
 
+/** windows cron timer callback handler */
+void wsvc_cron_cb(void* arg);
+
 #endif /* WINRC_WIN_SVC_H */