1ivykis(3) ivykis programmer's manual ivykis(3)
2
3
4
6 iv_examples - ivykis examples
7
9 ivykis is initialised by calling iv_init(3). This function is the
10 first function to call when dealing with ivykis -- it has to be called
11 before registering file descriptors or timers.
12
13 The ivykis main event loop is started by calling iv_main(3). This
14 function generally does not return, except when iv_quit(3) is called
15 somewhere during execution of the program.
16
17 An application asks ivykis to monitor a certain file descriptor by
18 filling out a structure of type 'struct iv_fd' with a file descriptor
19 number and a callback function, and calling the function iv_fd_regis‐
20 ter.
21
22 The first example program waits for data from standard input, and
23 writes a message to standard out whenever something is received:
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <iv.h>
28
29 struct iv_fd fd_stdin;
30
31 static void callback(void *dummy)
32 {
33 char buf[1024];
34 int len;
35
36 len = read(fd_stdin.fd, buf, sizeof(buf));
37 if (len <= 0) {
38 if (len < 0) {
39 if (errno == EAGAIN)
40 return;
41 perror("read");
42 }
43 exit(1);
44 }
45
46 printf("read %d bytes of data from stdin\n", len);
47 }
48
49 int main()
50 {
51 iv_init();
52
53 IV_FD_INIT(&fd_stdin);
54 fd_stdin.fd = 0;
55 fd_stdin.handler_in = callback;
56 iv_fd_register(&fd_stdin);
57
58 iv_main();
59
60 iv_deinit();
61
62 return 0;
63 }
64
65 The application is responsible for memory management of 'struct iv_fd's
66 passed to ivykis. For example, it should not free memory that contains
67 such structures that are still registered with ivykis (i.e. haven't had
68 iv_fd_unregister called on them).
69
70 iv_fd_register transparently sets the passed file descriptor to non‐
71 blocking mode, in anticipation of its future usage.
72
73 File descriptor callbacks are called in a level-triggered fashion.
74 Therefore, the way of dealing with fd_stdin in the example callback
75 function is safe. In case there arrives data between read and detect‐
76 ing EAGAIN, ivykis will re-call the callback function after it returns.
77 Also, if there are more than 1024 bytes waiting in the input buffer,
78 ivykis will re-call the callback function until all data from stdin
79 have been drained.
80
82 The second example accepts connections on TCP port 6667, and waits on
83 each of the connections for data. When data is received on any connec‐
84 tion, a message is printed to standard out.
85
86 #include <stdio.h>
87 #include <stdlib.h>
88 #include <iv.h>
89 #include <netinet/in.h>
90
91 struct connection
92 {
93 struct iv_fd fd;
94 /* other per-connection data goes here */
95 };
96
97 struct listening_socket
98 {
99 struct iv_fd fd;
100 /* other per-listening socket data goes here */
101 };
102
103
104 static void connection_handler(void *_conn)
105 {
106 struct connection *conn = (struct connection *)_conn;
107 char buf[1024];
108 int len;
109
110 len = read(conn->fd.fd, buf, sizeof(buf));
111 if (len <= 0) {
112 if (len < 0 && errno == EAGAIN)
113 return;
114 iv_fd_unregister(&conn->fd);
115 close(conn->fd.fd);
116 free(conn);
117 return;
118 }
119
120 printf("got %d bytes of data from %p\n", len, conn);
121 }
122
123 static void listening_socket_handler(void *_sock)
124 {
125 struct listening_socket *sock = (struct listening_socket *)_sock;
126 struct sockaddr_in addr;
127 socklen_t addrlen;
128 struct connection *conn;
129 int fd;
130
131 addrlen = sizeof(addr);
132 fd = accept(sock->fd.fd, (struct sockaddr *)&addr, &addrlen);
133 if (fd < 0) {
134 if (errno == EAGAIN)
135 return;
136 perror("accept");
137 exit(1);
138 }
139
140 conn = malloc(sizeof(*conn));
141 if (conn == NULL) {
142 fprintf(stderr, "listening_socket_handler: memory allocation error, dropping connection");
143 close(fd);
144 return;
145 }
146
147 IV_FD_INIT(&conn->fd);
148 conn->fd.fd = fd;
149 conn->fd.cookie = (void *)conn;
150 conn->fd.handler_in = connection_handler;
151 iv_fd_register(&conn->fd);
152 }
153
154 int main()
155 {
156 struct listening_socket s;
157 struct sockaddr_in addr;
158 int fd;
159
160 fd = socket(AF_INET, SOCK_STREAM, 0);
161 if (fd < 0) {
162 perror("socket");
163 exit(1);
164 }
165
166 addr.sin_family = AF_INET;
167 addr.sin_addr.s_addr = htonl(INADDR_ANY);
168 addr.sin_port = htons(6667);
169 if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
170 perror("bind");
171 exit(1);
172 }
173
174 if (listen(fd, 4) < 0) {
175 perror("listen");
176 exit(1);
177 }
178
179 iv_init();
180
181 IV_FD_INIT(&s.fd);
182 s.fd.fd = fd;
183 s.fd.cookie = (void *)&s;
184 s.fd.handler_in = listening_socket_handler;
185 iv_fd_register(&s.fd);
186
187 iv_main();
188
189 iv_deinit();
190
191 return 0;
192 }
193
194 As illustrated, it is possible to pass cookies into callback functions.
195 This is useful for conveying information on which higher-level entity
196 (such as 'connection' or 'listening socket') generated the event for
197 which the callback was called.
198
199 Note how it is possible to unregister and even free a 'struct iv_fd' in
200 its own callback function. There is logic in ivykis to deal with this
201 case.
202
204 This example extends the previous example by a per-connection timer
205 that disconnects the client after too long a period of inactivity.
206 Lines not present in example 2 or different than in example 2 are indi‐
207 cated by '//XXXX' in the right-hand margin.
208
209 #include <stdio.h>
210 #include <stdlib.h>
211 #include <iv.h>
212 #include <netinet/in.h>
213
214 #define CONNECTION_TIMEOUT (10)
215
216 struct connection
217 {
218 struct iv_fd fd;
219 struct iv_timer disconnect_timeout; //XXXX
220 /* other per-connection data goes here */
221 };
222
223 struct listening_socket
224 {
225 struct iv_fd fd;
226 /* other per-listening socket data goes here */
227 };
228
229
230 static void connection_handler(void *_conn)
231 {
232 struct connection *conn = (struct connection *)_conn;
233 char buf[1024];
234 int len;
235
236 len = read(conn->fd.fd, buf, sizeof(buf));
237 if (len <= 0) {
238 if (len < 0 && errno == EAGAIN)
239 return;
240 iv_timer_unregister(&conn->disconnect_timeout); //XXXX
241 iv_fd_unregister(&conn->fd);
242 close(conn->fd.fd);
243 free(conn);
244 return;
245 }
246
247 printf("got %d bytes of data from %p\n", len, conn);
248
249 iv_timer_unregister(&conn->disconnect_timeout); //XXXX
250 iv_validate_now(); //XXXX
251 conn->disconnect_timeout.expires = iv_now; //XXXX
252 conn->disconnect_timeout.expires.tv_sec += CONNECTION_TIMEOUT;//XXXX
253 iv_timer_register(&conn->disconnect_timeout); //XXXX
254 }
255
256 static void disconnect_timeout_expired(void *_conn) //XXXX
257 { //XXXX
258 struct connection *conn = (struct connection *)_conn; //XXXX
259 iv_fd_unregister(&conn->fd); //XXXX
260 close(conn->fd.fd); //XXXX
261 free(conn); //XXXX
262 } //XXXX
263
264 static void listening_socket_handler(void *_sock)
265 {
266 struct listening_socket *sock = (struct listening_socket *)_sock;
267 struct sockaddr_in addr;
268 socklen_t addrlen;
269 struct connection *conn;
270 int fd;
271
272 addrlen = sizeof(addr);
273 fd = accept(sock->fd.fd, (struct sockaddr *)&addr, &addrlen);
274 if (fd < 0) {
275 if (errno == EAGAIN)
276 return;
277 perror("accept");
278 exit(1);
279 }
280
281 conn = malloc(sizeof(*conn));
282 if (conn == NULL) {
283 fprintf(stderr, "listening_socket_handler: memory allocation error, dropping connection");
284 close(fd);
285 return;
286 }
287
288 IV_FD_INIT(&conn->fd);
289 conn->fd.fd = fd;
290 conn->fd.cookie = (void *)conn;
291 conn->fd.handler_in = connection_handler;
292 iv_fd_register(&conn->fd);
293
294 IV_TIMER_INIT(&conn->disconnect_timeout); //XXXX
295 iv_validate_now(); //XXXX
296 conn->disconnect_timeout.cookie = (void *)conn; //XXXX
297 conn->disconnect_timeout.handler = disconnect_timeout_expired;//XXXX
298 conn->disconnect_timeout.expires = iv_now; //XXXX
299 conn->disconnect_timeout.expires.tv_sec += CONNECTION_TIMEOUT;//XXXX
300 iv_timer_register(&conn->disconnect_timeout); //XXXX
301 }
302
303 int main()
304 {
305 struct listening_socket s;
306 struct sockaddr_in addr;
307 int fd;
308
309 fd = socket(AF_INET, SOCK_STREAM, 0);
310 if (fd < 0) {
311 perror("socket");
312 exit(1);
313 }
314
315 addr.sin_family = AF_INET;
316 addr.sin_addr.s_addr = htonl(INADDR_ANY);
317 addr.sin_port = htons(6667);
318 if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
319 perror("bind");
320 exit(1);
321 }
322
323 if (listen(fd, 4) < 0) {
324 perror("listen");
325 exit(1);
326 }
327
328 iv_init();
329
330 IV_FD_INIT(&s.fd);
331 s.fd.fd = fd;
332 s.fd.cookie = (void *)&s;
333 s.fd.handler_in = listening_socket_handler;
334 iv_fd_register(&s.fd);
335
336 iv_main();
337
338 iv_deinit();
339
340 return 0;
341 }
342
343 The global variable 'iv_now' represents a monotonic timer. However, it
344 is updated lazily, and its contents might be stale at any given time.
345 Before using it, iv_validate_now(3) must be called.
346
348 The fourth example demonstrates how to use a custom fatal error handler
349 that does not write the message to syslog.
350
351 #include <stdio.h>
352 #include <iv.h>
353
354 static void fatal_error(const char *msg)
355 {
356 fprintf(stderr, "ivykis: FATAL ERROR: %s\n", msg);
357 }
358
359 int main()
360 {
361 iv_init();
362 iv_set_fatal_msg_handler(fatal_error);
363
364 iv_fatal("Programmatically triggered fatal error %d.", 42);
365 printf("This code is never reached.\n");
366
367 iv_deinit();
368
369 return 0;
370 }
371
372 This program will abort immediately, with the error message printed to
373 the standard error stream.
374
376 ivykis(3), iv_fatal(3), iv_fd(3), iv_timer(3), iv_task(3), iv_init(3),
377 iv_time(3)
378
379
380
381ivykis 2003-03-29 ivykis(3)