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 \
$(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
$(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)
--- /dev/null
+/*
+ * UCW Library -- Fast Buffered I/O on Sockets with Timeouts
+ *
+ * (c) 2008 Martin Mares <mj@ucw.cz>
+ *
+ * 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 <stdio.h>
+#include <unistd.h>
+#include <poll.h>
+#include <errno.h>
+
+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 = "<socket>";
+ f->refill = fbs_refill;
+ f->spout = fbs_spout;
+ f->close = fbs_close;
+ f->can_overwrite_buffer = 1;
+ return f;
+}
+
+#ifdef TEST
+
+#include <stdlib.h>
+
+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
--- /dev/null
+/*
+ * UCW Library -- Fast Buffered I/O on Sockets with Timeouts
+ *
+ * (c) 2008 Martin Mares <mj@ucw.cz>
+ *
+ * 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