diff options
Diffstat (limited to 'imap.c')
| -rw-r--r-- | imap.c | 115 |
1 files changed, 115 insertions, 0 deletions
@@ -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; +} |
