commit 6bf2fad2fc8b42aa1521eebe69ad7bbc85b4b7f6 from: Martijn van Duren date: Fri Mar 29 15:47:15 2019 UTC Replace getline with custom function. Getline doesn't play nice with nonblocking io commit - 35699cf9db102f7ac133057073a650392bb1bbb2 commit + 6bf2fad2fc8b42aa1521eebe69ad7bbc85b4b7f6 blob - 3be970ff30966a8c4cb6ec200f15209ef9f5a374 blob + be114e97cf4fe0fa9ece5653d2d980aecd3fa2b9 --- smtp_proc.c +++ smtp_proc.c @@ -37,6 +37,7 @@ struct smtp_callback; struct smtp_request; static int smtp_register(char *, char *, char *, void *); +static ssize_t smtp_getline(char ** restrict, size_t * restrict); static void smtp_newline(int, short, void *); static void smtp_connect(struct smtp_callback *, int, struct timespec *, uint64_t, uint64_t, char *); @@ -106,6 +107,52 @@ smtp_run(int debug) event_dispatch(); } +static ssize_t +smtp_getline(char ** restrict buf, size_t * restrict size) +{ + static char *rbuf = NULL; + static size_t rsoff = 0, reoff = 0; + static size_t rbsize = 0; + char *sep; + size_t sepoff; + ssize_t strlen, nread; + + do { + if (rsoff != reoff) { + if ((sep = memchr(rbuf + rsoff, '\n', reoff - rsoff)) + != NULL) { + sepoff = sep - rbuf; + if (*buf == NULL) + *size = 0; + if (*size < (sepoff - rsoff + 1)) { + *size = sepoff - rsoff + 1; + *buf = realloc(*buf, sepoff - rsoff + 1); + if (*buf == NULL) + fatal(NULL); + } + sep[0] = '\0'; + strlen = strlcpy(*buf, rbuf + rsoff, *size); + if (strlen >= *size) + fatalx("copy buffer too small"); + rsoff = sepoff + 1; + return strlen; + } + } + if (reoff - rsoff < 1500) { + if ((rbuf = realloc(rbuf, rbsize + 4096)) == NULL) + fatal(NULL); + rbsize += 4096; + } + // If we can't fill at the end, move everything back. + if (rbsize - reoff < 1500) + memmove(rbuf + rsoff, rbuf, reoff - rsoff); + nread = read(STDIN_FILENO, rbuf + reoff, rbsize - reoff); + if (nread <= 0) + return nread; + reoff += nread; + } while (1); +} + static void smtp_newline(int fd, short event, void *arg) { @@ -119,12 +166,9 @@ smtp_newline(int fd, short event, void *arg) uint64_t reqid, token; int i; - while ((linelen = getline(&line, &linesize, stdin)) != -1) { + while ((linelen = smtp_getline(&line, &linesize)) > 0) { if ((linedup = strdup(line)) == NULL) fatalx(NULL); - if (line[linelen - 1] != '\n') - fatalx("Invalid line received: missing newline: %s", linedup); - line[linelen - 1] = '\0'; type = line; if ((start = strchr(type, '|')) == NULL) fatalx("Invalid line received: missing version: %s", linedup); @@ -186,7 +230,7 @@ smtp_newline(int fd, short event, void *arg) version, &tm, reqid, params); free(linedup); } - if (feof(stdin) || (ferror(stdin) && errno != EAGAIN)) + if (linelen == 0 || errno != EAGAIN) event_del(stdinev); }