Thread: Help - Tiny Webserver C In UNIX . TCPIP - Big Problem

  1. #1
    Registered User
    Join Date
    May 2018
    Posts
    1

    Exclamation Help - Tiny Webserver C In UNIX . TCPIP - Big Problem

    Hi! I have to make a tiny webserver in C in Unix. I have the first part of the code given by my teacher, and i have to add some extra tasks to it . I dont know why when i compile my code i have some errors. I post now the codes:
    1. teacher's first part of the code
    [spoiler]
    Code:
    // skeleton version of a tiny webserver, minimal error handling
    // by U. Willers - 07.11.2013
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <stdio.h>
    #include <strings.h>
    #include <stdlib.h>
    #include <errno.h> // size_t, pid_t
    // accept, bind, listen
    // sockaddr_in, htons
    // printf
    // bzero, strncmp
    // exit
    // strerror
     
    #define BUFSIZE 8096 // size of request buffer
     
    // Prototypes, maybe outsource to webserver.h
    void handle_request( int s1 );
    size_t strlen( const char *s );
    int setup_webserver( void );
    int respectRequests(char *request);
    int SplitTheRequest(char *request);
    int main( void )
        {
            int server_socket, client_socket, addrlen;
            struct sockaddr_in client_addr;
           
            printf( "Starting webserver...\n" );
            server_socket = setup_webserver(); // create socket and listen on it
            while( 1 )  // infinite loop
                {
                addrlen = sizeof( client_addr );    // wait for client requests
               
                client_socket = accept( server_socket, (struct sockaddr*) &client_addr, &addrlen ); // process request
               
                handle_request( client_socket );
                }
        }
       
    int setup_webserver( void )
        {
            int s, ret;
           
            struct sockaddr_in s_addr;  // create TCP/IP socket
           
            s = socket( AF_INET, SOCK_STREAM, 0 );  // listen on port 80 (http) at localhost for client requests
           
            bzero( &s_addr, sizeof( s_addr ) ); // clear data structure
           
            s_addr.sin_family = AF_INET;    // IP address
           
            s_addr.sin_port = htons( 80 );  // port is 80
           
            s_addr.sin_addr.s_addr = INADDR_ANY; // addr. is 127.0.0.1
            // bind port and addr. to socket
           
            ret = bind( s, (struct sockaddr*) &s_addr, sizeof( s_addr ) );
           
            if( ret < 0 )   // error?
                {
                // Yes, convert into error message
               
                printf( "Bind Error: %s\n", strerror( errno ) );
               
                exit( 1 );      // terminate program and return error code
                }
           
        listen( s, 5 ); // wait for requests, max. 5 requests in queue
       
        return( s );    // return server socket descriptor
       
        }   // Entry: cs is client socket descriptor
       
    void handle_request( int cs )
        {
        char request[BUFSIZE];  // buffer for first line of client request
       
        int i = 0;
       
        char c; // buffer for one input character
       
        // read client request and terminate it with 0
       
        printf( "Annalize & Getting request: " );
       
        while( read( cs, &c, 1 ) == 1 && c != '\n' && c != '\r' && i < sizeof( request ) -1 )
       
        request[i++] = c;
       
        request[i] = '\0';  // terminate string
        if(respectRequests(request)==0)
            {
                printf( "%s\n", request );  // print request
                SplitTheRequest(request);
            }
        if (respectRequests(request)==-1)
            {
                printf( " INCORRECT!!!\n"); // print request
            }
           
       
        close( cs );
        }
    [/spoiler]


    Tasks:


    [spoiler]Enhance the web server so that only GET requests will be processed. Extract the file name from the GET request and sent the contents of that file to the client. Map GET / to GET index.html. Prevent absolute paths and the relative path .. being used in the request. This restricts the webserver to the chosen document root folder.[/spoiler]
    [spoiler]Update your web server program to use child processes for each client request. Print all error messages to stderr.[/spoiler]
    [spoiler]Check if the client request ask for valid file extension. Supply the correct MIME type in the HTTP header of your answer to the client.[/spoiler]


    My new code made with my colleague's help:
    [spoiler]
    Code:
    // skeleton version of a tiny webserver, minimal error handling
    // by U. Willers - 07.11.2013
    
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <netdb.h>
    #include <arpa/inet.h>
    #include <string.h>
    #include <strings.h>
    #include <sys/stat.h>
    #include<fcntl.h>
    #include<errno.h>
    
    
    #define BUFSIZE 8096
    
    
    
    
    // Prototypes, maybe outsource to webserver.h
    
    
    
    
    void handle_request( int client_socket, int server_socket);
    int setup_webserver( void );
    void makeHeader(int type, char * request,int client_socket);
    void * openFile(char *request, int client_socket, char * read);
    char * readFile(char *uri);
    int prevent(char *request);
    char *withoutBar ( char * uri );
    char * checkUri (char * request);
    
    
    int main( void )
    {
    	int server_socket, client_socket, addrlen;
    	struct sockaddr_in server_addr, client_addr;
    
    
    	printf( "Starting webserver...\n" );
    	server_socket = setup_webserver(); // create socket and listen on it
    	while( 1 )
    	{
    		addrlen = sizeof( server_addr ); // wait for client requests
    		client_socket = accept( server_socket, (struct sockaddr*) &server_addr, &addrlen ); // process request
    		printf("Client connected ...\n");
    		handle_request( client_socket, server_socket);
    	}
    }
    
    
    int setup_webserver( void )
    {
    	int server_socket;
    	int on = 1;
    	struct sockaddr_in server_addr;
    
    
    	server_socket = socket( AF_INET, SOCK_STREAM, 0 );
    
    
    	setsockopt(server_socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(int));
    
    
    	bzero( &server_addr, sizeof( server_addr ) );
    	server_addr.sin_family = AF_INET;
    	server_addr.sin_addr.s_addr = INADDR_ANY;
    	server_addr.sin_port = htons( 80 );
    
    
    	if(bind(server_socket, (struct sockaddr *) &server_addr, sizeof(server_addr)) == -1)
    	{
    		perror("bind");
    		close(server_socket);
    		exit(1);
    	}
    	if(listen(server_socket,5) == -1 )
    	{
    		perror("listen");
    		close(server_socket);
    		exit(1);
    	}
    
    
    	return( server_socket );
    }
    
    
    
    
    void handle_request( int client_socket , int server_socket)
    {
    	char request[2048]; // buffer for first line of client request
    	int i = 0;
    	int status;
    	char c; // buffer for one input character
    
    
    	// read client request and terminate it with 0
    	printf( "Getting request: \n" );
    
    
    	read(client_socket,request,2047);
    	//printf( "Client request: %s\n", request );
    
    
    	waitpid(-1,&status,WNOHANG);
    	if(!fork())
    	{
    		// child process 
    		if(prevent(request) == 0)
    		{
    			close(server_socket);
    			makeHeader ( 200, request, client_socket );
    			exit(0);
    		}
    		else
    		{
    			makeHeader( 403, request, client_socket );
    		}
    
    
    
    
    	}
    	//parent process
    	waitpid(-1,&status,WNOHANG);
    	close( client_socket );
    }
    
    
    void * openFile(char *request, int client_socket, char * read)
    {
    	int fdimg;
    
    
    	if(!strncmp(request,"GET /favicon.ico", 16))
    	{
    		fdimg = open("icon.png", O_RDONLY);
    		sendfile(client_socket, fdimg, NULL, 4000);
    		close(fdimg);
    	}
    
    
    	else if(!strncmp(request,"GET /image.jpg", 14))
    	{
    		fdimg = open("image.jpg", O_RDONLY);
    		sendfile(client_socket, fdimg, NULL, 50000);
    		close(fdimg);
    	}
    	else
    	{
    		write(client_socket, read, strlen(read));
    	}
    		
    
    
    }
    
    
    void makeHeader(int type, char * request,int client_socket)
    {
    	if(type == 200)// ok
    	{
    		if(!strncmp(request,"GET / ",5))
    		{
    			char * read;
    			read = readFile("index.html");
    			openFile( request, client_socket, read );
    		}
    		else
    		{
    			char * file;
    			char * read;
    			
    			file = withoutBar(checkUri(request));
    			read = readFile(file);
    			openFile( request, client_socket, read );
    		}
    	}
    	else if(type == 403) // forbbiden
    	{
    		char *read;
    		read = readFile("forbidden.html");
    		openFile( request, client_socket, read );
    	}
    	else if(type == 404) // not found
    	{
    		char *read;
    		read = readFile("notfound.html");
    	}
    }
    
    
    char * readFile(char *uri)
    {
    	FILE *fp;
    	fp = fopen(uri,"r");
    	char *out = NULL;
    	char arquivo[1024], buffer[1024] = {""};
    
    
    	if(fp != NULL)
    	{
    		while(fgets(arquivo, sizeof(arquivo), (FILE*)fp) != NULL)
    			strcat(buffer, arquivo);
    		fclose(fp);
    		out = buffer;
    		return out;
    	}
    	else
    		return NULL;
    }
    
    
    
    
    int prevent(char *request)
    {
    	char verifica[4];
    	int i;
    	if(strncmp(request, "GET ", 4) == 0)
    	{
    		for(i = 0; i < strlen(request) - 1; i++)
    		{
    			verifica[0] = request[i];
    			verifica[1] = request[i+1];
    			if(strncmp(verifica, "..", 2) == 0)
    				return -1;
    		}
    		return 0;
    	}
    	else
    	{
    		return -1;
    	}
    
    
    }
    
    
    char * checkUri (char * request)
    {
    	char aux[256];
    	char *out;
    	int i;
    	
    	for(i = 5; strlen (request); i++)
    	{
    		if(request[i] != ' ')
    		{
    			aux[i-5] = request[i];
    		}
    		else
    		{
    			
    			out = aux;
    			return out;
    		}
    	}
    	return out;
    }
    
    
    char *withoutBar ( char * uri )
    {
    	int i;
    	char aux[256];
    	char * out;
    	for(i =1; i<strlen(uri);i++)
    	{
    		aux[i-1] = uri[i];
    	}
    	out = aux;
    	return out;
    	
    }
    [/spoiler]


    IF somebody has any ideeas how to solve this i am waiting for it !
    Thanks !!!

  2. #2
    Registered User
    Join Date
    May 2010
    Posts
    4,365
    Do you have a specific question or problem?

    Does your "instructor's" code compile without errors or warnings?

    Does your code compile without errors or warnings?

  3. #3
    Registered User
    Join Date
    Apr 2017
    Location
    Quetzaltenango
    Posts
    82
    Quote Originally Posted by jonsvici View Post
    Code:
    int setup_webserver( void )
        {
            int s, ret;
        ...    
        return( s );    // return server socket descriptor
       
        }   // Entry: cs is client socket descriptor
    The local automatic variable s is allocated on the stack. When the function returns, the stack allocated storage is destroyed. It appears your teacher is not teaching you about lifetime of variables. You can read a little about that here. For an int, you could pass a reference to it as a parameter. You also had some arrays allocated on the stack that you referenced later. You could allocate them on the heap instead with malloc.

  4. #4
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    608
    Quote Originally Posted by christophergray View Post
    The local automatic variable s is allocated on the stack. When the function returns, the stack allocated storage is destroyed. It appears your teacher is not teaching you about lifetime of variables. You can read a little about that here. For an int, you could pass a reference to it as a parameter. You also had some arrays allocated on the stack that you referenced later. You could allocate them on the heap instead with malloc.
    It's funny that you mention the "setup_webserver" function, since that's one case where the return value is OK. The functions that return pointers to automatic variables ("readFile", "checkUri", and "withoutBar") are buggy, though.

  5. #5
    Registered User
    Join Date
    Oct 2006
    Posts
    3,445
    You should avoid using global function names, such as 'read' and 'write' as variable names. It might not break anything, but it could potentially produce compiler errors that are difficult to understand.
    What can this strange device be?
    When I touch it, it gives forth a sound
    It's got wires that vibrate and give music
    What can this thing be that I found?

  6. #6
    Registered User
    Join Date
    Apr 2017
    Location
    Quetzaltenango
    Posts
    82
    Quote Originally Posted by christop View Post
    It's funny that you mention the "setup_webserver" function, since that's one case where the return value is OK. The functions that return pointers to automatic variables ("readFile", "checkUri", and "withoutBar") are buggy, though.
    Are you saying it is not an error?

  7. #7
    Registered User
    Join Date
    May 2012
    Location
    Arizona, USA
    Posts
    608
    Quote Originally Posted by christophergray View Post
    Are you saying it is not an error?
    This code is not an error (which resembles the setup_webserver function that you quoted):

    Code:
    int foo(void)
    {
        int s = 42;
        // ...    
        return s;
    }
    This code is an error:

    Code:
    int *foo(void)
    {
        int s = 42;
        // ...    
        return &s;
    }

  8. #8
    Registered User
    Join Date
    Apr 2017
    Location
    Quetzaltenango
    Posts
    82
    Quote Originally Posted by christop View Post
    This code is not an error (which resembles the setup_webserver function that you quoted):

    Code:
    int foo(void)
    {
        int s = 42;
        // ...    
        return s;
    }
    I took a look at the assembler output from gcc. Although I found it hard to read because it is a different format than MASM which also I haven't looked at for 32 years, it looks like your first example just pushes 42 onto the stack and returns. Whereas the second example pushes an address, and the compiler issues a warning.

  9. #9
    Registered User
    Join Date
    May 2010
    Posts
    4,365
    it looks like your first example just pushes 42 onto the stack and returns.
    Yes the function is just returning a value. So no problem, will work as expected.

    Whereas the second example pushes an address, and the compiler issues a warning.
    Yes, here the function is trying to return a pointer to a local variable which invokes undefined behaviour. Your compiler properly warns you about this issue, good.

    You can't return a pointer to a local variable since the variable is destroyed when the function returns.

  10. #10
    Registered User
    Join Date
    Apr 2017
    Location
    Quetzaltenango
    Posts
    82
    Quote Originally Posted by jimblumberg View Post
    You can't return a pointer to a local variable since the variable is destroyed when the function returns.
    But I can return a pointer to an address on the heap, right? So...
    Code:
    static char *withoutBar ( char * uri )
    {
        char *out = malloc(256);
        if (out != NULL) {
            size_t i;
            for(i =1; i<strlen(uri);i++)
            {
                out[i-1] = uri[i];
            }
        }
        return out;
    }

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    26,749
    Quote Originally Posted by christophergray
    But I can return a pointer to an address on the heap, right? So...
    Yes, though assuming a maximum string length of 255 then looping without checking for that may lead to a buffer overflow vulnerability. Then, there's the question of whether the destination string has been properly null terminated. Since malloc allows for the string's maximum length to be determined at run time, you're going to call strlen anyway, and <string.h> has been included, perhaps it would be better to write:
    Code:
    static char *withoutBar(const char *uri)
    {
        char *out = malloc(strlen(uri)); // exclude the source string's first character
        if (out)
        {
            strcpy(out, uri + 1);
        }
        return out;
    }
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. a tiny problem with a function
    By sing0 in forum C Programming
    Replies: 15
    Last Post: 11-20-2009, 07:02 AM
  2. not able to understand this tiny tiny method
    By noobcpp in forum C++ Programming
    Replies: 5
    Last Post: 10-20-2008, 10:42 AM
  3. Winsock Webserver Problem
    By RunningBon in forum Networking/Device Communication
    Replies: 4
    Last Post: 06-08-2005, 04:05 PM
  4. Well I tried but i have a tiny problem
    By dapernia in forum C Programming
    Replies: 0
    Last Post: 09-03-2003, 01:20 PM
  5. Just a tiny little problem...
    By Nutshell in forum C Programming
    Replies: 26
    Last Post: 02-08-2003, 04:54 AM

Tags for this Thread