]> mj.ucw.cz Git - libucw.git/blob - ucw/fb-socket.c
make Sherlock compilable on Darwin without hacks due to missing direct IO
[libucw.git] / ucw / fb-socket.c
1 /*
2  *      UCW Library -- Fast Buffered I/O on Sockets with Timeouts
3  *
4  *      (c) 2008 Martin Mares <mj@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #include "ucw/lib.h"
11 #include "ucw/fastbuf.h"
12 #include "ucw/fb-socket.h"
13
14 #include <stdio.h>
15 #include <unistd.h>
16 #include <poll.h>
17 #include <errno.h>
18
19 struct fb_sock {
20   struct fastbuf fb;
21   struct fbsock_params par;
22   byte buf[0];
23 };
24
25 #define FB_SOCK(f) ((struct fb_sock *)(f)->is_fastbuf)
26
27 static int
28 fbs_refill(struct fastbuf *f)
29 {
30   struct fbsock_params *p = &FB_SOCK(f)->par;
31   struct pollfd pf = {
32       .fd = p->fd,
33       .events = POLLIN
34   };
35
36   for (;;)
37     {
38       int e = poll(&pf, 1, p->timeout_ms);
39       if (e < 0)
40         {
41           p->err(p->data, FBSOCK_READ, "read error");
42           return 0;
43         }
44       if (!e)
45         {
46           p->err(p->data, FBSOCK_READ | FBSOCK_TIMEOUT, "read timeout");
47           return 0;
48         }
49
50       f->bptr = f->buffer;
51       int l = read(p->fd, f->buffer, f->bufend-f->buffer);
52       if (l < 0)
53         {
54           if (errno == EINTR || errno == EAGAIN)
55             continue;
56           p->err(p->data, FBSOCK_READ, "read error");
57           return 0;
58         }
59       f->bstop = f->buffer + l;
60       f->pos += l;
61       return l;
62     }
63 }
64
65 static void
66 fbs_spout(struct fastbuf *f)
67 {
68   struct fbsock_params *p = &FB_SOCK(f)->par;
69   struct pollfd pf = {
70       .fd = p->fd,
71       .events = POLLOUT,
72   };
73
74   int l = f->bptr - f->buffer;
75   f->bptr = f->buffer;
76   char *buf = f->buffer;
77
78   while (l)
79     {
80       int e = poll(&pf, 1, p->timeout_ms);
81       if (e < 0)
82         {
83           p->err(p->data, FBSOCK_WRITE, "write error");
84           return;
85         }
86       if (!e)
87         {
88           p->err(p->data, FBSOCK_WRITE | FBSOCK_TIMEOUT, "write timeout");
89           return;
90         }
91
92       e = write(p->fd, buf, l);
93       if (e < 0)
94         {
95           if (errno == EINTR || errno == EAGAIN)
96             continue;
97           p->err(p->data, FBSOCK_WRITE, "write error");
98           return;
99         }
100       buf += e;
101       l -= e;
102     }
103 }
104
105 static void
106 fbs_close(struct fastbuf *f)
107 {
108   close(FB_SOCK(f)->par.fd);
109   xfree(f);
110 }
111
112 struct fastbuf *
113 fbsock_create(struct fbsock_params *p)
114 {
115   struct fb_sock *F = xmalloc(sizeof(*F) + p->bufsize);
116   struct fastbuf *f = &F->fb;
117
118   bzero(F, sizeof(*F));
119   F->par = *p;
120   f->buffer = F->buf;
121   f->bptr = f->bstop = f->buffer;
122   f->bufend = f->buffer + p->bufsize;
123   f->name = "<socket>";
124   f->refill = fbs_refill;
125   f->spout = fbs_spout;
126   f->close = fbs_close;
127   f->can_overwrite_buffer = 1;
128   return f;
129 }
130
131 #ifdef TEST
132
133 #include <stdlib.h>
134
135 static void test_err(void *x UNUSED, uns flags, char *msg UNUSED)
136 {
137   if (flags & FBSOCK_READ)
138     printf("READ");
139   else if (flags & FBSOCK_WRITE)
140     printf("WRITE");
141   if (flags & FBSOCK_TIMEOUT)
142     printf(" TIMEOUT\n");
143   else
144     printf(" ERROR\n");
145   exit(0);
146 }
147
148 int main(void)
149 {
150   int fd[2];
151   if (pipe(fd) < 0)
152     ASSERT(0);
153
154   struct fbsock_params p = {
155       .fd = fd[0],
156       .bufsize = 16,
157       .timeout_ms = 100,
158       .err = test_err
159   };
160   struct fastbuf *f = fbsock_create(&p);
161
162   bputsn(f, "Oook!");           // This fits in PIPE_BUF
163   bflush(f);
164
165   char buf[256];
166   if (!bgets(f, buf, sizeof(buf)))
167     die("bgets failed");
168   if (strcmp(buf, "Oook!"))
169     die("Misread input");
170
171   bgets(f, buf, sizeof(buf));
172   puts("WRONG");
173   exit(0);
174 }
175
176 #endif