]> git.ozlabs.org Git - ccan/blob - ccan/io/io.c
1c0af6b97e05f0ac6018c0cc7cba7fa1e0ef08a9
[ccan] / ccan / io / io.c
1 /* Licensed under LGPLv2.1+ - see LICENSE file for details */
2 #include "io.h"
3 #include "backend.h"
4 #include <sys/types.h>
5 #include <sys/socket.h>
6 #include <netdb.h>
7 #include <string.h>
8 #include <errno.h>
9 #include <stdlib.h>
10 #include <assert.h>
11 #include <poll.h>
12
13 void *io_loop_return;
14
15 #ifdef DEBUG
16 bool io_plan_for_other;
17 struct io_conn *current;
18 bool (*io_debug)(struct io_conn *conn);
19 bool io_debug_wakeup;
20
21 void io_plan_debug(struct io_plan *plan)
22 {
23         if (io_plan_for_other) {
24                 io_plan_for_other = false;
25                 return;
26         }
27
28         if (!io_debug || !current)
29                 return;
30
31         if (!io_debug(current) && !io_debug_wakeup)
32                 return;
33
34         io_debug_wakeup = false;
35         current->plan = *plan;
36         backend_plan_changed(current);
37
38         /* Call back into the loop immediately. */
39         io_loop_return = io_loop();
40 }
41
42 static void debug_io_wake(struct io_conn *conn)
43 {
44         /* We want linear if we wake a debugged connection, too. */
45         if (io_debug && io_debug(conn))
46                 io_debug_wakeup = true;
47 }
48 #else
49 static void debug_io_wake(struct io_conn *conn)
50 {
51 }
52 #endif
53
54 struct io_listener *io_new_listener_(int fd,
55                                      void (*init)(int fd, void *arg),
56                                      void *arg)
57 {
58         struct io_listener *l = malloc(sizeof(*l));
59
60         if (!l)
61                 return NULL;
62
63         l->fd.listener = true;
64         l->fd.fd = fd;
65         l->init = init;
66         l->arg = arg;
67         if (!add_listener(l)) {
68                 free(l);
69                 return NULL;
70         }
71         return l;
72 }
73
74 void io_close_listener(struct io_listener *l)
75 {
76         close(l->fd.fd);
77         del_listener(l);
78         free(l);
79 }
80
81 struct io_conn *io_new_conn_(int fd, struct io_plan plan)
82 {
83         struct io_conn *conn = malloc(sizeof(*conn));
84
85         if (!conn)
86                 return NULL;
87
88         conn->fd.listener = false;
89         conn->fd.fd = fd;
90         conn->plan = plan;
91         conn->finish = NULL;
92         conn->finish_arg = NULL;
93         conn->duplex = NULL;
94         conn->timeout = NULL;
95         if (!add_conn(conn)) {
96                 free(conn);
97                 return NULL;
98         }
99         return conn;
100 }
101
102 void io_set_finish_(struct io_conn *conn,
103                     void (*finish)(struct io_conn *, void *),
104                     void *arg)
105 {
106         conn->finish = finish;
107         conn->finish_arg = arg;
108 }
109
110 struct io_conn *io_duplex_(struct io_conn *old, struct io_plan plan)
111 {
112         struct io_conn *conn;
113
114         assert(!old->duplex);
115
116         conn = malloc(sizeof(*conn));
117         if (!conn)
118                 return NULL;
119
120         conn->fd.listener = false;
121         conn->fd.fd = old->fd.fd;
122         conn->plan = plan;
123         conn->duplex = old;
124         conn->finish = NULL;
125         conn->finish_arg = NULL;
126         conn->timeout = NULL;
127         if (!add_duplex(conn)) {
128                 free(conn);
129                 return NULL;
130         }
131         old->duplex = conn;
132         return conn;
133 }
134
135 bool io_timeout_(struct io_conn *conn, struct timespec ts,
136                  struct io_plan (*cb)(struct io_conn *, void *), void *arg)
137 {
138         assert(cb);
139
140         if (!conn->timeout) {
141                 conn->timeout = malloc(sizeof(*conn->timeout));
142                 if (!conn->timeout)
143                         return false;
144         } else
145                 assert(!timeout_active(conn));
146
147         conn->timeout->next = cb;
148         conn->timeout->next_arg = arg;
149         backend_add_timeout(conn, ts);
150         return true;
151 }
152
153 /* Returns true if we're finished. */
154 static int do_write(int fd, struct io_plan *plan)
155 {
156         ssize_t ret = write(fd, plan->u.write.buf, plan->u.write.len);
157         if (ret < 0)
158                 return -1;
159
160         plan->u.write.buf += ret;
161         plan->u.write.len -= ret;
162         return (plan->u.write.len == 0);
163 }
164
165 /* Queue some data to be written. */
166 struct io_plan io_write_(const void *data, size_t len,
167                          struct io_plan (*cb)(struct io_conn *, void *),
168                          void *arg)
169 {
170         struct io_plan plan;
171
172         assert(cb);
173         plan.u.write.buf = data;
174         plan.u.write.len = len;
175         plan.io = do_write;
176         plan.next = cb;
177         plan.next_arg = arg;
178         plan.pollflag = POLLOUT;
179
180         io_plan_debug(&plan);
181         return plan;
182 }
183
184 static int do_read(int fd, struct io_plan *plan)
185 {
186         ssize_t ret = read(fd, plan->u.read.buf, plan->u.read.len);
187         if (ret <= 0)
188                 return -1;
189
190         plan->u.read.buf += ret;
191         plan->u.read.len -= ret;
192         return (plan->u.read.len == 0);
193 }
194
195 /* Queue a request to read into a buffer. */
196 struct io_plan io_read_(void *data, size_t len,
197                         struct io_plan (*cb)(struct io_conn *, void *),
198                         void *arg)
199 {
200         struct io_plan plan;
201
202         assert(cb);
203         plan.u.read.buf = data;
204         plan.u.read.len = len;
205         plan.io = do_read;
206         plan.next = cb;
207         plan.next_arg = arg;
208         plan.pollflag = POLLIN;
209
210         io_plan_debug(&plan);
211         return plan;
212 }
213
214 static int do_read_partial(int fd, struct io_plan *plan)
215 {
216         ssize_t ret = read(fd, plan->u.readpart.buf, *plan->u.readpart.lenp);
217         if (ret <= 0)
218                 return -1;
219
220         *plan->u.readpart.lenp = ret;
221         return 1;
222 }
223
224 /* Queue a partial request to read into a buffer. */
225 struct io_plan io_read_partial_(void *data, size_t *len,
226                                 struct io_plan (*cb)(struct io_conn *, void *),
227                                 void *arg)
228 {
229         struct io_plan plan;
230
231         assert(cb);
232         plan.u.readpart.buf = data;
233         plan.u.readpart.lenp = len;
234         plan.io = do_read_partial;
235         plan.next = cb;
236         plan.next_arg = arg;
237         plan.pollflag = POLLIN;
238
239         io_plan_debug(&plan);
240         return plan;
241 }
242
243 static int do_write_partial(int fd, struct io_plan *plan)
244 {
245         ssize_t ret = write(fd, plan->u.writepart.buf, *plan->u.writepart.lenp);
246         if (ret < 0)
247                 return -1;
248
249         *plan->u.writepart.lenp = ret;
250         return 1;
251 }
252
253 /* Queue a partial write request. */
254 struct io_plan io_write_partial_(const void *data, size_t *len,
255                                  struct io_plan (*cb)(struct io_conn*, void *),
256                                  void *arg)
257 {
258         struct io_plan plan;
259
260         assert(cb);
261         plan.u.writepart.buf = data;
262         plan.u.writepart.lenp = len;
263         plan.io = do_write_partial;
264         plan.next = cb;
265         plan.next_arg = arg;
266         plan.pollflag = POLLOUT;
267
268         io_plan_debug(&plan);
269         return plan;
270 }
271
272 struct io_plan io_idle(void)
273 {
274         struct io_plan plan;
275
276         plan.pollflag = 0;
277         plan.io = NULL;
278         /* Never called (overridded by io_wake), but NULL means closing */
279         plan.next = io_close;
280
281         io_plan_debug(&plan);
282         return plan;
283 }
284
285 void io_wake_(struct io_conn *conn, struct io_plan plan)
286
287 {
288         /* It might be closing, but we haven't called its finish() yet. */
289         if (!conn->plan.next)
290                 return;
291         /* It was idle, right? */
292         assert(!conn->plan.io);
293         conn->plan = plan;
294         backend_plan_changed(conn);
295
296         debug_io_wake(conn);
297 }
298
299 void io_ready(struct io_conn *conn)
300 {
301         switch (conn->plan.io(conn->fd.fd, &conn->plan)) {
302         case -1: /* Failure means a new plan: close up. */
303                 set_current(conn);
304                 conn->plan = io_close(NULL, NULL);
305                 backend_plan_changed(conn);
306                 set_current(NULL);
307                 break;
308         case 0: /* Keep going with plan. */
309                 break;
310         case 1: /* Done: get next plan. */
311                 set_current(conn);
312                 if (timeout_active(conn))
313                         backend_del_timeout(conn);
314                 conn->plan = conn->plan.next(conn, conn->plan.next_arg);
315                 backend_plan_changed(conn);
316                 set_current(NULL);
317         }
318 }
319
320 /* Useful next functions. */
321 /* Close the connection, we're done. */
322 struct io_plan io_close(struct io_conn *conn, void *arg)
323 {
324         struct io_plan plan;
325
326         plan.pollflag = 0;
327         /* This means we're closing. */
328         plan.next = NULL;
329
330         io_plan_debug(&plan);
331         return plan;
332 }
333
334 /* Exit the loop, returning this (non-NULL) arg. */
335 struct io_plan io_break_(void *ret, struct io_plan plan)
336 {
337         assert(ret);
338         io_loop_return = ret;
339
340         return plan;
341 }