From 4a3645d50bfa8753f0d3e37d177863452bf824bb Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Tue, 17 Jun 2008 22:45:51 +0200 Subject: [PATCH] Added a new fastbuf backend for sockets with timeouts. --- lib/Makefile | 6 +- lib/fb-socket.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/fb-socket.h | 31 +++++++++ lib/fb-socket.t | 5 ++ 4 files changed, 216 insertions(+), 2 deletions(-) create mode 100644 lib/fb-socket.c create mode 100644 lib/fb-socket.h create mode 100644 lib/fb-socket.t diff --git a/lib/Makefile b/lib/Makefile index 9661e50a..c5b3f58e 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -18,7 +18,7 @@ LIBUCW_MODS= \ ipaccess \ profile \ fastbuf ff-binary ff-string ff-printf ff-unicode \ - fb-file carefulio fb-mem fb-temp fb-mmap fb-limfd fb-buffer fb-grow fb-pool fb-atomic fb-param \ + fb-file carefulio fb-mem fb-temp fb-mmap fb-limfd fb-buffer fb-grow fb-pool fb-atomic fb-param fb-socket \ str_ctype str_upper str_lower unicode stkstring \ wildmatch wordsplit ctmatch patimatch patmatch regex \ prime primetable random timer randomkey \ @@ -96,7 +96,8 @@ $(o)/lib/kmp-test: $(o)/lib/kmp-test.o $(LIBUCW) $(LIBCHARSET) $(o)/lib/ipaccess-test: $(o)/lib/ipaccess-test.o $(LIBUCW) TESTS+=$(addprefix $(o)/lib/,regex.test unicode.test hash-test.test mempool.test stkstring.test \ - slists.test kmp-test.test bbuf.test getopt.test fastbuf.test ff-unicode.test eltpool.test) + slists.test kmp-test.test bbuf.test getopt.test fastbuf.test ff-unicode.test eltpool.test \ + fb-socket.test) $(o)/lib/regex.test: $(o)/lib/regex-t $(o)/lib/unicode.test: $(o)/lib/unicode-t @@ -111,6 +112,7 @@ $(o)/lib/getopt.test: $(o)/lib/getopt-t $(o)/lib/fastbuf.test: $(o)/lib/fb-file-t $(o)/lib/fb-grow-t $(o)/lib/fb-pool-t $(o)/lib/ff-unicode.test: $(o)/lib/ff-unicode-t $(o)/lib/eltpool.test: $(o)/lib/eltpool-t +$(o)/lib/fb-socket.test: $(o)/lib/fb-socket-t ifdef CONFIG_UCW_THREADS TESTS+=$(addprefix $(o)/lib/,asio.test) diff --git a/lib/fb-socket.c b/lib/fb-socket.c new file mode 100644 index 00000000..841e0cf0 --- /dev/null +++ b/lib/fb-socket.c @@ -0,0 +1,176 @@ +/* + * UCW Library -- Fast Buffered I/O on Sockets with Timeouts + * + * (c) 2008 Martin Mares + * + * This software may be freely distributed and used according to the terms + * of the GNU Lesser General Public License. + */ + +#include "lib/lib.h" +#include "lib/fastbuf.h" +#include "lib/fb-socket.h" + +#include +#include +#include +#include + +struct fb_sock { + struct fastbuf fb; + struct fbsock_params par; + byte buf[0]; +}; + +#define FB_SOCK(f) ((struct fb_sock *)(f)->is_fastbuf) + +static int +fbs_refill(struct fastbuf *f) +{ + struct fbsock_params *p = &FB_SOCK(f)->par; + struct pollfd pf = { + .fd = p->fd, + .events = POLLIN + }; + + for (;;) + { + int e = poll(&pf, 1, p->timeout_ms); + if (e < 0) + { + p->err(p->data, FBSOCK_READ, "read error"); + return 0; + } + if (!e) + { + p->err(p->data, FBSOCK_READ | FBSOCK_TIMEOUT, "read timeout"); + return 0; + } + + f->bptr = f->buffer; + int l = read(p->fd, f->buffer, f->bufend-f->buffer); + if (l < 0) + { + if (errno == EINTR || errno == EAGAIN) + continue; + p->err(p->data, FBSOCK_READ, "read error"); + return 0; + } + f->bstop = f->buffer + l; + f->pos += l; + return l; + } +} + +static void +fbs_spout(struct fastbuf *f) +{ + struct fbsock_params *p = &FB_SOCK(f)->par; + struct pollfd pf = { + .fd = p->fd, + .events = POLLOUT, + }; + + int l = f->bptr - f->buffer; + f->bptr = f->buffer; + char *buf = f->buffer; + + while (l) + { + int e = poll(&pf, 1, p->timeout_ms); + if (e < 0) + { + p->err(p->data, FBSOCK_WRITE, "write error"); + return; + } + if (!e) + { + p->err(p->data, FBSOCK_WRITE | FBSOCK_TIMEOUT, "write timeout"); + return; + } + + e = write(p->fd, buf, l); + if (e < 0) + { + if (errno == EINTR || errno == EAGAIN) + continue; + p->err(p->data, FBSOCK_WRITE, "write error"); + return; + } + buf += e; + l -= e; + } +} + +static void +fbs_close(struct fastbuf *f) +{ + close(FB_SOCK(f)->par.fd); + xfree(f); +} + +struct fastbuf * +fbsock_create(struct fbsock_params *p) +{ + struct fb_sock *F = xmalloc(sizeof(*F) + p->bufsize); + struct fastbuf *f = &F->fb; + + bzero(F, sizeof(*F)); + F->par = *p; + f->buffer = F->buf; + f->bptr = f->bstop = f->buffer; + f->bufend = f->buffer + p->bufsize; + f->name = ""; + f->refill = fbs_refill; + f->spout = fbs_spout; + f->close = fbs_close; + f->can_overwrite_buffer = 1; + return f; +} + +#ifdef TEST + +#include + +static void test_err(void *x UNUSED, uns flags, char *msg UNUSED) +{ + if (flags & FBSOCK_READ) + printf("READ"); + else if (flags & FBSOCK_WRITE) + printf("WRITE"); + if (flags & FBSOCK_TIMEOUT) + printf(" TIMEOUT\n"); + else + printf(" ERROR\n"); + exit(0); +} + +int main(void) +{ + int fd[2]; + if (pipe(fd) < 0) + ASSERT(0); + + struct fbsock_params p = { + .fd = fd[0], + .bufsize = 16, + .timeout_ms = 100, + .err = test_err + }; + struct fastbuf *f = fbsock_create(&p); + + bputsn(f, "Oook!"); // This fits in PIPE_BUF + bflush(f); + + char buf[256]; + if (!bgets(f, buf, sizeof(buf))) + die("bgets failed"); + if (strcmp(buf, "Oook!")) + die("Misread input"); + + bgets(f, buf, sizeof(buf)); + puts("WRONG"); + exit(0); +} + +#endif diff --git a/lib/fb-socket.h b/lib/fb-socket.h new file mode 100644 index 00000000..ff5ae7d0 --- /dev/null +++ b/lib/fb-socket.h @@ -0,0 +1,31 @@ +/* + * UCW Library -- Fast Buffered I/O on Sockets with Timeouts + * + * (c) 2008 Martin Mares + * + * This software may be freely distributed and used according to the terms + * of the GNU Lesser General Public License. + */ + +#ifndef _UCW_FB_SOCKET_H +#define _UCW_FB_SOCKET_H + +#include "lib/fastbuf.h" + +struct fbsock_params { + int fd; + uns bufsize; + uns timeout_ms; + void (*err)(void *data, uns flags, char *msg); + void *data; // Passed to the err callback +}; + +enum fbsock_err_flags { + FBSOCK_READ = 1, // Happened during read + FBSOCK_WRITE = 2, // Happened during write + FBSOCK_TIMEOUT = 4, // The error is a timeout +}; + +struct fastbuf *fbsock_create(struct fbsock_params *par); + +#endif diff --git a/lib/fb-socket.t b/lib/fb-socket.t new file mode 100644 index 00000000..32f49acb --- /dev/null +++ b/lib/fb-socket.t @@ -0,0 +1,5 @@ +# Tests for the fb-socket module + +Name: fb-socket +Run: ../obj/lib/fb-socket-t +Out: WRITE TIMEOUT -- 2.39.2