Commit Diff


commit - 72bd104e36737fc8780d993371b480fa6826eb37
commit + 816ddb539c058ce2c1ef4053478bca8f1b2c286c
blob - fb7692eac5e8f7835c79b3347e06670fb62eb0f0
blob + e44c70c2c1beac7b6b383b20529efc2023bcdeca
--- check_icmp.c
+++ check_icmp.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: check_icmp.c,v 1.9 2007/01/09 03:32:56 reyk Exp $	*/
+/*	$OpenBSD: check_icmp.c,v 1.10 2007/01/11 18:05:08 reyk Exp $	*/
 
 /*
  * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org>
@@ -33,53 +33,86 @@
 #include <unistd.h>
 #include <string.h>
 #include <stdlib.h>
+#include <err.h>
 
 #include "hoststated.h"
 
-int	icmp6_checks_done(struct ctl_icmp_event *);
-int	icmp4_checks_done(struct ctl_icmp_event *);
-void	send_icmp6(struct ctl_icmp_event *, struct host *);
-void	send_icmp4(struct ctl_icmp_event *, struct host *);
-void	recv_icmp6(int, short, void *);
-void	recv_icmp4(int, short, void *);
+void	icmp_setup(struct hoststated *, struct ctl_icmp_event *, int);
+void	check_icmp_add(struct ctl_icmp_event *, int, struct timeval *,
+	    void (*)(int, short, void *));
+int	icmp_checks_done(struct ctl_icmp_event *);
+void	icmp_checks_timeout(struct ctl_icmp_event *, const char *);
+void	send_icmp(int, short, void *);
+void	recv_icmp(int, short, void *);
 int	in_cksum(u_short *, int);
 
 void
-schedule_icmp(struct ctl_icmp_event *cie, struct table *table)
+icmp_setup(struct hoststated *env, struct ctl_icmp_event *cie, int af)
 {
-	struct host	*host;
+	int proto = IPPROTO_ICMP;
 
-	TAILQ_FOREACH(host, &table->hosts, entry) {
-		if (host->flags & F_DISABLE)
-			continue;
-		host->last_up = host->up;
-		host->flags &= ~F_CHECK_DONE;
-		if (((struct sockaddr *)&host->ss)->sa_family == AF_INET) {
-			send_icmp4(cie, host);
-		} else {
-			send_icmp6(cie, host);
-		}
-	}
+	if (af == AF_INET6)
+		proto = IPPROTO_ICMPV6;
+	if ((cie->s = socket(af, SOCK_RAW, proto)) < 0)
+		err(1, "icmp_init: socket");
+	session_socket_blockmode(cie->s, BM_NONBLOCK);
+	cie->env = env;
+	cie->af = af;
 }
 
 void
-check_icmp(struct ctl_icmp_event *cie)
+icmp_init(struct hoststated *env)
 {
-	struct timeval	tv;
+	icmp_setup(env, &env->icmp_send, AF_INET);
+	icmp_setup(env, &env->icmp_recv, AF_INET);
+	icmp_setup(env, &env->icmp6_send, AF_INET6);
+	icmp_setup(env, &env->icmp6_recv, AF_INET6);
+	env->id = getpid() & 0xffff;
+}
 
+void
+schedule_icmp(struct hoststated *env, struct host *host)
+{
+	host->last_up = host->up;
+	host->flags &= ~(F_CHECK_SENT|F_CHECK_DONE);
+
+	if (((struct sockaddr *)&host->ss)->sa_family == AF_INET)
+		env->has_icmp = 1;
+	else
+		env->has_icmp6 = 1;
+}
+
+void
+check_icmp_add(struct ctl_icmp_event *cie, int flags, struct timeval *start,
+    void (*fn)(int, short, void *))
+{
+	struct timeval	 tv;
+
+	if (start != NULL)
+		bcopy(start, &cie->tv_start, sizeof(cie->tv_start));
+	bcopy(&cie->env->timeout, &tv, sizeof(tv));
 	if (gettimeofday(&cie->tv_start, NULL))
-		fatal("check_icmp: gettimeofday");
-	bcopy(&cie->env->timeout, &tv, sizeof(tv));
-	if (cie->has_icmp4)
-		event_once(cie->icmp_sock, EV_READ|EV_TIMEOUT,
-		    recv_icmp4, cie, &tv);
-	if (cie->has_icmp6)
-		event_once(cie->icmp6_sock, EV_READ|EV_TIMEOUT,
-		    recv_icmp6, cie, &tv);
+		fatal("check_icmp_add: gettimeofday");
+	event_del(&cie->ev);
+	event_set(&cie->ev, cie->s, EV_TIMEOUT|flags, fn, cie);
+	event_add(&cie->ev, &tv);
 }
 
+void
+check_icmp(struct hoststated *env, struct timeval *tv)
+{
+	if (env->has_icmp) {
+		check_icmp_add(&env->icmp_recv, EV_READ, tv, recv_icmp);
+		check_icmp_add(&env->icmp_send, EV_WRITE, tv, send_icmp);
+	}
+	if (env->has_icmp6) {
+		check_icmp_add(&env->icmp6_recv, EV_READ, tv, recv_icmp);
+		check_icmp_add(&env->icmp6_send, EV_WRITE, tv, send_icmp);
+	}
+}
+
 int
-icmp6_checks_done(struct ctl_icmp_event *cie)
+icmp_checks_done(struct ctl_icmp_event *cie)
 {
 	struct table	*table;
 	struct host	*host;
@@ -88,8 +121,7 @@ icmp6_checks_done(struct ctl_icmp_event *cie)
 		if (table->flags & F_DISABLE || table->check != CHECK_ICMP)
 			continue;
 		TAILQ_FOREACH(host, &table->hosts, entry) {
-			if (((struct sockaddr *)&host->ss)->sa_family !=
-			    AF_INET6)
+			if (((struct sockaddr *)&host->ss)->sa_family != cie->af)
 				continue;
 			if (!(host->flags & F_CHECK_DONE))
 				return (0);
@@ -98,8 +130,8 @@ icmp6_checks_done(struct ctl_icmp_event *cie)
 	return (1);
 }
 
-int
-icmp4_checks_done(struct ctl_icmp_event *cie)
+void
+icmp_checks_timeout(struct ctl_icmp_event *cie, const char *msg)
 {
 	struct table	*table;
 	struct host	*host;
@@ -108,220 +140,156 @@ icmp4_checks_done(struct ctl_icmp_event *cie)
 		if (table->flags & F_DISABLE || table->check != CHECK_ICMP)
 			continue;
 		TAILQ_FOREACH(host, &table->hosts, entry) {
-			if (((struct sockaddr *)&host->ss)->sa_family !=
-			    AF_INET)
+			if (((struct sockaddr *)&host->ss)->sa_family != cie->af)
 				continue;
-			if (!(host->flags & F_CHECK_DONE)) {
-				return (0);
-			}
+			if (!(host->flags & F_CHECK_DONE))
+				host->up = HOST_DOWN;
+			hce_notify_done(host, msg);
 		}
 	}
-	return (1);
 }
 
 void
-send_icmp6(struct ctl_icmp_event *cie, struct host *host)
+send_icmp(int s, short event, void *arg)
 {
+	struct ctl_icmp_event	*cie = (struct ctl_icmp_event *)arg;
+	struct table		*table;
+	struct host		*host;
 	struct sockaddr		*to;
-	struct icmp6_hdr	*icp;
-	ssize_t			 i;
+	struct icmp		*icp;
+	struct icmp6_hdr	*icp6;
+	ssize_t			 r;
 	u_char			 packet[ICMP_BUF_SIZE];
+	socklen_t		 slen;
+	int			 i = 0;
 
-	cie->has_icmp6 = 1;
-	to = (struct sockaddr *)&host->ss;
-	bzero(&packet, sizeof(packet));
-	icp = (struct icmp6_hdr *)packet;
-	icp->icmp6_type = ICMP6_ECHO_REQUEST;
-	icp->icmp6_code = 0;
-	icp->icmp6_seq = 1;
-	icp->icmp6_id = getpid() & 0xffff;
-
-	memcpy((packet + sizeof(*icp)), &host->id, sizeof(host->id));
-
-	i = sendto(cie->icmp6_sock, packet, sizeof(packet), 0, to,
-	    sizeof(struct sockaddr_in6));
-	if (i < 0 || i != sizeof(packet)) {
-		host->up = HOST_DOWN;
-		hce_notify_done(host, "send_icmp6: cannot send");
+	if (event == EV_TIMEOUT) {
+		icmp_checks_timeout(cie, "send_icmp: timeout");
 		return;
 	}
-}
 
-void
-send_icmp4(struct ctl_icmp_event *cie, struct host *host)
-{
-	struct sockaddr	*to;
-	struct icmp	*icp;
-	ssize_t		 i;
-	u_char		 packet[ICMP_BUF_SIZE];
-
-	cie->has_icmp4 = 1;
-	to = (struct sockaddr *)&host->ss;
 	bzero(&packet, sizeof(packet));
 	icp = (struct icmp *)packet;
-	icp->icmp_type = ICMP_ECHO;
-	icp->icmp_code = 0;
-	icp->icmp_seq = htons(1);
-	icp->icmp_id = htons(getpid() & 0xffff);
-	icp->icmp_cksum = 0;
-
-	memcpy(icp->icmp_data, &host->id, sizeof(host->id));
-	icp->icmp_cksum = in_cksum((u_short *)icp, sizeof(packet));
-
-	i = sendto(cie->icmp_sock, packet, sizeof(packet), 0, to,
-	    sizeof(struct sockaddr_in));
-	if (i < 0 || i != sizeof(packet)) {
-		host->up = HOST_DOWN;
-		hce_notify_done(host, "send_icmp4: cannot send");
+	icp6 = (struct icmp6_hdr *)packet;
+	if (cie->af == AF_INET) {
+		icp->icmp_type = ICMP_ECHO;
+		icp->icmp_code = 0;
+		icp->icmp_id = htons(cie->env->id);
+		icp->icmp_cksum = 0;
+		slen = sizeof(struct sockaddr_in);
+	} else {
+		icp6->icmp6_type = ICMP6_ECHO_REQUEST;
+		icp6->icmp6_code = 0;
+		icp6->icmp6_cksum = 0;
+		icp6->icmp6_id = htons(cie->env->id);
+		slen = sizeof(struct sockaddr_in6);
 	}
-}
 
-void
-recv_icmp6(int s, short event, void *arg)
-{
-	struct ctl_icmp_event	*cie = arg;
-	u_char			 packet[ICMP_BUF_SIZE];
-	socklen_t		 len;
-	struct sockaddr_storage	 ss;
-	struct icmp6_hdr	*icp;
-	struct host		*host;
-	struct table		*table;
-	ssize_t			 i;
-	objid_t			 id;
-	struct timeval		 tv;
-	struct timeval		 tv_now;
-
-	if (event == EV_TIMEOUT) {
-		/*
-		 * mark all hosts which have not responded yet as down.
-		 */
-		TAILQ_FOREACH(table, &cie->env->tables, entry) {
-			if (table->check != CHECK_ICMP ||
-			    table->flags & F_DISABLE)
+	TAILQ_FOREACH(table, &cie->env->tables, entry) {
+		if (table->check != CHECK_ICMP || table->flags & F_DISABLE)
+			continue;
+		TAILQ_FOREACH(host, &table->hosts, entry) {
+			if (host->flags & (F_DISABLE | F_CHECK_SENT))
 				continue;
-			TAILQ_FOREACH(host, &table->hosts, entry) {
-				if (host->flags & F_DISABLE)
-					continue;
-				if (((struct sockaddr *)&host->ss)->sa_family
-				    != AF_INET6)
-					continue;
-				if (!(host->flags & F_CHECK_DONE)) {
-					host->up = HOST_DOWN;
-				}
+			if (((struct sockaddr *)&host->ss)->sa_family != cie->af)
+				continue;
+			i++;
+			to = (struct sockaddr *)&host->ss;
+			if (cie->af == AF_INET) {
+				icp->icmp_seq = htons(i);
+				icp->icmp_cksum = 0;
+				memcpy(icp->icmp_data, &host->id,
+				    sizeof(host->id));
+				icp->icmp_cksum = in_cksum((u_short *)icp,
+				    sizeof(packet));
+			} else {
+				icp6->icmp6_seq = htons(i);
+				icp6->icmp6_cksum = 0;
+				memcpy(packet + sizeof(*icp6), &host->id,
+				    sizeof(host->id));
+				icp6->icmp6_cksum = in_cksum((u_short *)icp6,
+				    sizeof(packet));
 			}
+
+			r = sendto(s, packet, sizeof(packet), 0, to, slen);
+			if (r == -1) {
+				if (errno == EAGAIN && errno == EINTR)
+					goto retry;
+				host->flags |= F_CHECK_SENT|F_CHECK_DONE;
+				host->up = HOST_DOWN;
+			} else if (r != sizeof(packet))
+				goto retry;
+			host->flags |= F_CHECK_SENT;
 		}
-		return;
 	}
-	bzero(&packet, sizeof(packet));
-	bzero(&ss, sizeof(ss));
-	len = sizeof(struct sockaddr_in6);
-	i = recvfrom(s, packet, sizeof(packet), 0, (struct sockaddr *)&ss, &len);
-	if (i < 0 || i != sizeof(packet)) {
-		log_warn("recv_icmp6: did not receive valid ping");
-		return;
-	}
-	icp = (struct icmp6_hdr *)(packet);
-	memcpy(&id, (packet + sizeof(*icp)), sizeof(id));
-	host = host_find(cie->env, id);
-	if (host == NULL)
-		log_warn("recv_icmp6: ping for unknown host received");
-	if (bcmp(&ss, &host->ss, len)) {
-		log_warnx("recv_icmp6: forged icmp packet ?");
-		return;
-	}
-	if (icp->icmp6_id != (getpid() & 0xffff)) {
-		log_warnx("recv_icmp6: did not receive valid ident");
-		host->up = HOST_DOWN;
-	} else
-		host->up = HOST_UP;
-	hce_notify_done(host, "recv_icmp6: final");
-	if (icmp6_checks_done(cie))
-		return;
-	if (gettimeofday(&tv_now, NULL))
-		fatal("recv_icmp6: gettimeofday");
-	bcopy(&cie->env->timeout, &tv, sizeof(tv));
-	timersub(&tv_now, &cie->tv_start, &tv_now);
-	timersub(&tv, &tv_now, &tv);
-	event_once(cie->icmp6_sock, EV_READ|EV_TIMEOUT, recv_icmp6, cie, &tv);
+
+	return;
+
+ retry:
+	event_again(&cie->ev, s, EV_TIMEOUT|EV_WRITE, send_icmp,
+	    &cie->tv_start, &cie->env->timeout, cie);
 }
 
 void
-recv_icmp4(int s, short event, void *arg)
+recv_icmp(int s, short event, void *arg)
 {
-	socklen_t		 len;
+	struct ctl_icmp_event	*cie = (struct ctl_icmp_event *)arg;
+	u_char			 packet[ICMP_BUF_SIZE];
+	socklen_t		 slen;
+	struct sockaddr_storage	 ss;
 	struct icmp		*icp;
-	struct ctl_icmp_event	*cie = arg;
-	u_char			 packet[ICMP_BUF_SIZE];
+	struct icmp6_hdr	*icp6;
+	u_int16_t		 icpid;
 	struct host		*host;
-	struct table		*table;
-	ssize_t			 i;
+	ssize_t			 r;
 	objid_t			 id;
-	struct timeval		 tv;
-	struct timeval		 tv_now;
-	struct sockaddr_storage	 ss;
 
 	if (event == EV_TIMEOUT) {
-		/*
-		 * mark all hosts which have not responded yet as down.
-		 */
-		TAILQ_FOREACH(table, &cie->env->tables, entry) {
-			if (table->check != CHECK_ICMP ||
-			    table->flags & F_DISABLE)
-				continue;
-			TAILQ_FOREACH(host, &table->hosts, entry) {
-				if (host->flags & F_DISABLE)
-					continue;
-				if (((struct sockaddr *)&host->ss)->sa_family
-				    != AF_INET)
-					continue;
-				if (!(host->flags & F_CHECK_DONE)) {
-					host->up = HOST_DOWN;
-				}
-			}
-		}
+		icmp_checks_timeout(cie, NULL);
 		return;
 	}
 
-	len = sizeof(struct sockaddr_in);
 	bzero(&packet, sizeof(packet));
 	bzero(&ss, sizeof(ss));
-	i = recvfrom(s, packet, sizeof(packet), 0, (struct sockaddr *)&ss, &len);
-	if (i < 0 || i != sizeof(packet)) {
-		log_warn("recv_icmp4: did not receive valid ping");
-		return;
+
+	r = recvfrom(s, packet, sizeof(packet), 0, (struct sockaddr *)&ss, &slen);
+	if (r == -1 || r != ICMP_BUF_SIZE) {
+		if (r == -1 && errno != EAGAIN && errno != EINTR)
+			log_debug("recv_icmp: receive error");
+		goto retry;
 	}
 
-	icp = (struct icmp *)(packet + sizeof(struct ip));
-	memcpy(&id, icp->icmp_data, sizeof(id));
+	if (cie->af == AF_INET) {
+		icp = (struct icmp *)(packet + sizeof(struct ip));
+		icpid = ntohs(icp->icmp_id);
+		memcpy(&id, icp->icmp_data, sizeof(id));
+	} else {
+		icp6 = (struct icmp6_hdr *)packet;
+		icpid = ntohs(icp6->icmp6_id);
+		memcpy(&id, packet + sizeof(*icp6), sizeof(id));
+	}
+	if (icpid != cie->env->id)
+		goto retry;
 	host = host_find(cie->env, id);
 	if (host == NULL) {
-		log_warnx("recv_icmp4: received ping for unknown host");
-		return;
+		log_warn("recv_icmp: ping for unknown host received");
+		goto retry;
 	}
-	if (bcmp(&ss, &host->ss, len)) {
-		log_warnx("recv_icmp4: forged icmp packet ?");
-		return;
+	if (bcmp(&ss, &host->ss, slen)) {
+		log_warnx("recv_icmp: forged icmp packet?");
+		goto retry;
 	}
-	if (ntohs(icp->icmp_id) != (getpid() & 0xffff)) {
-		log_warnx("recv_icmp4: did not receive valid ident");
-		host->up = HOST_DOWN;
-	} else
-		host->up = HOST_UP;
 
+	host->up = HOST_UP;
 	host->flags |= F_CHECK_DONE;
-	if (icmp4_checks_done(cie)) {
-		hce_notify_done(host, "recv_icmp4: all done");
+	hce_notify_done(host, "recv_icmp: done");
+
+	if (icmp_checks_done(cie))
 		return;
-	}
-	hce_notify_done(host, "recv_icmp4: host");
 
-	if (gettimeofday(&tv_now, NULL))
-		fatal("recv_icmp4: gettimeofday");
-
-	bcopy(&cie->env->timeout, &tv, sizeof(tv));
-	timersub(&tv_now, &cie->tv_start, &tv_now);
-	timersub(&tv, &tv_now, &tv);
-	event_once(cie->icmp_sock, EV_READ|EV_TIMEOUT, recv_icmp4, cie, &tv);
+ retry:
+	event_again(&cie->ev, s, EV_TIMEOUT|EV_READ, recv_icmp,
+	    &cie->tv_start, &cie->env->timeout, cie);
 }
 
 /* in_cksum from ping.c --
blob - 86b8244093f98fe98e0bfcb206aa78356fe48037
blob + fc365c18d9d0e6837fce084880032808f747f95e
--- check_tcp.c
+++ check_tcp.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: check_tcp.c,v 1.8 2007/01/09 00:45:32 deraadt Exp $	*/
+/*	$OpenBSD: check_tcp.c,v 1.9 2007/01/11 18:05:08 reyk Exp $	*/
 
 /*
  * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org>
@@ -71,17 +71,16 @@ check_tcp(struct ctl_tcp_event *cte)
 	if (fcntl(s, F_SETFL, O_NONBLOCK) == -1)
 		goto bad;
 
+	bcopy(&cte->table->timeout, &tv, sizeof(tv));
 	if (connect(s, (struct sockaddr *)&cte->host->ss, len) == -1) {
 		if (errno != EINPROGRESS)
 			goto bad;
-	} else {
+	} else
 		cte->host->up = HOST_UP;
-		tcp_host_up(s, cte);
-		return;
-	}
-	bcopy(&cte->table->timeout, &tv, sizeof(tv));
-	event_once(s, EV_TIMEOUT|EV_WRITE, tcp_write, cte, &tv);
+	event_set(&cte->ev, s, EV_TIMEOUT|EV_WRITE, tcp_write, cte);
+	event_add(&cte->ev, &tv);
 	return;
+
 bad:
 	close(s);
 	cte->host->up = HOST_DOWN;
@@ -102,7 +101,7 @@ tcp_write(int s, short event, void *arg)
 		len = sizeof(err);
 		if (getsockopt(s, SOL_SOCKET, SO_ERROR, &err, &len))
 			fatal("tcp_write: getsockopt");
-		if (err)
+		if (err != 0)
 			cte->host->up = HOST_DOWN;
 		else
 			cte->host->up = HOST_UP;
@@ -123,16 +122,18 @@ tcp_host_up(int s, struct ctl_tcp_event *cte)
 	switch (cte->table->check) {
 	case CHECK_TCP:
 		close(s);
-		hce_notify_done(cte->host, "tcp_write: success");
+		hce_notify_done(cte->host, "tcp_host_up: success");
 		break;
 	case CHECK_HTTP_CODE:
 	case CHECK_HTTP_DIGEST:
-		send_http_request(cte);
+		event_again(&cte->ev, s, EV_TIMEOUT|EV_WRITE, send_http_request,
+		    &cte->tv_start, &cte->table->timeout, cte);
 		break;
 	case CHECK_SEND_EXPECT:
-		start_send_expect(cte);
+		event_again(&cte->ev, s, EV_TIMEOUT|EV_WRITE, start_send_expect,
+		    &cte->tv_start, &cte->table->timeout, cte);
 		break;
 	default:
-		fatalx("tcp_write: unhandled check type");
+		fatalx("tcp_host_up: unhandled check type");
 	}
 }
blob - c951b5ba8bbc746805f65d42460dd39a3135c53e
blob + 012a5dbf63fb95683997e92d1be1dbd13b41a1ad
--- hce.c
+++ hce.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: hce.c,v 1.9 2007/01/09 13:50:11 pyr Exp $	*/
+/*	$OpenBSD: hce.c,v 1.10 2007/01/11 18:05:08 reyk Exp $	*/
 
 /*
  * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org>
@@ -82,12 +82,6 @@ hce(struct hoststated *x_env, int pipe_parent2pfe[2], 
 
 	env = x_env;
 
-	/* this is needed for icmp tests */
-	if ((env->icmp_sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0)
-		err(1, "socket");
-	if ((env->icmp6_sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) < 0)
-		err(1, "socket");
-
 	if ((pw = getpwnam(HOSTSTATED_USER)) == NULL)
 		fatal("hce: getpwnam");
 
@@ -99,15 +93,14 @@ hce(struct hoststated *x_env, int pipe_parent2pfe[2], 
 	setproctitle("host check engine");
 	hoststated_process = PROC_HCE;
 
+	/* this is needed for icmp tests */
+	icmp_init(env);
+
 	if (setgroups(1, &pw->pw_gid) ||
 	    setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
 	    setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
 		fatal("hce: can't drop privileges");
 
-	env->cie.icmp_sock = env->icmp_sock;
-	env->cie.icmp6_sock = env->icmp6_sock;
-	env->cie.env = env;
-
 	event_init();
 
 	signal_set(&ev_sigint, SIGINT, hce_sig_handler, NULL);
@@ -137,11 +130,10 @@ hce(struct hoststated *x_env, int pipe_parent2pfe[2], 
 	    ibuf_main->handler, ibuf_main);
 	event_add(&ibuf_main->ev, NULL);
 
-	evtimer_set(&env->ev, hce_launch_checks, NULL);
-	bcopy(&env->interval, &tv, sizeof(tv));
+	evtimer_set(&env->ev, hce_launch_checks, env);
+	bzero(&tv, sizeof(tv));
 	evtimer_add(&env->ev, &tv);
 
-	hce_launch_checks(0, 0, NULL);
 	event_dispatch();
 
 	hce_shutdown();
@@ -154,32 +146,52 @@ hce_launch_checks(int fd, short event, void *arg)
 {
 	struct host		*host;
 	struct table		*table;
+	struct timeval		 tv;
 
+	log_debug("hce_launch_checks: scheduled");
+
+	/*
+	 * notify pfe checks are done and schedule next check
+	 */
+	imsg_compose(ibuf_pfe, IMSG_SYNC, 0, 0, NULL, 0);
 	TAILQ_FOREACH(table, &env->tables, entry) {
+		TAILQ_FOREACH(host, &table->hosts, entry) {
+			host->flags &= ~(F_CHECK_SENT|F_CHECK_DONE);
+			event_del(&host->cte.ev);
+		}
+	}
+
+	if (gettimeofday(&tv, NULL))
+		fatal("hce_launch_checks: gettimeofday");
+
+	TAILQ_FOREACH(table, &env->tables, entry) {
 		if (table->flags & F_DISABLE)
 			continue;
 		if (table->check == CHECK_NOCHECK)
 			fatalx("hce_launch_checks: unknown check type");
-		if (table->check == CHECK_ICMP) {
-			schedule_icmp(&env->cie, table);
-			continue;
-		}
-		/*
-		 * tcp type checks follow
-		 */
+
 		TAILQ_FOREACH(host, &table->hosts, entry) {
 			if (host->flags & F_DISABLE)
 				continue;
+			if (table->check == CHECK_ICMP) {
+				schedule_icmp(env, host);
+				continue;
+			}
+
+			/* Any other TCP-style checks */
 			bzero(&host->cte, sizeof(host->cte));
 			host->last_up = host->up;
 			host->cte.host = host;
 			host->cte.table = table;
-			if (gettimeofday(&host->cte.tv_start, NULL))
-				fatal("hce_launch_checks: gettimeofday");
+			bcopy(&tv, &host->cte.tv_start,
+			    sizeof(host->cte.tv_start));
 			check_tcp(&host->cte);
 		}
 	}
-	check_icmp(&env->cie);
+	check_icmp(env, &tv);
+
+	bcopy(&env->interval, &tv, sizeof(tv));
+	evtimer_add(&env->ev, &tv);
 }
 
 int
@@ -205,35 +217,16 @@ void
 hce_notify_done(struct host *host, const char *msg)
 {
 	struct ctl_status	 st;
-	struct timeval		 tv;
-	struct table		*table;
 
 	st.id = host->id;
 	st.up = host->up;
-	host->flags |= F_CHECK_DONE;
+	host->flags |= (F_CHECK_SENT|F_CHECK_DONE);
 	if (msg)
-		log_debug("hce_notify_done: %s", msg);
+		log_debug("hce_notify_done: %s (%s)", host->name, msg);
 	if (host->up != host->last_up) {
 		imsg_compose(ibuf_pfe, IMSG_HOST_STATUS, 0, 0, &st, sizeof(st));
 		host->last_up = host->up;
 	}
-	/*
-	 * check if everything is done, I see no other way than going
-	 * through the tree for every host that calls this function.
-	 */
-	if (hce_checks_done()) {
-		/*
-		 * notify pfe checks are done and schedule next check
-		 */
-		imsg_compose(ibuf_pfe, IMSG_SYNC, 0, 0, NULL, 0);
-		TAILQ_FOREACH(table, &env->tables, entry) {
-			TAILQ_FOREACH(host, &table->hosts, entry)
-				host->flags &= ~F_CHECK_DONE;
-		}
-		bcopy(&env->interval, &tv, sizeof(tv));
-		evtimer_add(&env->ev, &tv);
-		bzero(&st, sizeof(st));
-	}
 }
 
 void
blob - 1507f4d19fb491d39a5fc6f05e7e344eb1542939
blob + 2062ad5e03bdde8a5ed155c4a2f4a48e3a0a0c07
--- relayd.c
+++ relayd.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: relayd.c,v 1.9 2007/01/09 13:50:11 pyr Exp $	*/
+/*	$OpenBSD: relayd.c,v 1.10 2007/01/11 18:05:08 reyk Exp $	*/
 
 /*
  * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org>
@@ -410,3 +410,24 @@ service_findbyname(struct hoststated *env, const char 
 			return (service);
 	return (NULL);
 }
+
+void
+event_again(struct event *ev, int fd, short event, void (*fn)(int, short, void *),
+    struct timeval *start, struct timeval *end, void *arg)
+{
+	struct timeval tv_next, tv_now, tv;
+
+	if (gettimeofday(&tv_now, NULL))
+		fatal("event_again: gettimeofday");
+
+	bcopy(end, &tv_next, sizeof(tv_next));
+	timersub(&tv_now, start, &tv_now);
+	timersub(&tv_next, &tv_now, &tv_next);
+
+	bzero(&tv, sizeof(tv));
+	if (timercmp(&tv_next, &tv, >))
+		bcopy(&tv_next, &tv, sizeof(tv));
+
+	event_set(ev, fd, event, fn, arg);
+	event_add(ev, &tv);
+}
blob - a21a3a4bd7f7bf45eb9c8ebc20059ea69a838fc0
blob + dc801ea20c97cc2368350c3ae52f3200837b6981
--- relayd.h
+++ relayd.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: relayd.h,v 1.13 2007/01/09 13:50:11 pyr Exp $	*/
+/*	$OpenBSD: relayd.h,v 1.14 2007/01/11 18:05:08 reyk Exp $	*/
 
 /*
  * Copyright (c) 2006 Pierre-Yves Ritschard <pyr@spootnik.org>
@@ -126,21 +126,20 @@ struct ctl_id {
 
 struct ctl_icmp_event {
 	struct hoststated	*env;
-	int			 icmp_sock;
-	int			 icmp6_sock;
-	int			 has_icmp4;
-	int			 has_icmp6;
+	int			 s;
+	int			 af;
 	int			 last_up;
 	struct event		 ev;
 	struct timeval		 tv_start;
 };
 
 struct ctl_tcp_event {
-	int		 s;
-	struct buf	*buf;
-	struct host	*host;
-	struct table	*table;
-	struct timeval	 tv_start;
+	int		 	 s;
+	struct buf		*buf;
+	struct host		*host;
+	struct table		*table;
+	struct timeval	 	 tv_start;
+	struct event	 	 ev;
 };
 
 struct address {
@@ -156,6 +155,7 @@ TAILQ_HEAD(addresslist, address);
 #define F_CHECK_DONE		0x02 /* reused for host */
 #define F_USED			0x04
 #define F_ACTIVE_RULESET	0x04 /* reused for service */
+#define F_CHECK_SENT		0x04 /* reused for host */
 #define F_DOWN			0x08
 #define F_ADD			0x10
 #define F_DEL			0x20
@@ -228,8 +228,6 @@ enum {
 struct hoststated {
 	u_int8_t		 opts;
 	struct pfdata		*pf;
-	int			 icmp_sock;
-	int			 icmp6_sock;
 	int			 tablecount;
 	int			 servicecount;
 	struct timeval		 interval;
@@ -238,7 +236,14 @@ struct hoststated {
 	struct event		 ev;
 	struct tablelist	 tables;
 	struct servicelist	 services;
-	struct ctl_icmp_event	 cie;
+	u_int16_t		 id;
+
+	int			 has_icmp;
+	int			 has_icmp6;
+	struct ctl_icmp_event	 icmp_send;
+	struct ctl_icmp_event	 icmp_recv;
+	struct ctl_icmp_event	 icmp6_send;
+	struct ctl_icmp_event	 icmp6_recv;
 };
 
 #define HOSTSTATED_OPT_VERBOSE	 0x01
@@ -334,17 +339,18 @@ pid_t	 hce(struct hoststated *, int [2], int [2], int 
 void	 hce_notify_done(struct host *, const char *);
 
 /* check_icmp.c */
-void	 schedule_icmp(struct ctl_icmp_event *, struct table *);
-void	 check_icmp(struct ctl_icmp_event *);
+void	 icmp_init(struct hoststated *);
+void	 schedule_icmp(struct hoststated *, struct host *);
+void	 check_icmp(struct hoststated *, struct timeval *);
 
 /* check_tcp.c */
 void	 check_tcp(struct ctl_tcp_event *);
 
 /* check_http.c */
-void	 send_http_request(struct ctl_tcp_event *);
+void	 send_http_request(int, short, void *);
 
 /* check_send_expect.c */
-void	 start_send_expect(struct ctl_tcp_event *);
+void	 start_send_expect(int, short, void *);
 
 /* hoststated.c */
 struct host	*host_find(struct hoststated *, objid_t);
@@ -353,3 +359,6 @@ struct service	*service_find(struct hoststated *, obji
 struct host	*host_findbyname(struct hoststated *, const char *);
 struct table	*table_findbyname(struct hoststated *, const char *);
 struct service	*service_findbyname(struct hoststated *, const char *);
+void		 event_again(struct event *, int, short,
+		    void (*)(int, short, void *),
+		    struct timeval *, struct timeval *, void *);