examples

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

commit f8cd81701c9ca4b161748ea198c9e5e73bd51895
parent 6f49ef2b8f25abbe4a5702b0b767aea9ecdeb97e
Author: Henry Wilson <henry@henryandlizzy.uk>
Date:   Tue, 16 Aug 2022 00:22:43 +0100

epoll: Add TCP support

Diffstat:
Msrc/epoll.c | 109+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
1 file changed, 99 insertions(+), 10 deletions(-)

diff --git a/src/epoll.c b/src/epoll.c @@ -2,6 +2,10 @@ #include <sys/timerfd.h> #include <sys/signalfd.h> #include <sys/inotify.h> +#include <sys/socket.h> +#include <netinet/ip.h> +#include <netinet/tcp.h> + #include <signal.h> #include <unistd.h> #include <stdio.h> @@ -12,7 +16,8 @@ #include <err.h> #include <errno.h> -static int timer, signals, notifications, event_queue; +static int timer, signals, notifications, tcp_socket, connection = -1, event_queue; +static char** args; static void check_err(char const* msg) { @@ -20,6 +25,29 @@ static void check_err(char const* msg) err(1, "%s", msg); } +static void puts_all(char const* msg) +{ + size_t len = strlen(msg); + char buf[len]; + + memcpy(buf, msg, len); + buf[len] = '\n'; + + write(STDOUT_FILENO, buf, len+1); + if (connection >= 0) + write(connection, buf, len+1); + check_err("write"); +} + +static void add_epollin(int fd, void(*cb)()) +{ + epoll_ctl(event_queue, EPOLL_CTL_ADD, fd, &(struct epoll_event){ + .events = EPOLLIN, + .data.ptr = cb, + }); + check_err("epoll_ctl"); +} + static void stdin_event(void) { char buf[64]; @@ -27,7 +55,7 @@ static void stdin_event(void) if (n <= 0) { - puts("Stdin closed."); + puts_all("Stdin closed."); exit(0); } for (int i = 0; i < n; ++i) @@ -36,6 +64,8 @@ static void stdin_event(void) buf[n] = '\0'; printf("Stdin: '%s'\n", buf); + if (connection >= 0) + dprintf(connection, "Stdin: '%s'\n", buf); } static void timerfd_event(void) @@ -45,6 +75,8 @@ static void timerfd_event(void) read(timer, &new_ticks, sizeof new_ticks); ticks += new_ticks; printf("Timer: +%lu %lu\n", new_ticks, ticks); + if (connection >= 0) + dprintf(connection, "Timer: +%lu %lu\n", new_ticks, ticks); } static void signalfd_event(void) @@ -61,21 +93,64 @@ static void inotify_event(void) struct inotify_event buf; read(notifications, &buf, sizeof buf); check_err("read"); - puts("Executable updated, exiting..."); - exit(0); + puts_all("Executable updated, restarting..."); + sleep(1); + close(timer); + close(signals); + close(notifications); + close(tcp_socket); + close(connection); + close(event_queue); + execv(args[0], args); + check_err("execv"); + exit(1); } -static void add_epollin(int fd, void(*cb)()) +static void recv_event(void) { - epoll_ctl(event_queue, EPOLL_CTL_ADD, fd, &(struct epoll_event){ - .events = EPOLLIN, - .data.ptr = cb, - }); - check_err("epoll_ctl"); + char buf[64]; + + int n = read(connection, buf, sizeof buf - 1); + + if (n <= 0) + { + puts("Connection closed."); + close(connection); + connection = -1; + return; + } + for (int i = 0; i < n; ++i) + if (iscntrl(buf[i])) + buf[i] = '.'; + buf[n] = '\0'; + + printf("TCP: '%s'\n", buf); +} + +static void connect_event(void) +{ + char const buf[] = "Hello, outside world!\n"; + struct sockaddr_in client; + socklen_t len = sizeof client; + + puts_all("TCP: greeting guest"); + + if (connection >= 0) + { + close(connection); + check_err("close"); + } + + connection = accept(tcp_socket, (struct sockaddr*)&client, &len); + check_err("accept"); + write(connection, buf, sizeof buf); + check_err("write"); + add_epollin(connection, recv_event); } int main(int, char* argv[]) { + args = argv; timer = timerfd_create(CLOCK_MONOTONIC, 0); check_err("timerfd_create"); timerfd_settime(timer, 0, &(struct itimerspec){ @@ -99,12 +174,26 @@ int main(int, char* argv[]) inotify_add_watch(notifications, argv[0], IN_ATTRIB | IN_MASK_CREATE); check_err("inotify_add_watch"); + int const reuseaddr = 1; + tcp_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + check_err("socket"); + setsockopt(tcp_socket, SOL_SOCKET, SO_REUSEADDR, &reuseaddr, sizeof reuseaddr); + check_err("setsockopt"); + bind(tcp_socket, (const struct sockaddr*)&(struct sockaddr_in){ + .sin_family = AF_INET, + .sin_port = htons(1337), + .sin_addr = {.s_addr = htonl(INADDR_ANY)} + }, sizeof (struct sockaddr_in)); + check_err("bind"); + listen(tcp_socket, 1); + event_queue = epoll_create1(0); check_err("epoll_create1"); add_epollin(STDIN_FILENO, stdin_event); add_epollin(timer, timerfd_event); add_epollin(signals, signalfd_event); add_epollin(notifications, inotify_event); + add_epollin(tcp_socket, connect_event); puts("\nepoll: processing events..."); for (;;)