diff --git a/Makefile b/Makefile index 5ab1387..6bd5674 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ SRC = $(wildcard src/*.c) OBJ = $(subst .c,.o,$(subst src,work,$(SRC))) -LIBS = -pthread -pie $(shell pkg-config --libs gnutls) +LIBS = -pthread -pie -lrt $(shell pkg-config --libs gnutls) CFLAGS := -O2 -pipe -Wall -Wpedantic -Werror CFLAGS += -Isrc/include -fpie $(shell pkg-config --cflags gnutls) INSTALLDIR := /usr/bin diff --git a/documentation/sitefiles.md b/documentation/sitefiles.md index 2cb55d4..be158cd 100644 --- a/documentation/sitefiles.md +++ b/documentation/sitefiles.md @@ -31,3 +31,4 @@ sitefiles also allow comments with # * TLS * ```key``` - The filepath of the private key to use if transport == TLS * ```cert``` - The filepath of the certificate to use if transport == TLS +* ```timeout``` - The amount of time to wait for data before closing the connection in ms diff --git a/example/sitefile b/example/sitefile index 3a17673..846e3a7 100644 --- a/example/sitefile +++ b/example/sitefile @@ -1,6 +1,7 @@ define transport TLS define key domain.key define cert domain.crt +define timeout 2000 set host localhost:8000 read ^/$ site/index.html diff --git a/src/connections.c b/src/connections.c index b444e2b..08ed7b0 100644 --- a/src/connections.c +++ b/src/connections.c @@ -53,6 +53,13 @@ int newConnection(Stream *stream, Connection *ret) { ret->body = NULL; //pointers to things that are allocated within functions should be //initialized to NULL so that free() doens't fail. + + struct timespec currentTime; + if (clock_gettime(CLOCK_MONOTONIC, ¤tTime) < 0) { + free(ret->currLine); + return 1; + } + memcpy(&ret->lastdata, ¤tTime, sizeof(struct timespec)); return 0; } @@ -195,14 +202,26 @@ static int processChar(Connection *conn, char c, Sitefile *site) { return 0; } +long diff(struct timespec *t1, struct timespec *t2) { + return (t2->tv_sec - t1->tv_sec) * 1000 + + (t2->tv_nsec - t1->tv_nsec) / 1000000; +} + int updateConnection(Connection *conn, Sitefile *site) { char buff[300]; for (;;) { + struct timespec currentTime; + if (clock_gettime(CLOCK_MONOTONIC, ¤tTime) < 0) + return 1; + if (site->timeout > 0 && + diff(&conn->lastdata, ¤tTime) > site->timeout) + return 1; ssize_t received = recvStream(conn->stream, buff, sizeof(buff)); if (received < 0) return errno != EAGAIN; if (received == 0) break; + memcpy(&conn->lastdata, ¤tTime, sizeof(struct timespec)); for (unsigned long i = 0; i < received; i++) { if (processChar(conn, buff[i], site)) return 1; diff --git a/src/include/connections.h b/src/include/connections.h index a84266e..6c76a29 100644 --- a/src/include/connections.h +++ b/src/include/connections.h @@ -37,6 +37,9 @@ typedef struct Connection { Stream *stream; ConnectionSteps progress; + struct timespec lastdata; + //the last time that data was received from this connection. + RequestType type; char *path; //ephemeral diff --git a/src/include/sitefile.h b/src/include/sitefile.h index 4704b69..b93faf7 100644 --- a/src/include/sitefile.h +++ b/src/include/sitefile.h @@ -39,6 +39,7 @@ typedef struct { SocketType type; char *key; char *cert; + int timeout; } Sitefile; Sitefile *parseSitefile(char *path); diff --git a/src/include/sockets.h b/src/include/sockets.h index 942ce05..f4b1c2b 100644 --- a/src/include/sockets.h +++ b/src/include/sockets.h @@ -44,7 +44,7 @@ Listener *createListener(SocketType type, uint16_t port, int backlog, ...); //extra arguments depend on type (similar to fcntl): //tcp: (void) //tls: (char *keyfile, char *certfile, char *ocspfile) -Stream *acceptStream(Listener *listener, int flags); +Stream *acceptStream(Listener *listener); //returns 1 on error, accepts fcntl flags void freeListener(Listener *listener); diff --git a/src/main.c b/src/main.c index c1af31c..944c8be 100644 --- a/src/main.c +++ b/src/main.c @@ -145,7 +145,7 @@ int main(int argc, char **argv) { createLog("swebs started"); for (;;) { - Stream *stream = acceptStream(listener, O_NONBLOCK); + Stream *stream = acceptStream(listener); if (stream == NULL) { createLog("Accepting a stream failed"); continue; diff --git a/src/runner.c b/src/runner.c index 4e93863..43ea5fd 100644 --- a/src/runner.c +++ b/src/runner.c @@ -15,6 +15,7 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ +#define _GNU_SOURCE #include #include #include @@ -49,15 +50,21 @@ void *runServer(RunnerArgs *args) { poll(fds, connCount, -1); for (int i = 1; i < connCount; i++) { - if (updateConnection(connections + i, site)) { - connCount--; - memcpy(fds + i, fds + connCount, - sizeof(struct pollfd)); - pending[id]--; - } + if (fds[i].revents & POLLRDHUP) + goto remove; + if (updateConnection(connections + i, site)) + goto remove; + continue; +remove: + connCount--; + memcpy(fds + i, fds + connCount, + sizeof(struct pollfd)); + memcpy(connections + i, fds + connCount, + sizeof(struct pollfd)); + pending[id]--; } - if (fds[0].revents == POLLIN) { + if (fds[0].revents & POLLIN) { if (connCount >= allocConns) { allocConns *= 2; struct pollfd *newfds = realloc(fds, @@ -76,7 +83,7 @@ void *runServer(RunnerArgs *args) { if (read(notify, &stream, sizeof(stream)) < sizeof(stream)) exit(EXIT_FAILURE); fds[connCount].fd = stream->fd; - fds[connCount].events = POLLIN; + fds[connCount].events = POLLIN | POLLRDHUP; if (newConnection(stream, connections + connCount)) exit(EXIT_FAILURE); diff --git a/src/sitefile.c b/src/sitefile.c index f66b95b..7710709 100644 --- a/src/sitefile.c +++ b/src/sitefile.c @@ -175,6 +175,7 @@ Sitefile *parseSitefile(char *path) { ret->type = TCP; ret->key = NULL; ret->cert = NULL; + ret->timeout = 0; int allocatedLength = 50; ret->size = 0; ret->content = malloc(allocatedLength * sizeof(SiteCommand)); @@ -237,6 +238,8 @@ setValue: ret->key = copyString(argv[2]); else if (strcmp(argv[1], "cert") == 0) ret->cert = copyString(argv[2]); + else if (strcmp(argv[1], "timeout") == 0) + ret->timeout = atoi(argv[2]); else goto error; continue; diff --git a/src/sockets.c b/src/sockets.c index 1bad478..12d6b44 100644 --- a/src/sockets.c +++ b/src/sockets.c @@ -91,7 +91,7 @@ error: return NULL; } -Stream *acceptStream(Listener *listener, int flags) { +Stream *acceptStream(Listener *listener) { Stream *ret = malloc(sizeof(Stream)); if (ret == NULL) return NULL; @@ -126,10 +126,6 @@ Stream *acceptStream(Listener *listener, int flags) { goto error; break; } - { - int flags = fcntl(ret->fd, F_GETFD); - fcntl(ret->fd, F_SETFD, flags | O_NONBLOCK); - } return ret; error: close(ret->fd);