summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLorenzo Torres <lorenzotorres@outlook.it>2026-06-14 15:29:08 +0200
committerLorenzo Torres <lorenzotorres@outlook.it>2026-06-14 15:29:08 +0200
commit17688ac50b4af33f228368213bf1c1798034c054 (patch)
tree9a52a6933a9b1181898f25d38dfeca1117e78cd5
basic echo server using epoll
-rw-r--r--.gitignore2
-rw-r--r--Makefile17
-rw-r--r--config.mk3
-rw-r--r--imap.c115
4 files changed, 137 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..419078f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+**/*.o
+imapd
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..6ef185b
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,17 @@
+include config.mk
+
+IMAP_SRC:=imap.c
+
+IMAP_OBJ:=$(IMAP_SRC:.c=.o)
+
+all: imap
+
+imap: $(IMAP_OBJ)
+ $(CC) $(LIBS) $(IMAP_OBJ) -o imapd
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c $< -o $@
+
+.PHONY: clean
+clean:
+ @rm -rfv imapd $(IMAP_OBJ)
diff --git a/config.mk b/config.mk
new file mode 100644
index 0000000..25b6154
--- /dev/null
+++ b/config.mk
@@ -0,0 +1,3 @@
+CC:=cc
+CFLAGS:=-Wall -Wextra -pedantic -std=c99 -ggdb
+LIBS:=
diff --git a/imap.c b/imap.c
new file mode 100644
index 0000000..295cfbd
--- /dev/null
+++ b/imap.c
@@ -0,0 +1,115 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/epoll.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#define PORT 8080
+#define MAX_EVENTS 64
+#define BUFFER_SIZE 1024
+
+void
+set_nonblocking(int32_t fd)
+{
+ int32_t flags = fcntl(fd, F_GETFL, 0);
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+}
+
+int32_t
+main(void)
+{
+ int32_t server_fd = socket(AF_INET, SOCK_STREAM, 0);
+ int32_t opt = 1;
+ setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+
+ struct sockaddr_in address = {
+ .sin_family = AF_INET,
+ .sin_addr.s_addr = INADDR_ANY,
+ .sin_port = htons(PORT)
+ };
+ bind(server_fd, (struct sockaddr *)&address, sizeof(address));
+ listen(server_fd, SOMAXCONN);
+
+ set_nonblocking(server_fd);
+ printf("server listening on port %d...\n", PORT);
+
+ int32_t epoll_fd = epoll_create1(0);
+ if (epoll_fd < 0) {
+ perror("epoll_create1 failed");
+ exit(EXIT_FAILURE);
+ }
+
+ struct epoll_event ev;
+ ev.events = EPOLLIN;
+ ev.data.fd = server_fd;
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev) < 0) {
+ perror("epoll_ctl: server_fd failed");
+ exit(EXIT_FAILURE);
+ }
+
+ struct epoll_event events[MAX_EVENTS];
+ char buffer[BUFFER_SIZE];
+
+ while (1) {
+ int32_t nfds = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
+ if (nfds < 0) {
+ perror("epoll_wait failed");
+ break;
+ }
+
+ for (int32_t i = 0; i < nfds; i++) {
+ if (events[i].data.fd == server_fd) {
+ struct sockaddr_in client_addr;
+ socklen_t client_len = sizeof(client_addr);
+
+ int32_t client_fd = accept(server_fd, (struct sockaddr *)&client_addr, &client_len);
+ if (client_fd < 0) {
+ perror("accept failed");
+ continue;
+ }
+
+ printf("connection accepted (client fd: %d)\n", client_fd);
+ set_nonblocking(client_fd);
+
+ ev.events = EPOLLIN | EPOLLET;
+ ev.data.fd = client_fd;
+ if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &ev) < 0) {
+ perror("epoll_ctl: client_fd failed");
+ close(client_fd);
+ }
+ } else {
+ int32_t client_fd = events[i].data.fd;
+
+ while (1) {
+ ssize_t bytes_read = read(client_fd, buffer, sizeof(buffer));
+
+ if (bytes_read > 0) {
+ write(client_fd, buffer, bytes_read);
+ } else if (bytes_read == 0) {
+ printf("client on fd %d closed connection.\n", client_fd);
+ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, NULL);
+ close(client_fd);
+ break;
+ } else {
+ if (errno == EAGAIN || errno == EWOULDBLOCK) {
+ break;
+ }
+
+ perror("read error");
+ epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, NULL);
+ close(client_fd);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ close(epoll_fd);
+ close(server_fd);
+ return 0;
+}