summaryrefslogtreecommitdiff
path: root/imap.c
diff options
context:
space:
mode:
Diffstat (limited to 'imap.c')
-rw-r--r--imap.c115
1 files changed, 115 insertions, 0 deletions
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;
+}