quark

quark web server
git clone git://git.suckless.org/quark
Log | Files | Refs | LICENSE

commit 4d3a6c5297015285f88a56cc47f6a53c372b1506
parent 5d0221dd68c0d2b8796479d06b602be666d0f4c6
Author: Laslo Hunhold <dev@frign.de>
Date:   Sun,  1 Nov 2020 00:10:54 +0100

Prepare http_send_buf() http_recv_header() for blocking I/O

Signed-off-by: Laslo Hunhold <dev@frign.de>

Diffstat:
Mhttp.c | 27+++++++++++++++++++++++----
Aqueue.c | 177+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aqueue.h | 32++++++++++++++++++++++++++++++++
3 files changed, 232 insertions(+), 4 deletions(-)

diff --git a/http.c b/http.c @@ -109,7 +109,17 @@ http_send_buf(int fd, struct buffer *buf) while (buf->len > 0) { if ((r = write(fd, buf->data, buf->len)) <= 0) { - return S_REQUEST_TIMEOUT; + if (errno == EAGAIN || errno == EWOULDBLOCK) { + /* + * socket is blocking, return normally. + * given the buffer still contains data, + * this indicates to the caller that we + * have been interrupted. + */ + return 0; + } else { + return S_REQUEST_TIMEOUT; + } } memmove(buf->data, buf->data + r, buf->len - r); buf->len -= r; @@ -145,8 +155,17 @@ http_recv_header(int fd, struct buffer *buf, int *done) while (1) { if ((r = read(fd, buf->data + buf->len, sizeof(buf->data) - buf->len)) <= 0) { - s = S_REQUEST_TIMEOUT; - goto err; + if (errno == EAGAIN || errno == EWOULDBLOCK) { + /* + * socket is drained, return normally, + * but set done to zero + */ + *done = 0; + return 0; + } else { + s = S_REQUEST_TIMEOUT; + goto err; + } } buf->len += r; @@ -181,7 +200,7 @@ http_parse_header(const char *h, struct request *req) const char *p, *q; char *m, *n; - /* empty all fields */ + /* empty the request struct */ memset(req, 0, sizeof(*req)); /* diff --git a/queue.c b/queue.c @@ -0,0 +1,177 @@ +/* See LICENSE file for copyright and license details. */ +#include <stddef.h> + +#ifdef __linux__ + #include <sys/epoll.h> +#else + #include <sys/types.h> + #include <sys/event.h> + #include <sys/time.h> +#endif + +#include "queue.h" +#include "util.h" + +int +queue_create(void) +{ + int qfd; + + #ifdef __linux__ + if ((qfd = epoll_create1(0)) < 0) { + warn("epoll_create1:"); + } + #else + + #endif + + return qfd; +} + +int +queue_add_fd(int qfd, int fd, enum queue_event_type t, int shared, + const void *data) +{ + #ifdef __linux__ + struct epoll_event e; + + /* set event flag */ + if (shared) { + /* + * if the fd is shared, "exclusive" is the only + * way to avoid spurious wakeups and "blocking" + * accept()'s. + */ + e.events = EPOLLEXCLUSIVE; + } else { + /* + * if we have the fd for ourselves (i.e. only + * within the thread), we want to be + * edge-triggered, as our logic makes sure + * that the buffers are drained when we return + * to epoll_wait() + */ + e.events = EPOLLET; + } + + switch (t) { + case QUEUE_EVENT_IN: + e.events |= EPOLLIN; + break; + case QUEUE_EVENT_OUT: + e.events |= EPOLLOUT; + break; + } + + /* set data */ + if (data == NULL) { + /* the data is the fd itself */ + e.data.fd = fd; + } else { + /* set data pointer */ + e.data.ptr = (void *)data; + } + + /* register fd in the interest list */ + if (epoll_ctl(qfd, EPOLL_CTL_ADD, fd, &e) < 0) { + warn("epoll_ctl:"); + return 1; + } + #else + + #endif + + return 0; +} + +int +queue_mod_fd(int qfd, int fd, enum queue_event_type t, const void *data) +{ + #ifdef __linux__ + struct epoll_event e; + + /* set event flag */ + e.events = EPOLLET; + switch (t) { + case QUEUE_EVENT_IN: + e.events |= EPOLLIN; + break; + case QUEUE_EVENT_OUT: + e.events |= EPOLLOUT; + break; + } + + /* set data */ + if (data == NULL) { + /* the data is the fd itself */ + e.data.fd = fd; + } else { + /* set data pointer */ + e.data.ptr = (void *)data; + } + + /* register fd in the interest list */ + if (epoll_ctl(qfd, EPOLL_CTL_MOD, fd, &e) < 0) { + warn("epoll_ctl:"); + return 1; + } + #else + + #endif + + return 0; +} + +int +queue_rem_fd(int qfd, int fd) +{ + #ifdef __linux__ + struct epoll_event e; + + if (epoll_ctl(qfd, EPOLL_CTL_DEL, fd, &e) < 0) { + warn("epoll_ctl:"); + return 1; + } + #else + + #endif + + return 0; +} + +ssize_t +queue_wait(int qfd, queue_event *e, size_t elen) +{ + ssize_t nready; + + #ifdef __linux__ + if ((nready = epoll_wait(qfd, e, elen, -1)) < 0) { + warn("epoll_wait:"); + return -1; + } + #else + + #endif + + return nready; +} + +int +queue_event_get_fd(const queue_event *e) +{ + #ifdef __linux__ + return e->data.fd; + #else + + #endif +} + +void * +queue_event_get_ptr(const queue_event *e) +{ + #ifdef __linux__ + return e->data.ptr; + #else + + #endif +} diff --git a/queue.h b/queue.h @@ -0,0 +1,32 @@ +#ifndef QUEUE_H +#define QUEUE_H + +#include <stddef.h> + +#ifdef __linux__ + #include <sys/epoll.h> + + typedef struct epoll_event queue_event; +#else + #include <sys/types.h> + #include <sys/event.h> + #include <sys/time.h> + + typedef struct kevent queue_event; +#endif + +enum queue_event_type { + QUEUE_EVENT_IN, + QUEUE_EVENT_OUT, +}; + +int queue_create(void); +int queue_add_fd(int, int, enum queue_event_type, int, const void *); +int queue_mod_fd(int, int, enum queue_event_type, const void *); +int queue_rem_fd(int, int); +ssize_t queue_wait(int, queue_event *, size_t); + +int queue_event_get_fd(const queue_event *); +void *queue_event_get_ptr(const queue_event *); + +#endif /* QUEUE_H */