tskrtt

Simple libev based gopher server
git clone https://git.inz.fi/tskrtt/
Log | Files | Refs | README

commit bc1edead2f59b9f449950863076acc1f2dbe7206
parent abbf1d9964e5eb1cdbd7c151ca314493ec32be2d
Author: Santtu Lakkala <inz@inz.fi>
Date:   Mon, 17 May 2021 23:46:14 +0300

Fix issues found in stress and memory testing

Diffstat:
Mmain.c | 83+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 67 insertions(+), 16 deletions(-)

diff --git a/main.c b/main.c @@ -221,7 +221,10 @@ bool strpfx(const char *haystack, const char *needle) static inline void *xmemdup(const void *p, size_t l) { - return memcpy(malloc(l), p, l); + void *m = malloc(l); + if (!m) + return NULL; + return memcpy(m, p, l); } static int filterdot(const struct dirent *e) @@ -237,25 +240,46 @@ static int xfdscandir(int dfd, struct dirent ***namelist, int (*filter)(const st struct dirent *e; d = fdopendir(dfd); - if (!d) + if (!d) { + *namelist = NULL; return 0; + } *namelist = malloc(sz * sizeof(**namelist)); + if (!*namelist) + goto err; + while ((e = readdir(d))) { size_t nl = strlen(e->d_name); if (filter && !filter(e)) continue; - if (n == sz) - *namelist = realloc(*namelist, (sz *= 2) * sizeof(**namelist)); - (*namelist)[n++] = xmemdup(e, FOFFSET(struct dirent, d_name) + nl + 1); + if (n == sz) { + void *np = realloc(*namelist, (sz *= 2) * sizeof(**namelist)); + if (!np) + goto err; + *namelist = np; + } + if (!((*namelist)[n] = xmemdup(e, FOFFSET(struct dirent, d_name) + nl + 1))) + goto err; + n++; } + closedir(d); - *namelist = realloc(*namelist, n * sizeof(**namelist)); qsort(*namelist, n, sizeof(**namelist), (int (*)(const void *, const void *))compar); return n; + +err: + while (n--) + free((*namelist)[n]); + free(*namelist); + *namelist = NULL; + + closedir(d); + + return 0; } static char *dupensurepath(const char *w) @@ -267,7 +291,10 @@ static char *dupensurepath(const char *w) return strdup(""); if (w[l - 1] == '/') l--; - rv = memcpy(malloc(l + 2), w, l); + rv = malloc(l + 2); + if (!rv) + return rv; + memcpy(rv, w, l); rv[l++] = '/'; rv[l] = '\0'; return rv; @@ -280,7 +307,10 @@ static char *dupdirname(const char *w) if (!ls++) return strdup(""); - rv = memcpy(malloc(ls - w + 1), w, ls - w); + rv = malloc(ls - w + 1); + if (!rv) + return rv; + memcpy(rv, w, ls - w); rv[ls - w] = '\0'; return rv; } @@ -305,6 +335,8 @@ static char *joinstr(const char *a, const char *b, char separator) if (!b) return strdup(a); rv = malloc(strlen(a) + strlen(b) + 2); + if (!rv) + return NULL; sprintf(rv, "%s%c%s", a, separator, b); return rv; } @@ -552,8 +584,8 @@ static void init_dir(EV_P_ struct client *c, int fd, struct stat *sb, const char c->task_data.dt.base = dupensurepath(path); if (*path) client_printf(c, "1..\t/%.*s\t%s\t%s\r\n", (int)(fn - path), path, hostname, oport); - c->task_data.dt.dfd = dup(fd); - c->task_data.dt.n = xfdscandir(fd, &c->task_data.dt.entries, filterdot, alphasort); + c->task_data.dt.dfd = fd; + c->task_data.dt.n = xfdscandir(dup(fd), &c->task_data.dt.entries, filterdot, alphasort); c->task_data.dt.i = 0; } @@ -678,6 +710,7 @@ static void read_cgi(EV_P_ ev_io *w, int revents) if (r <= 0) { close(c->task_data.ct.rfd); c->task_data.ct.rfd = -1; + ev_io_stop(EV_A_ &c->task_data.ct.input_watcher); ev_io_start(EV_A_ &c->watcher); return; @@ -714,7 +747,8 @@ static void init_cgi_common(EV_P_ struct client *c, struct cgi_task *ct, int fd, (void)fn; if (pipe(pfd)) { - client_close(EV_A_ c); + client_printf(c, "3Internal server error\t.\t.\t.\r\n.\r\n"); + c->task = TASK_ERROR; return; } @@ -722,9 +756,11 @@ static void init_cgi_common(EV_P_ struct client *c, struct cgi_task *ct, int fd, case 0: break; case -1: + close(fd); close(pfd[0]); close(pfd[1]); - client_close(EV_A_ c); + client_printf(c, "3Internal server error\t.\t.\t.\r\n.\r\n"); + c->task = TASK_ERROR; return; default: close(fd); @@ -972,6 +1008,7 @@ static bool process_gophermap_line(struct client *c, char *line, size_t linelen) return client_printf(c, "%.*s\t70\r\n", (int)linelen, line); else if (tabcount) return client_printf(c, "%.*s\t%s\t%s\r\n", (int)linelen, line, hostname, oport); + return client_printf(c, "i%.*s\t.\t.\t.\r\n", (int)linelen, line); } @@ -1396,14 +1433,29 @@ static void child_timeout(EV_P_ ev_timer *w, int revents) static void listen_cb(EV_P_ ev_io *w, int revents) { + struct sockaddr_storage addr; + socklen_t addrlen = sizeof(addr); struct listener *l = (struct listener *)w; - struct client *c = malloc(sizeof(*c)); + int fd; + struct client *c; - c->addrlen = sizeof(c->addr); (void)revents; - c->fd = accept(l->fd, (struct sockaddr *)&c->addr, &c->addrlen); + fd = accept(l->fd, (struct sockaddr *)&addr, &addrlen); + + if (fd < 0) + return; + + c = malloc(sizeof(*c)); + if (!c) { + close(fd); + return; + } + + memcpy(&c->addr, &addr, addrlen); + c->addrlen = addrlen; + c->fd = fd; fcntl(c->fd, F_SETFL, O_NONBLOCK); c->buffer_used = 0; @@ -1582,7 +1634,6 @@ int main (int argc, char *argv[]) gopherrootbuf[l + 1] = '\0'; gopherroot = gopherrootbuf; } - } if (dofork) {