]> mj.ucw.cz Git - libucw.git/commitdiff
Added a new fastbuf backend for sockets with timeouts.
authorMartin Mares <mj@ucw.cz>
Tue, 17 Jun 2008 20:45:51 +0000 (22:45 +0200)
committerMartin Mares <mj@ucw.cz>
Tue, 17 Jun 2008 20:45:51 +0000 (22:45 +0200)
lib/Makefile
lib/fb-socket.c [new file with mode: 0644]
lib/fb-socket.h [new file with mode: 0644]
lib/fb-socket.t [new file with mode: 0644]

index 9661e50a338a2f6f2f7bb87f07b42a7cd5b436f1..c5b3f58ed18f6853a6e7668b4b38d2435fa171a0 100644 (file)
@@ -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 (file)
index 0000000..841e0cf
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ *     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
diff --git a/lib/fb-socket.h b/lib/fb-socket.h
new file mode 100644 (file)
index 0000000..ff5ae7d
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ *     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
diff --git a/lib/fb-socket.t b/lib/fb-socket.t
new file mode 100644 (file)
index 0000000..32f49ac
--- /dev/null
@@ -0,0 +1,5 @@
+# Tests for the fb-socket module
+
+Name:  fb-socket
+Run:   ../obj/lib/fb-socket-t
+Out:   WRITE TIMEOUT