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 }