1*d3140113Seric /* $OpenBSD: queue_ram.c,v 1.11 2021/06/14 17:58:16 eric Exp $ */
265c4fdfbSgilles
365c4fdfbSgilles /*
465c4fdfbSgilles * Copyright (c) 2012 Eric Faurot <eric@openbsd.org>
565c4fdfbSgilles *
665c4fdfbSgilles * Permission to use, copy, modify, and distribute this software for any
765c4fdfbSgilles * purpose with or without fee is hereby granted, provided that the above
865c4fdfbSgilles * copyright notice and this permission notice appear in all copies.
965c4fdfbSgilles *
1065c4fdfbSgilles * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1165c4fdfbSgilles * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1265c4fdfbSgilles * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1365c4fdfbSgilles * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1465c4fdfbSgilles * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1565c4fdfbSgilles * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1665c4fdfbSgilles * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1765c4fdfbSgilles */
1865c4fdfbSgilles
1965c4fdfbSgilles #include <sys/stat.h>
2065c4fdfbSgilles
2165c4fdfbSgilles #include <stdlib.h>
2265c4fdfbSgilles #include <string.h>
2365c4fdfbSgilles #include <unistd.h>
2465c4fdfbSgilles
2565c4fdfbSgilles #include "smtpd.h"
2665c4fdfbSgilles #include "log.h"
2765c4fdfbSgilles
2865c4fdfbSgilles struct qr_envelope {
2965c4fdfbSgilles char *buf;
3065c4fdfbSgilles size_t len;
3165c4fdfbSgilles };
3265c4fdfbSgilles
3365c4fdfbSgilles struct qr_message {
3465c4fdfbSgilles char *buf;
3565c4fdfbSgilles size_t len;
3665c4fdfbSgilles struct tree envelopes;
3765c4fdfbSgilles };
3865c4fdfbSgilles
3965c4fdfbSgilles static struct tree messages;
4065c4fdfbSgilles
413f70ecafSeric static struct qr_message *
get_message(uint32_t msgid)423f70ecafSeric get_message(uint32_t msgid)
4365c4fdfbSgilles {
443f70ecafSeric struct qr_message *msg;
453f70ecafSeric
463f70ecafSeric msg = tree_get(&messages, msgid);
473f70ecafSeric if (msg == NULL)
483f70ecafSeric log_warn("warn: queue-ram: message not found");
493f70ecafSeric
503f70ecafSeric return (msg);
513f70ecafSeric }
523f70ecafSeric
533f70ecafSeric static int
queue_ram_message_create(uint32_t * msgid)543f70ecafSeric queue_ram_message_create(uint32_t *msgid)
553f70ecafSeric {
563f70ecafSeric struct qr_message *msg;
573f70ecafSeric
583f70ecafSeric msg = calloc(1, sizeof(*msg));
593f70ecafSeric if (msg == NULL) {
603f70ecafSeric log_warn("warn: queue-ram: calloc");
613f70ecafSeric return (0);
623f70ecafSeric }
633f70ecafSeric tree_init(&msg->envelopes);
643f70ecafSeric
653f70ecafSeric do {
663f70ecafSeric *msgid = queue_generate_msgid();
673f70ecafSeric } while (tree_check(&messages, *msgid));
683f70ecafSeric
693f70ecafSeric tree_xset(&messages, *msgid, msg);
7065c4fdfbSgilles
7165c4fdfbSgilles return (1);
7265c4fdfbSgilles }
7365c4fdfbSgilles
7465c4fdfbSgilles static int
queue_ram_message_commit(uint32_t msgid,const char * path)753f70ecafSeric queue_ram_message_commit(uint32_t msgid, const char *path)
7665c4fdfbSgilles {
7765c4fdfbSgilles struct qr_message *msg;
7865c4fdfbSgilles struct stat sb;
7965c4fdfbSgilles size_t n;
803f70ecafSeric FILE *f;
813f70ecafSeric int ret;
8265c4fdfbSgilles
833f70ecafSeric if ((msg = tree_get(&messages, msgid)) == NULL) {
843f70ecafSeric log_warnx("warn: queue-ram: msgid not found");
853f70ecafSeric return (0);
863f70ecafSeric }
8765c4fdfbSgilles
883f70ecafSeric f = fopen(path, "rb");
893f70ecafSeric if (f == NULL) {
903f70ecafSeric log_warn("warn: queue-ram: fopen: %s", path);
913f70ecafSeric return (0);
923f70ecafSeric }
933f70ecafSeric if (fstat(fileno(f), &sb) == -1) {
943f70ecafSeric log_warn("warn: queue-ram: fstat");
953f70ecafSeric fclose(f);
963f70ecafSeric return (0);
973f70ecafSeric }
983f70ecafSeric
993f70ecafSeric msg->len = sb.st_size;
1003f70ecafSeric msg->buf = malloc(msg->len);
1013f70ecafSeric if (msg->buf == NULL) {
1023f70ecafSeric log_warn("warn: queue-ram: malloc");
1033f70ecafSeric fclose(f);
1043f70ecafSeric return (0);
1053f70ecafSeric }
1063f70ecafSeric
1073f70ecafSeric ret = 0;
1083f70ecafSeric n = fread(msg->buf, 1, msg->len, f);
1093f70ecafSeric if (ferror(f))
1103f70ecafSeric log_warn("warn: queue-ram: fread");
1113f70ecafSeric else if ((off_t)n != sb.st_size)
1123f70ecafSeric log_warnx("warn: queue-ram: bad read");
1133f70ecafSeric else {
1143f70ecafSeric ret = 1;
1153f70ecafSeric stat_increment("queue.ram.message.size", msg->len);
1163f70ecafSeric }
1173f70ecafSeric fclose(f);
1183f70ecafSeric
1193f70ecafSeric return (ret);
1203f70ecafSeric }
1213f70ecafSeric
1223f70ecafSeric static int
queue_ram_message_delete(uint32_t msgid)1233f70ecafSeric queue_ram_message_delete(uint32_t msgid)
1243f70ecafSeric {
1253f70ecafSeric struct qr_message *msg;
1263f70ecafSeric struct qr_envelope *evp;
1273f70ecafSeric uint64_t evpid;
1283f70ecafSeric
1293f70ecafSeric if ((msg = tree_pop(&messages, msgid)) == NULL) {
1303f70ecafSeric log_warnx("warn: queue-ram: not found");
13165c4fdfbSgilles return (0);
13265c4fdfbSgilles }
13365c4fdfbSgilles while (tree_poproot(&messages, &evpid, (void**)&evp)) {
13465c4fdfbSgilles stat_decrement("queue.ram.envelope.size", evp->len);
13565c4fdfbSgilles free(evp->buf);
13665c4fdfbSgilles free(evp);
13765c4fdfbSgilles }
13865c4fdfbSgilles stat_decrement("queue.ram.message.size", msg->len);
13965c4fdfbSgilles free(msg->buf);
14065c4fdfbSgilles free(msg);
14165c4fdfbSgilles return (0);
14265c4fdfbSgilles }
14365c4fdfbSgilles
1443f70ecafSeric static int
queue_ram_message_fd_r(uint32_t msgid)1453f70ecafSeric queue_ram_message_fd_r(uint32_t msgid)
1463f70ecafSeric {
1473f70ecafSeric struct qr_message *msg;
1483f70ecafSeric size_t n;
1493f70ecafSeric FILE *f;
1503f70ecafSeric int fd, fd2;
15165c4fdfbSgilles
1523f70ecafSeric if ((msg = tree_get(&messages, msgid)) == NULL) {
1533f70ecafSeric log_warnx("warn: queue-ram: not found");
15465c4fdfbSgilles return (-1);
15565c4fdfbSgilles }
1563f70ecafSeric
15765c4fdfbSgilles fd = mktmpfile();
15865c4fdfbSgilles if (fd == -1) {
1593f70ecafSeric log_warn("warn: queue-ram: mktmpfile");
16065c4fdfbSgilles return (-1);
16165c4fdfbSgilles }
1623f70ecafSeric
16365c4fdfbSgilles fd2 = dup(fd);
16465c4fdfbSgilles if (fd2 == -1) {
1653f70ecafSeric log_warn("warn: queue-ram: dup");
16665c4fdfbSgilles close(fd);
16765c4fdfbSgilles return (-1);
16865c4fdfbSgilles }
16965c4fdfbSgilles f = fdopen(fd2, "w");
17065c4fdfbSgilles if (f == NULL) {
1713f70ecafSeric log_warn("warn: queue-ram: fdopen");
17265c4fdfbSgilles close(fd);
17365c4fdfbSgilles close(fd2);
17465c4fdfbSgilles return (-1);
17565c4fdfbSgilles }
17665c4fdfbSgilles n = fwrite(msg->buf, 1, msg->len, f);
17765c4fdfbSgilles if (n != msg->len) {
1783f70ecafSeric log_warn("warn: queue-ram: write");
17965c4fdfbSgilles close(fd);
18065c4fdfbSgilles fclose(f);
18165c4fdfbSgilles return (-1);
18265c4fdfbSgilles }
18365c4fdfbSgilles fclose(f);
18465c4fdfbSgilles lseek(fd, 0, SEEK_SET);
18565c4fdfbSgilles return (fd);
18665c4fdfbSgilles }
18765c4fdfbSgilles
18865c4fdfbSgilles static int
queue_ram_envelope_create(uint32_t msgid,const char * buf,size_t len,uint64_t * evpid)1893f70ecafSeric queue_ram_envelope_create(uint32_t msgid, const char *buf, size_t len,
1903f70ecafSeric uint64_t *evpid)
19165c4fdfbSgilles {
19265c4fdfbSgilles struct qr_envelope *evp;
19365c4fdfbSgilles struct qr_message *msg;
19465c4fdfbSgilles
1953f70ecafSeric if ((msg = get_message(msgid)) == NULL)
19665c4fdfbSgilles return (0);
19765c4fdfbSgilles
19865c4fdfbSgilles do {
19965c4fdfbSgilles *evpid = queue_generate_evpid(msgid);
20065c4fdfbSgilles } while (tree_check(&msg->envelopes, *evpid));
20165c4fdfbSgilles evp = calloc(1, sizeof *evp);
20265c4fdfbSgilles if (evp == NULL) {
2033f70ecafSeric log_warn("warn: queue-ram: calloc");
20465c4fdfbSgilles return (0);
20565c4fdfbSgilles }
20665c4fdfbSgilles evp->len = len;
20765c4fdfbSgilles evp->buf = malloc(len);
20865c4fdfbSgilles if (evp->buf == NULL) {
2093f70ecafSeric log_warn("warn: queue-ram: malloc");
2101c6ac251Seric free(evp);
21165c4fdfbSgilles return (0);
21265c4fdfbSgilles }
21365c4fdfbSgilles memmove(evp->buf, buf, len);
21465c4fdfbSgilles tree_xset(&msg->envelopes, *evpid, evp);
21565c4fdfbSgilles stat_increment("queue.ram.envelope.size", len);
21665c4fdfbSgilles return (1);
2173f70ecafSeric }
21865c4fdfbSgilles
2193f70ecafSeric static int
queue_ram_envelope_delete(uint64_t evpid)2203f70ecafSeric queue_ram_envelope_delete(uint64_t evpid)
2213f70ecafSeric {
2223f70ecafSeric struct qr_envelope *evp;
2233f70ecafSeric struct qr_message *msg;
2243f70ecafSeric
2253f70ecafSeric if ((msg = get_message(evpid_to_msgid(evpid))) == NULL)
2263f70ecafSeric return (0);
2273f70ecafSeric
2283f70ecafSeric if ((evp = tree_pop(&msg->envelopes, evpid)) == NULL) {
2293f70ecafSeric log_warnx("warn: queue-ram: not found");
23065c4fdfbSgilles return (0);
23165c4fdfbSgilles }
23265c4fdfbSgilles stat_decrement("queue.ram.envelope.size", evp->len);
23365c4fdfbSgilles free(evp->buf);
23465c4fdfbSgilles free(evp);
23565c4fdfbSgilles if (tree_empty(&msg->envelopes)) {
2363f70ecafSeric tree_xpop(&messages, evpid_to_msgid(evpid));
23765c4fdfbSgilles stat_decrement("queue.ram.message.size", msg->len);
23865c4fdfbSgilles free(msg->buf);
23965c4fdfbSgilles free(msg);
24065c4fdfbSgilles }
24165c4fdfbSgilles return (1);
24265c4fdfbSgilles }
24365c4fdfbSgilles
2443f70ecafSeric static int
queue_ram_envelope_update(uint64_t evpid,const char * buf,size_t len)2453f70ecafSeric queue_ram_envelope_update(uint64_t evpid, const char *buf, size_t len)
2463f70ecafSeric {
2473f70ecafSeric struct qr_envelope *evp;
2483f70ecafSeric struct qr_message *msg;
2493f70ecafSeric void *tmp;
2503f70ecafSeric
2513f70ecafSeric if ((msg = get_message(evpid_to_msgid(evpid))) == NULL)
2523f70ecafSeric return (0);
2533f70ecafSeric
2543f70ecafSeric if ((evp = tree_get(&msg->envelopes, evpid)) == NULL) {
2553f70ecafSeric log_warn("warn: queue-ram: not found");
25665c4fdfbSgilles return (0);
25765c4fdfbSgilles }
25865c4fdfbSgilles tmp = malloc(len);
25965c4fdfbSgilles if (tmp == NULL) {
2603f70ecafSeric log_warn("warn: queue-ram: malloc");
26165c4fdfbSgilles return (0);
26265c4fdfbSgilles }
26365c4fdfbSgilles memmove(tmp, buf, len);
26465c4fdfbSgilles free(evp->buf);
26565c4fdfbSgilles evp->len = len;
26665c4fdfbSgilles evp->buf = tmp;
26765c4fdfbSgilles stat_decrement("queue.ram.envelope.size", evp->len);
26865c4fdfbSgilles stat_increment("queue.ram.envelope.size", len);
26965c4fdfbSgilles return (1);
27065c4fdfbSgilles }
27165c4fdfbSgilles
2723f70ecafSeric static int
queue_ram_envelope_load(uint64_t evpid,char * buf,size_t len)2733f70ecafSeric queue_ram_envelope_load(uint64_t evpid, char *buf, size_t len)
2743f70ecafSeric {
2753f70ecafSeric struct qr_envelope *evp;
2763f70ecafSeric struct qr_message *msg;
2773f70ecafSeric
2783f70ecafSeric if ((msg = get_message(evpid_to_msgid(evpid))) == NULL)
2793f70ecafSeric return (0);
2803f70ecafSeric
2813f70ecafSeric if ((evp = tree_get(&msg->envelopes, evpid)) == NULL) {
2823f70ecafSeric log_warn("warn: queue-ram: not found");
28365c4fdfbSgilles return (0);
28465c4fdfbSgilles }
2853f70ecafSeric if (len < evp->len) {
2863f70ecafSeric log_warnx("warn: queue-ram: buffer too small");
2873f70ecafSeric return (0);
2883f70ecafSeric }
2893f70ecafSeric memmove(buf, evp->buf, evp->len);
2903f70ecafSeric return (evp->len);
2913f70ecafSeric }
2923f70ecafSeric
2933f70ecafSeric static int
queue_ram_envelope_walk(uint64_t * evpid,char * buf,size_t len)2943f70ecafSeric queue_ram_envelope_walk(uint64_t *evpid, char *buf, size_t len)
2953f70ecafSeric {
2963f70ecafSeric return (-1);
2973f70ecafSeric }
2983f70ecafSeric
2993f70ecafSeric static int
queue_ram_init(struct passwd * pw,int server,const char * conf)30098f67d16Seric queue_ram_init(struct passwd *pw, int server, const char * conf)
3013f70ecafSeric {
3023f70ecafSeric tree_init(&messages);
3033f70ecafSeric
3043f70ecafSeric queue_api_on_message_create(queue_ram_message_create);
3053f70ecafSeric queue_api_on_message_commit(queue_ram_message_commit);
3063f70ecafSeric queue_api_on_message_delete(queue_ram_message_delete);
3073f70ecafSeric queue_api_on_message_fd_r(queue_ram_message_fd_r);
3083f70ecafSeric queue_api_on_envelope_create(queue_ram_envelope_create);
3093f70ecafSeric queue_api_on_envelope_delete(queue_ram_envelope_delete);
3103f70ecafSeric queue_api_on_envelope_update(queue_ram_envelope_update);
3113f70ecafSeric queue_api_on_envelope_load(queue_ram_envelope_load);
3123f70ecafSeric queue_api_on_envelope_walk(queue_ram_envelope_walk);
3133f70ecafSeric
3143f70ecafSeric return (1);
3153f70ecafSeric }
3163f70ecafSeric
3173f70ecafSeric struct queue_backend queue_backend_ram = {
3183f70ecafSeric queue_ram_init,
3193f70ecafSeric };
320