Provided by: libivykis-dev_0.42.2-1_amd64 bug

NAME

       iv_examples - ivykis examples

EXAMPLE

       ivykis  is initialised by calling iv_init(3).  This function is the first function to call
       when dealing with ivykis -- it has to be called before  registering  file  descriptors  or
       timers.

       The ivykis main event loop is started by calling iv_main(3).  This function generally does
       not return, except when iv_quit(3) is called somewhere during execution of the program.

       An application asks ivykis to monitor a certain file descriptor by filling out a structure
       of  type 'struct iv_fd' with a file descriptor number and a callback function, and calling
       the function iv_fd_register.

       The first example program waits for data from standard input,  and  writes  a  message  to
       standard out whenever something is received:

       #include <stdio.h>
       #include <stdlib.h>
       #include <iv.h>

       struct iv_fd fd_stdin;

       static void callback(void *dummy)
       {
               char buf[1024];
               int len;

               len = read(fd_stdin.fd, buf, sizeof(buf));
               if (len <= 0) {
                       if (len < 0) {
                               if (errno == EAGAIN)
                                       return;
                               perror("read");
                       }
                       exit(1);
               }

               printf("read %d bytes of data from stdin\n", len);
       }

       int main()
       {
               iv_init();

               IV_FD_INIT(&fd_stdin);
               fd_stdin.fd = 0;
               fd_stdin.handler_in = callback;
               iv_fd_register(&fd_stdin);

               iv_main();

               iv_deinit();

               return 0;
       }

       The  application is responsible for memory management of 'struct iv_fd's passed to ivykis.
       For example, it should not free memory  that  contains  such  structures  that  are  still
       registered with ivykis (i.e. haven't had iv_fd_unregister called on them).

       iv_fd_register  transparently  sets  the  passed  file  descriptor to nonblocking mode, in
       anticipation of its future usage.

       File descriptor callbacks are called in a level-triggered fashion.  Therefore, the way  of
       dealing  with  fd_stdin  in  the example callback function is safe.  In case there arrives
       data between read and detecting EAGAIN, ivykis will re-call the callback function after it
       returns.  Also, if there are more than 1024 bytes waiting in the input buffer, ivykis will
       re-call the callback function until all data from stdin have been drained.

EXAMPLE 2

       The second example accepts connections on  TCP  port  6667,  and  waits  on  each  of  the
       connections  for  data.   When data is received on any connection, a message is printed to
       standard out.

       #include <stdio.h>
       #include <stdlib.h>
       #include <iv.h>
       #include <netinet/in.h>

       struct connection
       {
               struct iv_fd            fd;
               /* other per-connection data goes here */
       };

       struct listening_socket
       {
               struct iv_fd            fd;
               /* other per-listening socket data goes here */
       };

       static void connection_handler(void *_conn)
       {
               struct connection *conn = (struct connection *)_conn;
               char buf[1024];
               int len;

               len = read(conn->fd.fd, buf, sizeof(buf));
               if (len <= 0) {
                       if (len < 0 && errno == EAGAIN)
                               return;
                       iv_fd_unregister(&conn->fd);
                       close(conn->fd.fd);
                       free(conn);
                       return;
               }

               printf("got %d bytes of data from %p\n", len, conn);
       }

       static void listening_socket_handler(void *_sock)
       {
               struct listening_socket *sock = (struct listening_socket *)_sock;
               struct sockaddr_in addr;
               socklen_t addrlen;
               struct connection *conn;
               int fd;

               addrlen = sizeof(addr);
               fd = accept(sock->fd.fd, (struct sockaddr *)&addr, &addrlen);
               if (fd < 0) {
                       if (errno == EAGAIN)
                               return;
                       perror("accept");
                       exit(1);
               }

               conn = malloc(sizeof(*conn));
               if (conn == NULL) {
                       fprintf(stderr, "listening_socket_handler: memory allocation error, dropping connection");
                       close(fd);
                       return;
               }

               IV_FD_INIT(&conn->fd);
               conn->fd.fd = fd;
               conn->fd.cookie = (void *)conn;
               conn->fd.handler_in = connection_handler;
               iv_fd_register(&conn->fd);
       }

       int main()
       {
               struct listening_socket s;
               struct sockaddr_in addr;
               int fd;

               fd = socket(AF_INET, SOCK_STREAM, 0);
               if (fd < 0) {
                       perror("socket");
                       exit(1);
               }

               addr.sin_family = AF_INET;
               addr.sin_addr.s_addr = htonl(INADDR_ANY);
               addr.sin_port = htons(6667);
               if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
                       perror("bind");
                       exit(1);
               }

               if (listen(fd, 4) < 0) {
                       perror("listen");
                       exit(1);
               }

               iv_init();

               IV_FD_INIT(&s.fd);
               s.fd.fd = fd;
               s.fd.cookie = (void *)&s;
               s.fd.handler_in = listening_socket_handler;
               iv_fd_register(&s.fd);

               iv_main();

               iv_deinit();

               return 0;
       }

       As illustrated, it is possible to pass cookies into callback functions.   This  is  useful
       for conveying information on which higher-level entity (such as 'connection' or 'listening
       socket') generated the event for which the callback was called.

       Note how it is possible to unregister and even free a 'struct iv_fd' in its  own  callback
       function.  There is logic in ivykis to deal with this case.

EXAMPLE 3

       This  example  extends the previous example by a per-connection timer that disconnects the
       client after too long a period of inactivity.  Lines not present in example 2 or different
       than in example 2 are indicated by '//XXXX' in the right-hand margin.

       #include <stdio.h>
       #include <stdlib.h>
       #include <iv.h>
       #include <netinet/in.h>

       #define CONNECTION_TIMEOUT      (10)

       struct connection
       {
               struct iv_fd            fd;
               struct iv_timer         disconnect_timeout;              //XXXX
               /* other per-connection data goes here */
       };

       struct listening_socket
       {
               struct iv_fd            fd;
               /* other per-listening socket data goes here */
       };

       static void connection_handler(void *_conn)
       {
               struct connection *conn = (struct connection *)_conn;
               char buf[1024];
               int len;

               len = read(conn->fd.fd, buf, sizeof(buf));
               if (len <= 0) {
                       if (len < 0 && errno == EAGAIN)
                               return;
                       iv_timer_unregister(&conn->disconnect_timeout);  //XXXX
                       iv_fd_unregister(&conn->fd);
                       close(conn->fd.fd);
                       free(conn);
                       return;
               }

               printf("got %d bytes of data from %p\n", len, conn);

               iv_timer_unregister(&conn->disconnect_timeout);          //XXXX
               iv_validate_now();                                       //XXXX
               conn->disconnect_timeout.expires = iv_now;               //XXXX
               conn->disconnect_timeout.expires.tv_sec += CONNECTION_TIMEOUT;//XXXX
               iv_timer_register(&conn->disconnect_timeout);            //XXXX
       }

       static void disconnect_timeout_expired(void *_conn)              //XXXX
       {                                                                //XXXX
               struct connection *conn = (struct connection *)_conn;    //XXXX
               iv_fd_unregister(&conn->fd);                             //XXXX
               close(conn->fd.fd);                                      //XXXX
               free(conn);                                              //XXXX
       }                                                                //XXXX

       static void listening_socket_handler(void *_sock)
       {
               struct listening_socket *sock = (struct listening_socket *)_sock;
               struct sockaddr_in addr;
               socklen_t addrlen;
               struct connection *conn;
               int fd;

               addrlen = sizeof(addr);
               fd = accept(sock->fd.fd, (struct sockaddr *)&addr, &addrlen);
               if (fd < 0) {
                       if (errno == EAGAIN)
                               return;
                       perror("accept");
                       exit(1);
               }

               conn = malloc(sizeof(*conn));
               if (conn == NULL) {
                       fprintf(stderr, "listening_socket_handler: memory allocation error, dropping connection");
                       close(fd);
                       return;
               }

               IV_FD_INIT(&conn->fd);
               conn->fd.fd = fd;
               conn->fd.cookie = (void *)conn;
               conn->fd.handler_in = connection_handler;
               iv_fd_register(&conn->fd);

               IV_TIMER_INIT(&conn->disconnect_timeout);                //XXXX
               iv_validate_now();                                       //XXXX
               conn->disconnect_timeout.cookie = (void *)conn;          //XXXX
               conn->disconnect_timeout.handler = disconnect_timeout_expired;//XXXX
               conn->disconnect_timeout.expires = iv_now;               //XXXX
               conn->disconnect_timeout.expires.tv_sec += CONNECTION_TIMEOUT;//XXXX
               iv_timer_register(&conn->disconnect_timeout);            //XXXX
       }

       int main()
       {
               struct listening_socket s;
               struct sockaddr_in addr;
               int fd;

               fd = socket(AF_INET, SOCK_STREAM, 0);
               if (fd < 0) {
                       perror("socket");
                       exit(1);
               }

               addr.sin_family = AF_INET;
               addr.sin_addr.s_addr = htonl(INADDR_ANY);
               addr.sin_port = htons(6667);
               if (bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
                       perror("bind");
                       exit(1);
               }

               if (listen(fd, 4) < 0) {
                       perror("listen");
                       exit(1);
               }

               iv_init();

               IV_FD_INIT(&s.fd);
               s.fd.fd = fd;
               s.fd.cookie = (void *)&s;
               s.fd.handler_in = listening_socket_handler;
               iv_fd_register(&s.fd);

               iv_main();

               iv_deinit();

               return 0;
       }

       The global variable 'iv_now' represents a monotonic timer.  However, it is updated lazily,
       and its contents might be stale at any given time.  Before  using  it,  iv_validate_now(3)
       must be called.

EXAMPLE 4

       The  fourth  example  demonstrates  how  to use a custom fatal error handler that does not
       write the message to syslog.

       #include <stdio.h>
       #include <iv.h>

       static void fatal_error(const char *msg)
       {
               fprintf(stderr, "ivykis: FATAL ERROR: %s\n", msg);
       }

       int main()
       {
               iv_init();
               iv_set_fatal_msg_handler(fatal_error);

               iv_fatal("Programmatically triggered fatal error %d.", 42);
               printf("This code is never reached.\n");

               iv_deinit();

               return 0;
       }

       This program will abort immediately, with the error message printed to the standard  error
       stream.

SEE ALSO

       ivykis(3), iv_fatal(3), iv_fd(3), iv_timer(3), iv_task(3), iv_init(3), iv_time(3)