ivykis(3) ivykis programmer's manual ivykis(3)

# [NAME](#NAME)

iv\_examples - ivykis examples

# [EXAMPLE](#EXAMPLE)

ivykis is initialised by calling [**iv\_init**(3)](/man/os/ivykis/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)](/man/os/ivykis/iv_main.3). This function generally does not return, except when [**iv\_quit**(3)](/man/os/ivykis/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](#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](#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)](/man/os/ivykis/iv_validate_now.3) must be called.

# [EXAMPLE 4](#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](#SEE_ALSO)

[**ivykis**(3)](/man/os/ivykis/ivykis.3), [**iv\_fatal**(3)](/man/os/ivykis/iv_fatal.3), [**iv\_fd**(3)](/man/os/ivykis/iv_fd.3), [**iv\_timer**(3)](/man/os/ivykis/iv_timer.3), [**iv\_task**(3)](/man/os/ivykis/iv_task.3), [**iv\_init**(3)](/man/os/ivykis/iv_init.3), [**iv\_time**(3)](/man/os/ivykis/iv_time.3)

2003-03-29 ivykis

---

Document: iv_examples(3) from ivykis 0.43.2-r7 (Chainguard OS)
Source: https://github.com/buytenh/ivykis
