Download raw body.
bufferize smtp parsing in got-notify-email
rea(2)ing one byte at a time is a big ugly. This adds a buffer for the server replies and reworks read_smtp_code() to consume the data from said buffer first. it also makes got_poll_read_full_timeout() redundant. ok? diff /home/op/w/got commit - 39910b637a9a53cc48b0c63766da691dec0af593 path + /home/op/w/got blob - ef9b199c10bfcb34951de0d9a6e4c0915a91e274 file + gotd/libexec/got-notify-email/got-notify-email.c --- gotd/libexec/got-notify-email/got-notify-email.c +++ gotd/libexec/got-notify-email/got-notify-email.c @@ -18,6 +18,7 @@ #include <sys/socket.h> #include <errno.h> +#include <poll.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -33,7 +34,11 @@ #include "got_lib_poll.h" +#define SMTP_LINE_MAX 65535 + static int smtp_timeout = 60; /* in seconds */ +static char smtp_buf[SMTP_LINE_MAX]; +static size_t smtp_buflen; __dead static void usage(void) @@ -111,43 +116,54 @@ static int read_smtp_code(int s, const char *code) { const struct got_error *error; - char buf[4]; - size_t n; + char *endl; + size_t linelen; + ssize_t r; - error = got_poll_read_full_timeout(s, &n, buf, 3, 3, smtp_timeout); - if (error) - errx(1, "read: %s", error->msg); - if (strncmp(buf, code, 3) != 0) { - buf[3] = '\0'; - warnx("unexpected SMTP message code: %s", buf); - return -1; - } - - return 0; -} - -static int -skip_to_crlf(int s) -{ - const struct got_error *error; - char buf[1]; - size_t len; - for (;;) { - error = got_poll_read_full_timeout(s, &len, buf, 1, 1, - smtp_timeout); + endl = memmem(smtp_buf, smtp_buflen, "\r\n", 2); + if (endl != NULL) + break; + + if (smtp_buflen == sizeof(smtp_buf)) + errx(1, "line too long"); + + error = got_poll_fd(s, POLLIN, smtp_timeout); if (error) - errx(1, "read: %s", error->msg); - if (buf[0] == '\r') { - error = got_poll_read_full(s, &len, buf, 1, 1); - if (error) - errx(1, "read: %s", error->msg); - if (buf[0] == '\n') - return 0; - } + errx(1, "poll: %s", error->msg); + + r = read(s, smtp_buf + smtp_buflen, + sizeof(smtp_buf) - smtp_buflen); + if (r == -1 && errno != EAGAIN) + err(1, "read"); + if (r == 0) + errx(1, "unexpected EOF"); + smtp_buflen += r; } - return -1; + linelen = endl - smtp_buf; + if (linelen < 3) + errx(1, "invalid SMTP response"); + + if (strncmp(code, smtp_buf, 3) != 0) { + smtp_buf[3] = '\0'; + warnx("unexpected SMTP message code: %s", smtp_buf); + return -1; + } + + /* + * Normally we would get just one reply, but the regress doesn't + * use a real SMTP server and queues all the replies upfront. + */ + linelen += 2; + if (smtp_buflen == linelen) + smtp_buflen = 0; + else { + memmove(smtp_buf, smtp_buf + linelen, smtp_buflen - linelen); + smtp_buflen -= linelen; + } + + return 0; } static int @@ -216,36 +232,26 @@ send_email(int s, const char *myfromaddr, const char * if (read_smtp_code(s, "220")) errx(1, "unexpected SMTP greeting received"); - if (skip_to_crlf(s)) - errx(1, "invalid SMTP message received"); if (send_smtp_msg(s, "HELO localhost\r\n")) errx(1, "could not send HELO"); if (read_smtp_code(s, "250")) errx(1, "unexpected SMTP response received"); - if (skip_to_crlf(s)) - errx(1, "invalid SMTP message received"); if (send_smtp_msg(s, "MAIL FROM:<%s>\r\n", myfromaddr)) errx(1, "could not send MAIL FROM"); if (read_smtp_code(s, "250")) errx(1, "unexpected SMTP response received"); - if (skip_to_crlf(s)) - errx(1, "invalid SMTP message received"); if (send_smtp_msg(s, "RCPT TO:<%s>\r\n", recipient)) errx(1, "could not send MAIL FROM"); if (read_smtp_code(s, "250")) errx(1, "unexpected SMTP response received"); - if (skip_to_crlf(s)) - errx(1, "invalid SMTP message received"); if (send_smtp_msg(s, "DATA\r\n")) errx(1, "could not send MAIL FROM"); if (read_smtp_code(s, "354")) errx(1, "unexpected SMTP response received"); - if (skip_to_crlf(s)) - errx(1, "invalid SMTP message received"); if (send_smtp_msg(s, "From: %s\r\n", fromaddr)) errx(1, "could not send From header"); @@ -279,16 +285,12 @@ send_email(int s, const char *myfromaddr, const char * errx(1, "could not send data terminator"); if (read_smtp_code(s, "250")) errx(1, "unexpected SMTP response received"); - if (skip_to_crlf(s)) - errx(1, "invalid SMTP message received"); if (send_smtp_msg(s, "QUIT\r\n")) errx(1, "could not send QUIT"); if (read_smtp_code(s, "221")) errx(1, "unexpected SMTP response received"); - if (skip_to_crlf(s)) - errx(1, "invalid SMTP message received"); close(s); free(line);
bufferize smtp parsing in got-notify-email