commit a211223d04eb8add0ba4b89c31473196903d7296 from: Martijn van Duren date: Mon Apr 1 15:46:29 2019 UTC Add a custom printf function that's not susceptible to EAGAIN. commit - a287838f380d0bec3fca2f273a88d5e466dde790 commit + a211223d04eb8add0ba4b89c31473196903d7296 blob - 4b27868ec32fcc96ec3ffd47220c27aebe999789 blob + 511fe85a8f5024c97cd39a4467cb95e31180c0b4 --- smtp_proc.c +++ smtp_proc.c @@ -47,7 +47,17 @@ static void smtp_dataline(struct smtp_callback *, int, uint64_t, uint64_t, char *); static void smtp_in_link_disconnect(struct smtp_callback *, int, struct timespec *, uint64_t, char *); +static void smtp_printf(const char *, ...) + __attribute__((__format__ (printf, 1, 2))); +static void smtp_vprintf(const char *, va_list); +static void smtp_write(int, short, void *); +struct smtp_writebuf { + char *buf; + size_t bufsize; + size_t buflen; +}; + struct smtp_callback { char *type; char *phase; @@ -102,8 +112,7 @@ smtp_run(int debug) { struct event stdinev; - printf("register|ready\n"); - fflush(stdout); + smtp_printf("register|ready\n"); ready = 1; log_init(debug, LOG_MAIL); @@ -318,11 +327,77 @@ smtp_in_link_disconnect(struct smtp_callback *cb, int void smtp_filter_proceed(uint64_t reqid, uint64_t token) { - printf("filter-result|%016"PRIx64"|%016"PRIx64"|proceed\n", token, + smtp_printf("filter-result|%016"PRIx64"|%016"PRIx64"|proceed\n", token, reqid); - fflush(stdout); } +static void +smtp_printf(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + smtp_vprintf(fmt, ap); + va_end(ap); +} + +static void +smtp_vprintf(const char *fmt, va_list ap) +{ + va_list cap; + static struct smtp_writebuf buf = {NULL, 0, 0}; + int fmtlen; + + va_copy(cap, ap); + fmtlen = vsnprintf(buf.buf + buf.buflen, buf.bufsize - buf.buflen, fmt, + ap); + if (fmtlen == -1) + fatal("vsnprintf"); + if (fmtlen >= buf.bufsize - buf.buflen) { + buf.bufsize = buf.buflen + fmtlen + 1; + buf.buf = reallocarray(buf.buf, buf.bufsize, + sizeof(*(buf.buf))); + if (buf.buf == NULL) + fatalx(NULL); + fmtlen = vsnprintf(buf.buf + buf.buflen, + buf.bufsize - buf.buflen, fmt, cap); + if (fmtlen == -1) + fatal("vsnprintf"); + } + buf.buflen += fmtlen; + + if (strchr(buf.buf, '\n') != NULL) + smtp_write(STDOUT_FILENO, EV_WRITE, &buf); +} + +static void +smtp_write(int fd, short event, void *arg) +{ + struct smtp_writebuf *buf = arg; + static struct event ev; + static int evset = 0; + ssize_t wlen; + + if (buf->buflen == 0) + return; + if (!evset) { + event_set(&ev, fd, EV_WRITE, smtp_write, buf); + evset = 1; + } + wlen = write(fd, buf->buf, buf->buflen); + if (wlen == -1) { + if (errno != EAGAIN || errno != EINTR) + fatal("Failed to write to smtpd"); + event_add(&ev, NULL); + return; + } + if (wlen < buf->buflen) { + memmove(buf->buf, buf->buf + wlen, buf->buflen - wlen); + event_add(&ev, NULL); + } + buf->buflen -= wlen; +} + void smtp_filter_reject(uint64_t reqid, uint64_t token, int code, const char *reason, ...) @@ -332,13 +407,12 @@ smtp_filter_reject(uint64_t reqid, uint64_t token, int if (code < 200 || code > 599) fatalx("Invalid reject code"); - printf("filter-result|%016"PRIx64"|%016"PRIx64"|reject|%d ", token, + smtp_printf("filter-result|%016"PRIx64"|%016"PRIx64"|reject|%d ", token, reqid, code); va_start(ap, reason); - vprintf(reason, ap); + smtp_vprintf(reason, ap); va_end(ap); - putchar('\n'); - fflush(stdout); + smtp_printf("\n"); } void @@ -346,13 +420,12 @@ smtp_filter_disconnect(uint64_t reqid, uint64_t token, { va_list ap; - printf("filter-result|%016"PRIx64"|%016"PRIx64"|disconnect|421 ", + smtp_printf("filter-result|%016"PRIx64"|%016"PRIx64"|disconnect|421 ", token, reqid); va_start(ap, reason); - vprintf(reason, ap); + smtp_vprintf(reason, ap); va_end(ap); - putchar('\n'); - fflush(stdout); + smtp_printf("\n"); } void @@ -360,12 +433,11 @@ smtp_filter_dataline(uint64_t reqid, uint64_t token, c { va_list ap; - printf("filter-dataline|%016"PRIx64"|%016"PRIx64"|", token, reqid); + smtp_printf("filter-dataline|%016"PRIx64"|%016"PRIx64"|", token, reqid); va_start(ap, line); - vprintf(line, ap); + smtp_vprintf(line, ap); va_end(ap); - putchar('\n'); - fflush(stdout); + smtp_printf("\n"); } static int @@ -385,7 +457,8 @@ smtp_register(char *type, char *phase, char *direction return -1; } smtp_callbacks[i].cb = cb; - printf("register|%s|%s|%s\n", type, direction, phase); + smtp_printf("register|%s|%s|%s\n", type, direction, + phase); return 0; } }