diff options
author | Jacek Masiulaniec <jacekm@cvs.openbsd.org> | 2009-12-12 14:04:00 +0000 |
---|---|---|
committer | Jacek Masiulaniec <jacekm@cvs.openbsd.org> | 2009-12-12 14:04:00 +0000 |
commit | 9dfe6e27554c4e9ba33949827433f475758d59f1 (patch) | |
tree | 03fdbacb300cbac33848fe257e081297a144c613 /usr.sbin | |
parent | 32ca805073b05a555e12df3429094a6a0fd4d86d (diff) |
When acting as a client do content reads from the disk progressively
as the remote accepts more data instead of doing one big read into
the memory in the beginning of session.
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/smtpd/bounce.c | 17 | ||||
-rw-r--r-- | usr.sbin/smtpd/client.c | 121 | ||||
-rw-r--r-- | usr.sbin/smtpd/client.h | 10 | ||||
-rw-r--r-- | usr.sbin/smtpd/enqueue.c | 16 | ||||
-rw-r--r-- | usr.sbin/smtpd/mta.c | 7 |
5 files changed, 87 insertions, 84 deletions
diff --git a/usr.sbin/smtpd/bounce.c b/usr.sbin/smtpd/bounce.c index 52feb25ad5a..a313b8503a5 100644 --- a/usr.sbin/smtpd/bounce.c +++ b/usr.sbin/smtpd/bounce.c @@ -1,4 +1,4 @@ -/* $OpenBSD: bounce.c,v 1.13 2009/12/12 10:33:11 jacekm Exp $ */ +/* $OpenBSD: bounce.c,v 1.14 2009/12/12 14:03:59 jacekm Exp $ */ /* * Copyright (c) 2009 Gilles Chehade <gilles@openbsd.org> @@ -58,10 +58,14 @@ bounce_session(struct smtpd *env, int fd, struct message *messagep) int msgfd = -1; char *reason; + /* get message content */ + if ((msgfd = queue_open_message_file(messagep->message_id)) == -1) + goto fail; + /* init smtp session */ if ((cc = calloc(1, sizeof(*cc))) == NULL) goto fail; - cc->pcb = client_init(fd, env->sc_hostname, 1); + cc->pcb = client_init(fd, msgfd, env->sc_hostname, 1); cc->m = *messagep; client_ssl_optional(cc->pcb); @@ -77,7 +81,7 @@ bounce_session(struct smtpd *env, int fd, struct message *messagep) /* create message header */ /* XXX - The Date: header should be added during SMTP pickup. */ - client_data_printf(cc->pcb, + client_printf(cc->pcb, "Subject: Delivery status notification\n" "From: Mailer Daemon <MAILER-DAEMON@%s>\n" "To: %s@%s\n" @@ -100,13 +104,6 @@ bounce_session(struct smtpd *env, int fd, struct message *messagep) messagep->recipient.user, messagep->recipient.domain, reason); - /* append original message */ - if ((msgfd = queue_open_message_file(messagep->message_id)) == -1) - goto fail; - client_data_fd(cc->pcb, msgfd); - close(msgfd); - msgfd = -1; - /* setup event */ session_socket_blockmode(fd, BM_NONBLOCK); event_set(&cc->ev, fd, EV_WRITE, bounce_event, cc); diff --git a/usr.sbin/smtpd/client.c b/usr.sbin/smtpd/client.c index e00bf48b7ab..ab55f29d5c2 100644 --- a/usr.sbin/smtpd/client.c +++ b/usr.sbin/smtpd/client.c @@ -1,4 +1,4 @@ -/* $OpenBSD: client.c,v 1.18 2009/12/12 10:33:11 jacekm Exp $ */ +/* $OpenBSD: client.c,v 1.19 2009/12/12 14:03:59 jacekm Exp $ */ /* * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net> @@ -45,7 +45,7 @@ void client_status(struct smtp_client *, char *, ...); int client_getln(struct smtp_client *); void client_putln(struct smtp_client *, char *, ...); -void client_data_add(struct smtp_client *, char *, size_t); +void client_body(struct msgbuf *, FILE *); #ifndef CLIENT_NO_SSL int client_ssl_connect(struct smtp_client *); @@ -65,7 +65,7 @@ void fatalx(const char *); /* XXX */ * Initialize SMTP session. */ struct smtp_client * -client_init(int fd, char *ehlo, int verbose) +client_init(int fd, int body, char *ehlo, int verbose) { struct smtp_client *sp = NULL; @@ -92,8 +92,8 @@ client_init(int fd, char *ehlo, int verbose) sp->verbose = stdout; else if ((sp->verbose = fopen("/dev/null", "a")) == NULL) fatal("client_init: fopen"); - if ((sp->data = buf_dynamic(0, SIZE_T_MAX)) == NULL) - fatal(NULL); + if ((sp->body = fdopen(body, "r")) == NULL) + fatal("client_init: fdopen"); sp->state = CLIENT_INIT; sp->handler = client_write; sp->timeout.tv_sec = 300; @@ -208,44 +208,41 @@ client_rcpt(struct smtp_client *sp, void *p, char *fmt, ...) } /* - * Append file referenced by fd to the data buffer. - */ -void -client_data_fd(struct smtp_client *sp, int fd) -{ - struct stat sb; - char *map; - - if (fstat(fd, &sb) == -1) - fatal("client_data_fd: fstat"); - if ((size_t)sb.st_size > SIZE_T_MAX) - fatalx("client_data_fd: file too large"); - if (!S_ISREG(sb.st_mode)) - fatalx("client_data_fd: non-regular file"); - map = mmap(NULL, sb.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, - (off_t)0); - if (map == MAP_FAILED) - fatal("client_data_fd: mmap failed"); - madvise(map, sb.st_size, MADV_SEQUENTIAL); - client_data_add(sp, map, sb.st_size); - munmap(map, sb.st_size); -} - -/* * Append string to the data buffer. */ void -client_data_printf(struct smtp_client *sp, char *fmt, ...) +client_printf(struct smtp_client *sp, char *fmt, ...) { va_list ap; - char *p = NULL; + char *p, *ln, *tmp; int len; + if (sp->head == NULL) + sp->head = buf_dynamic(0, SIZE_T_MAX); + if (sp->head == NULL) + fatal(NULL); + va_start(ap, fmt); if ((len = vasprintf(&p, fmt, ap)) == -1) fatal("client_data_printf: vasprintf"); va_end(ap); - client_data_add(sp, p, len); + + /* must end with a newline */ + if (len == 0 || p[len - 1] != '\n') + fatalx("client_printf: invalid use"); + p[len - 1] = '\0'; + + /* split into lines, deal with dot escaping etc. */ + tmp = p; + while ((ln = strsep(&tmp, "\n"))) { + if (*ln == '.' && buf_add(sp->head, ".", 1)) + fatal(NULL); + if (buf_add(sp->head, ln, strlen(ln))) + fatal(NULL); + if (buf_add(sp->head, "\r\n", 2)) + fatal(NULL); + } + free(p); } @@ -503,10 +500,11 @@ client_write(struct smtp_client *sp) case CLIENT_DATA_BODY: sp->timeout.tv_sec = 180; - if (buf_add(sp->data, ".\r\n", 3) < 0) - fatal("client_write: buf_add failed"); - buf_close(&sp->w, sp->data); - sp->data = NULL; + if (sp->head) { + buf_close(&sp->w, sp->head); + sp->head = NULL; + } + client_body(&sp->w, sp->body); break; case CLIENT_QUIT: @@ -545,11 +543,12 @@ write: } } - /* - * Extend timeout after having sent final "." character. - */ - if (sp->state == CLIENT_DATA_BODY && sp->w.queued == 0) - sp->timeout.tv_sec = 600; + if (sp->state == CLIENT_DATA_BODY) { + if (!feof(sp->body)) + return (CLIENT_WANT_WRITE); + else + sp->timeout.tv_sec = 600; + } return (sp->w.queued ? CLIENT_WANT_WRITE : CLIENT_WANT_READ); } @@ -616,8 +615,8 @@ client_close(struct smtp_client *sp) free(sp->auth.plain); free(sp->auth.cert); free(sp->auth.key); - if (sp->data) - buf_free(sp->data); + if (sp->head) + buf_free(sp->head); msgbuf_clear(&sp->w); while ((rp = TAILQ_FIRST(&sp->recipients))) { TAILQ_REMOVE(&sp->recipients, rp, entry); @@ -775,9 +774,9 @@ client_putln(struct smtp_client *sp, char *fmt, ...) if ((cmd = buf_open(len + 2)) == NULL) fatal(NULL); - if (buf_add(cmd, p, len) < 0) + if (buf_add(cmd, p, len)) fatal(NULL); - if (buf_add(cmd, "\r\n", 2) < 0) + if (buf_add(cmd, "\r\n", 2)) fatal(NULL); buf_close(&sp->w, cmd); @@ -785,27 +784,35 @@ client_putln(struct smtp_client *sp, char *fmt, ...) } /* - * Append buffer to the data buffer, performing necessary transformations. + * Put chunk of message content to output buffer. */ void -client_data_add(struct smtp_client *sp, char *buf, size_t len) +client_body(struct msgbuf *out, FILE *fp) { - char *ln; + struct buf *b; + char *ln; + size_t len, total = 0; - /* must end with a newline */ - if (len == 0 || buf[len - 1] != '\n') - fatalx("client_data_add: bad buffer"); - buf[len - 1] = '\0'; + if ((b = buf_dynamic(0, SIZE_T_MAX)) == NULL) + fatal(NULL); - /* split into lines, deal with dot escaping etc. */ - while ((ln = strsep(&buf, "\n"))) { - if (*ln == '.' && buf_add(sp->data, ".", 1) < 0) + while ((ln = fgetln(fp, &len)) && total < 4096) { + if (ln[len - 1] == '\n') + len--; + if (*ln == '.' && buf_add(b, ".", 1)) fatal(NULL); - if (buf_add(sp->data, ln, strlen(ln)) < 0) + if (buf_add(b, ln, len)) fatal(NULL); - if (buf_add(sp->data, "\r\n", 2) < 0) + if (buf_add(b, "\r\n", 2)) fatal(NULL); + total += len; } + if (ferror(fp)) + fatal("client_body: fgetln"); + if (feof(fp) && buf_add(b, ".\r\n", 3)) + fatal(NULL); + + buf_close(out, b); } /* diff --git a/usr.sbin/smtpd/client.h b/usr.sbin/smtpd/client.h index d038ab0acc4..f81832e819f 100644 --- a/usr.sbin/smtpd/client.h +++ b/usr.sbin/smtpd/client.h @@ -1,4 +1,4 @@ -/* $OpenBSD: client.h,v 1.5 2009/12/12 10:33:11 jacekm Exp $ */ +/* $OpenBSD: client.h,v 1.6 2009/12/12 14:03:59 jacekm Exp $ */ /* * Copyright (c) 2009 Jacek Masiulaniec <jacekm@dobremiasto.net> @@ -81,7 +81,8 @@ struct smtp_client { size_t rcptokay; struct buf_read r; struct msgbuf w; - struct buf *data; + struct buf *head; + FILE *body; struct client_ext exts[CLIENT_EXT_MAX]; int (*handler)(struct smtp_client *); void *ssl_state; @@ -92,7 +93,7 @@ struct smtp_client { FILE *verbose; }; -struct smtp_client *client_init(int, char *, int); +struct smtp_client *client_init(int, int, char *, int); void client_ssl_smtps(struct smtp_client *); void client_ssl_optional(struct smtp_client *); void client_certificate(struct smtp_client *, char *, @@ -100,7 +101,6 @@ void client_certificate(struct smtp_client *, char *, void client_auth(struct smtp_client *, char *); void client_sender(struct smtp_client *, char *, ...); void client_rcpt(struct smtp_client *, void *, char *, ...); -void client_data_fd(struct smtp_client *, int); -void client_data_printf(struct smtp_client *, char *, ...); +void client_printf(struct smtp_client *, char *, ...); int client_talk(struct smtp_client *); void client_close(struct smtp_client *); diff --git a/usr.sbin/smtpd/enqueue.c b/usr.sbin/smtpd/enqueue.c index f5f6c949f95..251a2346c1f 100644 --- a/usr.sbin/smtpd/enqueue.c +++ b/usr.sbin/smtpd/enqueue.c @@ -1,4 +1,4 @@ -/* $OpenBSD: enqueue.c,v 1.28 2009/12/12 10:33:11 jacekm Exp $ */ +/* $OpenBSD: enqueue.c,v 1.29 2009/12/12 14:03:59 jacekm Exp $ */ /* * Copyright (c) 2005 Henning Brauer <henning@bulabula.org> @@ -27,6 +27,7 @@ #include <err.h> #include <errno.h> #include <event.h> +#include <fcntl.h> #include <netdb.h> #include <pwd.h> #include <signal.h> @@ -190,7 +191,8 @@ enqueue(int argc, char *argv[]) msg.fd = open_connection(); /* init session */ - pcb = client_init(msg.fd, "localhost", verbose); + pcb = client_init(msg.fd, open("/dev/null", O_RDONLY), "localhost", + verbose); /* parse message */ if ((body = buf_dynamic(0, SIZE_T_MAX)) < 0) @@ -208,25 +210,25 @@ enqueue(int argc, char *argv[]) /* add From */ if (!msg.saw_from) - client_data_printf(pcb, "From: %s%s<%s>\n", + client_printf(pcb, "From: %s%s<%s>\n", msg.fromname ? msg.fromname : "", msg.fromname ? " " : "", msg.from); /* add Date */ if (!msg.saw_date) - client_data_printf(pcb, "Date: %s\n", time_to_text(timestamp)); + client_printf(pcb, "Date: %s\n", time_to_text(timestamp)); /* add Message-Id */ if (!msg.saw_msgid) - client_data_printf(pcb, "Message-Id: <%llu.enqueue@%s>\n", + client_printf(pcb, "Message-Id: <%llu.enqueue@%s>\n", generate_uid(), host); /* add separating newline */ if (noheader) - client_data_printf(pcb, "\n"); + client_printf(pcb, "\n"); - client_data_printf(pcb, "%.*s", buf_size(body), body->buf); + client_printf(pcb, "%.*s", buf_size(body), body->buf); buf_free(body); /* run the protocol engine */ diff --git a/usr.sbin/smtpd/mta.c b/usr.sbin/smtpd/mta.c index 99ecc7ccd3f..660fd113afd 100644 --- a/usr.sbin/smtpd/mta.c +++ b/usr.sbin/smtpd/mta.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mta.c,v 1.80 2009/12/12 10:33:11 jacekm Exp $ */ +/* $OpenBSD: mta.c,v 1.81 2009/12/12 14:03:59 jacekm Exp $ */ /* * Copyright (c) 2008 Pierre-Yves Ritschard <pyr@openbsd.org> @@ -636,7 +636,7 @@ mta_enter_state(struct mta_session *s, int newstate, void *p) */ log_debug("mta: entering smtp phase"); - pcb = client_init(s->fd, s->env->sc_hostname, 1); + pcb = client_init(s->fd, s->datafd, s->env->sc_hostname, 1); /* lookup SSL certificate */ if (s->cert) { @@ -679,9 +679,6 @@ mta_enter_state(struct mta_session *s, int newstate, void *p) client_rcpt(pcb, m, "%s@%s", m->recipient.user, m->recipient.domain); - /* load message body */ - client_data_fd(pcb, s->datafd); - s->pcb = pcb; event_set(&s->ev, s->fd, EV_WRITE, mta_event, s); event_add(&s->ev, &pcb->timeout); |