summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorGilles Chehade <gilles@cvs.openbsd.org>2012-08-18 18:18:24 +0000
committerGilles Chehade <gilles@cvs.openbsd.org>2012-08-18 18:18:24 +0000
commit9228f249a15e8408c65a9892fe8c9d845c867714 (patch)
treebbf9e12e35607c9a3c09a8c68ea4650040b414eb /usr.sbin
parent3da4234ae91599a538335d99a70e54983df19d04 (diff)
- introduce stat_backend, an API for pluggable statistic backends
> statistics are no longer static structures in shared memory > statistics are only set, smtpd never uses them in its logic > each statistic is a key/value where key can be any (dynamic) string - convert all uses of the former API to use the new one - implement stat_ramstat that keeps non-persistent stats in ram structure ok eric@, ok chl@
Diffstat (limited to 'usr.sbin')
-rw-r--r--usr.sbin/smtpd/control.c70
-rw-r--r--usr.sbin/smtpd/dns.c16
-rw-r--r--usr.sbin/smtpd/lka.c5
-rw-r--r--usr.sbin/smtpd/queue.c4
-rw-r--r--usr.sbin/smtpd/scheduler.c4
-rw-r--r--usr.sbin/smtpd/scheduler_ramqueue.c15
-rw-r--r--usr.sbin/smtpd/smtp.c25
-rw-r--r--usr.sbin/smtpd/smtp_session.c29
-rw-r--r--usr.sbin/smtpd/smtpctl.c179
-rw-r--r--usr.sbin/smtpd/smtpctl/Makefile4
-rw-r--r--usr.sbin/smtpd/smtpd.c22
-rw-r--r--usr.sbin/smtpd/smtpd.h115
-rw-r--r--usr.sbin/smtpd/smtpd/Makefile7
-rw-r--r--usr.sbin/smtpd/stat_backend.c82
-rw-r--r--usr.sbin/smtpd/stat_ramstat.c165
-rw-r--r--usr.sbin/smtpd/stats.c79
16 files changed, 472 insertions, 349 deletions
diff --git a/usr.sbin/smtpd/control.c b/usr.sbin/smtpd/control.c
index ce9356e18f6..969a437e7cb 100644
--- a/usr.sbin/smtpd/control.c
+++ b/usr.sbin/smtpd/control.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: control.c,v 1.67 2012/08/10 09:16:02 eric Exp $ */
+/* $OpenBSD: control.c,v 1.68 2012/08/18 18:18:23 gilles Exp $ */
/*
* Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -61,10 +61,17 @@ void control_dispatch_ext(int, short, void *);
struct ctl_connlist ctl_conns;
+static struct stat_backend *stat_backend = NULL;
+extern const char *backend_stat;
+
+static size_t sessions;
+
void
control_imsg(struct imsgev *iev, struct imsg *imsg)
{
struct ctl_conn *c;
+ char *key;
+ struct stat_kv *stat_kv;
log_imsg(PROC_CONTROL, iev->proc, imsg);
@@ -80,6 +87,24 @@ control_imsg(struct imsgev *iev, struct imsg *imsg)
}
}
+ switch (imsg->hdr.type) {
+ case IMSG_STAT_INCREMENT:
+ key = imsg->data;
+ if (stat_backend)
+ stat_backend->increment(key);
+ return;
+ case IMSG_STAT_DECREMENT:
+ key = imsg->data;
+ if (stat_backend)
+ stat_backend->decrement(key);
+ return;
+ case IMSG_STAT_SET:
+ stat_kv = (struct stat_kv *)imsg->data;
+ if (stat_backend)
+ stat_backend->set(stat_kv->key, stat_kv->val);
+ return;
+ }
+
errx(1, "control_imsg: unexpected %s imsg",
imsg_to_str(imsg->hdr.type));
}
@@ -109,11 +134,12 @@ control(void)
struct event ev_sigint;
struct event ev_sigterm;
struct peer peers [] = {
- { PROC_SCHEDULER, imsg_dispatch },
- { PROC_QUEUE, imsg_dispatch },
- { PROC_SMTP, imsg_dispatch },
- { PROC_MFA, imsg_dispatch },
- { PROC_PARENT, imsg_dispatch },
+ { PROC_SCHEDULER, imsg_dispatch },
+ { PROC_QUEUE, imsg_dispatch },
+ { PROC_SMTP, imsg_dispatch },
+ { PROC_MFA, imsg_dispatch },
+ { PROC_PARENT, imsg_dispatch },
+ { PROC_LKA, imsg_dispatch }
};
switch (pid = fork()) {
@@ -160,6 +186,9 @@ control(void)
session_socket_blockmode(fd, BM_NONBLOCK);
control_state.fd = fd;
+ stat_backend = env->sc_stat;
+ stat_backend->init();
+
if (chroot(pw->pw_dir) == -1)
fatal("control: chroot");
if (chdir("/") == -1)
@@ -255,7 +284,9 @@ control_accept(int listenfd, short event, void *arg)
event_add(&c->iev.ev, NULL);
TAILQ_INSERT_TAIL(&ctl_conns, c, entry);
- if (stat_increment(STATS_CONTROL_SESSION) >= env->sc_maxconn) {
+ stat_backend->increment("control.session");
+
+ if (++sessions >= env->sc_maxconn) {
log_warnx("ctl client limit hit, disabling new connections");
event_del(&control_state.ev);
}
@@ -288,7 +319,9 @@ control_close(int fd)
close(fd);
free(c);
- if (stat_decrement(STATS_CONTROL_SESSION) < env->sc_maxconn &&
+ stat_backend->decrement("control.session");
+
+ if (--sessions < env->sc_maxconn &&
!event_pending(&control_state.ev, EV_READ, NULL)) {
log_warnx("re-enabling ctl connections");
event_add(&control_state.ev, NULL);
@@ -305,6 +338,10 @@ control_dispatch_ext(int fd, short event, void *arg)
uid_t euid;
gid_t egid;
uint64_t id;
+ struct stat_kv *kvp;
+ char *key;
+ size_t val;
+
if (getpeereid(fd, &euid, &egid) == -1)
fatal("getpeereid");
@@ -352,8 +389,21 @@ control_dispatch_ext(int fd, short event, void *arg)
case IMSG_STATS:
if (euid)
goto badcred;
- imsg_compose_event(&c->iev, IMSG_STATS, 0, 0, -1,
- env->stats, sizeof(struct stats));
+ imsg_compose_event(&c->iev, IMSG_STATS, 0, 0, -1, NULL, 0);
+ break;
+
+ case IMSG_STATS_GET:
+ if (euid)
+ goto badcred;
+ kvp = imsg.data;
+ if (! stat_backend->iter(&kvp->iter, &key, &val))
+ kvp->iter = NULL;
+ else {
+ strlcpy(kvp->key, key, sizeof kvp->key);
+ kvp->val = val;
+ }
+ imsg_compose_event(&c->iev, IMSG_STATS_GET, 0, 0, -1,
+ kvp, sizeof *kvp);
break;
case IMSG_CTL_SHUTDOWN:
diff --git a/usr.sbin/smtpd/dns.c b/usr.sbin/smtpd/dns.c
index d502ef9396b..03746eb0987 100644
--- a/usr.sbin/smtpd/dns.c
+++ b/usr.sbin/smtpd/dns.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dns.c,v 1.51 2012/08/08 17:31:55 eric Exp $ */
+/* $OpenBSD: dns.c,v 1.52 2012/08/18 18:18:23 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -145,14 +145,14 @@ dns_async(struct imsgev *asker, int type, struct dns *query)
return;
}
dnssession_mx_insert(s, query->host, 0);
- stat_increment(STATS_LKA_SESSION_HOST);
+ stat_increment("lka.session.host");
dns_asr_dispatch_host(s);
return;
case IMSG_DNS_PTR:
s->as = getnameinfo_async((struct sockaddr*)&query->ss,
query->ss.ss_len,
s->query.host, sizeof(s->query.host), NULL, 0, 0, NULL);
- stat_increment(STATS_LKA_SESSION_CNAME);
+ stat_increment("lka.session.cname");
if (s->as == NULL) {
log_debug("dns_async: asr_query_cname error");
break;
@@ -162,7 +162,7 @@ dns_async(struct imsgev *asker, int type, struct dns *query)
case IMSG_DNS_MX:
log_debug("dns: lookup mx \"%s\"", query->host);
s->as = res_query_async(query->host, C_IN, T_MX, NULL, 0, NULL);
- stat_increment(STATS_LKA_SESSION_MX);
+ stat_increment("lka.session.mx");
if (s->as == NULL) {
log_debug("dns_async: asr_query_dns error");
break;
@@ -174,7 +174,7 @@ dns_async(struct imsgev *asker, int type, struct dns *query)
break;
}
- stat_increment(STATS_LKA_FAILURE);
+ stat_increment("lka.failure");
dnssession_destroy(s);
}
@@ -223,7 +223,7 @@ dns_asr_error(int ar_err)
return DNS_OK;
case NO_DATA:
case NO_RECOVERY:
- stat_increment(STATS_LKA_FAILURE);
+ stat_increment("lka.failure");
return DNS_EINVAL;
default:
return DNS_RETRY;
@@ -354,7 +354,7 @@ dnssession_init(struct dns *query)
if (s == NULL)
fatal("dnssession_init: calloc");
- stat_increment(STATS_LKA_SESSION);
+ stat_increment("lka.session");
s->id = query->id;
s->query = *query;
@@ -365,7 +365,7 @@ dnssession_init(struct dns *query)
static void
dnssession_destroy(struct dnssession *s)
{
- stat_decrement(STATS_LKA_SESSION);
+ stat_decrement("lka.session");
SPLAY_REMOVE(dnstree, &dns_sessions, s);
event_del(&s->ev);
free(s);
diff --git a/usr.sbin/smtpd/lka.c b/usr.sbin/smtpd/lka.c
index 169662dd521..1e1bae88ee9 100644
--- a/usr.sbin/smtpd/lka.c
+++ b/usr.sbin/smtpd/lka.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: lka.c,v 1.133 2012/05/12 15:31:43 gilles Exp $ */
+/* $OpenBSD: lka.c,v 1.134 2012/08/18 18:18:23 gilles Exp $ */
/*
* Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -256,7 +256,8 @@ lka(void)
{ PROC_MFA, imsg_dispatch },
{ PROC_QUEUE, imsg_dispatch },
{ PROC_SMTP, imsg_dispatch },
- { PROC_MTA, imsg_dispatch }
+ { PROC_MTA, imsg_dispatch },
+ { PROC_CONTROL, imsg_dispatch }
};
switch (pid = fork()) {
diff --git a/usr.sbin/smtpd/queue.c b/usr.sbin/smtpd/queue.c
index f7e4586057f..ece47ff5bc2 100644
--- a/usr.sbin/smtpd/queue.c
+++ b/usr.sbin/smtpd/queue.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: queue.c,v 1.125 2012/08/11 19:18:36 chl Exp $ */
+/* $OpenBSD: queue.c,v 1.126 2012/08/18 18:18:23 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -85,7 +85,7 @@ queue_imsg(struct imsgev *iev, struct imsg *imsg)
msgid = evpid_to_msgid(e->id);
if (queue_message_commit(msgid)) {
stat_increment(e->flags & DF_ENQUEUED ?
- STATS_QUEUE_LOCAL : STATS_QUEUE_REMOTE);
+ "queue.local" : "queue.remote");
imsg_compose_event(env->sc_ievs[PROC_SCHEDULER],
IMSG_QUEUE_COMMIT_MESSAGE, 0, 0, -1,
&msgid, sizeof msgid);
diff --git a/usr.sbin/smtpd/scheduler.c b/usr.sbin/smtpd/scheduler.c
index b71249b4956..bf7ddf9d24d 100644
--- a/usr.sbin/smtpd/scheduler.c
+++ b/usr.sbin/smtpd/scheduler.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: scheduler.c,v 1.11 2012/08/09 19:16:26 eric Exp $ */
+/* $OpenBSD: scheduler.c,v 1.12 2012/08/18 18:18:23 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -408,6 +408,4 @@ scheduler_process_mta(struct scheduler_batch *batch)
imsg_compose_event(env->sc_ievs[PROC_QUEUE], IMSG_BATCH_CLOSE,
0, 0, -1, NULL, 0);
-
- stat_increment(STATS_MTA_SESSION);
}
diff --git a/usr.sbin/smtpd/scheduler_ramqueue.c b/usr.sbin/smtpd/scheduler_ramqueue.c
index 1630d6e5cb2..44cbd31cf2c 100644
--- a/usr.sbin/smtpd/scheduler_ramqueue.c
+++ b/usr.sbin/smtpd/scheduler_ramqueue.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: scheduler_ramqueue.c,v 1.13 2012/08/11 19:19:19 chl Exp $ */
+/* $OpenBSD: scheduler_ramqueue.c,v 1.14 2012/08/18 18:18:23 gilles Exp $ */
/*
* Copyright (c) 2012 Gilles Chehade <gilles@openbsd.org>
@@ -160,8 +160,10 @@ scheduler_ramqueue_insert(struct scheduler_info *si)
}
/* find/prepare the host in ramqueue update */
- if ((host = rq_host_lookup(&update->hosts, si->destination)) == NULL)
+ if ((host = rq_host_lookup(&update->hosts, si->destination)) == NULL) {
host = rq_host_create(&update->hosts, si->destination);
+ stat_increment("scheduler.ramqueue.host");
+ }
/* find/prepare the hosttree message in ramqueue update */
if ((batch = tree_get(&host->batches, msgid)) == NULL) {
@@ -169,6 +171,7 @@ scheduler_ramqueue_insert(struct scheduler_info *si)
batch->msgid = msgid;
tree_init(&batch->envelopes);
tree_xset(&host->batches, msgid, batch);
+ stat_increment("scheduler.ramqueue.batch");
}
/* find/prepare the msgtree message in ramqueue update */
@@ -177,6 +180,7 @@ scheduler_ramqueue_insert(struct scheduler_info *si)
message->msgid = msgid;
tree_init(&message->envelopes);
tree_xset(&update->messages, msgid, message);
+ stat_increment("scheduler.ramqueue.message");
}
/* create envelope in ramqueue message */
@@ -188,6 +192,8 @@ scheduler_ramqueue_insert(struct scheduler_info *si)
envelope->sched = scheduler_compute_schedule(si);
envelope->expire = si->creation + si->expire;
+ stat_increment("scheduler.ramqueue.envelope");
+
if (envelope->expire < envelope->sched) {
envelope->flags |= RQ_ENVELOPE_EXPIRED;
tree_xset(&update->expired, envelope->evpid, envelope);
@@ -619,6 +625,7 @@ rq_envelope_delete(struct rq_queue *rq, struct rq_envelope *envelope)
if (tree_empty(&message->envelopes)) {
tree_xpop(&rq->messages, msgid);
free(message);
+ stat_decrement("scheduler.ramqueue.message");
}
tree_xpop(&batch->envelopes, envelope->evpid);
@@ -627,10 +634,14 @@ rq_envelope_delete(struct rq_queue *rq, struct rq_envelope *envelope)
if (tree_empty(&host->batches)) {
SPLAY_REMOVE(hosttree, &rq->hosts, host);
free(host);
+ stat_decrement("scheduler.ramqueue.host");
}
free(batch);
+ stat_decrement("scheduler.ramqueue.batch");
}
free(envelope);
+
+ stat_decrement("scheduler.ramqueue.envelope");
}
static const char *
diff --git a/usr.sbin/smtpd/smtp.c b/usr.sbin/smtpd/smtp.c
index a9b217df20e..c4d7ab3aa58 100644
--- a/usr.sbin/smtpd/smtp.c
+++ b/usr.sbin/smtpd/smtp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtp.c,v 1.103 2012/08/09 09:48:02 eric Exp $ */
+/* $OpenBSD: smtp.c,v 1.104 2012/08/18 18:18:23 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -49,6 +49,7 @@ static void smtp_accept(int, short, void *);
static struct session *smtp_new(struct listener *);
static struct session *session_lookup(u_int64_t);
+static size_t sessions;
static void
smtp_imsg(struct imsgev *iev, struct imsg *imsg)
@@ -516,15 +517,17 @@ smtp_new(struct listener *l)
strlcpy(s->s_msg.tag, l->tag, sizeof(s->s_msg.tag));
SPLAY_INSERT(sessiontree, &env->sc_sessions, s);
- if (stat_increment(STATS_SMTP_SESSION) >= env->sc_maxconn) {
+ stat_increment("smtp.session");
+
+ if (++sessions >= env->sc_maxconn) {
log_warnx("client limit hit, disabling incoming connections");
smtp_pause();
}
if (s->s_l->ss.ss_family == AF_INET)
- stat_increment(STATS_SMTP_SESSION_INET4);
+ stat_increment("smtp.session.inet4");
if (s->s_l->ss.ss_family == AF_INET6)
- stat_increment(STATS_SMTP_SESSION_INET6);
+ stat_increment("smtp.session.inet6");
iobuf_init(&s->s_iobuf, MAX_LINE_SIZE, MAX_LINE_SIZE);
io_init(&s->s_io, -1, s, session_io, &s->s_iobuf);
@@ -533,6 +536,20 @@ smtp_new(struct listener *l)
return (s);
}
+void
+smtp_destroy(struct session *session)
+{
+ size_t resume;
+
+ resume = env->sc_maxconn * 95 / 100;
+
+ if (--sessions == resume) {
+ log_warnx("re-enabling incoming connections");
+ smtp_resume();
+ }
+}
+
+
/*
* Helper function for handling IMSG replies.
*/
diff --git a/usr.sbin/smtpd/smtp_session.c b/usr.sbin/smtpd/smtp_session.c
index 396f3ef3fb1..d173fef7599 100644
--- a/usr.sbin/smtpd/smtp_session.c
+++ b/usr.sbin/smtpd/smtp_session.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtp_session.c,v 1.164 2012/08/18 16:05:54 chl Exp $ */
+/* $OpenBSD: smtp_session.c,v 1.165 2012/08/18 18:18:23 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -610,9 +610,9 @@ session_io(struct io *io, int evt)
case IO_TLSREADY:
s->s_flags |= F_SECURE;
if (s->s_l->flags & F_SMTPS)
- stat_increment(STATS_SMTP_SMTPS);
+ stat_increment("smtp.smtps");
if (s->s_l->flags & F_STARTTLS)
- stat_increment(STATS_SMTP_STARTTLS);
+ stat_increment("smtp.tls");
if (s->s_state == S_INIT) {
io_set_write(&s->s_io);
session_respond(s, SMTPD_BANNER, env->sc_hostname);
@@ -694,7 +694,7 @@ session_pickup(struct session *s, struct submit_status *ss)
if ((ss != NULL && ss->code == 421) ||
(s->s_dstatus & DS_TEMPFAILURE)) {
- env->stats->smtp.tempfail++;
+ stat_increment("smtp.tempfail");
session_respond(s, "421 Service temporarily unavailable");
session_enter_state(s, S_QUIT);
io_reload(&s->s_io);
@@ -924,7 +924,7 @@ session_line(struct session *s, char *line, size_t len)
tempfail:
session_respond(s, "421 4.0.0 Service temporarily unavailable");
- env->stats->smtp.tempfail++;
+ stat_increment("smtp.tempfail");
session_enter_state(s, S_QUIT);
}
@@ -947,7 +947,7 @@ session_read_data(struct session *s, char *line)
} else if (s->s_dstatus & DS_TEMPFAILURE) {
session_respond(s, "421 4.0.0 Temporary failure");
session_enter_state(s, S_QUIT);
- env->stats->smtp.tempfail++;
+ stat_increment("smtp.tempfail");
} else {
session_imsg(s, PROC_QUEUE, IMSG_QUEUE_COMMIT_MESSAGE,
0, 0, -1, &s->s_msg, sizeof(s->s_msg));
@@ -991,8 +991,6 @@ session_read_data(struct session *s, char *line)
void
session_destroy(struct session *s, const char * reason)
{
- size_t resume;
-
log_debug("smtp: %p: deleting session: %s", s, reason);
if (s->s_flags & F_ZOMBIE)
@@ -1009,10 +1007,10 @@ session_destroy(struct session *s, const char * reason)
if (s->s_ssl) {
if (s->s_l->flags & F_SMTPS)
if (s->s_flags & F_SECURE)
- stat_decrement(STATS_SMTP_SMTPS);
+ stat_decrement("smtp.smtps");
if (s->s_l->flags & F_STARTTLS)
if (s->s_flags & F_SECURE)
- stat_decrement(STATS_SMTP_STARTTLS);
+ stat_decrement("smtp.tls");
}
event_del(&s->s_ev); /* in case something was scheduled */
@@ -1020,11 +1018,7 @@ session_destroy(struct session *s, const char * reason)
iobuf_clear(&s->s_iobuf);
/* resume when session count decreases to 95% */
- resume = env->sc_maxconn * 95 / 100;
- if (stat_decrement(STATS_SMTP_SESSION) == resume) {
- log_warnx("re-enabling incoming connections");
- smtp_resume();
- }
+ stat_decrement("smtp.session");
/* If the session is waiting for an imsg, do not kill it now, since
* the id must still be valid.
@@ -1035,6 +1029,9 @@ session_destroy(struct session *s, const char * reason)
}
finalize:
+
+ smtp_destroy(s);
+
SPLAY_REMOVE(sessiontree, &env->sc_sessions, s);
bzero(s, sizeof(*s));
free(s);
@@ -1130,7 +1127,7 @@ session_respond(struct session *s, char *fmt, ...)
struct timeval tv = { delay, 0 };
io_pause(&s->s_io, IO_PAUSE_OUT);
- env->stats->smtp.delays++;
+ stat_increment("smtp.delays");
/* in case session_respond is called multiple times */
evtimer_del(&s->s_ev);
diff --git a/usr.sbin/smtpd/smtpctl.c b/usr.sbin/smtpd/smtpctl.c
index af948be20fa..e8fb5e80f78 100644
--- a/usr.sbin/smtpd/smtpctl.c
+++ b/usr.sbin/smtpd/smtpctl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpctl.c,v 1.85 2012/08/08 17:33:55 eric Exp $ */
+/* $OpenBSD: smtpctl.c,v 1.86 2012/08/18 18:18:23 gilles Exp $ */
/*
* Copyright (c) 2006 Pierre-Yves Ritschard <pyr@openbsd.org>
@@ -45,7 +45,7 @@
void usage(void);
static void setup_env(struct smtpd *);
static int show_command_output(struct imsg *);
-static int show_stats_output(struct imsg *);
+static void show_stats_output(void);
static void show_queue(int);
static void show_envelope(struct envelope *, int);
static void getflag(u_int *, int, char *, char *, size_t);
@@ -262,7 +262,8 @@ connected:
done = show_command_output(&imsg);
break;
case SHOW_STATS:
- done = show_stats_output(&imsg);
+ show_stats_output();
+ done = 1;
break;
case NONE:
break;
@@ -299,141 +300,55 @@ show_command_output(struct imsg *imsg)
}
static void
-stat_print(int stat, int what)
+show_stats_output(void)
{
- static const char *names[STATS_MAX] = {
- "smtp.sessions",
- "smtp.sessions.inet4",
- "smtp.sessions.inet6",
- "smtp.sessions.smtps",
- "smtp.sessions.starttls",
-
- "mta.sessions",
-
- "mda.sessions",
-
- "control.sessions",
-
- "lka.sessions",
- "lka.sessions.mx",
- "lka.sessions.host",
- "lka.sessions.cname",
- "lka.sessions.failure",
-
- "scheduler",
- "scheduler.bounces",
-
- "queue.inserts.local",
- "queue.inserts.remote",
-
- "ramqueue.envelopes",
- "ramqueue.messages",
- "ramqueue.batches",
- "ramqueue.hosts",
- };
- const char *sfx;
-
- if (what == STAT_ACTIVE)
- sfx = ".active";
- else if (what == STAT_MAXACTIVE)
- sfx = ".maxactive";
- else
- sfx = "";
+ struct stat_kv kv, *kvp;
+ struct imsg imsg;
+ int n;
- printf("%s%s=%zd\n", names[stat], sfx, stat_get(stat, what));
-}
-static int
-show_stats_output(struct imsg *imsg)
-{
- struct stats *stats;
+ bzero(&kv, sizeof kv);
- if (imsg->hdr.type != IMSG_STATS)
- errx(1, "show_stats_output: bad hdr type (%d)", imsg->hdr.type);
+again:
+ imsg_compose(ibuf, IMSG_STATS_GET, 0, 0, -1, &kv, sizeof kv);
- if (imsg->hdr.len - IMSG_HEADER_SIZE != sizeof(*stats))
- errx(1, "show_stats_output: bad data size");
-
- stats = imsg->data;
- stat_init(stats->counters, STATS_MAX);
-
- stat_print(STATS_CONTROL_SESSION, STAT_COUNT);
- stat_print(STATS_CONTROL_SESSION, STAT_ACTIVE);
- stat_print(STATS_CONTROL_SESSION, STAT_MAXACTIVE);
-
- stat_print(STATS_MDA_SESSION, STAT_COUNT);
- stat_print(STATS_MDA_SESSION, STAT_ACTIVE);
- stat_print(STATS_MDA_SESSION, STAT_MAXACTIVE);
-
- stat_print(STATS_MTA_SESSION, STAT_COUNT);
- stat_print(STATS_MTA_SESSION, STAT_ACTIVE);
- stat_print(STATS_MTA_SESSION, STAT_MAXACTIVE);
-
- stat_print(STATS_LKA_SESSION, STAT_COUNT);
- stat_print(STATS_LKA_SESSION, STAT_ACTIVE);
- stat_print(STATS_LKA_SESSION, STAT_MAXACTIVE);
- stat_print(STATS_LKA_SESSION_MX, STAT_COUNT);
- stat_print(STATS_LKA_SESSION_HOST, STAT_COUNT);
- stat_print(STATS_LKA_SESSION_CNAME, STAT_COUNT);
- stat_print(STATS_LKA_FAILURE, STAT_COUNT);
-
- printf("parent.uptime=%lld\n",
- (long long int) (time(NULL) - stats->parent.start));
-
- stat_print(STATS_QUEUE_LOCAL, STAT_COUNT);
- stat_print(STATS_QUEUE_REMOTE, STAT_COUNT);
-
- stat_print(STATS_SCHEDULER, STAT_COUNT);
- stat_print(STATS_SCHEDULER, STAT_ACTIVE);
- stat_print(STATS_SCHEDULER, STAT_MAXACTIVE);
-
- stat_print(STATS_SCHEDULER_BOUNCES, STAT_COUNT);
- stat_print(STATS_SCHEDULER_BOUNCES, STAT_ACTIVE);
- stat_print(STATS_SCHEDULER_BOUNCES, STAT_MAXACTIVE);
-
- stat_print(STATS_RAMQUEUE_HOST, STAT_ACTIVE);
- stat_print(STATS_RAMQUEUE_BATCH, STAT_ACTIVE);
- stat_print(STATS_RAMQUEUE_MESSAGE, STAT_ACTIVE);
- stat_print(STATS_RAMQUEUE_ENVELOPE, STAT_ACTIVE);
-
- stat_print(STATS_RAMQUEUE_HOST, STAT_MAXACTIVE);
- stat_print(STATS_RAMQUEUE_BATCH, STAT_MAXACTIVE);
- stat_print(STATS_RAMQUEUE_MESSAGE, STAT_MAXACTIVE);
- stat_print(STATS_RAMQUEUE_ENVELOPE, STAT_MAXACTIVE);
-
- printf("smtp.errors.delays=%zd\n", stats->smtp.delays);
- printf("smtp.errors.linetoolong=%zd\n", stats->smtp.linetoolong);
- printf("smtp.errors.read_eof=%zd\n", stats->smtp.read_eof);
- printf("smtp.errors.read_system=%zd\n", stats->smtp.read_error);
- printf("smtp.errors.read_timeout=%zd\n", stats->smtp.read_timeout);
- printf("smtp.errors.tempfail=%zd\n", stats->smtp.tempfail);
- printf("smtp.errors.toofast=%zd\n", stats->smtp.toofast);
- printf("smtp.errors.write_eof=%zd\n", stats->smtp.write_eof);
- printf("smtp.errors.write_system=%zd\n", stats->smtp.write_error);
- printf("smtp.errors.write_timeout=%zd\n", stats->smtp.write_timeout);
-
- stat_print(STATS_SMTP_SESSION, STAT_COUNT);
- stat_print(STATS_SMTP_SESSION_INET4, STAT_COUNT);
- stat_print(STATS_SMTP_SESSION_INET6, STAT_COUNT);
- printf("smtp.sessions.aborted=%zd\n", stats->smtp.read_eof +
- stats->smtp.read_error + stats->smtp.write_eof +
- stats->smtp.write_error);
-
- stat_print(STATS_SMTP_SESSION, STAT_ACTIVE);
- stat_print(STATS_SMTP_SESSION, STAT_MAXACTIVE);
-
- printf("smtp.sessions.timeout=%zd\n", stats->smtp.read_timeout +
- stats->smtp.write_timeout);
-
- stat_print(STATS_SMTP_SMTPS, STAT_COUNT);
- stat_print(STATS_SMTP_SMTPS, STAT_ACTIVE);
- stat_print(STATS_SMTP_SMTPS, STAT_MAXACTIVE);
-
- stat_print(STATS_SMTP_STARTTLS, STAT_COUNT);
- stat_print(STATS_SMTP_STARTTLS, STAT_ACTIVE);
- stat_print(STATS_SMTP_STARTTLS, STAT_MAXACTIVE);
+ while (ibuf->w.queued)
+ if (msgbuf_write(&ibuf->w) < 0)
+ err(1, "write error");
- return (1);
+ do {
+ if ((n = imsg_read(ibuf)) == -1)
+ errx(1, "imsg_read error");
+ if (n == 0)
+ errx(1, "pipe closed");
+
+ do {
+ if ((n = imsg_get(ibuf, &imsg)) == -1)
+ errx(1, "imsg_get error");
+ if (n == 0)
+ break;
+ if (imsg.hdr.type != IMSG_STATS_GET)
+ errx(1, "invalid imsg type");
+
+ kvp = imsg.data;
+ if (kvp->iter == NULL) {
+ imsg_free(&imsg);
+ return;
+ }
+
+ if (strcmp(kvp->key, "uptime") == 0)
+ printf("%s=%zd\n", kvp->key, time(NULL) - kvp->val);
+ else
+ printf("%s=%zd\n", kvp->key, kvp->val);
+
+ kv = *kvp;
+
+ imsg_free(&imsg);
+ goto again;
+
+ } while (n != 0);
+
+ } while (n != 0);
}
static void
diff --git a/usr.sbin/smtpd/smtpctl/Makefile b/usr.sbin/smtpd/smtpctl/Makefile
index aa80005a8d8..c55c89d1380 100644
--- a/usr.sbin/smtpd/smtpctl/Makefile
+++ b/usr.sbin/smtpd/smtpctl/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.22 2012/01/11 22:24:37 gilles Exp $
+# $OpenBSD: Makefile,v 1.23 2012/08/18 18:18:23 gilles Exp $
.PATH: ${.CURDIR}/..
@@ -18,7 +18,7 @@ CFLAGS+= -Wsign-compare -Wbounded
SRCS= enqueue.c parser.c log.c envelope.c
SRCS+= queue_backend.c queue_fsqueue.c
-SRCS+= smtpctl.c stats.c util.c
+SRCS+= smtpctl.c util.c
LDADD+= -lutil
DPADD+= ${LIBUTIL} ${LIBEVENT}
diff --git a/usr.sbin/smtpd/smtpd.c b/usr.sbin/smtpd/smtpd.c
index 28cf891ed98..1d8e6e31d5e 100644
--- a/usr.sbin/smtpd/smtpd.c
+++ b/usr.sbin/smtpd/smtpd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.c,v 1.157 2012/08/09 09:48:02 eric Exp $ */
+/* $OpenBSD: smtpd.c,v 1.158 2012/08/18 18:18:23 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -93,6 +93,7 @@ struct smtpd *env = NULL;
const char *backend_queue = "fs";
const char *backend_scheduler = "ramqueue";
+const char *backend_stat = "ram";
static void
parent_imsg(struct imsgev *iev, struct imsg *imsg)
@@ -454,6 +455,8 @@ main(int argc, char *argv[])
backend_queue = strchr(optarg, '=') + 1;
else if (strstr(optarg, "scheduler=") == optarg)
backend_scheduler = strchr(optarg, '=') + 1;
+ else if (strstr(optarg, "stat=") == optarg)
+ backend_stat = strchr(optarg, '=') + 1;
else
log_warnx("invalid backend specifier %s", optarg);
break;
@@ -486,6 +489,8 @@ main(int argc, char *argv[])
verbose |= TRACE_BOUNCE;
else if (!strcmp(optarg, "scheduler"))
verbose |= TRACE_SCHEDULER;
+ else if (!strcmp(optarg, "stat"))
+ verbose |= TRACE_STAT;
else if (!strcmp(optarg, "all"))
verbose |= ~TRACE_VERBOSE;
else
@@ -548,6 +553,7 @@ main(int argc, char *argv[])
log_debug("using \"%s\" queue backend", backend_queue);
log_debug("using \"%s\" scheduler backend", backend_scheduler);
+ log_debug("using \"%s\" stat backend", backend_stat);
env->sc_queue = queue_backend_lookup(backend_queue);
if (env->sc_queue == NULL)
@@ -556,6 +562,10 @@ main(int argc, char *argv[])
if (!env->sc_queue->init(1))
errx(1, "could not initialize queue backend");
+ env->sc_stat = stat_backend_lookup(backend_stat);
+ if (env->sc_stat == NULL)
+ errx(1, "could not find stat backend \"%s\"", backend_stat);
+
log_init(debug);
log_verbose(verbose);
@@ -567,15 +577,7 @@ main(int argc, char *argv[])
if (env->sc_hostname[0] == '\0')
errx(1, "machine does not have a hostname set");
-
- env->stats = mmap(NULL, sizeof(struct stats), PROT_WRITE|PROT_READ,
- MAP_ANON|MAP_SHARED, -1, (off_t)0);
- if (env->stats == MAP_FAILED)
- fatal("mmap");
- bzero(env->stats, sizeof(struct stats));
- stat_init(env->stats->counters, STATS_MAX);
-
- env->stats->parent.start = time(NULL);
+ env->sc_uptime = time(NULL);
fork_peers();
diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h
index d0b0f7222fd..3feb220ecdb 100644
--- a/usr.sbin/smtpd/smtpd.h
+++ b/usr.sbin/smtpd/smtpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: smtpd.h,v 1.321 2012/08/18 15:45:12 eric Exp $ */
+/* $OpenBSD: smtpd.h,v 1.322 2012/08/18 18:18:23 gilles Exp $ */
/*
* Copyright (c) 2008 Gilles Chehade <gilles@openbsd.org>
@@ -170,7 +170,6 @@ enum imsg_type {
IMSG_PARENT_AUTHENTICATE,
IMSG_PARENT_SEND_CONFIG,
- IMSG_STATS,
IMSG_SMTP_ENQUEUE,
IMSG_SMTP_PAUSE,
IMSG_SMTP_RESUME,
@@ -178,7 +177,14 @@ enum imsg_type {
IMSG_DNS_HOST,
IMSG_DNS_HOST_END,
IMSG_DNS_MX,
- IMSG_DNS_PTR
+ IMSG_DNS_PTR,
+
+ IMSG_STAT_INCREMENT,
+ IMSG_STAT_DECREMENT,
+ IMSG_STAT_SET,
+
+ IMSG_STATS,
+ IMSG_STATS_GET,
};
enum blockmodes {
@@ -587,6 +593,9 @@ struct smtpd {
char sc_hostname[MAXHOSTNAMELEN];
struct queue_backend *sc_queue;
struct scheduler_backend *sc_scheduler;
+ struct stat_backend *sc_stat;
+
+ time_t sc_uptime;
TAILQ_HEAD(filterlist, filter) *sc_filters;
@@ -600,7 +609,6 @@ struct smtpd {
SPLAY_HEAD(mfatree, mfa_session) mfa_sessions;
LIST_HEAD(mdalist, mda_session) mda_sessions;
- struct stats *stats;
u_int64_t filtermask;
};
@@ -611,74 +619,8 @@ struct smtpd {
#define TRACE_MTA 0x0010
#define TRACE_BOUNCE 0x0020
#define TRACE_SCHEDULER 0x0040
+#define TRACE_STAT 0x0080
-enum {
- STATS_SMTP_SESSION = 0,
- STATS_SMTP_SESSION_INET4,
- STATS_SMTP_SESSION_INET6,
- STATS_SMTP_SMTPS,
- STATS_SMTP_STARTTLS,
-
- STATS_MTA_SESSION,
-
- STATS_MDA_SESSION,
-
- STATS_CONTROL_SESSION,
-
- STATS_LKA_SESSION,
- STATS_LKA_SESSION_MX,
- STATS_LKA_SESSION_HOST,
- STATS_LKA_SESSION_CNAME,
- STATS_LKA_FAILURE,
-
- STATS_SCHEDULER,
- STATS_SCHEDULER_BOUNCES,
-
- STATS_QUEUE_LOCAL,
- STATS_QUEUE_REMOTE,
-
- STATS_RAMQUEUE_ENVELOPE,
- STATS_RAMQUEUE_MESSAGE,
- STATS_RAMQUEUE_BATCH,
- STATS_RAMQUEUE_HOST,
-
- STATS_MAX,
-};
-
-#define STAT_COUNT 0
-#define STAT_ACTIVE 1
-#define STAT_MAXACTIVE 2
-
-struct stat_counter {
- size_t count;
- size_t active;
- size_t maxactive;
-};
-
-struct s_parent {
- time_t start;
-};
-
-struct s_session {
- size_t read_error;
- size_t read_timeout;
- size_t read_eof;
- size_t write_error;
- size_t write_timeout;
- size_t write_eof;
- size_t toofast;
- size_t tempfail;
- size_t linetoolong;
- size_t delays;
-};
-
-struct stats {
- struct s_parent parent;
- struct s_session mta;
- struct s_session smtp;
-
- struct stat_counter counters[STATS_MAX];
-};
struct submit_status {
u_int64_t id;
@@ -954,6 +896,24 @@ struct scheduler_backend {
void (*remove)(u_int64_t);
};
+
+#define STAT_KEY_SIZE 1024
+struct stat_kv {
+ void *iter;
+ char key[STAT_KEY_SIZE];
+ size_t val;
+};
+
+struct stat_backend {
+ void (*init)(void);
+ void (*close)(void);
+ void (*increment)(const char *);
+ void (*decrement)(const char *);
+ void (*set)(const char *, size_t);
+ int (*iter)(void **, char **, size_t *);
+};
+
+
extern struct smtpd *env;
extern void (*imsg_callback)(struct imsgev *, struct imsg *);
@@ -1118,7 +1078,7 @@ time_t scheduler_compute_schedule(struct scheduler_info *);
/* smtp.c */
pid_t smtp(void);
void smtp_resume(void);
-
+void smtp_destroy(struct session *);
/* smtp_session.c */
void session_init(struct listener *, struct session *);
@@ -1159,11 +1119,12 @@ SPLAY_PROTOTYPE(ssltree, ssl, ssl_nodes, ssl_cmp);
int ssl_ctx_use_private_key(void *, char *, off_t);
int ssl_ctx_use_certificate_chain(void *, char *, off_t);
-/* stats.c */
-void stat_init(struct stat_counter *, int);
-size_t stat_get(int, int);
-size_t stat_increment(int);
-size_t stat_decrement(int);
+
+/* stat_backend.c */
+struct stat_backend *stat_backend_lookup(const char *);
+void stat_increment(const char *);
+void stat_decrement(const char *);
+void stat_set(const char *, size_t);
/* tree.c */
diff --git a/usr.sbin/smtpd/smtpd/Makefile b/usr.sbin/smtpd/smtpd/Makefile
index 3d9467405e9..44fcb194fb5 100644
--- a/usr.sbin/smtpd/smtpd/Makefile
+++ b/usr.sbin/smtpd/smtpd/Makefile
@@ -1,4 +1,4 @@
-# $OpenBSD: Makefile,v 1.46 2012/08/07 21:47:58 eric Exp $
+# $OpenBSD: Makefile,v 1.47 2012/08/18 18:18:23 gilles Exp $
.PATH: ${.CURDIR}/.. ${.CURDIR}/../../../lib/libc/asr
@@ -10,7 +10,8 @@ SRCS= aliases.c auth.c bounce.c config.c control.c \
mfa.c mfa_session.c mta.c mta_session.c parse.y \
queue.c queue_backend.c ruleset.c \
scheduler.c scheduler_backend.c smtp.c smtp_session.c \
- smtpd.c ssl.c ssl_privsep.c stats.c tree.c user.c util.c
+ smtpd.c ssl.c ssl_privsep.c stat_backend.c tree.c \
+ user.c util.c
# backends
SRCS+= auth_bsd.c
@@ -24,6 +25,8 @@ SRCS+= map_static.c
SRCS+= map_stdio.c
SRCS+= queue_fsqueue.c
SRCS+= scheduler_ramqueue.c
+SRCS+= stat_ramstat.c
+#SRCS+= stat_sqlite.c
SRCS+= user_pwd.c
# resolver
diff --git a/usr.sbin/smtpd/stat_backend.c b/usr.sbin/smtpd/stat_backend.c
new file mode 100644
index 00000000000..b77ce3abc83
--- /dev/null
+++ b/usr.sbin/smtpd/stat_backend.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2012 Gilles Chehade <gilles@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+#include <sys/tree.h>
+#include <sys/param.h>
+
+#include <event.h>
+#include <imsg.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "log.h"
+#include "smtpd.h"
+
+struct stat_backend stat_backend_ramstat;
+struct stat_backend stat_backend_sqlite;
+
+struct stat_backend *
+stat_backend_lookup(const char *name)
+{
+ if (!strcmp(name, "ram"))
+ return &stat_backend_ramstat;
+
+ if (!strcmp(name, "sqlite"))
+ return &stat_backend_sqlite;
+
+ return (NULL);
+}
+
+void
+stat_increment(const char *name)
+{
+ char key[STAT_KEY_SIZE];
+
+ if (strlcpy(key, name, sizeof key) >= sizeof key)
+ log_warn("stat_increment: truncated key '%s', ignored", name);
+
+ imsg_compose_event(env->sc_ievs[PROC_CONTROL],
+ IMSG_STAT_INCREMENT, 0, 0, -1, key, sizeof key);
+}
+
+void
+stat_decrement(const char *name)
+{
+ char key[STAT_KEY_SIZE];
+
+ if (strlcpy(key, name, sizeof key) >= sizeof key)
+ log_warn("stat_increment: truncated key '%s', ignored", name);
+
+ imsg_compose_event(env->sc_ievs[PROC_CONTROL],
+ IMSG_STAT_DECREMENT, 0, 0, -1, key, sizeof key);
+}
+
+void
+stat_set(const char *name, size_t value)
+{
+ struct stat_kv kv;
+
+ bzero(&kv, sizeof kv);
+ if (strlcpy(kv.key, name, sizeof kv.key) >= sizeof kv.key)
+ log_warn("stat_increment: truncated key '%s', ignored", name);
+ kv.val = value;
+
+ imsg_compose_event(env->sc_ievs[PROC_CONTROL],
+ IMSG_STAT_SET, 0, 0, -1, &kv, sizeof kv);
+}
diff --git a/usr.sbin/smtpd/stat_ramstat.c b/usr.sbin/smtpd/stat_ramstat.c
new file mode 100644
index 00000000000..996f8ff8a24
--- /dev/null
+++ b/usr.sbin/smtpd/stat_ramstat.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2012 Gilles Chehade <gilles@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/queue.h>
+#include <sys/tree.h>
+#include <sys/param.h>
+
+#include <event.h>
+#include <imsg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "smtpd.h"
+#include "log.h"
+
+
+static void ramstat_init(void);
+static void ramstat_close(void);
+static void ramstat_increment(const char *);
+static void ramstat_decrement(const char *);
+static void ramstat_set(const char *, size_t);
+static int ramstat_iter(void **, char **, size_t *);
+
+struct ramstat_entry {
+ RB_ENTRY(ramstat_entry) entry;
+
+ char key[STAT_KEY_SIZE];
+ size_t value;
+};
+RB_HEAD(stats_tree, ramstat_entry) stats;
+RB_PROTOTYPE(stats_tree, ramstat_entry, entry, ramstat_entry_cmp);
+
+struct stat_backend stat_backend_ramstat = {
+ ramstat_init,
+ ramstat_close,
+ ramstat_increment,
+ ramstat_decrement,
+ ramstat_set,
+ ramstat_iter
+};
+
+static void
+ramstat_init(void)
+{
+ log_trace(TRACE_STAT, "ramstat: init");
+ RB_INIT(&stats);
+
+ /* ramstat_set() should be called for each key we want
+ * to have displayed by smtpctl show stats at startup.
+ */
+ ramstat_set("uptime", env->sc_uptime);
+}
+
+static void
+ramstat_close(void)
+{
+ log_trace(TRACE_STAT, "ramstat: close");
+}
+
+static void
+ramstat_increment(const char *name)
+{
+ struct ramstat_entry *np, lk;
+
+ log_trace(TRACE_STAT, "ramstat: increment: %s", name);
+ strlcpy(lk.key, name, sizeof (lk.key));
+ np = RB_FIND(stats_tree, &stats, &lk);
+ if (np == NULL) {
+ np = calloc(1, sizeof *np);
+ if (np == NULL)
+ fatal("calloc");
+ strlcpy(np->key, name, sizeof (np->key));
+ RB_INSERT(stats_tree, &stats, np);
+ }
+ log_trace(TRACE_STAT, "ramstat: %s (%p): %d -> %d",
+ name, name, (int)np->value, (int)np->value + 1);
+ np->value++;
+}
+
+static void
+ramstat_decrement(const char *name)
+{
+ struct ramstat_entry *np, lk;
+
+ log_trace(TRACE_STAT, "ramstat: decrement: %s", name);
+ strlcpy(lk.key, name, sizeof (lk.key));
+ np = RB_FIND(stats_tree, &stats, &lk);
+ if (np == NULL) {
+ np = calloc(1, sizeof *np);
+ if (np == NULL)
+ fatal("calloc");
+ strlcpy(np->key, name, sizeof (np->key));
+ RB_INSERT(stats_tree, &stats, np);
+ }
+ log_trace(TRACE_STAT, "ramstat: %s (%p): %d -> %d",
+ name, name, (int)np->value, (int)np->value - 1);
+ np->value--;
+}
+
+static void
+ramstat_set(const char *name, size_t val)
+{
+ struct ramstat_entry *np, lk;
+
+ log_trace(TRACE_STAT, "ramstat: set");
+ strlcpy(lk.key, name, sizeof (lk.key));
+ np = RB_FIND(stats_tree, &stats, &lk);
+ if (np == NULL) {
+ np = calloc(1, sizeof *np);
+ if (np == NULL)
+ fatal("calloc");
+ strlcpy(np->key, name, sizeof (np->key));
+ RB_INSERT(stats_tree, &stats, np);
+ }
+ log_trace(TRACE_STAT, "ramstat: %s: %d -> %d",
+ name, (int)np->value, (int)val);
+ np->value = val;
+}
+
+static int
+ramstat_iter(void **iter, char **name, size_t *val)
+{
+ struct ramstat_entry *np;
+
+ log_trace(TRACE_STAT, "ramstat: iter");
+ if (RB_EMPTY(&stats))
+ return 0;
+
+ if (*iter == NULL)
+ np = RB_ROOT(&stats);
+ else
+ np = RB_NEXT(stats_tree, &stats, *iter);
+
+ if (np) {
+ *name = np->key;
+ *val = np->value;
+ }
+ *iter = np;
+ return 1;
+}
+
+
+static int
+ramstat_entry_cmp(struct ramstat_entry *e1, struct ramstat_entry *e2)
+{
+ return strcmp(e1->key, e2->key);
+}
+
+RB_GENERATE(stats_tree, ramstat_entry, entry, ramstat_entry_cmp);
diff --git a/usr.sbin/smtpd/stats.c b/usr.sbin/smtpd/stats.c
index fb9715d2ddb..e69de29bb2d 100644
--- a/usr.sbin/smtpd/stats.c
+++ b/usr.sbin/smtpd/stats.c
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2011 Eric Faurot <eric@openbsd.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/queue.h>
-#include <sys/tree.h>
-#include <sys/param.h>
-
-#include <event.h>
-#include <imsg.h>
-#include <stdio.h>
-
-#include "smtpd.h"
-
-static struct stat_counter *counters = NULL;
-static int ncounter = 0;
-
-void
-stat_init(struct stat_counter *c, int n)
-{
- counters = c;
- ncounter = n;
-}
-
-size_t
-stat_increment(int stat)
-{
- if (stat < 0 || stat >= ncounter)
- return (-1);
-
- counters[stat].count++;
- if (++counters[stat].active > counters[stat].maxactive)
- counters[stat].maxactive = counters[stat].active;
-
- return (counters[stat].active);
-}
-
-size_t
-stat_decrement(int stat)
-{
- if (stat < 0 || stat >= ncounter)
- return (-1);
-
- counters[stat].active--;
-
- return (counters[stat].active);
-}
-
-size_t
-stat_get(int stat, int what)
-{
- if (stat < 0 || stat >= ncounter)
- return (-1);
-
- switch (what) {
- case STAT_COUNT:
- return counters[stat].count;
- case STAT_ACTIVE:
- return counters[stat].active;
- case STAT_MAXACTIVE:
- return counters[stat].maxactive;
- default:
- return (-1);
- }
-}