From 0d575036cb0f31f4fdc20088e832beb092563e76 Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Thu, 12 Mar 2009 16:31:57 +0000 Subject: [PATCH] update anchors on win. git-svn-id: file:///svn/unbound/trunk@1524 be551aaa-1e26-0410-a405-d3ace91eadb9 --- Makefile.in | 13 ++- daemon/worker.c | 6 +- doc/Changelog | 1 + libunbound/libworker.c | 8 +- smallapp/worker_cb.c | 8 +- util/fptr_wlist.c | 3 + winrc/anchor-update.c | 158 +++++++++++++++++++++++++++++ winrc/rsrc_anchorupd.rc | 40 ++++++++ winrc/service.conf | 2 +- winrc/setup.nsi | 6 ++ winrc/vista_user.manifest | 16 +++ winrc/win_svc.c | 207 ++++++++++++++++++++++++++++++++++---- winrc/win_svc.h | 9 ++ 13 files changed, 451 insertions(+), 26 deletions(-) create mode 100644 winrc/anchor-update.c create mode 100644 winrc/rsrc_anchorupd.rc create mode 100644 winrc/vista_user.manifest diff --git a/Makefile.in b/Makefile.in index fbea65750..55d7dfbd7 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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) diff --git a/daemon/worker.c b/daemon/worker.c index cd5490ff0..611781ace 100644 --- a/daemon/worker.c +++ b/daemon/worker.c @@ -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); diff --git a/doc/Changelog b/doc/Changelog index 67a275446..66ffc5ae8 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -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. diff --git a/libunbound/libworker.c b/libunbound/libworker.c index a68a4092d..63fd0082d 100644 --- a/libunbound/libworker.c +++ b/libunbound/libworker.c @@ -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 */ diff --git a/smallapp/worker_cb.c b/smallapp/worker_cb.c index a020a48ab..684f3a9f3 100644 --- a/smallapp/worker_cb.c +++ b/smallapp/worker_cb.c @@ -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)) diff --git a/util/fptr_wlist.c b/util/fptr_wlist.c index 0e3742cac..6bae9fb3f 100644 --- a/util/fptr_wlist.c +++ b/util/fptr_wlist.c @@ -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 index 000000000..4971bc6eb --- /dev/null +++ b/winrc/anchor-update.c @@ -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 index 000000000..2419bfad5 --- /dev/null +++ b/winrc/rsrc_anchorupd.rc @@ -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" diff --git a/winrc/service.conf b/winrc/service.conf index 4b6b49060..bda45e447 100644 --- a/winrc/service.conf +++ b/winrc/service.conf @@ -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 diff --git a/winrc/setup.nsi b/winrc/setup.nsi index baa3443b8..74755885e 100644 --- a/winrc/setup.nsi +++ b/winrc/setup.nsi @@ -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 index 000000000..24f5164aa --- /dev/null +++ b/winrc/vista_user.manifest @@ -0,0 +1,16 @@ + + + + Retrieve latest version of trust anchor + + + + + + + + + diff --git a/winrc/win_svc.c b/winrc/win_svc.c index f04fc0fdf..c06c1f9a0 100644 --- a/winrc/win_svc.c +++ b/winrc/win_svc.c @@ -53,17 +53,25 @@ #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; +} diff --git a/winrc/win_svc.h b/winrc/win_svc.h index 332a5268c..737658727 100644 --- a/winrc/win_svc.h +++ b/winrc/win_svc.h @@ -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 */