Advertisement
Guest User

Untitled

a guest
Oct 24th, 2016
60
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 10.38 KB | None | 0 0
  1. /*
  2.  * -- simplehttpd.c --
  3.  * A (very) simple HTTP server
  4.  *
  5.  * Sistemas Operativos 2014/2015
  6.  */
  7.  
  8. #include <stdio.h>
  9. #include <sys/types.h>
  10. #include <sys/socket.h>
  11. #include <netinet/in.h>
  12. #include <arpa/inet.h>
  13. #include <unistd.h>
  14. #include <ctype.h>
  15. #include <sys/stat.h>
  16. #include <sys/wait.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <signal.h>
  20. #include <sys/shm.h>
  21. #include <sys/ipc.h>
  22. #include <sys/msg.h>
  23. #include <time.h>
  24. #include <pthread.h>
  25. #include <errno.h>
  26.  
  27. // Produce debug information
  28. #define DEBUG       1  
  29.  
  30. // Header of HTTP reply to client
  31. #define SERVER_STRING   "Server: simpleserver/0.1.0\r\n"
  32. #define HEADER_1    "HTTP/1.0 200 OK\r\n"
  33. #define HEADER_2    "Content-Type: text/html\r\n\r\n"
  34.  
  35. #define GET_EXPR    "GET /"
  36. #define CGI_EXPR    "cgi-bin/"
  37. #define SIZE_BUF    1024
  38.  
  39. #define DEFAULT_THREADS 5
  40.  
  41. // Configurations Structure
  42.  typedef struct allowed{
  43.     char name[50];
  44.     struct allowed * next;
  45. }allowed;
  46.  
  47. typedef struct config{
  48.     int s_port;
  49.     int scheduling;
  50.     int thread_pool;
  51.     allowed files [SIZE_BUF];
  52. }config;
  53.  
  54. //Statitics Structure
  55.  
  56. typedef struct statistics{
  57.     int n_static;
  58.     int n_compressed;
  59.     int t_static_ncompressed;
  60.     int t_static_compressed;
  61. }statistics;
  62.  
  63.     /* data */
  64.  
  65. int  fireup(int port);
  66. void identify(int socket);
  67. void get_request(int socket);
  68. int  read_line(int socket, int n);
  69. void send_header(int socket);
  70. void send_page(int socket);
  71. void execute_script(int socket);
  72. void not_found(int socket);
  73. void catch_ctrlc(int);
  74. void cannot_execute(int socket);
  75. void * worker(void * t);
  76. void * scheduler(void * t);
  77. void init(int port);
  78. void initialConfig(int port);
  79.  
  80. char buf[SIZE_BUF];
  81. char req_buf[SIZE_BUF];
  82. char buf_tmp[SIZE_BUF];
  83. int port,socket_conn,new_conn;
  84. int shm;
  85.  
  86. config* cfg=(config*)malloc(sizeof(config));
  87. statistics* stats;
  88.  
  89.  
  90. int main(int argc, char ** argv)
  91. {
  92.     struct sockaddr_in client_name;
  93.     socklen_t client_name_len = sizeof(client_name);
  94.     int port,i;
  95.  
  96.     signal(SIGINT,catch_ctrlc);
  97.    
  98.     // Verify number of arguments
  99.     if (argc!=2) {
  100.         printf("Usage: %s <port>\n",argv[0]);
  101.         exit(1);
  102.     }
  103.     port=atoi(argv[1]);
  104.     printf("Listening for HTTP requests on port %d\n",port);
  105.  
  106.     // Configure listening port
  107.     if ((socket_conn=fireup(port))==-1)
  108.         exit(1);
  109.     else{
  110.         init(port);
  111.         pthread_t threads[cfg->thread_pool];
  112.         int thread_id[cfg->thread_pool];
  113.  
  114.         thread_id[0] = 0;
  115.  
  116.         if (pthread_create(&threads[0],NULL,scheduler, &thread_id[0]) != 0)
  117.             perror("Error creating scheduler");
  118.  
  119.         for(i=1;i<cfg->thread_pool;i++){
  120.             thread_id[i] = i;
  121.             if (pthread_create(&threads[i],NULL,worker,&thread_id[i]) != 0)
  122.                 perror("Error creating threads");
  123.         }
  124.         for(i=0;i<cfg->thread_pool;i++){
  125.             pthread_join(threads[i],NULL);
  126.         }
  127.     }
  128.  
  129.     // Serve requests
  130.     while (1)
  131.     {
  132.         // Accept connection on socket
  133.         if ( (new_conn = accept(socket_conn,(struct sockaddr *)&client_name,&client_name_len)) == -1 ) {
  134.             printf("Error accepting connection\n");
  135.             exit(1);
  136.         }
  137.  
  138.         // Identify new client
  139.         identify(new_conn);
  140.  
  141.         // Process request
  142.         get_request(new_conn);
  143.  
  144.         // Verify if request is for a page or script
  145.         if(!strncmp(req_buf,CGI_EXPR,strlen(CGI_EXPR)))
  146.             execute_script(new_conn);  
  147.         else
  148.             // Search file with html page and send to client
  149.             send_page(new_conn);
  150.  
  151.         if(fork()==0){
  152.                 /*processo filho para as estatisticas*/
  153.             }
  154.    
  155.         // Terminate connection with client
  156.         close(new_conn);
  157.  
  158.     }
  159.  
  160.  
  161.  
  162.  
  163. }
  164.  
  165. void * worker(void * t){
  166.     int my_id = *((int*)t);
  167.     printf ("Worker's ID: %d\n", my_id);
  168.     pthread_exit(NULL);
  169.    
  170. }
  171.  
  172. void * scheduler(void * t){
  173.     int my_id = *((int*)t);
  174.     printf ("Scheduler's ID:  %d\n", my_id);
  175.     pthread_exit(NULL);
  176. }
  177. // Processes request from client
  178. void get_request(int socket)
  179. {
  180.     int i,j;
  181.     int found_get;
  182.  
  183.     found_get=0;
  184.     while ( read_line(socket,SIZE_BUF) > 0 ) {
  185.         if(!strncmp(buf,GET_EXPR,strlen(GET_EXPR))) {
  186.             // GET received, extract the requested page/script
  187.             found_get=1;
  188.             i=strlen(GET_EXPR);
  189.             j=0;
  190.             while( (buf[i]!=' ') && (buf[i]!='\0') )
  191.                 req_buf[j++]=buf[i++];
  192.             req_buf[j]='\0';
  193.         }
  194.     }  
  195.  
  196.     // Currently only supports GET
  197.     if(!found_get) {
  198.         printf("Request from client without a GET\n");
  199.         exit(1);
  200.     }
  201.     // If no particular page is requested then we consider htdocs/index.html
  202.     if(!strlen(req_buf))
  203.         sprintf(req_buf,"index.html");
  204.  
  205.     #if DEBUG
  206.     printf("get_request: client requested the following page: %s\n",req_buf);
  207.     #endif
  208.  
  209.     return;
  210. }
  211.  
  212.  
  213. // Send message header (before html page) to client
  214. void send_header(int socket)
  215. {
  216.     #if DEBUG
  217.     printf("send_header: sending HTTP header to client\n");
  218.     #endif
  219.     sprintf(buf,HEADER_1);
  220.     send(socket,buf,strlen(HEADER_1),0);
  221.     sprintf(buf,SERVER_STRING);
  222.     send(socket,buf,strlen(SERVER_STRING),0);
  223.     sprintf(buf,HEADER_2);
  224.     send(socket,buf,strlen(HEADER_2),0);
  225.  
  226.     return;
  227. }
  228.  
  229.  
  230. // Execute script in /cgi-bin
  231. void execute_script(int socket)
  232. {
  233.     // Currently unsupported, return error code to client
  234.     cannot_execute(socket);
  235.    
  236.     return;
  237. }
  238.  
  239.  
  240. // Send html page to client
  241. void send_page(int socket)
  242. {
  243.     FILE * fp;
  244.  
  245.     // Searchs for page in directory htdocs
  246.     sprintf(buf_tmp,"htdocs/%s",req_buf);
  247.  
  248.     #if DEBUG
  249.     printf("send_page: searching for %s\n",buf_tmp);
  250.     #endif
  251.  
  252.     // Verifies if file exists
  253.     if((fp=fopen(buf_tmp,"rt"))==NULL) {
  254.         // Page not found, send error to client
  255.         printf("send_page: page %s not found, alerting client\n",buf_tmp);
  256.         not_found(socket);
  257.     }
  258.     else {
  259.         // Page found, send to client
  260.    
  261.         // First send HTTP header back to client
  262.         send_header(socket);
  263.  
  264.         printf("send_page: sending page %s to client\n",buf_tmp);
  265.         while(fgets(buf_tmp,SIZE_BUF,fp))
  266.             send(socket,buf_tmp,strlen(buf_tmp),0);
  267.        
  268.         // Close file
  269.         fclose(fp);
  270.     }
  271.  
  272.     return;
  273.  
  274. }
  275.  
  276.  
  277. // Identifies client (address and port) from socket
  278. void identify(int socket)
  279. {
  280.     char ipstr[INET6_ADDRSTRLEN];
  281.     socklen_t len;
  282.     struct sockaddr_in *s;
  283.     int port;
  284.     struct sockaddr_storage addr;
  285.  
  286.     len = sizeof addr;
  287.     getpeername(socket, (struct sockaddr*)&addr, &len);
  288.  
  289.     // Assuming only IPv4
  290.     s = (struct sockaddr_in *)&addr;
  291.     port = ntohs(s->sin_port);
  292.     inet_ntop(AF_INET, &s->sin_addr, ipstr, sizeof ipstr);
  293.  
  294.     printf("identify: received new request from %s port %d\n",ipstr,port);
  295.  
  296.     return;
  297. }
  298.  
  299.  
  300. // Reads a line (of at most 'n' bytes) from socket
  301. int read_line(int socket,int n)
  302. {
  303.     int n_read;
  304.     int not_eol;
  305.     int ret;
  306.     char new_char;
  307.  
  308.     n_read=0;
  309.     not_eol=1;
  310.  
  311.     while (n_read<n && not_eol) {
  312.         ret = read(socket,&new_char,sizeof(char));
  313.         if (ret == -1) {
  314.             printf("Error reading from socket (read_line)");
  315.             return -1;
  316.         }
  317.         else if (ret == 0) {
  318.             return 0;
  319.         }
  320.         else if (new_char=='\r') {
  321.             not_eol = 0;
  322.             // consumes next byte on buffer (LF)
  323.             read(socket,&new_char,sizeof(char));
  324.             continue;
  325.         }      
  326.         else {
  327.             buf[n_read]=new_char;
  328.             n_read++;
  329.         }
  330.     }
  331.  
  332.     buf[n_read]='\0';
  333.     #if DEBUG
  334.     printf("read_line: new line read from client socket: %s\n",buf);
  335.     #endif
  336.    
  337.     return n_read;
  338. }
  339.  
  340.  
  341. // Creates, prepares and returns new socket
  342. int fireup(int port)
  343. {
  344.     int new_sock;
  345.     struct sockaddr_in name;
  346.  
  347.     // Creates socket
  348.     if ((new_sock = socket(PF_INET, SOCK_STREAM, 0))==-1) {
  349.         printf("Error creating socket\n");
  350.         return -1;
  351.     }
  352.  
  353.     // Binds new socket to listening port
  354.     name.sin_family = AF_INET;
  355.     name.sin_port = htons(port);
  356.     name.sin_addr.s_addr = htonl(INADDR_ANY);
  357.     if (bind(new_sock, (struct sockaddr *)&name, sizeof(name)) < 0) {
  358.         printf("Error binding to socket\n");
  359.         return -1;
  360.     }
  361.  
  362.     // Starts listening on socket
  363.     if (listen(new_sock, 5) < 0) {
  364.         printf("Error listening to socket\n");
  365.         return -1;
  366.     }
  367.  
  368.     return(new_sock);
  369. }
  370.  
  371.  
  372. // Sends a 404 not found status message to client (page not found)
  373. void not_found(int socket)
  374. {
  375.     sprintf(buf,"HTTP/1.0 404 NOT FOUND\r\n");
  376.     send(socket,buf, strlen(buf), 0);
  377.     sprintf(buf,SERVER_STRING);
  378.     send(socket,buf, strlen(buf), 0);
  379.     sprintf(buf,"Content-Type: text/html\r\n");
  380.     send(socket,buf, strlen(buf), 0);
  381.     sprintf(buf,"\r\n");
  382.     send(socket,buf, strlen(buf), 0);
  383.     sprintf(buf,"<HTML><TITLE>Not Found</TITLE>\r\n");
  384.     send(socket,buf, strlen(buf), 0);
  385.     sprintf(buf,"<BODY><P>Resource unavailable or nonexistent.\r\n");
  386.     send(socket,buf, strlen(buf), 0);
  387.     sprintf(buf,"</BODY></HTML>\r\n");
  388.     send(socket,buf, strlen(buf), 0);
  389.  
  390.     return;
  391. }
  392.  
  393.  
  394. // Send a 5000 internal server error (script not configured for execution)
  395. void cannot_execute(int socket)
  396. {
  397.     sprintf(buf,"HTTP/1.0 500 Internal Server Error\r\n");
  398.     send(socket,buf, strlen(buf), 0);
  399.     sprintf(buf,"Content-type: text/html\r\n");
  400.     send(socket,buf, strlen(buf), 0);
  401.     sprintf(buf,"\r\n");
  402.     send(socket,buf, strlen(buf), 0);
  403.     sprintf(buf,"<P>Error prohibited CGI execution.\r\n");
  404.     send(socket,buf, strlen(buf), 0);
  405.  
  406.     return;
  407. }
  408.  
  409.  
  410. // Closes socket before closing
  411. void catch_ctrlc(int sig)
  412. {
  413.     printf("Server terminating\n");
  414.     close(socket_conn);
  415.     exit(0);
  416. }
  417.  
  418.  
  419.  
  420. void init(int port){
  421.  
  422.     shm = shmget(1234,sizeof(config),IPC_CREAT|0777);
  423.     stats = (statistics *)shmat(shm,NULL,0);
  424.     initialConfig(port);
  425.  
  426.    
  427. }
  428.  
  429.  
  430. void initialConfig(int port){
  431.     FILE * fp;
  432.     char line[SIZE_BUF];
  433.     char split[2] = ";";
  434.     int i;
  435.     char *token;
  436.    
  437.    
  438.     cfg->files->next = NULL;
  439.     allowed * ptr = cfg->files;
  440.     allowed * new;
  441.    
  442.  
  443.  
  444.     i=0;
  445.  
  446.    
  447.  
  448.            
  449.     if((fp=fopen("config.txt","rt"))==NULL) {
  450.        
  451.         printf("Configuration file not found.\n");
  452.         cfg->s_port= port;
  453.         cfg->scheduling = 0;
  454.         cfg->thread_pool = DEFAULT_THREADS;
  455.         strcpy (cfg->files->name, "ALL");
  456.     }
  457.  
  458.     else {
  459.        
  460.         while(fgets(line, 1024, fp) != NULL){
  461.    
  462.             if (i==0){
  463.                
  464.                 if (atoi(line) != port){
  465.                     printf("The actual port doesn't match the one in config file. The server will shutdown.");
  466.                     exit(0);
  467.                 }
  468.             }
  469.             else if (i==1){
  470.                
  471.                 cfg->scheduling = atoi(line);
  472.            
  473.             }
  474.             else if (i==2){
  475.                
  476.                 cfg->thread_pool = atoi(line);
  477.             }
  478.             else if (i==3){
  479.                
  480.                 token = strtok(line,split);
  481.                 while (token != NULL){
  482.                    
  483.                     new = (allowed *) malloc ( sizeof(allowed));
  484.                     new->next = NULL;
  485.                     strcpy(new->name, token);
  486.                     ptr->next = new;
  487.                     ptr = new;
  488.                    
  489.                     token = strtok(NULL,split);
  490.  
  491.                        
  492.                 }
  493.  
  494.             }
  495.             i++;
  496.         }
  497.  
  498.         ptr = cfg->files;
  499.         printf("\n%d",cfg->s_port);
  500.         printf("\n%d",cfg->scheduling);
  501.         printf("\n%d\n",cfg->thread_pool);
  502.        
  503.         while(ptr != NULL){
  504.             printf("%s\n",ptr->name);
  505.             ptr = ptr->next;
  506.         }
  507.         // Close file
  508.         fclose(fp);
  509.     }
  510.  
  511.          
  512.     free(ptr);
  513. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement