Skip to content

Instantly share code, notes, and snippets.

@asauber
Last active August 29, 2015 14:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save asauber/223c21e1895a52f88490 to your computer and use it in GitHub Desktop.
Save asauber/223c21e1895a52f88490 to your computer and use it in GitHub Desktop.
World Wide Daemon
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <errno.h>
#include <arpa/inet.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#define BUFSIZE 1024
#define LISTEN_ADDR "0.0.0.0"
#define PORT 80
#define BEFORE_URI 0
#define WITHIN_URI 1
#define PARSE_COMPLETE 2
#define INTSTR_SIZE 11
int s_sockfd;
int parse_uri (char **uri, char *buf);
int resp_200 (int c_sockfd, FILE* req_file);
int resp_4x (int c_sockfd, int code);
void sig_handler(int signo) {
if (signo == SIGINT) {
close(s_sockfd);
exit(1);
}
}
int main (int argc, char *argv[]) {
// create a socket
// use the internet address family
// request a stream socket (tcp)
// use the internet protocl
s_sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (s_sockfd == -1) {
perror("could not create socket:");
exit(1);
}
printf("[I] wwd starting up\n");
// close the socket on SIGINT
if (signal(SIGINT, sig_handler) == SIG_ERR) {
printf("Can't catch SIGINT\n");
exit(1);
}
// initialize a socket address for the server
struct sockaddr_in s_addr = {0};
// use the internet address family
s_addr.sin_family = AF_INET;
// choose a port number
s_addr.sin_port = htons(PORT);
// bind to all routable network adapters
s_addr.sin_addr.s_addr = inet_addr(LISTEN_ADDR);
// bind the socket to a local address
int rval = bind(s_sockfd, (struct sockaddr *)&s_addr, sizeof(struct sockaddr));
if (rval == -1) {
perror("could not bind:");
exit(1);
}
printf("[I] wwd bound to %s on port %d\n", LISTEN_ADDR, PORT);
// listen on socket
rval = listen(s_sockfd, 32);
if (rval == -1) {
perror("cound not listen:");
exit(1);
}
printf("[I] wwd listening for incoming connections\n");
// accept client connections
while (true) {
struct sockaddr_in c_addr;
unsigned int sin_size = sizeof(struct sockaddr_in);
int c_sockfd = accept(s_sockfd, (struct sockaddr *)&c_addr, &sin_size);
if (c_sockfd == -1) {
perror("cound not accept:");
exit(1);
}
printf("[I] Accepted connection from %s\n",
inet_ntoa(c_addr.sin_addr));
char buf[BUFSIZE];
memset(buf, 0, BUFSIZ);
recv(c_sockfd, &buf, BUFSIZE, 0);
printf("[I] http request:\n%s", buf);
char *uri = NULL;
rval = parse_uri(&uri, buf);
if (rval == -1) {
resp_4x(c_sockfd, 414);
close(c_sockfd);
continue;
}
printf("[I] uri requested: %s\n", uri);
FILE *req_file = fopen(uri + 1, "r");
if (req_file == NULL) {
resp_4x(c_sockfd, 404);
close(c_sockfd);
continue;
}
resp_200(c_sockfd, req_file);
close(c_sockfd);
}
return 0;
}
int resp_200 (int c_sockfd, FILE* req_file) {
int req_fd = fileno(req_file);
struct stat req_stat;
fstat(req_fd, &req_stat);
int clen = req_stat.st_size;
char buf[BUFSIZE];
sprintf((char *)buf, "%s%d%s",
"HTTP/1.1 200 OK\r\n"
"Content Type: text/html\r\n"
"Content Length: ", clen, "\r\n"
"\r\n");
int headerlen = strlen((char *)buf);
send(c_sockfd, buf, headerlen, 0);
memset(buf, 0, BUFSIZ);
int bytes_read = 0;
while ((bytes_read = read(req_fd, buf, BUFSIZE)) > 0) {
send(c_sockfd, buf, bytes_read, 0);
}
return 0;
}
int resp_4x (int c_sockfd, int code) {
char *body, *firstline;
if (code == 404) {
body = "<html><body>404 File not found</body></html>";
firstline = "HTTP/1.1 404 Not Found";
} else if (code == 414) {
body = "<html><body>414 Request URI too long</body></html>";
firstline = "HTTP/1.1 414 Request URI Too Long";
} else {
return -1;
}
int bodylen = strlen(body);
char clen[INTSTR_SIZE];
snprintf(clen, INTSTR_SIZE, "%d", bodylen);
char *headerbuf[BUFSIZE];
sprintf((char *)headerbuf, "%s%s%s%s",
firstline, "\r\n"
"Content Type: text/html\r\n"
"Content Length: ", clen, "\r\n"
"\r\n");
int headerlen = strlen((char *)headerbuf);
send(c_sockfd, headerbuf, headerlen, 0);
send(c_sockfd, body, bodylen, 0);
return 0;
}
int parse_uri (char **uri, char *buf) {
char *p = buf;
*uri = NULL;
int parse_state = BEFORE_URI;
while (parse_state != PARSE_COMPLETE) {
switch(parse_state) {
case BEFORE_URI:
if (*p == ' ') {
*uri = p + 1;
parse_state = WITHIN_URI;
}
break;
case WITHIN_URI:
if (*p == ' ') {
*p = '\0';
parse_state = PARSE_COMPLETE;
}
break;
}
p++;
if (p > (buf + BUFSIZE)) {
return -1;
}
}
return 0;
}
CC = gcc
CFLAGS = -Wall -O3 --std=c11
CDEBUGFLAGS = -Wall -O0 --std=c11 -g
wwd: main.c
$(CC) $(CFLAGS) -o $@ $<
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment