Last active
August 29, 2015 14:11
-
-
Save asauber/223c21e1895a52f88490 to your computer and use it in GitHub Desktop.
World Wide Daemon
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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