Skip to content

Instantly share code, notes, and snippets.

@yne
Last active August 18, 2024 15:20
Show Gist options
  • Save yne/d93dccc34184a8f9488bdc088d631050 to your computer and use it in GitHub Desktop.
Save yne/d93dccc34184a8f9488bdc088d631050 to your computer and use it in GitHub Desktop.
Tiny epoll-based HTTP server
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#define MAXEVENTS 64
static const char reply[] =
"HTTP/1.0 200 OK\r\n"
"Content-type: text/html\r\n"
"Connection: close\r\n"
"Content-Length: 82\r\n"
"\r\n"
"test";
int main(int argc, char *argv[]) {
if (argc != 2) return fprintf(stderr, "Usage: %s [port]\n", argv[0]), -1;
int sfd = socket(AF_INET, SOCK_STREAM, 0);
bind(sfd,
(struct sockaddr *)&((struct sockaddr_in){
.sin_family = AF_INET, htons(atoi(argv[1])), {}}),
sizeof(struct sockaddr_in));
fcntl(sfd, F_SETFL, fcntl(sfd, F_GETFL, 0) | O_NONBLOCK);
listen(sfd, SOMAXCONN);
int efd = epoll_create1(0);
static struct epoll_event events[MAXEVENTS];
struct epoll_event event = {.data.fd = sfd, .events = EPOLLIN | EPOLLET};
int s = epoll_ctl(efd, EPOLL_CTL_ADD, sfd, &event);
while (1) {
int n = epoll_wait(efd, events, sizeof(events) / sizeof(*events), -1);
for (int i = 0; i < n; i++) {
if ((events[i].events & EPOLLERR) || (events[i].events & EPOLLHUP) || (!(events[i].events & EPOLLIN))) {
close(events[i].data.fd);
} else if (sfd == events[i].data.fd) {
while (1) {
struct sockaddr in_addr;
socklen_t in_len = sizeof in_addr;
int infd = accept(sfd, &in_addr, &in_len);
if (infd == -1) {
break;
}
fcntl(infd, F_SETFL, fcntl(infd, F_GETFL, 0) | O_NONBLOCK);
event.data.fd = infd;
event.events = EPOLLIN | EPOLLET;
epoll_ctl(efd, EPOLL_CTL_ADD, infd, &event);
}
} else {
int done = 0;
while (1) {
char buf[512];
ssize_t count = read(events[i].data.fd, buf, sizeof buf);
done = (count == -1 && errno != EAGAIN) || !count;
if (count <= 0) break;
write(events[i].data.fd, reply, sizeof(reply));
}
if (done) {
close(events[i].data.fd);
}
}
}
}
close(sfd);
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment