]> git.ozlabs.org Git - ccan/blob - ccan/io/io.c
70e4f1b5037cff62493baee8b1adc7c6faaaae22
[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 bool 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                 /* Override next function to close us. */
159                 plan->next = io_close;
160                 return true;
161         }
162
163         plan->u.write.buf += ret;
164         plan->u.write.len -= ret;
165         return (plan->u.write.len == 0);
166 }
167
168 /* Queue some data to be written. */
169 struct io_plan io_write_(const void *data, size_t len,
170                          struct io_plan (*cb)(struct io_conn *, void *),
171                          void *arg)
172 {
173         struct io_plan plan;
174
175         assert(cb);
176         plan.u.write.buf = data;
177         plan.u.write.len = len;
178         plan.io = do_write;
179         plan.next = cb;
180         plan.next_arg = arg;
181         plan.pollflag = POLLOUT;
182
183         io_plan_debug(&plan);
184         return plan;
185 }
186
187 static bool do_read(int fd, struct io_plan *plan)
188 {
189         ssize_t ret = read(fd, plan->u.read.buf, plan->u.read.len);
190         if (ret <= 0) {
191                 /* Override next function to close us. */
192                 plan->next = io_close;
193                 return true;
194         }
195
196         plan->u.read.buf += ret;
197         plan->u.read.len -= ret;
198         return (plan->u.read.len == 0);
199 }
200
201 /* Queue a request to read into a buffer. */
202 struct io_plan io_read_(void *data, size_t len,
203                         struct io_plan (*cb)(struct io_conn *, void *),
204                         void *arg)
205 {
206         struct io_plan plan;
207
208         assert(cb);
209         plan.u.read.buf = data;
210         plan.u.read.len = len;
211         plan.io = do_read;
212         plan.next = cb;
213         plan.next_arg = arg;
214         plan.pollflag = POLLIN;
215
216         io_plan_debug(&plan);
217         return plan;
218 }
219
220 static bool do_read_partial(int fd, struct io_plan *plan)
221 {
222         ssize_t ret = read(fd, plan->u.readpart.buf, *plan->u.readpart.lenp);
223         if (ret <= 0) {
224                 /* Override next function to close us. */
225                 plan->next = io_close;
226                 return true;
227         }
228
229         *plan->u.readpart.lenp = ret;
230         return true;
231 }
232
233 /* Queue a partial request to read into a buffer. */
234 struct io_plan io_read_partial_(void *data, size_t *len,
235                                 struct io_plan (*cb)(struct io_conn *, void *),
236                                 void *arg)
237 {
238         struct io_plan plan;
239
240         assert(cb);
241         plan.u.readpart.buf = data;
242         plan.u.readpart.lenp = len;
243         plan.io = do_read_partial;
244         plan.next = cb;
245         plan.next_arg = arg;
246         plan.pollflag = POLLIN;
247
248         io_plan_debug(&plan);
249         return plan;
250 }
251
252 static bool do_write_partial(int fd, struct io_plan *plan)
253 {
254         ssize_t ret = write(fd, plan->u.writepart.buf, *plan->u.writepart.lenp);
255         if (ret < 0) {
256                 /* Override next function to close us. */
257                 plan->next = io_close;
258                 return true;
259         }
260
261         *plan->u.writepart.lenp = ret;
262         return true;
263 }
264
265 /* Queue a partial write request. */
266 struct io_plan io_write_partial_(const void *data, size_t *len,
267                                  struct io_plan (*cb)(struct io_conn*, void *),
268                                  void *arg)
269 {
270         struct io_plan plan;
271
272         assert(cb);
273         plan.u.writepart.buf = data;
274         plan.u.writepart.lenp = len;
275         plan.io = do_write_partial;
276         plan.next = cb;
277         plan.next_arg = arg;
278         plan.pollflag = POLLOUT;
279
280         io_plan_debug(&plan);
281         return plan;
282 }
283
284 struct io_plan io_idle(void)
285 {
286         struct io_plan plan;
287
288         plan.pollflag = 0;
289         plan.io = NULL;
290         /* Never called (overridded by io_wake), but NULL means closing */
291         plan.next = io_close;
292
293         io_plan_debug(&plan);
294         return plan;
295 }
296
297 void io_wake_(struct io_conn *conn, struct io_plan plan)
298
299 {
300         /* It might be closing, but we haven't called its finish() yet. */
301         if (!conn->plan.next)
302                 return;
303         /* It was idle, right? */
304         assert(!conn->plan.io);
305         conn->plan = plan;
306         backend_plan_changed(conn);
307
308         debug_io_wake(conn);
309 }
310
311 void io_ready(struct io_conn *conn)
312 {
313         if (conn->plan.io(conn->fd.fd, &conn->plan)) {
314                 set_current(conn);
315                 if (timeout_active(conn))
316                         backend_del_timeout(conn);
317                 conn->plan = conn->plan.next(conn, conn->plan.next_arg);
318                 backend_plan_changed(conn);
319                 set_current(NULL);
320         }
321 }
322
323 /* Useful next functions. */
324 /* Close the connection, we're done. */
325 struct io_plan io_close(struct io_conn *conn, void *arg)
326 {
327         struct io_plan plan;
328
329         plan.pollflag = 0;
330         /* This means we're closing. */
331         plan.next = NULL;
332
333         io_plan_debug(&plan);
334         return plan;
335 }
336
337 /* Exit the loop, returning this (non-NULL) arg. */
338 struct io_plan io_break_(void *ret, struct io_plan plan)
339 {
340         assert(ret);
341         io_loop_return = ret;
342
343         return plan;
344 }