examples

Toy examples in single C files.
git clone git://henryandlizzy.uk/examples
Log | Files | Refs

epoll.c (4606B)


      1 #include <sys/epoll.h>
      2 #include <sys/timerfd.h>
      3 #include <sys/signalfd.h>
      4 #include <sys/inotify.h>
      5 #include <sys/socket.h>
      6 #include <netinet/ip.h>
      7 #include <netinet/tcp.h>
      8 
      9 #include <signal.h>
     10 #include <unistd.h>
     11 #include <stdio.h>
     12 #include <stdint.h>
     13 #include <stdlib.h>
     14 #include <ctype.h>
     15 #include <string.h>
     16 #include <err.h>
     17 #include <errno.h>
     18 
     19 static int timer, signals, notifications, tcp_socket, connection = -1, event_queue;
     20 static char** args;
     21 
     22 static void check_err(char const* msg)
     23 {
     24 	if (errno)
     25 		err(1, "%s", msg);
     26 }
     27 
     28 static void puts_all(char const* msg)
     29 {
     30 	size_t len = strlen(msg);
     31 	char buf[len];
     32 
     33 	memcpy(buf, msg, len);
     34 	buf[len] = '\n';
     35 
     36 	write(STDOUT_FILENO, buf, len+1);
     37 	if (connection >= 0)
     38 		write(connection, buf, len+1);
     39 	check_err("write");
     40 }
     41 
     42 static void add_epollin(int fd, void(*cb)())
     43 {
     44 	epoll_ctl(event_queue, EPOLL_CTL_ADD, fd, &(struct epoll_event){
     45 		.events = EPOLLIN,
     46 		.data.ptr = cb,
     47 	});
     48 	check_err("epoll_ctl");
     49 }
     50 
     51 static void stdin_event(void)
     52 {
     53 	char buf[64];
     54 	int n = read(STDIN_FILENO, buf, sizeof buf - 1);
     55 
     56 	if (n <= 0)
     57 	{
     58 		puts_all("Stdin closed.");
     59 		exit(0);
     60 	}
     61 	for (int i = 0; i < n; ++i)
     62 		if (iscntrl(buf[i]))
     63 			buf[i] = '.';
     64 	buf[n] = '\0';
     65 
     66 	printf("Stdin: '%s'\n", buf);
     67 	if (connection >= 0)
     68 		dprintf(connection, "Stdin: '%s'\n", buf);
     69 }
     70 
     71 static void timerfd_event(void)
     72 {
     73 	static uint64_t ticks;
     74 	uint64_t new_ticks;
     75 	read(timer, &new_ticks, sizeof new_ticks);
     76 	ticks += new_ticks;
     77 	printf("Timer: +%lu %lu\n", new_ticks, ticks);
     78 	if (connection >= 0)
     79 		dprintf(connection, "Timer: +%lu %lu\n", new_ticks, ticks);
     80 }
     81 
     82 static void signalfd_event(void)
     83 {
     84 	struct signalfd_siginfo buf;
     85 	read(signals, &buf, sizeof buf);
     86 	check_err("read");
     87 	printf("Signal: %s\n", strsignal(buf.ssi_signo));
     88 	exit(0);
     89 }
     90 
     91 static void inotify_event(void)
     92 {
     93 	struct inotify_event buf;
     94 	read(notifications, &buf, sizeof buf);
     95 	check_err("read");
     96 	puts_all("Executable updated, restarting...");
     97 	sleep(1);
     98 	close(timer);
     99 	close(signals);
    100 	close(notifications);
    101 	close(tcp_socket);
    102 	close(connection);
    103 	close(event_queue);
    104 	execv(args[0], args);
    105 	check_err("execv");
    106 	exit(1);
    107 }
    108 
    109 static void recv_event(void)
    110 {
    111 	char buf[64];
    112 
    113 	int n = read(connection, buf, sizeof buf - 1);
    114 
    115 	if (n <= 0)
    116 	{
    117 		puts("Connection closed.");
    118 		close(connection);
    119 		connection = -1;
    120 		return;
    121 	}
    122 	for (int i = 0; i < n; ++i)
    123 		if (iscntrl(buf[i]))
    124 			buf[i] = '.';
    125 	buf[n] = '\0';
    126 
    127 	printf("TCP: '%s'\n", buf);
    128 }
    129 
    130 static void connect_event(void)
    131 {
    132 	char const buf[] = "Hello, outside world!\n";
    133 	struct sockaddr_in client;
    134 	socklen_t len = sizeof client;
    135 
    136 	puts_all("TCP: greeting guest");
    137 
    138 	if (connection >= 0)
    139 	{
    140 		close(connection);
    141 		check_err("close");
    142 	}
    143 
    144 	connection = accept(tcp_socket, (struct sockaddr*)&client, &len);
    145 	check_err("accept");
    146 	write(connection, buf, sizeof buf);
    147 	check_err("write");
    148 	add_epollin(connection, recv_event);
    149 }
    150 
    151 int main(int, char* argv[])
    152 {
    153 	args = argv;
    154 	timer = timerfd_create(CLOCK_MONOTONIC, 0);
    155 	check_err("timerfd_create");
    156 	timerfd_settime(timer, 0, &(struct itimerspec){
    157 		.it_interval = {1, 0},  /* Interval for periodic timer */
    158 		.it_value = {1, 0},     /* Initial expiration */
    159 	}, NULL);
    160 	check_err("timerfd_settime");
    161 
    162 	sigset_t sigset;
    163 	sigemptyset(&sigset);
    164 	check_err("sigemptyset");
    165 	sigaddset(&sigset, SIGINT);
    166 	check_err("sigaddset");
    167 	sigprocmask(SIG_SETMASK, &sigset, NULL);
    168 	check_err("sigprocmask");
    169 	signals = signalfd(-1, &sigset, 0);
    170 	check_err("signalfd");
    171 
    172 	notifications = inotify_init();
    173 	check_err("inotify_init");
    174 	inotify_add_watch(notifications, argv[0], IN_ATTRIB | IN_MASK_CREATE);
    175 	check_err("inotify_add_watch");
    176 
    177 	int const reuseaddr = 1;
    178 	tcp_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    179 	check_err("socket");
    180 	setsockopt(tcp_socket, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof reuseaddr);
    181 	check_err("setsockopt");
    182 	bind(tcp_socket, (const struct sockaddr*)&(struct sockaddr_in){
    183 		.sin_family = AF_INET,
    184 		.sin_port = htons(1337),
    185 		.sin_addr = {.s_addr = htonl(INADDR_ANY)}
    186 	}, sizeof (struct sockaddr_in));
    187 	check_err("bind");
    188 	listen(tcp_socket, 1);
    189 
    190 	event_queue = epoll_create1(0);
    191 	check_err("epoll_create1");
    192 	add_epollin(STDIN_FILENO, stdin_event);
    193 	add_epollin(timer, timerfd_event);
    194 	add_epollin(signals, signalfd_event);
    195 	add_epollin(notifications, inotify_event);
    196 	add_epollin(tcp_socket, connect_event);
    197 
    198 	puts("\nepoll: processing events...");
    199 	for (;;)
    200 	{
    201 		struct epoll_event events[8];
    202 		int n_events = epoll_wait(event_queue, events, sizeof events / sizeof *events, -1);
    203 		check_err("epoll_wait");
    204 
    205 		for (int i = 0; i < n_events; ++i)
    206 			((void(*)(void))events[i].data.ptr)();
    207 	}
    208 }