Created
December 16, 2009 19:58
-
-
Save ankurs/258118 to your computer and use it in GitHub Desktop.
This file contains 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
/* | |
* Initial implementation of a HTTP server, this is just a test which | |
* only manages GET request for file names | |
* Author: Ankur Shrivastava | |
* Licence: GPLv3+ | |
*/ | |
#include<unistd.h> | |
#include<stdio.h> | |
#include<stdlib.h> | |
#include<string.h> | |
#include<sys/wait.h> | |
#include<sys/socket.h> | |
#include<sys/types.h> | |
#include<sys/stat.h> | |
#include<netinet/in.h> | |
#include<errno.h> | |
#include<sys/sendfile.h> | |
#include<fcntl.h> | |
#define PORT_NUMBER 9090 | |
#define BUF_LEN 1024 | |
#define PROCESS_NUMBER 10 | |
#define INDEX_FILE "index.html" | |
int readline(int soc, char *line, int len) | |
{ | |
/* | |
* Reads a line from socket, line should be terminated by \n | |
* #TODO replace with a more efficient version | |
*/ | |
char *ptr,c; | |
int num=0; | |
ptr = line; | |
while (1) | |
{ | |
if ( (read(soc,&c,1) == 1 ) && ( len > num)) | |
{ | |
*ptr++ = c; | |
if (c == '\n') | |
{ | |
*ptr = '\0'; | |
return --num; | |
} | |
num++; | |
} | |
else | |
{ | |
if (num >= len) | |
{ | |
line = realloc(line,BUF_LEN * 2); | |
ptr = line + num; | |
len = BUF_LEN * 2; | |
} | |
if (errno != EINTR) | |
break; | |
} | |
} | |
return -1; | |
} | |
char * get_file(char* line) | |
{ | |
if ( !strncmp(line,"GET",3)) | |
{ | |
char *lineptr; | |
lineptr = line + 5; | |
char name[40], *ptr; | |
ptr = name; | |
while (strncmp(lineptr," ",1)) | |
{ | |
*ptr = *lineptr; | |
ptr++; | |
lineptr++; | |
} | |
*ptr = '\0'; | |
strcpy(line,name); | |
if (strlen(line) == 0) | |
{ | |
return NULL; | |
} | |
return line; | |
} | |
return NULL; | |
} | |
int main(int argv, char **args) | |
{ | |
struct sockaddr_in cliaddr, servaddr; // socket structure | |
int listenfd, connfd; | |
pid_t clipid; | |
if ( (listenfd = socket(AF_INET,SOCK_STREAM,0)) < 0 ) | |
{ | |
perror("socket"); | |
exit(1); | |
} | |
memset( &servaddr, 0, sizeof(servaddr) ); // set serveraddr to zero | |
servaddr.sin_family = AF_INET; // internet socket | |
servaddr.sin_addr.s_addr = htonl(INADDR_ANY); // any host address | |
servaddr.sin_port = htons(PORT_NUMBER); // port | |
if ( bind(listenfd, (struct sockaddr *) &servaddr, sizeof(servaddr)) < 0) | |
{ | |
perror("bind"); | |
exit(1); | |
} | |
if ( listen(listenfd, 10) < 0 ) // listen with wait queue of 10 | |
{ | |
perror("listen"); | |
exit(1); | |
} | |
int i; | |
for(i=0;i<PROCESS_NUMBER;i++) | |
{ | |
if ( (clipid = fork()) == 0) // fork processes | |
{ | |
printf("Started PID -> %i\n",getpid()); | |
while (1) // server infinitely | |
{ | |
socklen_t clilen = sizeof(cliaddr); | |
/* accept blocks till we have new client connection*/ | |
connfd = accept(listenfd, (struct sockaddr *) &cliaddr, &clilen); | |
// handle HTTP request here | |
// DIRTY Clean it | |
char *line; | |
line = (char *) malloc(BUF_LEN); | |
readline(connfd,line,BUF_LEN); // read the first request line | |
printf("%s", line ); | |
char *filename; | |
filename = get_file(line); // get file to be opened | |
if (filename == NULL) | |
{ // if / then we send the index file | |
filename = malloc(sizeof(char)*strlen(INDEX_FILE)); | |
strcpy(filename,"index.html\0"); | |
} | |
// reply | |
char con_len[50]; | |
char *head = "HTTP/1.1 200 OK\r\n"; // OK always #TODO handle all HTTP | |
char *head2 = "Content-type: text/html\r\n"; // #TODO get mime type of file | |
write(connfd,head,strlen(head)); | |
write(connfd,head2,strlen(head2)); | |
char *page_not_found = "<html><head><title>Server</title></head><body><h1>404 Not Found</h1></body></html>"; // page not found text | |
struct stat file_status; | |
if (!stat(filename,&file_status)) | |
{ // if file exists | |
int fd = open(filename,O_RDONLY); // open file | |
size_t size = file_status.st_size; // get size | |
sprintf(con_len,"Content-length: %i \r\n\r\n",size); // set file size | |
write(connfd,con_len,strlen(con_len)); // send Content-length | |
sendfile(connfd,fd,NULL,size); // send file | |
} | |
else | |
{ // send file not found | |
sprintf(con_len,"Content-length: %i \r\n\r\n",strlen(page_not_found)); | |
write(connfd,con_len,strlen(con_len)); | |
write(connfd,page_not_found,strlen(page_not_found)); | |
} | |
free(line); | |
// till here | |
close(connfd); | |
//exit(0); | |
} | |
} | |
} | |
int stat; | |
waitpid(-1,&stat,0); // #TODO handle signals | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment