xref: /openbsd/usr.sbin/relayd/hce.c (revision 0ca734d7)
1*0ca734d7Sreyk /*	$OpenBSD: hce.c,v 1.36 2007/11/24 17:07:28 reyk Exp $	*/
2feb9ff76Sreyk 
3feb9ff76Sreyk /*
436f5dc5eSpyr  * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
5feb9ff76Sreyk  *
6feb9ff76Sreyk  * Permission to use, copy, modify, and distribute this software for any
7feb9ff76Sreyk  * purpose with or without fee is hereby granted, provided that the above
8feb9ff76Sreyk  * copyright notice and this permission notice appear in all copies.
9feb9ff76Sreyk  *
10feb9ff76Sreyk  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11feb9ff76Sreyk  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12feb9ff76Sreyk  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13feb9ff76Sreyk  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14feb9ff76Sreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15feb9ff76Sreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16feb9ff76Sreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17feb9ff76Sreyk  */
18feb9ff76Sreyk 
19feb9ff76Sreyk #include <sys/param.h>
20*0ca734d7Sreyk #include <sys/queue.h>
21feb9ff76Sreyk #include <sys/time.h>
22feb9ff76Sreyk #include <sys/stat.h>
23feb9ff76Sreyk #include <sys/socket.h>
24feb9ff76Sreyk #include <sys/un.h>
25*0ca734d7Sreyk 
26*0ca734d7Sreyk #include <net/if.h>
27feb9ff76Sreyk #include <netinet/in_systm.h>
28feb9ff76Sreyk #include <netinet/in.h>
29feb9ff76Sreyk #include <netinet/ip.h>
30*0ca734d7Sreyk 
31feb9ff76Sreyk #include <errno.h>
32feb9ff76Sreyk #include <event.h>
33feb9ff76Sreyk #include <fcntl.h>
34feb9ff76Sreyk #include <stdlib.h>
35feb9ff76Sreyk #include <string.h>
36feb9ff76Sreyk #include <unistd.h>
37feb9ff76Sreyk #include <err.h>
38feb9ff76Sreyk #include <pwd.h>
39feb9ff76Sreyk 
40e8fb3979Spyr #include <openssl/ssl.h>
41e8fb3979Spyr 
42ee9f3836Sderaadt #include "hoststated.h"
43feb9ff76Sreyk 
44c99a0f3cSblambert __dead void hce_shutdown(void);
45feb9ff76Sreyk void	hce_sig_handler(int sig, short, void *);
46feb9ff76Sreyk void	hce_dispatch_imsg(int, short, void *);
47feb9ff76Sreyk void	hce_dispatch_parent(int, short, void *);
48feb9ff76Sreyk void	hce_launch_checks(int, short, void *);
49641b8bafSpyr void	hce_setup_events(void);
50641b8bafSpyr void	hce_disable_events(void);
51feb9ff76Sreyk 
528f79868bSpyr static struct hoststated *env = NULL;
53feb9ff76Sreyk struct imsgbuf		*ibuf_pfe;
54feb9ff76Sreyk struct imsgbuf		*ibuf_main;
55780e8f79Spyr int			 pipe_pfe;
56780e8f79Spyr int			 pipe_parent;
57780e8f79Spyr int			 running = 0;
58feb9ff76Sreyk 
59feb9ff76Sreyk void
60feb9ff76Sreyk hce_sig_handler(int sig, short event, void *arg)
61feb9ff76Sreyk {
62feb9ff76Sreyk 	switch (sig) {
63feb9ff76Sreyk 	case SIGINT:
64feb9ff76Sreyk 	case SIGTERM:
65feb9ff76Sreyk 		hce_shutdown();
66780e8f79Spyr 		break;
67feb9ff76Sreyk 	default:
68feb9ff76Sreyk 		fatalx("hce_sig_handler: unexpected signal");
69feb9ff76Sreyk 	}
70feb9ff76Sreyk }
71feb9ff76Sreyk 
72feb9ff76Sreyk pid_t
738f79868bSpyr hce(struct hoststated *x_env, int pipe_parent2pfe[2], int pipe_parent2hce[2],
74053249cdSpyr     int pipe_parent2relay[RELAY_MAXPROC][2], int pipe_pfe2hce[2],
752edd718bSreyk     int pipe_pfe2relay[RELAY_MAXPROC][2])
76feb9ff76Sreyk {
77feb9ff76Sreyk 	pid_t		 pid;
78feb9ff76Sreyk 	struct passwd	*pw;
792edd718bSreyk 	int		 i;
80641b8bafSpyr 	struct event	 ev_sigint;
81641b8bafSpyr 	struct event	 ev_sigterm;
82feb9ff76Sreyk 
83feb9ff76Sreyk 	switch (pid = fork()) {
84feb9ff76Sreyk 	case -1:
85feb9ff76Sreyk 		fatal("hce: cannot fork");
86feb9ff76Sreyk 	case 0:
87feb9ff76Sreyk 		break;
88feb9ff76Sreyk 	default:
89feb9ff76Sreyk 		return (pid);
90feb9ff76Sreyk 	}
91feb9ff76Sreyk 
92feb9ff76Sreyk 	env = x_env;
9379446c9fSpyr 	purge_config(env, PURGE_SERVICES|PURGE_RELAYS|PURGE_PROTOS);
94feb9ff76Sreyk 
958f79868bSpyr 	if ((pw = getpwnam(HOSTSTATED_USER)) == NULL)
96feb9ff76Sreyk 		fatal("hce: getpwnam");
97feb9ff76Sreyk 
98adf98c11Spyr #ifndef DEBUG
99feb9ff76Sreyk 	if (chroot(pw->pw_dir) == -1)
100feb9ff76Sreyk 		fatal("hce: chroot");
101feb9ff76Sreyk 	if (chdir("/") == -1)
102feb9ff76Sreyk 		fatal("hce: chdir(\"/\")");
103adf98c11Spyr #else
104adf98c11Spyr #warning disabling privilege revocation and chroot in DEBUG mode
105adf98c11Spyr #endif
106feb9ff76Sreyk 
107feb9ff76Sreyk 	setproctitle("host check engine");
1088f79868bSpyr 	hoststated_process = PROC_HCE;
109feb9ff76Sreyk 
11001d85ec5Sreyk 	/* this is needed for icmp tests */
11101d85ec5Sreyk 	icmp_init(env);
11201d85ec5Sreyk 
113adf98c11Spyr #ifndef DEBUG
114feb9ff76Sreyk 	if (setgroups(1, &pw->pw_gid) ||
115feb9ff76Sreyk 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
116feb9ff76Sreyk 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
117feb9ff76Sreyk 		fatal("hce: can't drop privileges");
118adf98c11Spyr #endif
119feb9ff76Sreyk 
120641b8bafSpyr 	event_init();
121feb9ff76Sreyk 
122641b8bafSpyr 	if ((ibuf_pfe = calloc(1, sizeof(struct imsgbuf))) == NULL ||
123641b8bafSpyr 	    (ibuf_main = calloc(1, sizeof(struct imsgbuf))) == NULL)
124641b8bafSpyr 		fatal("hce");
125641b8bafSpyr 	imsg_init(ibuf_pfe, pipe_pfe2hce[0], hce_dispatch_imsg);
126641b8bafSpyr 	imsg_init(ibuf_main, pipe_parent2hce[1], hce_dispatch_parent);
127641b8bafSpyr 
128641b8bafSpyr 	ibuf_pfe->events = EV_READ;
129641b8bafSpyr 	event_set(&ibuf_pfe->ev, ibuf_pfe->fd, ibuf_pfe->events,
130641b8bafSpyr 	    ibuf_pfe->handler, ibuf_pfe);
131641b8bafSpyr 	event_add(&ibuf_pfe->ev, NULL);
132641b8bafSpyr 
133641b8bafSpyr 	ibuf_main->events = EV_READ;
134641b8bafSpyr 	event_set(&ibuf_main->ev, ibuf_main->fd, ibuf_main->events,
135641b8bafSpyr 	    ibuf_main->handler, ibuf_main);
136641b8bafSpyr 	event_add(&ibuf_main->ev, NULL);
137641b8bafSpyr 
138641b8bafSpyr 	signal_set(&ev_sigint, SIGINT, hce_sig_handler, NULL);
139641b8bafSpyr 	signal_set(&ev_sigterm, SIGTERM, hce_sig_handler, NULL);
140641b8bafSpyr 	signal_add(&ev_sigint, NULL);
141641b8bafSpyr 	signal_add(&ev_sigterm, NULL);
142641b8bafSpyr 	signal(SIGPIPE, SIG_IGN);
143fda2844dSpyr 	signal(SIGHUP, SIG_IGN);
144feb9ff76Sreyk 
145feb9ff76Sreyk 	/* setup pipes */
146feb9ff76Sreyk 	close(pipe_pfe2hce[1]);
147feb9ff76Sreyk 	close(pipe_parent2hce[0]);
148feb9ff76Sreyk 	close(pipe_parent2pfe[0]);
149feb9ff76Sreyk 	close(pipe_parent2pfe[1]);
1502edd718bSreyk 	for (i = 0; i < env->prefork_relay; i++) {
151053249cdSpyr 		close(pipe_parent2relay[i][0]);
152053249cdSpyr 		close(pipe_parent2relay[i][1]);
1532edd718bSreyk 		close(pipe_pfe2relay[i][0]);
1542edd718bSreyk 		close(pipe_pfe2relay[i][1]);
1552edd718bSreyk 	}
156feb9ff76Sreyk 
157641b8bafSpyr 	hce_setup_events();
158641b8bafSpyr 	event_dispatch();
159780e8f79Spyr 	hce_shutdown();
160780e8f79Spyr 
161780e8f79Spyr 	return (0);
162780e8f79Spyr }
163780e8f79Spyr 
164780e8f79Spyr void
165641b8bafSpyr hce_setup_events(void)
166780e8f79Spyr {
167780e8f79Spyr 	struct timeval	 tv;
168780e8f79Spyr 	struct table	*table;
169780e8f79Spyr 
170780e8f79Spyr 	if (!TAILQ_EMPTY(env->tables)) {
17101d85ec5Sreyk 		evtimer_set(&env->ev, hce_launch_checks, env);
17201d85ec5Sreyk 		bzero(&tv, sizeof(tv));
173feb9ff76Sreyk 		evtimer_add(&env->ev, &tv);
1742edd718bSreyk 	}
175feb9ff76Sreyk 
176e8fb3979Spyr 	if (env->flags & F_SSL) {
177e8fb3979Spyr 		ssl_init(env);
178780e8f79Spyr 		TAILQ_FOREACH(table, env->tables, entry) {
17968b79041Spyr 			if (!(table->conf.flags & F_SSL))
180e8fb3979Spyr 				continue;
181e8fb3979Spyr 			table->ssl_ctx = ssl_ctx_create(env);
182e8fb3979Spyr 		}
183e8fb3979Spyr 	}
184641b8bafSpyr }
185641b8bafSpyr 
186641b8bafSpyr void
187641b8bafSpyr hce_disable_events(void)
188641b8bafSpyr {
189641b8bafSpyr 	struct table	*table;
190641b8bafSpyr 	struct host	*host;
191641b8bafSpyr 
192641b8bafSpyr 	evtimer_del(&env->ev);
193641b8bafSpyr 	TAILQ_FOREACH(table, env->tables, entry) {
194641b8bafSpyr 		TAILQ_FOREACH(host, &table->hosts, entry) {
195641b8bafSpyr 			event_del(&host->cte.ev);
196641b8bafSpyr 			close(host->cte.s);
197641b8bafSpyr 		}
198641b8bafSpyr 	}
199641b8bafSpyr 	if (env->has_icmp) {
200641b8bafSpyr 		event_del(&env->icmp_send.ev);
201641b8bafSpyr 		event_del(&env->icmp_recv.ev);
202641b8bafSpyr 	}
203641b8bafSpyr 	if (env->has_icmp6) {
204641b8bafSpyr 		event_del(&env->icmp6_send.ev);
205641b8bafSpyr 		event_del(&env->icmp6_recv.ev);
206641b8bafSpyr 	}
207feb9ff76Sreyk }
208feb9ff76Sreyk 
209feb9ff76Sreyk void
210feb9ff76Sreyk hce_launch_checks(int fd, short event, void *arg)
211feb9ff76Sreyk {
212feb9ff76Sreyk 	struct host		*host;
213feb9ff76Sreyk 	struct table		*table;
21401d85ec5Sreyk 	struct timeval		 tv;
21501d85ec5Sreyk 
21601d85ec5Sreyk 	/*
21701d85ec5Sreyk 	 * notify pfe checks are done and schedule next check
21801d85ec5Sreyk 	 */
2197a0be62eSmsf 	imsg_compose(ibuf_pfe, IMSG_SYNC, 0, 0, -1, NULL, 0);
220780e8f79Spyr 	TAILQ_FOREACH(table, env->tables, entry) {
22101d85ec5Sreyk 		TAILQ_FOREACH(host, &table->hosts, entry) {
22201d85ec5Sreyk 			host->flags &= ~(F_CHECK_SENT|F_CHECK_DONE);
22301d85ec5Sreyk 			event_del(&host->cte.ev);
22401d85ec5Sreyk 		}
22501d85ec5Sreyk 	}
22601d85ec5Sreyk 
22701d85ec5Sreyk 	if (gettimeofday(&tv, NULL))
22801d85ec5Sreyk 		fatal("hce_launch_checks: gettimeofday");
229feb9ff76Sreyk 
230780e8f79Spyr 	TAILQ_FOREACH(table, env->tables, entry) {
23168b79041Spyr 		if (table->conf.flags & F_DISABLE)
2327e351ffdSreyk 			continue;
23318de159aSpyr 		if (table->conf.skip_cnt) {
23418de159aSpyr 			if (table->skipped++ > table->conf.skip_cnt)
23518de159aSpyr 				table->skipped = 0;
23618de159aSpyr 			if (table->skipped != 1)
23718de159aSpyr 				continue;
23818de159aSpyr 		}
23968b79041Spyr 		if (table->conf.check == CHECK_NOCHECK)
2407e351ffdSreyk 			fatalx("hce_launch_checks: unknown check type");
24101d85ec5Sreyk 
2427e351ffdSreyk 		TAILQ_FOREACH(host, &table->hosts, entry) {
2437e351ffdSreyk 			if (host->flags & F_DISABLE)
2447e351ffdSreyk 				continue;
2454156152fSreyk 			switch (table->conf.check) {
2464156152fSreyk 			case CHECK_ICMP:
24701d85ec5Sreyk 				schedule_icmp(env, host);
2484156152fSreyk 				break;
2494156152fSreyk 			case CHECK_SCRIPT:
2504156152fSreyk 				check_script(host);
2514156152fSreyk 				break;
2524156152fSreyk 			default:
25301d85ec5Sreyk 				/* Any other TCP-style checks */
2547e351ffdSreyk 				bzero(&host->cte, sizeof(host->cte));
2557e351ffdSreyk 				host->last_up = host->up;
2567e351ffdSreyk 				host->cte.host = host;
2577e351ffdSreyk 				host->cte.table = table;
25801d85ec5Sreyk 				bcopy(&tv, &host->cte.tv_start,
25901d85ec5Sreyk 				    sizeof(host->cte.tv_start));
2607e351ffdSreyk 				check_tcp(&host->cte);
2614156152fSreyk 				break;
2624156152fSreyk 			}
2637e351ffdSreyk 		}
2647e351ffdSreyk 	}
26501d85ec5Sreyk 	check_icmp(env, &tv);
26601d85ec5Sreyk 
26701d85ec5Sreyk 	bcopy(&env->interval, &tv, sizeof(tv));
26801d85ec5Sreyk 	evtimer_add(&env->ev, &tv);
2697e351ffdSreyk }
2707e351ffdSreyk 
2717e351ffdSreyk void
2727e351ffdSreyk hce_notify_done(struct host *host, const char *msg)
2737e351ffdSreyk {
274609cf3a7Sreyk 	struct table		*table;
2757e351ffdSreyk 	struct ctl_status	 st;
276609cf3a7Sreyk 	struct timeval		 tv_now, tv_dur;
277609cf3a7Sreyk 	u_long			 duration;
278609cf3a7Sreyk 	u_int			 logopt;
2797e351ffdSreyk 
2802edd718bSreyk 	if (host->up == HOST_DOWN && host->retry_cnt) {
2812edd718bSreyk 		log_debug("hce_notify_done: host %s retry %d",
28268b79041Spyr 		    host->conf.name, host->retry_cnt);
283bd2508bcSreyk 		host->up = host->last_up;
2842edd718bSreyk 		host->retry_cnt--;
2852edd718bSreyk 	} else
28668b79041Spyr 		host->retry_cnt = host->conf.retry;
2872edd718bSreyk 	if (host->up != HOST_UNKNOWN) {
2882edd718bSreyk 		host->check_cnt++;
2892edd718bSreyk 		if (host->up == HOST_UP)
2902edd718bSreyk 			host->up_cnt++;
2912edd718bSreyk 	}
29268b79041Spyr 	st.id = host->conf.id;
293feb9ff76Sreyk 	st.up = host->up;
2942edd718bSreyk 	st.check_cnt = host->check_cnt;
2952edd718bSreyk 	st.retry_cnt = host->retry_cnt;
29601d85ec5Sreyk 	host->flags |= (F_CHECK_SENT|F_CHECK_DONE);
2977e351ffdSreyk 	if (msg)
29868b79041Spyr 		log_debug("hce_notify_done: %s (%s)", host->conf.name, msg);
299609cf3a7Sreyk 
3007a0be62eSmsf 	imsg_compose(ibuf_pfe, IMSG_HOST_STATUS, 0, 0, -1, &st, sizeof(st));
3012edd718bSreyk 	if (host->up != host->last_up)
3022edd718bSreyk 		logopt = HOSTSTATED_OPT_LOGUPDATE;
3032edd718bSreyk 	else
304609cf3a7Sreyk 		logopt = HOSTSTATED_OPT_LOGNOTIFY;
305609cf3a7Sreyk 
306609cf3a7Sreyk 	if (gettimeofday(&tv_now, NULL))
307609cf3a7Sreyk 		fatal("hce_notify_done: gettimeofday");
308609cf3a7Sreyk 	timersub(&tv_now, &host->cte.tv_start, &tv_dur);
309609cf3a7Sreyk 	if (timercmp(&host->cte.tv_start, &tv_dur, >))
310609cf3a7Sreyk 		duration = (tv_dur.tv_sec * 1000) + (tv_dur.tv_usec / 1000.0);
311609cf3a7Sreyk 	else
312609cf3a7Sreyk 		duration = 0;
313609cf3a7Sreyk 
31468b79041Spyr 	if ((table = table_find(env, host->conf.tableid)) == NULL)
3152edd718bSreyk 		fatalx("hce_notify_done: invalid table id");
3162edd718bSreyk 
317609cf3a7Sreyk 	if (env->opts & logopt) {
3182edd718bSreyk 		log_info("host %s, check %s%s (%lums), state %s -> %s, "
3192edd718bSreyk 		    "availability %s",
32068b79041Spyr 		    host->conf.name, table_check(table->conf.check),
32168b79041Spyr 		    (table->conf.flags & F_SSL) ? " use ssl" : "", duration,
3222edd718bSreyk 		    host_status(host->last_up), host_status(host->up),
3232edd718bSreyk 		    print_availability(host->check_cnt, host->up_cnt));
324feb9ff76Sreyk 	}
325609cf3a7Sreyk 	host->last_up = host->up;
326feb9ff76Sreyk }
327feb9ff76Sreyk 
328feb9ff76Sreyk void
329feb9ff76Sreyk hce_shutdown(void)
330feb9ff76Sreyk {
331feb9ff76Sreyk 	log_info("host check engine exiting");
332feb9ff76Sreyk 	_exit(0);
333feb9ff76Sreyk }
334feb9ff76Sreyk 
335feb9ff76Sreyk void
336feb9ff76Sreyk hce_dispatch_imsg(int fd, short event, void *ptr)
337feb9ff76Sreyk {
338feb9ff76Sreyk 	struct imsgbuf		*ibuf;
339feb9ff76Sreyk 	struct imsg		 imsg;
340feb9ff76Sreyk 	ssize_t			 n;
341feb9ff76Sreyk 	objid_t			 id;
342feb9ff76Sreyk 	struct host		*host;
343feb9ff76Sreyk 	struct table		*table;
344feb9ff76Sreyk 
345feb9ff76Sreyk 	ibuf = ptr;
346feb9ff76Sreyk 	switch (event) {
347feb9ff76Sreyk 	case EV_READ:
348feb9ff76Sreyk 		if ((n = imsg_read(ibuf)) == -1)
349feb9ff76Sreyk 			fatal("hce_dispatch_imsg: imsg_read_error");
350ddfd9103Spyr 		if (n == 0) {
351ddfd9103Spyr 			/* this pipe is dead, so remove the event handler */
352ddfd9103Spyr 			event_del(&ibuf->ev);
353ddfd9103Spyr 			event_loopexit(NULL);
354ddfd9103Spyr 			return;
355ddfd9103Spyr 		}
356feb9ff76Sreyk 		break;
357feb9ff76Sreyk 	case EV_WRITE:
358feb9ff76Sreyk 		if (msgbuf_write(&ibuf->w) == -1)
359feb9ff76Sreyk 			fatal("hce_dispatch_imsg: msgbuf_write");
360feb9ff76Sreyk 		imsg_event_add(ibuf);
361feb9ff76Sreyk 		return;
362feb9ff76Sreyk 	default:
363feb9ff76Sreyk 		fatalx("hce_dispatch_imsg: unknown event");
364feb9ff76Sreyk 	}
365feb9ff76Sreyk 
366feb9ff76Sreyk 	for (;;) {
367feb9ff76Sreyk 		if ((n = imsg_get(ibuf, &imsg)) == -1)
368feb9ff76Sreyk 			fatal("hce_dispatch_imsg: imsg_read error");
369feb9ff76Sreyk 		if (n == 0)
370feb9ff76Sreyk 			break;
371feb9ff76Sreyk 
372feb9ff76Sreyk 		switch (imsg.hdr.type) {
373feb9ff76Sreyk 		case IMSG_HOST_DISABLE:
374feb9ff76Sreyk 			memcpy(&id, imsg.data, sizeof(id));
375feb9ff76Sreyk 			if ((host = host_find(env, id)) == NULL)
376feb9ff76Sreyk 				fatalx("hce_dispatch_imsg: desynchronized");
377feb9ff76Sreyk 			host->flags |= F_DISABLE;
378feb9ff76Sreyk 			host->up = HOST_UNKNOWN;
3792edd718bSreyk 			host->check_cnt = 0;
3802edd718bSreyk 			host->up_cnt = 0;
381feb9ff76Sreyk 			break;
382feb9ff76Sreyk 		case IMSG_HOST_ENABLE:
383feb9ff76Sreyk 			memcpy(&id, imsg.data, sizeof(id));
384feb9ff76Sreyk 			if ((host = host_find(env, id)) == NULL)
385feb9ff76Sreyk 				fatalx("hce_dispatch_imsg: desynchronized");
386feb9ff76Sreyk 			host->flags &= ~(F_DISABLE);
387feb9ff76Sreyk 			host->up = HOST_UNKNOWN;
388feb9ff76Sreyk 			break;
389feb9ff76Sreyk 		case IMSG_TABLE_DISABLE:
390feb9ff76Sreyk 			memcpy(&id, imsg.data, sizeof(id));
391feb9ff76Sreyk 			if ((table = table_find(env, id)) == NULL)
392feb9ff76Sreyk 				fatalx("hce_dispatch_imsg: desynchronized");
39368b79041Spyr 			table->conf.flags |= F_DISABLE;
394feb9ff76Sreyk 			TAILQ_FOREACH(host, &table->hosts, entry)
395feb9ff76Sreyk 				host->up = HOST_UNKNOWN;
396feb9ff76Sreyk 			break;
397feb9ff76Sreyk 		case IMSG_TABLE_ENABLE:
398feb9ff76Sreyk 			memcpy(&id, imsg.data, sizeof(id));
399feb9ff76Sreyk 			if ((table = table_find(env, id)) == NULL)
400feb9ff76Sreyk 				fatalx("hce_dispatch_imsg: desynchronized");
40168b79041Spyr 			table->conf.flags &= ~(F_DISABLE);
402feb9ff76Sreyk 			TAILQ_FOREACH(host, &table->hosts, entry)
403feb9ff76Sreyk 				host->up = HOST_UNKNOWN;
404feb9ff76Sreyk 			break;
405cd65ce7bSpyr 		case IMSG_CTL_POLL:
406cd65ce7bSpyr 			evtimer_del(&env->ev);
407f98352d8Spyr 			TAILQ_FOREACH(table, env->tables, entry)
408f98352d8Spyr 				table->skipped = 0;
409cd65ce7bSpyr 			hce_launch_checks(-1, EV_TIMEOUT, env);
410cd65ce7bSpyr 			break;
411feb9ff76Sreyk 		default:
412feb9ff76Sreyk 			log_debug("hce_dispatch_msg: unexpected imsg %d",
413feb9ff76Sreyk 			    imsg.hdr.type);
414feb9ff76Sreyk 			break;
415feb9ff76Sreyk 		}
416feb9ff76Sreyk 		imsg_free(&imsg);
417feb9ff76Sreyk 	}
418feb9ff76Sreyk 	imsg_event_add(ibuf);
419feb9ff76Sreyk }
420feb9ff76Sreyk 
421feb9ff76Sreyk void
422feb9ff76Sreyk hce_dispatch_parent(int fd, short event, void * ptr)
423feb9ff76Sreyk {
424feb9ff76Sreyk 	struct imsgbuf		*ibuf;
425feb9ff76Sreyk 	struct imsg		 imsg;
4264156152fSreyk 	struct ctl_script	 scr;
427feb9ff76Sreyk 	ssize_t			 n;
428adf98c11Spyr 	size_t			 len;
429adf98c11Spyr 
430adf98c11Spyr 	static struct table	*table = NULL;
431adf98c11Spyr 	struct host		*host;
432feb9ff76Sreyk 
433feb9ff76Sreyk 	ibuf = ptr;
434feb9ff76Sreyk 	switch (event) {
435feb9ff76Sreyk 	case EV_READ:
436feb9ff76Sreyk 		if ((n = imsg_read(ibuf)) == -1)
437feb9ff76Sreyk 			fatal("hce_dispatch_parent: imsg_read error");
438ddfd9103Spyr 		if (n == 0) {
439ddfd9103Spyr 			/* this pipe is dead, so remove the event handler */
440ddfd9103Spyr 			event_del(&ibuf->ev);
441ddfd9103Spyr 			event_loopexit(NULL);
442ddfd9103Spyr 			return;
443ddfd9103Spyr 		}
444feb9ff76Sreyk 		break;
445feb9ff76Sreyk 	case EV_WRITE:
446feb9ff76Sreyk 		if (msgbuf_write(&ibuf->w) == -1)
447feb9ff76Sreyk 			fatal("hce_dispatch_parent: msgbuf_write");
448feb9ff76Sreyk 		imsg_event_add(ibuf);
449feb9ff76Sreyk 		return;
450feb9ff76Sreyk 	default:
451feb9ff76Sreyk 		fatalx("hce_dispatch_parent: unknown event");
452feb9ff76Sreyk 	}
453feb9ff76Sreyk 
454feb9ff76Sreyk 	for (;;) {
455feb9ff76Sreyk 		if ((n = imsg_get(ibuf, &imsg)) == -1)
456feb9ff76Sreyk 			fatal("hce_dispatch_parent: imsg_read error");
457feb9ff76Sreyk 		if (n == 0)
458feb9ff76Sreyk 			break;
459feb9ff76Sreyk 
460feb9ff76Sreyk 		switch (imsg.hdr.type) {
4614156152fSreyk 		case IMSG_SCRIPT:
4624156152fSreyk 			if (imsg.hdr.len - IMSG_HEADER_SIZE !=
4634156152fSreyk 			    sizeof(scr))
4644156152fSreyk 				fatalx("hce_dispatch_parent: "
4654156152fSreyk 				    "invalid size of script request");
4664156152fSreyk 			bcopy(imsg.data, &scr, sizeof(scr));
4674156152fSreyk 			script_done(env, &scr);
4684156152fSreyk 			break;
469adf98c11Spyr 		case IMSG_RECONF:
470adf98c11Spyr 			log_debug("hce: reloading configuration");
471adf98c11Spyr 			if (imsg.hdr.len !=
472adf98c11Spyr 			    sizeof(struct hoststated) + IMSG_HEADER_SIZE)
473adf98c11Spyr 				fatalx("corrupted reload data");
474adf98c11Spyr 			hce_disable_events();
475adf98c11Spyr 			purge_config(env, PURGE_TABLES);
476adf98c11Spyr 			merge_config(env, (struct hoststated *)imsg.data);
477adf98c11Spyr 
478adf98c11Spyr 			env->tables = calloc(1, sizeof(*env->tables));
479adf98c11Spyr 			if (env->tables == NULL)
480adf98c11Spyr 				fatal(NULL);
481adf98c11Spyr 
482adf98c11Spyr 			TAILQ_INIT(env->tables);
483adf98c11Spyr 			break;
484adf98c11Spyr 		case IMSG_RECONF_TABLE:
485adf98c11Spyr 			if ((table = calloc(1, sizeof(*table))) == NULL)
486adf98c11Spyr 				fatal(NULL);
487adf98c11Spyr 			memcpy(&table->conf, imsg.data, sizeof(table->conf));
488adf98c11Spyr 			TAILQ_INIT(&table->hosts);
489adf98c11Spyr 			TAILQ_INSERT_TAIL(env->tables, table, entry);
490adf98c11Spyr 			break;
491adf98c11Spyr 		case IMSG_RECONF_SENDBUF:
492adf98c11Spyr 			len = imsg.hdr.len - IMSG_HEADER_SIZE;
493adf98c11Spyr 			table->sendbuf = calloc(1, len);
494adf98c11Spyr 			(void)strlcpy(table->sendbuf, (char *)imsg.data, len);
495adf98c11Spyr 			break;
496adf98c11Spyr 		case IMSG_RECONF_HOST:
497adf98c11Spyr 			if ((host = calloc(1, sizeof(*host))) == NULL)
498adf98c11Spyr 				fatal(NULL);
499adf98c11Spyr 			memcpy(&host->conf, imsg.data, sizeof(host->conf));
500adf98c11Spyr 			host->tablename = table->conf.name;
501adf98c11Spyr 			TAILQ_INSERT_TAIL(&table->hosts, host, entry);
502adf98c11Spyr 			break;
503adf98c11Spyr 		case IMSG_RECONF_END:
504adf98c11Spyr 			log_warnx("hce: configuration reloaded");
505adf98c11Spyr 			hce_setup_events();
506adf98c11Spyr 			break;
507feb9ff76Sreyk 		default:
508feb9ff76Sreyk 			log_debug("hce_dispatch_parent: unexpected imsg %d",
509feb9ff76Sreyk 			    imsg.hdr.type);
510feb9ff76Sreyk 			break;
511feb9ff76Sreyk 		}
512feb9ff76Sreyk 		imsg_free(&imsg);
513feb9ff76Sreyk 	}
5144156152fSreyk 	imsg_event_add(ibuf);
515feb9ff76Sreyk }
516