Skip to content

Instantly share code, notes, and snippets.

@petabyt
Last active February 24, 2022 15:47
Show Gist options
  • Save petabyt/12c7d12dfa12c2b19cf41f3e712a2be8 to your computer and use it in GitHub Desktop.
Save petabyt/12c7d12dfa12c2b19cf41f3e712a2be8 to your computer and use it in GitHub Desktop.
tiny c99 web server
// Inspired by https://gist.github.com/laobubu/d6d0e9beb934b60b2e552c2d03e1409e
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <signal.h>
#define MAX_CONNECTION 100
#define RESP_BUF_MAX 1000
int recieve(char url[]);
int serv_init(int port, int *listenfd) {
char port_s[16];
snprintf(port_s, 16, "%u", port);
printf("Starting on http://127.0.0.1:%s\n", port_s);
struct addrinfo hints, *res;
// Pre set to empty connections
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
if (getaddrinfo(NULL, port_s, &hints, &res)) {
perror("getaddrinfo() failed\n");
return 1;
}
for (struct addrinfo *p = res; p != NULL; p = p->ai_next) {
int option = 1;
*listenfd = socket(p->ai_family, p->ai_socktype, 0);
setsockopt(*listenfd, SOL_SOCKET, SO_REUSEADDR, &option, sizeof(option));
if (*listenfd == -1) {
continue;
}
if (!bind(*listenfd, p->ai_addr, p->ai_addrlen)) {
break;
}
}
freeaddrinfo(res);
if (listen(*listenfd, MAX_CONNECTION)) {
perror("listen() error");
return 1;
}
}
//client connection
int respond(int n, int clients[MAX_CONNECTION]) {
char *buf = malloc(RESP_BUF_MAX);
int rcvd = recv(clients[n], buf, RESP_BUF_MAX, 0);
if (rcvd < 0) {
perror("recv() error\n");
return 1;
} else if (rcvd == 0) {
perror("Client disconnected upexpectedly\n");
return 1;
}
// Quickly filter parameters from response dump
char *url = strtok(buf, "\n");
while (url != NULL) {
if (!strncmp(url, "GET ", 4)) {
url = strtok(url + 4, " ");
break;
}
url = strtok(NULL, "\n");
}
// Route file descriptor into stdout
dup2(clients[n], STDOUT_FILENO);
close(clients[n]);
recieve(url);
fflush(stdout);
shutdown(STDOUT_FILENO, SHUT_WR);
close(STDOUT_FILENO);
clients[n] = -1;
return 0;
}
int serv_start(int port) {
int clients[MAX_CONNECTION];
memset(clients, -1, sizeof(int) * MAX_CONNECTION);
struct sockaddr_in clientaddr;
int listenfd;
serv_init(port, &listenfd);
// Ignore SIGCHLD to avoid zombie threads
signal(SIGCHLD, SIG_IGN);
while (1) {
int slot = 0;
socklen_t addrlen = sizeof(clientaddr);
clients[slot] = accept(listenfd, (struct sockaddr *) &clientaddr, &addrlen);
if (clients[slot] < 0) {
perror("accept() error");
} else {
if (fork() == 0) {
respond(slot, clients);
break;
}
}
while (clients[slot]!=-1) {
slot = (slot + 1) % MAX_CONNECTION;
}
}
return 0;
}
int recieve(char url[]) {
printf("HTTP/1.1 200 OK\rContent-type: text/html\n\r\n");
printf("<title>Basic test</title>You are on URL, [%s]\n", url);
}
int main() {
serv_start(1234);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment