1ivykis(3)                 ivykis programmer's manual                 ivykis(3)
2
3
4

NAME

6       iv_examples - ivykis examples
7

EXAMPLE

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

EXAMPLE 2

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

EXAMPLE 3

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

EXAMPLE 4

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

SEE ALSO

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)
Impressum