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