Commit Diff


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;
 		}
 	}