commit f8cd81701c9ca4b161748ea198c9e5e73bd51895
parent 6f49ef2b8f25abbe4a5702b0b767aea9ecdeb97e
Author: Henry Wilson <henry@henryandlizzy.uk>
Date: Tue, 16 Aug 2022 00:22:43 +0100
epoll: Add TCP support
Diffstat:
M | src/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 (;;)