xref: /openbsd/usr.sbin/relayd/hce.c (revision adf98c11)
1*adf98c11Spyr /*	$OpenBSD: hce.c,v 1.26 2007/06/07 07:19:50 pyr Exp $	*/
2feb9ff76Sreyk 
3feb9ff76Sreyk /*
4feb9ff76Sreyk  * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.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/queue.h>
20feb9ff76Sreyk #include <sys/param.h>
21feb9ff76Sreyk #include <sys/types.h>
22feb9ff76Sreyk #include <sys/time.h>
23feb9ff76Sreyk #include <sys/stat.h>
24feb9ff76Sreyk #include <sys/socket.h>
25feb9ff76Sreyk #include <sys/un.h>
26feb9ff76Sreyk #include <netinet/in_systm.h>
27feb9ff76Sreyk #include <netinet/in.h>
28feb9ff76Sreyk #include <netinet/ip.h>
29feb9ff76Sreyk #include <net/if.h>
30feb9ff76Sreyk #include <errno.h>
31feb9ff76Sreyk #include <event.h>
32feb9ff76Sreyk #include <fcntl.h>
33feb9ff76Sreyk #include <stdlib.h>
34feb9ff76Sreyk #include <string.h>
35feb9ff76Sreyk #include <unistd.h>
36feb9ff76Sreyk #include <err.h>
37feb9ff76Sreyk #include <pwd.h>
38feb9ff76Sreyk 
39e8fb3979Spyr #include <openssl/ssl.h>
40e8fb3979Spyr 
41ee9f3836Sderaadt #include "hoststated.h"
42feb9ff76Sreyk 
43feb9ff76Sreyk void	hce_sig_handler(int sig, short, void *);
44feb9ff76Sreyk void	hce_shutdown(void);
45feb9ff76Sreyk void	hce_dispatch_imsg(int, short, void *);
46feb9ff76Sreyk void	hce_dispatch_parent(int, short, void *);
47feb9ff76Sreyk void	hce_launch_checks(int, short, void *);
48641b8bafSpyr void	hce_setup_events(void);
49641b8bafSpyr void	hce_disable_events(void);
50feb9ff76Sreyk 
518f79868bSpyr static struct hoststated *env = NULL;
52feb9ff76Sreyk struct imsgbuf		*ibuf_pfe;
53feb9ff76Sreyk struct imsgbuf		*ibuf_main;
54780e8f79Spyr int			 pipe_pfe;
55780e8f79Spyr int			 pipe_parent;
56780e8f79Spyr int			 running = 0;
57feb9ff76Sreyk 
58feb9ff76Sreyk void
59feb9ff76Sreyk hce_sig_handler(int sig, short event, void *arg)
60feb9ff76Sreyk {
61feb9ff76Sreyk 	switch (sig) {
62feb9ff76Sreyk 	case SIGINT:
63feb9ff76Sreyk 	case SIGTERM:
64feb9ff76Sreyk 		hce_shutdown();
65780e8f79Spyr 		break;
66780e8f79Spyr 	case SIGHUP:
67*adf98c11Spyr 		/* nothing */
68780e8f79Spyr 		break;
69feb9ff76Sreyk 	default:
70feb9ff76Sreyk 		fatalx("hce_sig_handler: unexpected signal");
71feb9ff76Sreyk 	}
72feb9ff76Sreyk }
73feb9ff76Sreyk 
74feb9ff76Sreyk pid_t
758f79868bSpyr hce(struct hoststated *x_env, int pipe_parent2pfe[2], int pipe_parent2hce[2],
76053249cdSpyr     int pipe_parent2relay[RELAY_MAXPROC][2], int pipe_pfe2hce[2],
772edd718bSreyk     int pipe_pfe2relay[RELAY_MAXPROC][2])
78feb9ff76Sreyk {
79feb9ff76Sreyk 	pid_t		 pid;
80feb9ff76Sreyk 	struct passwd	*pw;
812edd718bSreyk 	int		 i;
82641b8bafSpyr 	struct event	 ev_sigint;
83641b8bafSpyr 	struct event	 ev_sigterm;
84*adf98c11Spyr 	struct event	 ev_sighup;
85feb9ff76Sreyk 
86feb9ff76Sreyk 	switch (pid = fork()) {
87feb9ff76Sreyk 	case -1:
88feb9ff76Sreyk 		fatal("hce: cannot fork");
89feb9ff76Sreyk 	case 0:
90feb9ff76Sreyk 		break;
91feb9ff76Sreyk 	default:
92feb9ff76Sreyk 		return (pid);
93feb9ff76Sreyk 	}
94feb9ff76Sreyk 
95feb9ff76Sreyk 	env = x_env;
9679446c9fSpyr 	purge_config(env, PURGE_SERVICES|PURGE_RELAYS|PURGE_PROTOS);
97feb9ff76Sreyk 
988f79868bSpyr 	if ((pw = getpwnam(HOSTSTATED_USER)) == NULL)
99feb9ff76Sreyk 		fatal("hce: getpwnam");
100feb9ff76Sreyk 
101*adf98c11Spyr #ifndef DEBUG
102feb9ff76Sreyk 	if (chroot(pw->pw_dir) == -1)
103feb9ff76Sreyk 		fatal("hce: chroot");
104feb9ff76Sreyk 	if (chdir("/") == -1)
105feb9ff76Sreyk 		fatal("hce: chdir(\"/\")");
106*adf98c11Spyr #else
107*adf98c11Spyr #warning disabling privilege revocation and chroot in DEBUG mode
108*adf98c11Spyr #endif
109feb9ff76Sreyk 
110feb9ff76Sreyk 	setproctitle("host check engine");
1118f79868bSpyr 	hoststated_process = PROC_HCE;
112feb9ff76Sreyk 
11301d85ec5Sreyk 	/* this is needed for icmp tests */
11401d85ec5Sreyk 	icmp_init(env);
11501d85ec5Sreyk 
116*adf98c11Spyr #ifndef DEBUG
117feb9ff76Sreyk 	if (setgroups(1, &pw->pw_gid) ||
118feb9ff76Sreyk 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
119feb9ff76Sreyk 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
120feb9ff76Sreyk 		fatal("hce: can't drop privileges");
121*adf98c11Spyr #endif
122feb9ff76Sreyk 
123641b8bafSpyr 	event_init();
124feb9ff76Sreyk 
125641b8bafSpyr 	if ((ibuf_pfe = calloc(1, sizeof(struct imsgbuf))) == NULL ||
126641b8bafSpyr 	    (ibuf_main = calloc(1, sizeof(struct imsgbuf))) == NULL)
127641b8bafSpyr 		fatal("hce");
128641b8bafSpyr 	imsg_init(ibuf_pfe, pipe_pfe2hce[0], hce_dispatch_imsg);
129641b8bafSpyr 	imsg_init(ibuf_main, pipe_parent2hce[1], hce_dispatch_parent);
130641b8bafSpyr 
131641b8bafSpyr 	ibuf_pfe->events = EV_READ;
132641b8bafSpyr 	event_set(&ibuf_pfe->ev, ibuf_pfe->fd, ibuf_pfe->events,
133641b8bafSpyr 	    ibuf_pfe->handler, ibuf_pfe);
134641b8bafSpyr 	event_add(&ibuf_pfe->ev, NULL);
135641b8bafSpyr 
136641b8bafSpyr 	ibuf_main->events = EV_READ;
137641b8bafSpyr 	event_set(&ibuf_main->ev, ibuf_main->fd, ibuf_main->events,
138641b8bafSpyr 	    ibuf_main->handler, ibuf_main);
139641b8bafSpyr 	event_add(&ibuf_main->ev, NULL);
140641b8bafSpyr 
141641b8bafSpyr 	signal_set(&ev_sigint, SIGINT, hce_sig_handler, NULL);
142641b8bafSpyr 	signal_set(&ev_sigterm, SIGTERM, hce_sig_handler, NULL);
143*adf98c11Spyr 	signal_set(&ev_sighup, SIGHUP, hce_sig_handler, NULL);
144641b8bafSpyr 	signal_add(&ev_sigint, NULL);
145641b8bafSpyr 	signal_add(&ev_sigterm, NULL);
146*adf98c11Spyr 	signal_add(&ev_sighup, NULL);
147641b8bafSpyr 	signal(SIGPIPE, SIG_IGN);
148feb9ff76Sreyk 
149feb9ff76Sreyk 	/* setup pipes */
150feb9ff76Sreyk 	close(pipe_pfe2hce[1]);
151feb9ff76Sreyk 	close(pipe_parent2hce[0]);
152feb9ff76Sreyk 	close(pipe_parent2pfe[0]);
153feb9ff76Sreyk 	close(pipe_parent2pfe[1]);
1542edd718bSreyk 	for (i = 0; i < env->prefork_relay; i++) {
155053249cdSpyr 		close(pipe_parent2relay[i][0]);
156053249cdSpyr 		close(pipe_parent2relay[i][1]);
1572edd718bSreyk 		close(pipe_pfe2relay[i][0]);
1582edd718bSreyk 		close(pipe_pfe2relay[i][1]);
1592edd718bSreyk 	}
160feb9ff76Sreyk 
161641b8bafSpyr 	hce_setup_events();
162641b8bafSpyr 	event_dispatch();
163780e8f79Spyr 	hce_shutdown();
164780e8f79Spyr 
165780e8f79Spyr 	return (0);
166780e8f79Spyr }
167780e8f79Spyr 
168780e8f79Spyr void
169641b8bafSpyr hce_setup_events(void)
170780e8f79Spyr {
171780e8f79Spyr 	struct timeval	 tv;
172780e8f79Spyr 	struct table	*table;
173780e8f79Spyr 
174780e8f79Spyr 	if (!TAILQ_EMPTY(env->tables)) {
17501d85ec5Sreyk 		evtimer_set(&env->ev, hce_launch_checks, env);
17601d85ec5Sreyk 		bzero(&tv, sizeof(tv));
177feb9ff76Sreyk 		evtimer_add(&env->ev, &tv);
1782edd718bSreyk 	}
179feb9ff76Sreyk 
180e8fb3979Spyr 	if (env->flags & F_SSL) {
181e8fb3979Spyr 		ssl_init(env);
182780e8f79Spyr 		TAILQ_FOREACH(table, env->tables, entry) {
18368b79041Spyr 			if (!(table->conf.flags & F_SSL))
184e8fb3979Spyr 				continue;
185e8fb3979Spyr 			table->ssl_ctx = ssl_ctx_create(env);
186e8fb3979Spyr 		}
187e8fb3979Spyr 	}
188641b8bafSpyr }
189641b8bafSpyr 
190641b8bafSpyr void
191641b8bafSpyr hce_disable_events(void)
192641b8bafSpyr {
193641b8bafSpyr 	struct table	*table;
194641b8bafSpyr 	struct host	*host;
195641b8bafSpyr 
196641b8bafSpyr 	evtimer_del(&env->ev);
197641b8bafSpyr 	TAILQ_FOREACH(table, env->tables, entry) {
198641b8bafSpyr 		TAILQ_FOREACH(host, &table->hosts, entry) {
199641b8bafSpyr 			event_del(&host->cte.ev);
200641b8bafSpyr 			close(host->cte.s);
201641b8bafSpyr 		}
202641b8bafSpyr 	}
203641b8bafSpyr 	if (env->has_icmp) {
204641b8bafSpyr 		event_del(&env->icmp_send.ev);
205641b8bafSpyr 		event_del(&env->icmp_recv.ev);
206641b8bafSpyr 	}
207641b8bafSpyr 	if (env->has_icmp6) {
208641b8bafSpyr 		event_del(&env->icmp6_send.ev);
209641b8bafSpyr 		event_del(&env->icmp6_recv.ev);
210641b8bafSpyr 	}
211feb9ff76Sreyk }
212feb9ff76Sreyk 
213feb9ff76Sreyk void
214feb9ff76Sreyk hce_launch_checks(int fd, short event, void *arg)
215feb9ff76Sreyk {
216feb9ff76Sreyk 	struct host		*host;
217feb9ff76Sreyk 	struct table		*table;
21801d85ec5Sreyk 	struct timeval		 tv;
21901d85ec5Sreyk 
22001d85ec5Sreyk 	/*
22101d85ec5Sreyk 	 * notify pfe checks are done and schedule next check
22201d85ec5Sreyk 	 */
22301d85ec5Sreyk 	imsg_compose(ibuf_pfe, IMSG_SYNC, 0, 0, NULL, 0);
224780e8f79Spyr 	TAILQ_FOREACH(table, env->tables, entry) {
22501d85ec5Sreyk 		TAILQ_FOREACH(host, &table->hosts, entry) {
22601d85ec5Sreyk 			host->flags &= ~(F_CHECK_SENT|F_CHECK_DONE);
22701d85ec5Sreyk 			event_del(&host->cte.ev);
22801d85ec5Sreyk 		}
22901d85ec5Sreyk 	}
23001d85ec5Sreyk 
23101d85ec5Sreyk 	if (gettimeofday(&tv, NULL))
23201d85ec5Sreyk 		fatal("hce_launch_checks: gettimeofday");
233feb9ff76Sreyk 
234780e8f79Spyr 	TAILQ_FOREACH(table, env->tables, entry) {
23568b79041Spyr 		if (table->conf.flags & F_DISABLE)
2367e351ffdSreyk 			continue;
23768b79041Spyr 		if (table->conf.check == CHECK_NOCHECK)
2387e351ffdSreyk 			fatalx("hce_launch_checks: unknown check type");
23901d85ec5Sreyk 
2407e351ffdSreyk 		TAILQ_FOREACH(host, &table->hosts, entry) {
2417e351ffdSreyk 			if (host->flags & F_DISABLE)
2427e351ffdSreyk 				continue;
2434156152fSreyk 			switch (table->conf.check) {
2444156152fSreyk 			case CHECK_ICMP:
24501d85ec5Sreyk 				schedule_icmp(env, host);
2464156152fSreyk 				break;
2474156152fSreyk 			case CHECK_SCRIPT:
2484156152fSreyk 				check_script(host);
2494156152fSreyk 				break;
2504156152fSreyk 			default:
25101d85ec5Sreyk 				/* Any other TCP-style checks */
2527e351ffdSreyk 				bzero(&host->cte, sizeof(host->cte));
2537e351ffdSreyk 				host->last_up = host->up;
2547e351ffdSreyk 				host->cte.host = host;
2557e351ffdSreyk 				host->cte.table = table;
25601d85ec5Sreyk 				bcopy(&tv, &host->cte.tv_start,
25701d85ec5Sreyk 				    sizeof(host->cte.tv_start));
2587e351ffdSreyk 				check_tcp(&host->cte);
2594156152fSreyk 				break;
2604156152fSreyk 			}
2617e351ffdSreyk 		}
2627e351ffdSreyk 	}
26301d85ec5Sreyk 	check_icmp(env, &tv);
26401d85ec5Sreyk 
26501d85ec5Sreyk 	bcopy(&env->interval, &tv, sizeof(tv));
26601d85ec5Sreyk 	evtimer_add(&env->ev, &tv);
2677e351ffdSreyk }
2687e351ffdSreyk 
2697e351ffdSreyk void
2707e351ffdSreyk hce_notify_done(struct host *host, const char *msg)
2717e351ffdSreyk {
272609cf3a7Sreyk 	struct table		*table;
2737e351ffdSreyk 	struct ctl_status	 st;
274609cf3a7Sreyk 	struct timeval		 tv_now, tv_dur;
275609cf3a7Sreyk 	u_long			 duration;
276609cf3a7Sreyk 	u_int			 logopt;
2777e351ffdSreyk 
2782edd718bSreyk 	if (host->up == HOST_DOWN && host->retry_cnt) {
2792edd718bSreyk 		log_debug("hce_notify_done: host %s retry %d",
28068b79041Spyr 		    host->conf.name, host->retry_cnt);
281bd2508bcSreyk 		host->up = host->last_up;
2822edd718bSreyk 		host->retry_cnt--;
2832edd718bSreyk 	} else
28468b79041Spyr 		host->retry_cnt = host->conf.retry;
2852edd718bSreyk 	if (host->up != HOST_UNKNOWN) {
2862edd718bSreyk 		host->check_cnt++;
2872edd718bSreyk 		if (host->up == HOST_UP)
2882edd718bSreyk 			host->up_cnt++;
2892edd718bSreyk 	}
29068b79041Spyr 	st.id = host->conf.id;
291feb9ff76Sreyk 	st.up = host->up;
2922edd718bSreyk 	st.check_cnt = host->check_cnt;
2932edd718bSreyk 	st.retry_cnt = host->retry_cnt;
29401d85ec5Sreyk 	host->flags |= (F_CHECK_SENT|F_CHECK_DONE);
2957e351ffdSreyk 	if (msg)
29668b79041Spyr 		log_debug("hce_notify_done: %s (%s)", host->conf.name, msg);
297609cf3a7Sreyk 
2987e351ffdSreyk 	imsg_compose(ibuf_pfe, IMSG_HOST_STATUS, 0, 0, &st, sizeof(st));
2992edd718bSreyk 	if (host->up != host->last_up)
3002edd718bSreyk 		logopt = HOSTSTATED_OPT_LOGUPDATE;
3012edd718bSreyk 	else
302609cf3a7Sreyk 		logopt = HOSTSTATED_OPT_LOGNOTIFY;
303609cf3a7Sreyk 
304609cf3a7Sreyk 	if (gettimeofday(&tv_now, NULL))
305609cf3a7Sreyk 		fatal("hce_notify_done: gettimeofday");
306609cf3a7Sreyk 	timersub(&tv_now, &host->cte.tv_start, &tv_dur);
307609cf3a7Sreyk 	if (timercmp(&host->cte.tv_start, &tv_dur, >))
308609cf3a7Sreyk 		duration = (tv_dur.tv_sec * 1000) + (tv_dur.tv_usec / 1000.0);
309609cf3a7Sreyk 	else
310609cf3a7Sreyk 		duration = 0;
311609cf3a7Sreyk 
31268b79041Spyr 	if ((table = table_find(env, host->conf.tableid)) == NULL)
3132edd718bSreyk 		fatalx("hce_notify_done: invalid table id");
3142edd718bSreyk 
315609cf3a7Sreyk 	if (env->opts & logopt) {
3162edd718bSreyk 		log_info("host %s, check %s%s (%lums), state %s -> %s, "
3172edd718bSreyk 		    "availability %s",
31868b79041Spyr 		    host->conf.name, table_check(table->conf.check),
31968b79041Spyr 		    (table->conf.flags & F_SSL) ? " use ssl" : "", duration,
3202edd718bSreyk 		    host_status(host->last_up), host_status(host->up),
3212edd718bSreyk 		    print_availability(host->check_cnt, host->up_cnt));
322feb9ff76Sreyk 	}
323609cf3a7Sreyk 	host->last_up = host->up;
324feb9ff76Sreyk }
325feb9ff76Sreyk 
326feb9ff76Sreyk void
327feb9ff76Sreyk hce_shutdown(void)
328feb9ff76Sreyk {
329feb9ff76Sreyk 	log_info("host check engine exiting");
330feb9ff76Sreyk 	_exit(0);
331feb9ff76Sreyk }
332feb9ff76Sreyk 
333feb9ff76Sreyk void
334feb9ff76Sreyk hce_dispatch_imsg(int fd, short event, void *ptr)
335feb9ff76Sreyk {
336feb9ff76Sreyk 	struct imsgbuf		*ibuf;
337feb9ff76Sreyk 	struct imsg		 imsg;
338feb9ff76Sreyk 	ssize_t			 n;
339feb9ff76Sreyk 	objid_t			 id;
340feb9ff76Sreyk 	struct host		*host;
341feb9ff76Sreyk 	struct table		*table;
342feb9ff76Sreyk 
343feb9ff76Sreyk 	ibuf = ptr;
344feb9ff76Sreyk 	switch (event) {
345feb9ff76Sreyk 	case EV_READ:
346feb9ff76Sreyk 		if ((n = imsg_read(ibuf)) == -1)
347feb9ff76Sreyk 			fatal("hce_dispatch_imsg: imsg_read_error");
348feb9ff76Sreyk 		if (n == 0)
349feb9ff76Sreyk 			fatalx("hce_dispatch_imsg: pipe closed");
350feb9ff76Sreyk 		break;
351feb9ff76Sreyk 	case EV_WRITE:
352feb9ff76Sreyk 		if (msgbuf_write(&ibuf->w) == -1)
353feb9ff76Sreyk 			fatal("hce_dispatch_imsg: msgbuf_write");
354feb9ff76Sreyk 		imsg_event_add(ibuf);
355feb9ff76Sreyk 		return;
356feb9ff76Sreyk 	default:
357feb9ff76Sreyk 		fatalx("hce_dispatch_imsg: unknown event");
358feb9ff76Sreyk 	}
359feb9ff76Sreyk 
360feb9ff76Sreyk 	for (;;) {
361feb9ff76Sreyk 		if ((n = imsg_get(ibuf, &imsg)) == -1)
362feb9ff76Sreyk 			fatal("hce_dispatch_imsg: imsg_read error");
363feb9ff76Sreyk 		if (n == 0)
364feb9ff76Sreyk 			break;
365feb9ff76Sreyk 
366feb9ff76Sreyk 		switch (imsg.hdr.type) {
367feb9ff76Sreyk 		case IMSG_HOST_DISABLE:
368feb9ff76Sreyk 			memcpy(&id, imsg.data, sizeof(id));
369feb9ff76Sreyk 			if ((host = host_find(env, id)) == NULL)
370feb9ff76Sreyk 				fatalx("hce_dispatch_imsg: desynchronized");
371feb9ff76Sreyk 			host->flags |= F_DISABLE;
372feb9ff76Sreyk 			host->up = HOST_UNKNOWN;
3732edd718bSreyk 			host->check_cnt = 0;
3742edd718bSreyk 			host->up_cnt = 0;
375feb9ff76Sreyk 			break;
376feb9ff76Sreyk 		case IMSG_HOST_ENABLE:
377feb9ff76Sreyk 			memcpy(&id, imsg.data, sizeof(id));
378feb9ff76Sreyk 			if ((host = host_find(env, id)) == NULL)
379feb9ff76Sreyk 				fatalx("hce_dispatch_imsg: desynchronized");
380feb9ff76Sreyk 			host->flags &= ~(F_DISABLE);
381feb9ff76Sreyk 			host->up = HOST_UNKNOWN;
382feb9ff76Sreyk 			break;
383feb9ff76Sreyk 		case IMSG_TABLE_DISABLE:
384feb9ff76Sreyk 			memcpy(&id, imsg.data, sizeof(id));
385feb9ff76Sreyk 			if ((table = table_find(env, id)) == NULL)
386feb9ff76Sreyk 				fatalx("hce_dispatch_imsg: desynchronized");
38768b79041Spyr 			table->conf.flags |= F_DISABLE;
388feb9ff76Sreyk 			TAILQ_FOREACH(host, &table->hosts, entry)
389feb9ff76Sreyk 				host->up = HOST_UNKNOWN;
390feb9ff76Sreyk 			break;
391feb9ff76Sreyk 		case IMSG_TABLE_ENABLE:
392feb9ff76Sreyk 			memcpy(&id, imsg.data, sizeof(id));
393feb9ff76Sreyk 			if ((table = table_find(env, id)) == NULL)
394feb9ff76Sreyk 				fatalx("hce_dispatch_imsg: desynchronized");
39568b79041Spyr 			table->conf.flags &= ~(F_DISABLE);
396feb9ff76Sreyk 			TAILQ_FOREACH(host, &table->hosts, entry)
397feb9ff76Sreyk 				host->up = HOST_UNKNOWN;
398feb9ff76Sreyk 			break;
399feb9ff76Sreyk 		default:
400feb9ff76Sreyk 			log_debug("hce_dispatch_msg: unexpected imsg %d",
401feb9ff76Sreyk 			    imsg.hdr.type);
402feb9ff76Sreyk 			break;
403feb9ff76Sreyk 		}
404feb9ff76Sreyk 		imsg_free(&imsg);
405feb9ff76Sreyk 	}
406feb9ff76Sreyk 	imsg_event_add(ibuf);
407feb9ff76Sreyk }
408feb9ff76Sreyk 
409feb9ff76Sreyk void
410feb9ff76Sreyk hce_dispatch_parent(int fd, short event, void * ptr)
411feb9ff76Sreyk {
412feb9ff76Sreyk 	struct imsgbuf		*ibuf;
413feb9ff76Sreyk 	struct imsg		 imsg;
4144156152fSreyk 	struct ctl_script	 scr;
415feb9ff76Sreyk 	ssize_t		 	 n;
416*adf98c11Spyr 	size_t			 len;
417*adf98c11Spyr 
418*adf98c11Spyr 	static struct table	*table = NULL;
419*adf98c11Spyr 	struct host		*host;
420feb9ff76Sreyk 
421feb9ff76Sreyk 	ibuf = ptr;
422feb9ff76Sreyk 	switch (event) {
423feb9ff76Sreyk 	case EV_READ:
424feb9ff76Sreyk 		if ((n = imsg_read(ibuf)) == -1)
425feb9ff76Sreyk 			fatal("hce_dispatch_parent: imsg_read error");
4262edd718bSreyk 		if (n == 0)
427feb9ff76Sreyk 			fatalx("hce_dispatch_parent: pipe closed");
428feb9ff76Sreyk 		break;
429feb9ff76Sreyk 	case EV_WRITE:
430feb9ff76Sreyk 		if (msgbuf_write(&ibuf->w) == -1)
431feb9ff76Sreyk 			fatal("hce_dispatch_parent: msgbuf_write");
432feb9ff76Sreyk 		imsg_event_add(ibuf);
433feb9ff76Sreyk 		return;
434feb9ff76Sreyk 	default:
435feb9ff76Sreyk 		fatalx("hce_dispatch_parent: unknown event");
436feb9ff76Sreyk 	}
437feb9ff76Sreyk 
438feb9ff76Sreyk 	for (;;) {
439feb9ff76Sreyk 		if ((n = imsg_get(ibuf, &imsg)) == -1)
440feb9ff76Sreyk 			fatal("hce_dispatch_parent: imsg_read error");
441feb9ff76Sreyk 		if (n == 0)
442feb9ff76Sreyk 			break;
443feb9ff76Sreyk 
444feb9ff76Sreyk 		switch (imsg.hdr.type) {
4454156152fSreyk 		case IMSG_SCRIPT:
4464156152fSreyk 			if (imsg.hdr.len - IMSG_HEADER_SIZE !=
4474156152fSreyk 			    sizeof(scr))
4484156152fSreyk 				fatalx("hce_dispatch_parent: "
4494156152fSreyk 				    "invalid size of script request");
4504156152fSreyk 			bcopy(imsg.data, &scr, sizeof(scr));
4514156152fSreyk 			script_done(env, &scr);
4524156152fSreyk 			break;
453*adf98c11Spyr 		case IMSG_RECONF:
454*adf98c11Spyr 			log_debug("hce: reloading configuration");
455*adf98c11Spyr 			if (imsg.hdr.len !=
456*adf98c11Spyr 			    sizeof(struct hoststated) + IMSG_HEADER_SIZE)
457*adf98c11Spyr 				fatalx("corrupted reload data");
458*adf98c11Spyr 			hce_disable_events();
459*adf98c11Spyr 			purge_config(env, PURGE_TABLES);
460*adf98c11Spyr 			merge_config(env, (struct hoststated *)imsg.data);
461*adf98c11Spyr 
462*adf98c11Spyr 			env->tables = calloc(1, sizeof(*env->tables));
463*adf98c11Spyr 			if (env->tables == NULL)
464*adf98c11Spyr 				fatal(NULL);
465*adf98c11Spyr 
466*adf98c11Spyr 			TAILQ_INIT(env->tables);
467*adf98c11Spyr 			break;
468*adf98c11Spyr 		case IMSG_RECONF_TABLE:
469*adf98c11Spyr 			if ((table = calloc(1, sizeof(*table))) == NULL)
470*adf98c11Spyr 				fatal(NULL);
471*adf98c11Spyr 			memcpy(&table->conf, imsg.data, sizeof(table->conf));
472*adf98c11Spyr 			TAILQ_INIT(&table->hosts);
473*adf98c11Spyr 			TAILQ_INSERT_TAIL(env->tables, table, entry);
474*adf98c11Spyr 			break;
475*adf98c11Spyr 		case IMSG_RECONF_SENDBUF:
476*adf98c11Spyr 			len = imsg.hdr.len - IMSG_HEADER_SIZE;
477*adf98c11Spyr 			table->sendbuf = calloc(1, len);
478*adf98c11Spyr 			(void)strlcpy(table->sendbuf, (char *)imsg.data, len);
479*adf98c11Spyr 			break;
480*adf98c11Spyr 		case IMSG_RECONF_HOST:
481*adf98c11Spyr 			if ((host = calloc(1, sizeof(*host))) == NULL)
482*adf98c11Spyr 				fatal(NULL);
483*adf98c11Spyr 			memcpy(&host->conf, imsg.data, sizeof(host->conf));
484*adf98c11Spyr 			host->tablename = table->conf.name;
485*adf98c11Spyr 			TAILQ_INSERT_TAIL(&table->hosts, host, entry);
486*adf98c11Spyr 			break;
487*adf98c11Spyr 		case IMSG_RECONF_END:
488*adf98c11Spyr 			log_warnx("hce: configuration reloaded");
489*adf98c11Spyr 			hce_setup_events();
490*adf98c11Spyr 			break;
491feb9ff76Sreyk 		default:
492feb9ff76Sreyk 			log_debug("hce_dispatch_parent: unexpected imsg %d",
493feb9ff76Sreyk 			    imsg.hdr.type);
494feb9ff76Sreyk 			break;
495feb9ff76Sreyk 		}
496feb9ff76Sreyk 		imsg_free(&imsg);
497feb9ff76Sreyk 	}
4984156152fSreyk 	imsg_event_add(ibuf);
499feb9ff76Sreyk }
500