Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * -- simplehttpd.c --
- * A (very) simple HTTP server
- *
- * Sistemas Operativos 2014/2015
- */
- #include <stdio.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <unistd.h>
- #include <ctype.h>
- #include <sys/stat.h>
- #include <sys/wait.h>
- #include <stdlib.h>
- #include <string.h>
- #include <signal.h>
- #include <sys/shm.h>
- #include <sys/ipc.h>
- #include <sys/msg.h>
- #include <time.h>
- #include <pthread.h>
- #include <errno.h>
- // Produce debug information
- #define DEBUG 1
- // Header of HTTP reply to client
- #define SERVER_STRING "Server: simpleserver/0.1.0\r\n"
- #define HEADER_1 "HTTP/1.0 200 OK\r\n"
- #define HEADER_2 "Content-Type: text/html\r\n\r\n"
- #define GET_EXPR "GET /"
- #define CGI_EXPR "cgi-bin/"
- #define SIZE_BUF 1024
- #define DEFAULT_THREADS 5
- // Configurations Structure
- typedef struct allowed{
- char name[50];
- struct allowed * next;
- }allowed;
- typedef struct config{
- int s_port;
- int scheduling;
- int thread_pool;
- allowed files [SIZE_BUF];
- }config;
- //Statitics Structure
- typedef struct statistics{
- int n_static;
- int n_compressed;
- int t_static_ncompressed;
- int t_static_compressed;
- }statistics;
- /* data */
- int fireup(int port);
- void identify(int socket);
- void get_request(int socket);
- int read_line(int socket, int n);
- void send_header(int socket);
- void send_page(int socket);
- void execute_script(int socket);
- void not_found(int socket);
- void catch_ctrlc(int);
- void cannot_execute(int socket);
- void * worker(void * t);
- void * scheduler(void * t);
- void init(int port);
- void initialConfig(int port);
- char buf[SIZE_BUF];
- char req_buf[SIZE_BUF];
- char buf_tmp[SIZE_BUF];
- int port,socket_conn,new_conn;
- int shm;
- config* cfg=(config*)malloc(sizeof(config));
- statistics* stats;
- int main(int argc, char ** argv)
- {
- struct sockaddr_in client_name;
- socklen_t client_name_len = sizeof(client_name);
- int port,i;
- signal(SIGINT,catch_ctrlc);
- // Verify number of arguments
- if (argc!=2) {
- printf("Usage: %s <port>\n",argv[0]);
- exit(1);
- }
- port=atoi(argv[1]);
- printf("Listening for HTTP requests on port %d\n",port);
- // Configure listening port
- if ((socket_conn=fireup(port))==-1)
- exit(1);
- else{
- init(port);
- pthread_t threads[cfg->thread_pool];
- int thread_id[cfg->thread_pool];
- thread_id[0] = 0;
- if (pthread_create(&threads[0],NULL,scheduler, &thread_id[0]) != 0)
- perror("Error creating scheduler");
- for(i=1;i<cfg->thread_pool;i++){
- thread_id[i] = i;
- if (pthread_create(&threads[i],NULL,worker,&thread_id[i]) != 0)
- perror("Error creating threads");
- }
- for(i=0;i<cfg->thread_pool;i++){
- pthread_join(threads[i],NULL);
- }
- }
- // Serve requests
- while (1)
- {
- // Accept connection on socket
- if ( (new_conn = accept(socket_conn,(struct sockaddr *)&client_name,&client_name_len)) == -1 ) {
- printf("Error accepting connection\n");
- exit(1);
- }
- // Identify new client
- identify(new_conn);
- // Process request
- get_request(new_conn);
- // Verify if request is for a page or script
- if(!strncmp(req_buf,CGI_EXPR,strlen(CGI_EXPR)))
- execute_script(new_conn);
- else
- // Search file with html page and send to client
- send_page(new_conn);
- if(fork()==0){
- /*processo filho para as estatisticas*/
- }
- // Terminate connection with client
- close(new_conn);
- }
- }
- void * worker(void * t){
- int my_id = *((int*)t);
- printf ("Worker's ID: %d\n", my_id);
- pthread_exit(NULL);
- }
- void * scheduler(void * t){
- int my_id = *((int*)t);
- printf ("Scheduler's ID: %d\n", my_id);
- pthread_exit(NULL);
- }
- // Processes request from client
- void get_request(int socket)
- {
- int i,j;
- int found_get;
- found_get=0;
- while ( read_line(socket,SIZE_BUF) > 0 ) {
- if(!strncmp(buf,GET_EXPR,strlen(GET_EXPR))) {
- // GET received, extract the requested page/script
- found_get=1;
- i=strlen(GET_EXPR);
- j=0;
- while( (buf[i]!=' ') && (buf[i]!='\0') )
- req_buf[j++]=buf[i++];
- req_buf[j]='\0';
- }
- }
- // Currently only supports GET
- if(!found_get) {
- printf("Request from client without a GET\n");
- exit(1);
- }
- // If no particular page is requested then we consider htdocs/index.html
- if(!strlen(req_buf))
- sprintf(req_buf,"index.html");
- #if DEBUG
- printf("get_request: client requested the following page: %s\n",req_buf);
- #endif
- return;
- }
- // Send message header (before html page) to client
- void send_header(int socket)
- {
- #if DEBUG
- printf("send_header: sending HTTP header to client\n");
- #endif
- sprintf(buf,HEADER_1);
- send(socket,buf,strlen(HEADER_1),0);
- sprintf(buf,SERVER_STRING);
- send(socket,buf,strlen(SERVER_STRING),0);
- sprintf(buf,HEADER_2);
- send(socket,buf,strlen(HEADER_2),0);
- return;
- }
- // Execute script in /cgi-bin
- void execute_script(int socket)
- {
- // Currently unsupported, return error code to client
- cannot_execute(socket);
- return;
- }
- // Send html page to client
- void send_page(int socket)
- {
- FILE * fp;
- // Searchs for page in directory htdocs
- sprintf(buf_tmp,"htdocs/%s",req_buf);
- #if DEBUG
- printf("send_page: searching for %s\n",buf_tmp);
- #endif
- // Verifies if file exists
- if((fp=fopen(buf_tmp,"rt"))==NULL) {
- // Page not found, send error to client
- printf("send_page: page %s not found, alerting client\n",buf_tmp);
- not_found(socket);
- }
- else {
- // Page found, send to client
- // First send HTTP header back to client
- send_header(socket);
- printf("send_page: sending page %s to client\n",buf_tmp);
- while(fgets(buf_tmp,SIZE_BUF,fp))
- send(socket,buf_tmp,strlen(buf_tmp),0);
- // Close file
- fclose(fp);
- }
- return;
- }
- // Identifies client (address and port) from socket
- void identify(int socket)
- {
- char ipstr[INET6_ADDRSTRLEN];
- socklen_t len;
- struct sockaddr_in *s;
- int port;
- struct sockaddr_storage addr;
- len = sizeof addr;
- getpeername(socket, (struct sockaddr*)&addr, &len);
- // Assuming only IPv4
- s = (struct sockaddr_in *)&addr;
- port = ntohs(s->sin_port);
- inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
- printf("identify: received new request from %s port %d\n",ipstr,port);
- return;
- }
- // Reads a line (of at most 'n' bytes) from socket
- int read_line(int socket,int n)
- {
- int n_read;
- int not_eol;
- int ret;
- char new_char;
- n_read=0;
- not_eol=1;
- while (n_read<n && not_eol) {
- ret = read(socket,&new_char,sizeof(char));
- if (ret == -1) {
- printf("Error reading from socket (read_line)");
- return -1;
- }
- else if (ret == 0) {
- return 0;
- }
- else if (new_char=='\r') {
- not_eol = 0;
- // consumes next byte on buffer (LF)
- read(socket,&new_char,sizeof(char));
- continue;
- }
- else {
- buf[n_read]=new_char;
- n_read++;
- }
- }
- buf[n_read]='\0';
- #if DEBUG
- printf("read_line: new line read from client socket: %s\n",buf);
- #endif
- return n_read;
- }
- // Creates, prepares and returns new socket
- int fireup(int port)
- {
- int new_sock;
- struct sockaddr_in name;
- // Creates socket
- if ((new_sock = socket(PF_INET, SOCK_STREAM, 0))==-1) {
- printf("Error creating socket\n");
- return -1;
- }
- // Binds new socket to listening port
- name.sin_family = AF_INET;
- name.sin_port = htons(port);
- name.sin_addr.s_addr = htonl(INADDR_ANY);
- if (bind(new_sock, (struct sockaddr *)&name, sizeof(name)) < 0) {
- printf("Error binding to socket\n");
- return -1;
- }
- // Starts listening on socket
- if (listen(new_sock, 5) < 0) {
- printf("Error listening to socket\n");
- return -1;
- }
- return(new_sock);
- }
- // Sends a 404 not found status message to client (page not found)
- void not_found(int socket)
- {
- sprintf(buf,"HTTP/1.0 404 NOT FOUND\r\n");
- send(socket,buf, strlen(buf), 0);
- sprintf(buf,SERVER_STRING);
- send(socket,buf, strlen(buf), 0);
- sprintf(buf,"Content-Type: text/html\r\n");
- send(socket,buf, strlen(buf), 0);
- sprintf(buf,"\r\n");
- send(socket,buf, strlen(buf), 0);
- sprintf(buf,"<HTML><TITLE>Not Found</TITLE>\r\n");
- send(socket,buf, strlen(buf), 0);
- sprintf(buf,"<BODY><P>Resource unavailable or nonexistent.\r\n");
- send(socket,buf, strlen(buf), 0);
- sprintf(buf,"</BODY></HTML>\r\n");
- send(socket,buf, strlen(buf), 0);
- return;
- }
- // Send a 5000 internal server error (script not configured for execution)
- void cannot_execute(int socket)
- {
- sprintf(buf,"HTTP/1.0 500 Internal Server Error\r\n");
- send(socket,buf, strlen(buf), 0);
- sprintf(buf,"Content-type: text/html\r\n");
- send(socket,buf, strlen(buf), 0);
- sprintf(buf,"\r\n");
- send(socket,buf, strlen(buf), 0);
- sprintf(buf,"<P>Error prohibited CGI execution.\r\n");
- send(socket,buf, strlen(buf), 0);
- return;
- }
- // Closes socket before closing
- void catch_ctrlc(int sig)
- {
- printf("Server terminating\n");
- close(socket_conn);
- exit(0);
- }
- void init(int port){
- shm = shmget(1234,sizeof(config),IPC_CREAT|0777);
- stats = (statistics *)shmat(shm,NULL,0);
- initialConfig(port);
- }
- void initialConfig(int port){
- FILE * fp;
- char line[SIZE_BUF];
- char split[2] = ";";
- int i;
- char *token;
- cfg->files->next = NULL;
- allowed * ptr = cfg->files;
- allowed * new;
- i=0;
- if((fp=fopen("config.txt","rt"))==NULL) {
- printf("Configuration file not found.\n");
- cfg->s_port= port;
- cfg->scheduling = 0;
- cfg->thread_pool = DEFAULT_THREADS;
- strcpy (cfg->files->name, "ALL");
- }
- else {
- while(fgets(line, 1024, fp) != NULL){
- if (i==0){
- if (atoi(line) != port){
- printf("The actual port doesn't match the one in config file. The server will shutdown.");
- exit(0);
- }
- }
- else if (i==1){
- cfg->scheduling = atoi(line);
- }
- else if (i==2){
- cfg->thread_pool = atoi(line);
- }
- else if (i==3){
- token = strtok(line,split);
- while (token != NULL){
- new = (allowed *) malloc ( sizeof(allowed));
- new->next = NULL;
- strcpy(new->name, token);
- ptr->next = new;
- ptr = new;
- token = strtok(NULL,split);
- }
- }
- i++;
- }
- ptr = cfg->files;
- printf("\n%d",cfg->s_port);
- printf("\n%d",cfg->scheduling);
- printf("\n%d\n",cfg->thread_pool);
- while(ptr != NULL){
- printf("%s\n",ptr->name);
- ptr = ptr->next;
- }
- // Close file
- fclose(fp);
- }
- free(ptr);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement