update anchors on win.

git-svn-id: file:///svn/unbound/trunk@1524 be551aaa-1e26-0410-a405-d3ace91eadb9
This commit is contained in:
Wouter Wijngaards 2009-03-12 16:31:57 +00:00
parent afe9d4bb67
commit 0d575036cb
13 changed files with 451 additions and 26 deletions

View 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)

View 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);

View 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.

View 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 */

View 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))

View 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;
}

158
winrc/anchor-update.c Normal file
View File

@ -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;
}

40
winrc/rsrc_anchorupd.rc Normal file
View File

@ -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"

View 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

View 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"

16
winrc/vista_user.manifest Normal file
View File

@ -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>

View File

@ -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;
}

View 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 */