]> git.ozlabs.org Git - ccan/blob - ccan/io/_info
ccan/io: io_connect()
[ccan] / ccan / io / _info
1 #include <stdio.h>
2 #include <string.h>
3 #include "config.h"
4
5 /**
6  * io - simple library for asynchronous io handling.
7  *
8  * io provides a mechanism to write I/O servers with multiple
9  * connections.  Each callback indicates what I/O they plan next
10  * (eg. read, write).  It is also possible to write custom I/O
11  * plans.
12  *
13  * When compiled with DEBUG, control flow is changed so that rather
14  * than returning to the main io_loop(), plans are executed sequentially
15  * providing a backtrace showing what has occurred on that connection.
16  * Which connection(s) do this depends on the user-specified io_debug
17  * function.
18  *
19  * Example:
20  * // Given tr A-Z a-z outputs tr a-z a-z
21  * #include <ccan/io/io.h>
22  * #include <ccan/err/err.h>
23  * #include <assert.h>
24  * #include <stdlib.h>
25  * #include <signal.h>
26  * #include <sys/types.h>
27  * #include <sys/wait.h>
28  *
29  * struct buffer {
30  *      size_t max, off, rlen;
31  *      char *buf;
32  * };
33  *
34  * struct stdin_buffer {
35  *      struct io_conn *reader, *writer;
36  *      size_t len;
37  *      char inbuf[4096];
38  * };
39  *
40  * // This reads from stdin.
41  * static struct io_plan wake_writer(struct io_conn *, struct stdin_buffer *);
42  * // This writes the stdin buffer to the child.
43  * static struct io_plan wake_reader(struct io_conn *, struct stdin_buffer *);
44  *
45  * static struct io_plan wake_writer(struct io_conn *c, struct stdin_buffer *b)
46  * {
47  *      assert(c == b->reader);
48  *      io_wake(b->writer, io_write(b->inbuf, b->len, wake_reader, b));
49  *      return io_idle();
50  * }
51  *
52  * static void reader_exit(struct io_conn *c, struct stdin_buffer *b)
53  * {
54  *      assert(c == b->reader);
55  *      io_wake(b->writer, io_close());
56  *      b->reader = NULL;
57  * }
58  *
59  * static struct io_plan wake_reader(struct io_conn *c, struct stdin_buffer *b)
60  * {
61  *      assert(c == b->writer);
62  *      if (!b->reader)
63  *              return io_close();
64  *      b->len = sizeof(b->inbuf);
65  *      io_wake(b->reader, io_read_partial(b->inbuf, &b->len, wake_writer, b));
66  *      return io_idle();
67  * }
68  *
69  * static void fail_child_write(struct io_conn *conn, struct stdin_buffer *b)
70  * {
71  *      if (b->reader)
72  *              err(1, "Failed writing to child.");
73  * }
74  *
75  * // This reads from the child and saves it into buffer.
76  * static struct io_plan read_from_child(struct io_conn *conn,
77  *                                       struct buffer *b)
78  * {
79  *      b->off += b->rlen;
80  *
81  *      if (b->off == b->max)
82  *              b->buf = realloc(b->buf, b->max *= 2);
83  *
84  *      b->rlen = b->max - b->off;
85  *      return io_read_partial(b->buf + b->off, &b->rlen, read_from_child, b);
86  * }
87  *
88  * // Feed a program our stdin, gather its stdout, print that at end.
89  * int main(int argc, char *argv[])
90  * {
91  *      int tochild[2], fromchild[2];
92  *      struct buffer out;
93  *      struct stdin_buffer sbuf;
94  *      int status;
95  *      size_t off;
96  *      ssize_t ret;
97  *      struct io_conn *from_child;
98  *
99  *      if (argc == 1)
100  *              errx(1, "Usage: runner <cmdline>...");
101  *
102  *      if (pipe(tochild) != 0 || pipe(fromchild) != 0)
103  *              err(1, "Creating pipes");
104  *
105  *      if (!fork()) {
106  *              // Child runs command.
107  *              close(tochild[1]);
108  *              close(fromchild[0]);
109  *
110  *              dup2(tochild[0], STDIN_FILENO);
111  *              dup2(fromchild[1], STDOUT_FILENO);
112  *              execvp(argv[1], argv + 1);
113  *              exit(127);
114  *      }
115  *
116  *      close(tochild[0]);
117  *      close(fromchild[1]);
118  *      signal(SIGPIPE, SIG_IGN);
119  *
120  *      sbuf.len = sizeof(sbuf.inbuf);
121  *      sbuf.reader = io_new_conn(STDIN_FILENO,
122  *                                io_read_partial(sbuf.inbuf, &sbuf.len,
123  *                                                wake_writer, &sbuf));
124  *      sbuf.writer = io_new_conn(tochild[1], io_idle());
125  *
126  *      out.max = 128;
127  *      out.off = 0;
128  *      out.rlen = 128;
129  *      out.buf = malloc(out.max);
130  *      from_child = io_new_conn(fromchild[0],
131  *                               io_read_partial(out.buf, &out.rlen,
132  *                                               read_from_child, &out));
133  *      if (!sbuf.reader || !sbuf.writer || !from_child)
134  *              err(1, "Allocating connections");
135  *
136  *      io_set_finish(sbuf.reader, reader_exit, &sbuf);
137  *      io_set_finish(sbuf.writer, fail_child_write, &sbuf);
138  *
139  *      io_loop();
140  *      wait(&status);
141  *
142  *      for (off = 0; off < out.off; off += ret) {
143  *              ret = write(STDOUT_FILENO, out.buf+off, out.off-off);
144  *              if (ret < 0)
145  *                      err(1, "Writing stdout");
146  *      }
147  *      free(out.buf);
148  *
149  *      return WIFEXITED(status) ? WEXITSTATUS(status) : 2;
150  * }
151  *
152  * License: LGPL (v2.1 or any later version)
153  * Author: Rusty Russell <rusty@rustcorp.com.au>
154  */
155 int main(int argc, char *argv[])
156 {
157         if (argc != 2)
158                 return 1;
159
160         if (strcmp(argv[1], "depends") == 0) {
161                 printf("ccan/time\n");
162                 printf("ccan/timer\n");
163                 return 0;
164         }
165
166         return 1;
167 }