diff options
-rw-r--r-- | usr.sbin/smtpd/scheduler_api.c | 416 | ||||
-rw-r--r-- | usr.sbin/smtpd/scheduler_backend.c | 5 | ||||
-rw-r--r-- | usr.sbin/smtpd/scheduler_null.c | 2 | ||||
-rw-r--r-- | usr.sbin/smtpd/scheduler_proc.c | 423 | ||||
-rw-r--r-- | usr.sbin/smtpd/scheduler_ramqueue.c | 2 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd-api.h | 93 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd.h | 54 | ||||
-rw-r--r-- | usr.sbin/smtpd/smtpd/Makefile | 3 |
8 files changed, 940 insertions, 58 deletions
diff --git a/usr.sbin/smtpd/scheduler_api.c b/usr.sbin/smtpd/scheduler_api.c new file mode 100644 index 00000000000..6f0b214d798 --- /dev/null +++ b/usr.sbin/smtpd/scheduler_api.c @@ -0,0 +1,416 @@ +/* $OpenBSD: scheduler_api.c,v 1.1 2013/07/19 21:34:31 eric Exp $ */ + +/* + * Copyright (c) 2013 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/queue.h> +#include <sys/uio.h> + +#include <imsg.h> +#include <pwd.h> +#include <string.h> +#include <unistd.h> + +#include "smtpd-defines.h" +#include "smtpd-api.h" +#include "log.h" + +static int (*handler_init)(void); +static int (*handler_insert)(struct scheduler_info *); +static size_t (*handler_commit)(uint32_t); +static size_t (*handler_rollback)(uint32_t); +static int (*handler_update)(struct scheduler_info *); +static int (*handler_delete)(uint64_t); +static int (*handler_batch)(int, struct scheduler_batch *); +static size_t (*handler_messages)(uint32_t, uint32_t *, size_t); +static size_t (*handler_envelopes)(uint64_t, struct evpstate *, size_t); +static int (*handler_schedule)(uint64_t); +static int (*handler_remove)(uint64_t); +static int (*handler_suspend)(uint64_t); +static int (*handler_resume)(uint64_t); + +#define MAX_BATCH_SIZE 1024 + +static struct imsgbuf ibuf; +static struct imsg imsg; +static size_t rlen; +static char *rdata; +static struct ibuf *buf; +static char *rootpath = PATH_CHROOT; +static char *user = SMTPD_USER; + +static void +scheduler_msg_get(void *dst, size_t len) +{ + if (len > rlen) { + log_warnx("warn: scheduler-proc: bad msg len"); + fatalx("scheduler-proc: exiting"); + } + + if (len == 0) + return; + + if (dst) + memmove(dst, rdata, len); + + rlen -= len; + rdata += len; +} + +static void +scheduler_msg_end(void) +{ + if (rlen) { + log_warnx("warn: scheduler-proc: bogus data"); + fatalx("scheduler-proc: exiting"); + } + imsg_free(&imsg); +} + +static void +scheduler_msg_add(const void *data, size_t len) +{ + if (buf == NULL) + buf = imsg_create(&ibuf, PROC_SCHEDULER_OK, 0, 0, 1024); + if (buf == NULL) { + log_warnx("warn: table-api: imsg_create failed"); + fatalx("table-api: exiting"); + } + if (imsg_add(buf, data, len) == -1) { + log_warnx("warn: table-api: imsg_add failed"); + fatalx("table-api: exiting"); + } +} + +static void +scheduler_msg_close(void) +{ + imsg_close(&ibuf, buf); + buf = NULL; +} + +static void +scheduler_msg_dispatch(void) +{ + size_t n, sz; + struct evpstate evpstates[MAX_BATCH_SIZE]; + uint64_t evpid, evpids[MAX_BATCH_SIZE]; + uint32_t msgids[MAX_BATCH_SIZE], version, msgid; + struct scheduler_info info; + struct scheduler_batch batch; + int typemask, r; + + switch (imsg.hdr.type) { + case PROC_SCHEDULER_INIT: + log_debug("scheduler-api: PROC_SCHEDULER_INIT"); + scheduler_msg_get(&version, sizeof(version)); + scheduler_msg_end(); + + if (version != PROC_SCHEDULER_API_VERSION) { + log_warnx("warn: scheduler-api: bad API version"); + fatalx("scheduler-api: exiting"); + } + + r = handler_init(); + + imsg_compose(&ibuf, PROC_SCHEDULER_OK, 0, 0, -1, &r, sizeof(r)); + break; + + case PROC_SCHEDULER_INSERT: + log_debug("scheduler-api: PROC_SCHEDULER_INSERT"); + scheduler_msg_get(&info, sizeof(info)); + scheduler_msg_end(); + + r = handler_insert(&info); + + imsg_compose(&ibuf, PROC_SCHEDULER_OK, 0, 0, -1, &r, sizeof(r)); + break; + + case PROC_SCHEDULER_COMMIT: + log_debug("scheduler-api: PROC_SCHEDULER_COMMIT"); + scheduler_msg_get(&msgid, sizeof(msgid)); + scheduler_msg_end(); + + n = handler_commit(msgid); + + imsg_compose(&ibuf, PROC_SCHEDULER_OK, 0, 0, -1, &n, sizeof(n)); + break; + + case PROC_SCHEDULER_ROLLBACK: + log_debug("scheduler-api: PROC_SCHEDULER_ROLLBACK"); + scheduler_msg_get(&msgid, sizeof(msgid)); + scheduler_msg_end(); + + n = handler_rollback(msgid); + + imsg_compose(&ibuf, PROC_SCHEDULER_OK, 0, 0, -1, &n, sizeof(n)); + break; + + case PROC_SCHEDULER_UPDATE: + log_debug("scheduler-api: PROC_SCHEDULER_UPDATE"); + scheduler_msg_get(&info, sizeof(info)); + scheduler_msg_end(); + + r = handler_update(&info); + + scheduler_msg_add(&r, sizeof(r)); + if (r == 1) + scheduler_msg_add(&info, sizeof(info)); + scheduler_msg_close(); + break; + + case PROC_SCHEDULER_DELETE: + log_debug("scheduler-api: PROC_SCHEDULER_DELETE"); + scheduler_msg_get(&evpid, sizeof(evpid)); + scheduler_msg_end(); + + r = handler_delete(evpid); + + imsg_compose(&ibuf, PROC_SCHEDULER_OK, 0, 0, -1, &r, sizeof(r)); + break; + + case PROC_SCHEDULER_BATCH: + log_debug("scheduler-api: PROC_SCHEDULER_BATCH"); + scheduler_msg_get(&typemask, sizeof(typemask)); + scheduler_msg_get(&batch.evpcount, sizeof(batch.evpcount)); + scheduler_msg_end(); + + if (batch.evpcount > MAX_BATCH_SIZE) + batch.evpcount = MAX_BATCH_SIZE; + batch.evpids = evpids; + + handler_batch(typemask, &batch); + + scheduler_msg_add(&batch, sizeof(batch)); + scheduler_msg_add(evpids, sizeof(*evpids) * batch.evpcount); + scheduler_msg_close(); + break; + + case PROC_SCHEDULER_MESSAGES: + log_debug("scheduler-api: PROC_SCHEDULER_MESSAGES"); + scheduler_msg_get(&msgid, sizeof(msgid)); + scheduler_msg_get(&sz, sizeof(sz)); + scheduler_msg_end(); + + if (sz > MAX_BATCH_SIZE) + sz = MAX_BATCH_SIZE; + + n = handler_messages(msgid, msgids, sz); + + imsg_compose(&ibuf, PROC_SCHEDULER_OK, 0, 0, -1, msgids, + n * sizeof(*msgids)); + break; + + case PROC_SCHEDULER_ENVELOPES: + log_debug("scheduler-api: PROC_SCHEDULER_ENVELOPES"); + scheduler_msg_get(&evpid, sizeof(evpid)); + scheduler_msg_get(&sz, sizeof(sz)); + scheduler_msg_end(); + + if (sz > MAX_BATCH_SIZE) + sz = MAX_BATCH_SIZE; + + n = handler_envelopes(evpid, evpstates, sz); + + imsg_compose(&ibuf, PROC_SCHEDULER_OK, 0, 0, -1, evpstates, + n * sizeof(*evpstates)); + break; + + case PROC_SCHEDULER_SCHEDULE: + log_debug("scheduler-api: PROC_SCHEDULER_SCHEDULE"); + scheduler_msg_get(&evpid, sizeof(evpid)); + scheduler_msg_end(); + + r = handler_schedule(evpid); + + imsg_compose(&ibuf, PROC_SCHEDULER_OK, 0, 0, -1, &r, sizeof(r)); + break; + + case PROC_SCHEDULER_REMOVE: + log_debug("scheduler-api: PROC_SCHEDULER_REMOVE"); + scheduler_msg_get(&evpid, sizeof(evpid)); + scheduler_msg_end(); + + r = handler_remove(evpid); + + imsg_compose(&ibuf, PROC_SCHEDULER_OK, 0, 0, -1, &r, sizeof(r)); + break; + + case PROC_SCHEDULER_SUSPEND: + log_debug("scheduler-api: PROC_SCHEDULER_SUSPEND"); + scheduler_msg_get(&evpid, sizeof(evpid)); + scheduler_msg_end(); + + r = handler_suspend(evpid); + + imsg_compose(&ibuf, PROC_SCHEDULER_OK, 0, 0, -1, &r, sizeof(r)); + break; + + case PROC_SCHEDULER_RESUME: + log_debug("scheduler-api: PROC_SCHEDULER_RESUME"); + scheduler_msg_get(&evpid, sizeof(evpid)); + scheduler_msg_end(); + + r = handler_resume(evpid); + + imsg_compose(&ibuf, PROC_SCHEDULER_OK, 0, 0, -1, &r, sizeof(r)); + break; + + default: + log_warnx("warn: scheduler-api: bad message %i", imsg.hdr.type); + fatalx("scheduler-api: exiting"); + } +} + +void +scheduler_api_on_init(int(*cb)(void)) +{ + handler_init = cb; +} + +void +scheduler_api_on_insert(int(*cb)(struct scheduler_info *)) +{ + handler_insert = cb; +} + +void +scheduler_api_on_commit(size_t(*cb)(uint32_t)) +{ + handler_commit = cb; +} + +void +scheduler_api_on_rollback(size_t(*cb)(uint32_t)) +{ + handler_rollback = cb; +} + +void +scheduler_api_on_update(int(*cb)(struct scheduler_info *)) +{ + handler_update = cb; +} + +void +scheduler_api_on_delete(int(*cb)(uint64_t)) +{ + handler_delete = cb; +} + +void +scheduler_api_on_batch(int(*cb)(int, struct scheduler_batch *)) +{ + handler_batch = cb; +} + +void +scheduler_api_on_messages(size_t(*cb)(uint32_t, uint32_t *, size_t)) +{ + handler_messages = cb; +} + +void +scheduler_api_on_envelopes(size_t(*cb)(uint64_t, struct evpstate *, size_t)) +{ + handler_envelopes = cb; +} + +void +scheduler_api_on_schedule(int(*cb)(uint64_t)) +{ + handler_schedule = cb; +} + +void +scheduler_api_on_remove(int(*cb)(uint64_t)) +{ + handler_remove = cb; +} + +void +scheduler_api_on_suspend(int(*cb)(uint64_t)) +{ + handler_suspend = cb; +} + +void +scheduler_api_on_resume(int(*cb)(uint64_t)) +{ + handler_resume = cb; +} + +int +scheduler_api_dispatch(void) +{ + struct passwd *pw; + ssize_t n; + + pw = getpwnam(user); + if (pw == NULL) { + log_warn("scheduler-api: getpwnam"); + fatalx("scheduler-api: exiting"); + } + + if (rootpath) { + if (chroot(rootpath) == -1) { + log_warn("scheduler-api: chroot"); + fatalx("scheduler-api: exiting"); + } + if (chdir("/") == -1) { + log_warn("scheduler-api: chdir"); + fatalx("scheduler-api: exiting"); + } + } + + 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)) { + log_warn("scheduler-api: cannot drop privileges"); + fatalx("scheduler-api: exiting"); + } + + imsg_init(&ibuf, 0); + + while (1) { + n = imsg_get(&ibuf, &imsg); + if (n == -1) { + log_warn("warn: scheduler-api: imsg_get"); + break; + } + + if (n) { + rdata = imsg.data; + rlen = imsg.hdr.len - IMSG_HEADER_SIZE; + scheduler_msg_dispatch(); + imsg_flush(&ibuf); + continue; + } + + n = imsg_read(&ibuf); + if (n == -1) { + log_warn("warn: scheduler-api: imsg_read"); + break; + } + if (n == 0) { + log_warnx("warn: scheduler-api: pipe closed"); + break; + } + } + + return (1); +} diff --git a/usr.sbin/smtpd/scheduler_backend.c b/usr.sbin/smtpd/scheduler_backend.c index 34d9d204c71..8df4d3693a3 100644 --- a/usr.sbin/smtpd/scheduler_backend.c +++ b/usr.sbin/smtpd/scheduler_backend.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scheduler_backend.c,v 1.10 2013/07/19 15:14:23 eric Exp $ */ +/* $OpenBSD: scheduler_backend.c,v 1.11 2013/07/19 21:34:31 eric Exp $ */ /* * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> @@ -34,6 +34,7 @@ #include "log.h" extern struct scheduler_backend scheduler_backend_null; +extern struct scheduler_backend scheduler_backend_proc; extern struct scheduler_backend scheduler_backend_ramqueue; struct scheduler_backend * @@ -41,6 +42,8 @@ scheduler_backend_lookup(const char *name) { if (!strcmp(name, "null")) return &scheduler_backend_null; + if (!strcmp(name, "proc")) + return &scheduler_backend_proc; if (!strcmp(name, "ramqueue")) return &scheduler_backend_ramqueue; diff --git a/usr.sbin/smtpd/scheduler_null.c b/usr.sbin/smtpd/scheduler_null.c index 943b762d38e..020f05869b6 100644 --- a/usr.sbin/smtpd/scheduler_null.c +++ b/usr.sbin/smtpd/scheduler_null.c @@ -1,4 +1,4 @@ -/* $OpenBSD: scheduler_null.c,v 1.3 2013/07/19 15:14:23 eric Exp $ */ +/* $OpenBSD: scheduler_null.c,v 1.4 2013/07/19 21:34:31 eric Exp $ */ /* * Copyright (c) 2012 Eric Faurot <eric@openbsd.org> diff --git a/usr.sbin/smtpd/scheduler_proc.c b/usr.sbin/smtpd/scheduler_proc.c new file mode 100644 index 00000000000..dd962d93289 --- /dev/null +++ b/usr.sbin/smtpd/scheduler_proc.c @@ -0,0 +1,423 @@ +/* $OpenBSD: scheduler_proc.c,v 1.1 2013/07/19 21:34:31 eric Exp $ */ + +/* + * Copyright (c) 2013 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/queue.h> +#include <sys/tree.h> +#include <sys/param.h> +#include <sys/socket.h> + +#include <ctype.h> +#include <err.h> +#include <errno.h> +#include <event.h> +#include <fcntl.h> +#include <imsg.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "smtpd.h" +#include "log.h" + +static pid_t pid; +static struct imsgbuf ibuf; +static struct imsg imsg; +static size_t rlen; +static char *rdata; + +static const char *execpath = "/usr/libexec/smtpd/backend-scheduler"; + +static void +scheduler_proc_call(void) +{ + ssize_t n; + + if (imsg_flush(&ibuf) == -1) { + log_warn("warn: scheduler-proc: imsg_flush"); + fatalx("scheduler-proc: exiting"); + } + + while (1) { + if ((n = imsg_get(&ibuf, &imsg)) == -1) { + log_warn("warn: scheduler-proc: imsg_get"); + break; + } + if (n) { + rlen = imsg.hdr.len - IMSG_HEADER_SIZE; + rdata = imsg.data; + + if (imsg.hdr.type != PROC_SCHEDULER_OK) { + log_warnx("warn: scheduler-proc: bad response"); + break; + } + return; + } + + if ((n = imsg_read(&ibuf)) == -1) { + log_warn("warn: scheduler-proc: imsg_read"); + break; + } + + if (n == 0) { + log_warnx("warn: scheduler-proc: pipe closed"); + break; + } + } + + fatalx("scheduler-proc: exiting"); +} + +static void +scheduler_proc_read(void *dst, size_t len) +{ + if (len > rlen) { + log_warnx("warn: scheduler-proc: bad msg len"); + fatalx("scheduler-proc: exiting"); + } + + memmove(dst, rdata, len); + rlen -= len; + rdata += len; +} + +static void +scheduler_proc_end(void) +{ + if (rlen) { + log_warnx("warn: scheduler-proc: bogus data"); + fatalx("scheduler-proc: exiting"); + } + imsg_free(&imsg); +} + +/* + * API + */ + +static int +scheduler_proc_init(void) +{ + int sp[2], r; + uint32_t version; + + errno = 0; + + if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, sp) < 0) { + log_warn("warn: scheduler-proc: socketpair"); + goto err; + } + + if ((pid = fork()) == -1) { + log_warn("warn: scheduler-proc: fork"); + goto err; + } + + if (pid == 0) { + /* child process */ + dup2(sp[0], STDIN_FILENO); + if (closefrom(STDERR_FILENO + 1) < 0) + exit(1); + + execl(execpath, "scheduler-proc", NULL); + err(1, "execl"); + } + + /* parent process */ + close(sp[0]); + imsg_init(&ibuf, sp[1]); + + version = PROC_SCHEDULER_API_VERSION; + imsg_compose(&ibuf, PROC_SCHEDULER_INIT, 0, 0, -1, + &version, sizeof(version)); + + scheduler_proc_call(); + scheduler_proc_read(&r, sizeof(r)); + scheduler_proc_end(); + + return (r); + +err: + close(sp[0]); + close(sp[1]); + fatalx("scheduler-proc: exiting"); + + return (0); +} + +static int +scheduler_proc_insert(struct scheduler_info *si) +{ + int r; + + log_debug("debug: scheduler-proc: PROC_SCHEDULER_INSERT"); + + imsg_compose(&ibuf, PROC_SCHEDULER_INSERT, 0, 0, -1, si, sizeof(*si)); + + scheduler_proc_call(); + scheduler_proc_read(&r, sizeof(r)); + scheduler_proc_end(); + + return (r); +} + +static size_t +scheduler_proc_commit(uint32_t msgid) +{ + size_t s; + + log_debug("debug: scheduler-proc: PROC_SCHEDULER_COMMIT"); + + imsg_compose(&ibuf, PROC_SCHEDULER_COMMIT, 0, 0, -1, + &msgid, sizeof(msgid)); + + scheduler_proc_call(); + scheduler_proc_read(&s, sizeof(s)); + scheduler_proc_end(); + + return (s); +} + +static size_t +scheduler_proc_rollback(uint32_t msgid) +{ + size_t s; + + log_debug("debug: scheduler-proc: PROC_SCHEDULER_ROLLBACK"); + + imsg_compose(&ibuf, PROC_SCHEDULER_ROLLBACK, 0, 0, -1, + &msgid, sizeof(msgid)); + + scheduler_proc_call(); + scheduler_proc_read(&s, sizeof(s)); + scheduler_proc_end(); + + return (s); +} + +static int +scheduler_proc_update(struct scheduler_info *si) +{ + int r; + + log_debug("debug: scheduler-proc: PROC_SCHEDULER_UPDATE"); + + imsg_compose(&ibuf, PROC_SCHEDULER_UPDATE, 0, 0, -1, si, sizeof(*si)); + + scheduler_proc_call(); + scheduler_proc_read(&r, sizeof(r)); + if (r == 1) + scheduler_proc_read(si, sizeof(*si)); + scheduler_proc_end(); + + return (r); +} + +static int +scheduler_proc_delete(uint64_t evpid) +{ + int r; + + log_debug("debug: scheduler-proc: PROC_SCHEDULER_DELETE"); + + imsg_compose(&ibuf, PROC_SCHEDULER_DELETE, 0, 0, -1, + &evpid, sizeof(evpid)); + + scheduler_proc_call(); + scheduler_proc_read(&r, sizeof(r)); + scheduler_proc_end(); + + return (r); +} + +static int +scheduler_proc_batch(int typemask, struct scheduler_batch *ret) +{ + struct ibuf *buf; + uint64_t *evpids; + + log_debug("debug: scheduler-proc: PROC_SCHEDULER_BATCH"); + + buf = imsg_create(&ibuf, PROC_SCHEDULER_BATCH, 0, 0, + sizeof(typemask) + sizeof(ret->evpcount)); + if (buf == NULL) + return (-1); + if (imsg_add(buf, &typemask, sizeof(typemask)) == -1) + return (-1); + if (imsg_add(buf, &ret->evpcount, sizeof(ret->evpcount)) == -1) + return (-1); + imsg_close(&ibuf, buf); + + evpids = ret->evpids; + + scheduler_proc_call(); + + scheduler_proc_read(ret, sizeof(*ret)); + scheduler_proc_read(evpids, sizeof(*evpids) * ret->evpcount); + scheduler_proc_end(); + + ret->evpids = evpids; + + if (ret->type == SCHED_NONE) + return (0); + + return (1); +} + +static size_t +scheduler_proc_messages(uint32_t from, uint32_t *dst, size_t size) +{ + struct ibuf *buf; + size_t s; + + log_debug("debug: scheduler-proc: PROC_SCHEDULER_MESSAGES"); + + buf = imsg_create(&ibuf, PROC_SCHEDULER_MESSAGES, 0, 0, + sizeof(from) + sizeof(size)); + if (buf == NULL) + return (-1); + if (imsg_add(buf, &from, sizeof(from)) == -1) + return (-1); + if (imsg_add(buf, &size, sizeof(size)) == -1) + return (-1); + imsg_close(&ibuf, buf); + + scheduler_proc_call(); + + s = rlen / sizeof(*dst); + scheduler_proc_read(dst, s * sizeof(*dst)); + scheduler_proc_end(); + + return (s); +} + +static size_t +scheduler_proc_envelopes(uint64_t from, struct evpstate *dst, size_t size) +{ + struct ibuf *buf; + size_t s; + + log_debug("debug: scheduler-proc: PROC_SCHEDULER_ENVELOPES"); + + buf = imsg_create(&ibuf, PROC_SCHEDULER_ENVELOPES, 0, 0, + sizeof(from) + sizeof(size)); + if (buf == NULL) + return (-1); + if (imsg_add(buf, &from, sizeof(from)) == -1) + return (-1); + if (imsg_add(buf, &size, sizeof(size)) == -1) + return (-1); + imsg_close(&ibuf, buf); + + scheduler_proc_call(); + + s = rlen / sizeof(*dst); + scheduler_proc_read(dst, s * sizeof(*dst)); + scheduler_proc_end(); + + return (s); +} + +static int +scheduler_proc_schedule(uint64_t evpid) +{ + int r; + + log_debug("debug: scheduler-proc: PROC_SCHEDULER_SCHEDULE"); + + imsg_compose(&ibuf, PROC_SCHEDULER_SCHEDULE, 0, 0, -1, + &evpid, sizeof(evpid)); + + scheduler_proc_call(); + + scheduler_proc_read(&r, sizeof(r)); + scheduler_proc_end(); + + return (r); +} + +static int +scheduler_proc_remove(uint64_t evpid) +{ + int r; + + log_debug("debug: scheduler-proc: PROC_SCHEDULER_REMOVE"); + + imsg_compose(&ibuf, PROC_SCHEDULER_REMOVE, 0, 0, -1, + &evpid, sizeof(evpid)); + + scheduler_proc_call(); + + scheduler_proc_read(&r, sizeof(r)); + scheduler_proc_end(); + + return (r); +} + +static int +scheduler_proc_suspend(uint64_t evpid) +{ + int r; + + log_debug("debug: scheduler-proc: PROC_SCHEDULER_SUSPEND"); + + imsg_compose(&ibuf, PROC_SCHEDULER_SUSPEND, 0, 0, -1, + &evpid, sizeof(evpid)); + + scheduler_proc_call(); + + scheduler_proc_read(&r, sizeof(r)); + scheduler_proc_end(); + + return (r); +} + +static int +scheduler_proc_resume(uint64_t evpid) +{ + int r; + + log_debug("debug: scheduler-proc: PROC_SCHEDULER_RESUME"); + + imsg_compose(&ibuf, PROC_SCHEDULER_RESUME, 0, 0, -1, + &evpid, sizeof(evpid)); + + scheduler_proc_call(); + + scheduler_proc_read(&r, sizeof(r)); + scheduler_proc_end(); + + return (r); +} + +struct scheduler_backend scheduler_backend_proc = { + scheduler_proc_init, + scheduler_proc_insert, + scheduler_proc_commit, + scheduler_proc_rollback, + scheduler_proc_update, + scheduler_proc_delete, + scheduler_proc_batch, + scheduler_proc_messages, + scheduler_proc_envelopes, + scheduler_proc_schedule, + scheduler_proc_remove, + scheduler_proc_suspend, + scheduler_proc_resume, +}; diff --git a/usr.sbin/smtpd/scheduler_ramqueue.c b/usr.sbin/smtpd/scheduler_ramqueue.c index 482928d8ed5..4efd88d132b 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.29 2013/07/19 15:14:23 eric Exp $ */ +/* $OpenBSD: scheduler_ramqueue.c,v 1.30 2013/07/19 21:34:31 eric Exp $ */ /* * Copyright (c) 2012 Gilles Chehade <gilles@poolp.org> diff --git a/usr.sbin/smtpd/smtpd-api.h b/usr.sbin/smtpd/smtpd-api.h index 7c4f4f6cf58..b7353667b6d 100644 --- a/usr.sbin/smtpd/smtpd-api.h +++ b/usr.sbin/smtpd/smtpd-api.h @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd-api.h,v 1.7 2013/07/19 20:37:07 eric Exp $ */ +/* $OpenBSD: smtpd-api.h,v 1.8 2013/07/19 21:34:31 eric Exp $ */ /* * Copyright (c) 2013 Eric Faurot <eric@openbsd.org> @@ -105,6 +105,81 @@ enum { PROC_QUEUE_ENVELOPE_WALK, }; +#define PROC_SCHEDULER_API_VERSION 1 + +struct scheduler_info; +struct scheduler_batch; + +enum { + PROC_SCHEDULER_OK, + PROC_SCHEDULER_FAIL, + PROC_SCHEDULER_INIT, + PROC_SCHEDULER_INSERT, + PROC_SCHEDULER_COMMIT, + PROC_SCHEDULER_ROLLBACK, + PROC_SCHEDULER_UPDATE, + PROC_SCHEDULER_DELETE, + PROC_SCHEDULER_BATCH, + PROC_SCHEDULER_MESSAGES, + PROC_SCHEDULER_ENVELOPES, + PROC_SCHEDULER_SCHEDULE, + PROC_SCHEDULER_REMOVE, + PROC_SCHEDULER_SUSPEND, + PROC_SCHEDULER_RESUME, +}; + +enum envelope_flags { + EF_AUTHENTICATED = 0x01, + EF_BOUNCE = 0x02, + EF_INTERNAL = 0x04, /* Internal expansion forward */ + + /* runstate, not saved on disk */ + + EF_PENDING = 0x10, + EF_INFLIGHT = 0x20, + EF_SUSPEND = 0x40, +}; + +struct evpstate { + uint64_t evpid; + uint16_t flags; + uint16_t retry; + time_t time; +}; + +enum delivery_type { + D_MDA, + D_MTA, + D_BOUNCE, +}; + +struct scheduler_info { + uint64_t evpid; + enum delivery_type type; + uint16_t retry; + time_t creation; + time_t expire; + time_t lasttry; + time_t lastbounce; + time_t nexttry; + uint8_t penalty; +}; + +#define SCHED_NONE 0x00 +#define SCHED_DELAY 0x01 +#define SCHED_REMOVE 0x02 +#define SCHED_EXPIRE 0x04 +#define SCHED_BOUNCE 0x08 +#define SCHED_MDA 0x10 +#define SCHED_MTA 0x20 + +struct scheduler_batch { + int type; + time_t delay; + size_t evpcount; + uint64_t *evpids; +}; + #define PROC_TABLE_API_VERSION 1 enum table_service { @@ -196,6 +271,22 @@ void queue_api_on_envelope_load(int(*)(uint64_t, char *, size_t)); void queue_api_on_envelope_walk(int(*)(uint64_t *, char *, size_t)); int queue_api_dispatch(void); +/* scheduler */ +void scheduler_api_on_init(int(*)(void)); +void scheduler_api_on_insert(int(*)(struct scheduler_info *)); +void scheduler_api_on_commit(size_t(*)(uint32_t)); +void scheduler_api_on_rollback(size_t(*)(uint32_t)); +void scheduler_api_on_update(int(*)(struct scheduler_info *)); +void scheduler_api_on_delete(int(*)(uint64_t)); +void scheduler_api_on_batch(int(*)(int, struct scheduler_batch *)); +void scheduler_api_on_messages(size_t(*)(uint32_t, uint32_t *, size_t)); +void scheduler_api_on_envelopes(size_t(*)(uint64_t, struct evpstate *, size_t)); +void scheduler_api_on_schedule(int(*)(uint64_t)); +void scheduler_api_on_remove(int(*)(uint64_t)); +void scheduler_api_on_suspend(int(*)(uint64_t)); +void scheduler_api_on_resume(int(*)(uint64_t)); +int scheduler_api_dispatch(void); + /* table */ void table_api_on_update(int(*)(void)); void table_api_on_check(int(*)(int, const char *)); diff --git a/usr.sbin/smtpd/smtpd.h b/usr.sbin/smtpd/smtpd.h index 9dbe77e26e0..961b8a78ab4 100644 --- a/usr.sbin/smtpd/smtpd.h +++ b/usr.sbin/smtpd/smtpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: smtpd.h,v 1.421 2013/07/19 21:14:52 eric Exp $ */ +/* $OpenBSD: smtpd.h,v 1.422 2013/07/19 21:34:31 eric Exp $ */ /* * Copyright (c) 2008 Gilles Chehade <gilles@poolp.org> @@ -356,12 +356,6 @@ struct rule { time_t r_qexpire; }; -enum delivery_type { - D_MDA, - D_MTA, - D_BOUNCE, -}; - struct delivery_mda { enum action_type method; char usertable[SMTPD_MAXPATHLEN]; @@ -425,18 +419,6 @@ struct expand { struct expandnode *parent; }; -enum envelope_flags { - EF_AUTHENTICATED = 0x01, - EF_BOUNCE = 0x02, - EF_INTERNAL = 0x04, /* Internal expansion forward */ - - /* runstate, not saved on disk */ - - EF_PENDING = 0x10, - EF_INFLIGHT = 0x20, - EF_SUSPEND = 0x40, -}; - #define SMTPD_ENVELOPE_VERSION 1 struct envelope { TAILQ_ENTRY(envelope) entry; @@ -819,40 +801,6 @@ struct delivery_backend { void (*open)(struct deliver *); }; -struct evpstate { - uint64_t evpid; - uint16_t flags; - uint16_t retry; - time_t time; -}; - -struct scheduler_info { - uint64_t evpid; - enum delivery_type type; - uint16_t retry; - time_t creation; - time_t expire; - time_t lasttry; - time_t lastbounce; - time_t nexttry; - uint8_t penalty; -}; - -#define SCHED_NONE 0x00 -#define SCHED_DELAY 0x01 -#define SCHED_REMOVE 0x02 -#define SCHED_EXPIRE 0x04 -#define SCHED_BOUNCE 0x08 -#define SCHED_MDA 0x10 -#define SCHED_MTA 0x20 - -struct scheduler_batch { - int type; - time_t delay; - size_t evpcount; - uint64_t *evpids; -}; - struct scheduler_backend { int (*init)(void); diff --git a/usr.sbin/smtpd/smtpd/Makefile b/usr.sbin/smtpd/smtpd/Makefile index fa024ced24e..c6ac4b63cfd 100644 --- a/usr.sbin/smtpd/smtpd/Makefile +++ b/usr.sbin/smtpd/smtpd/Makefile @@ -1,4 +1,4 @@ -# $OpenBSD: Makefile,v 1.64 2013/07/19 21:14:52 eric Exp $ +# $OpenBSD: Makefile,v 1.65 2013/07/19 21:34:31 eric Exp $ .PATH: ${.CURDIR}/.. @@ -31,6 +31,7 @@ SRCS+= queue_proc.c SRCS+= queue_ram.c SRCS+= scheduler_ramqueue.c SRCS+= scheduler_null.c +SRCS+= scheduler_proc.c SRCS+= stat_ramstat.c MAN= smtpd.8 smtpd.conf.5 |