tags:

views:

135

answers:

2

Hi,

I am a beginner when it comes to Socket Programming. I am currently trying to develop a web server that can service basic GET and POST http requests from a browser. I am using my laptop as the server and the client both. So the idea is that I should be able to type http://127.0.0.1:PORT/ in Firefox and my web server should be able to connect to that port and start talking.

So far the code I have written does not seem to work. I'm using ConText and Cygwin to be able to run and execute the program in Windows. I've removed firewalls from the port I'm using as well. However, the webserver does not seem to recognise the connection.

Any ideas why? I'm attaching the code I have written so far. Any help would be very greatly appreciated. At the moment the program doesnt go past "Listening on port..". I have isolated the fault and it seems that its stuck on the statement that I have highlighted.

/* Webserver Code  */

#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>             // for the use of inet_ntop()
#include <netinet/in.h>

#define PORT "1500"                // the port we will connect to
#define BACKLOG 10                 // how many pending connections the queue will hold

void *get_in_addr(struct sockaddr *sa);


int main (void) {

    int sockfd, new_fd=0;
    int status;
    struct addrinfo hints;
    struct addrinfo *servinfo;      
    struct sockaddr_storage their_addr;
    char s[INET6_ADDRSTRLEN];
    socklen_t addr_size;            

    FILE *errors;

    memset(&hints, 0, sizeof hints); 
    hints.ai_family = AF_UNSPEC;     
    hints.ai_socktype = SOCK_STREAM; 
    hints.ai_flags = AI_PASSIVE;     


    errors = fopen("Errors.txt", "w");
        fprintf(errors,"testing...\n");
    if(errors == NULL){
        fprintf(stderr, "Cant open output file\n");
    }
    if ((status = getaddrinfo(NULL, PORT, &hints, &servinfo)) != 0) {
        fprintf(errors, "getaddrinfo error: %s\n", gai_strerror(status));
        exit(1);
    }

    // make a socket
    // socket() function returns a socket file descriptor called sockfd
    sockfd = socket(servinfo->ai_family, servinfo->ai_socktype, 0);

    // bind to the port we passed in to getaddrinfo()
    if((bind(sockfd, servinfo->ai_addr, servinfo->ai_addrlen))== -1) {
        fprintf(errors, "Binding Failed\n");
        exit(1);
    }                                   

    // listen on the port
    if((listen(sockfd, BACKLOG))== -1) {
      fprintf(errors, "Listening failed\n");
      exit(1);
    } else {
      printf("Listening on port...\n");
 }

    //now accept an incoming connection
    addr_size = sizeof(their_addr);
    **new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &addr_size)**;
 printf( "new_fd = %d\n", new_fd);
    if(new_fd == -1) {
      fprintf(errors, "Accepting failed\n");
      exit(1);
 } else {
  printf("The Accepting worked\n");
 }

     //Prints out the address of the connector
    inet_ntop(their_addr.ss_family, get_in_addr((struct sockaddr *)&their_addr), s, sizeof(s));
    printf("server: got connection from %s\n", s);
    fclose(errors);

 return 0;
}



// To obtain the client's information
void *get_in_addr(struct sockaddr *sa)
{
    if (sa->sa_family == AF_INET) {
        return &(((struct sockaddr_in*)sa)->sin_addr);
    }

    return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
+1  A: 

getaddrinfo() might return multiple entries, including the IPv6 ones. And that might be your problem.

N.B. the error check is missing after the getaddrinfo() call.

If you want browser being able to connect to "127.0.0.1:PORT", you should either:

  • bind() to the INADDR_LOOPBACK and the PORT without any help from the getaddrinfo()
  • properly setup call to getaddrinfo(), setting ai_family to AF_INET (so that you have only IPv4).

Note that if first parameter to getaddrinfo() is NULL, then the returned address would be set to INADDR_ANY/IN6ADDR_ANY, meaning that your server would also accept connections from outside. To limit connections to localhost, set the first parameter to "localhost" instead of NULL.


To perpetuate the piece, here goes my getaddrinfo() result dumper code:

    struct addrinfo hints, *aires=0, *ai;
    int i;
    int rc;

    memset( &hints, 0, sizeof(hints) );
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;
    rc = getaddrinfo( "localhost", "1500", &hints, &aires );
    if (rc == 0) {
        for ( ai=aires, i=0; ai; ai=ai->ai_next, i++ ) {
            printf( "gai: ai[%d].ai_canonname = %s\n", i, ai->ai_canonname );
            printf( "gai: ai[%d].ai_flags     = %d\n", i, ai->ai_flags );
            printf( "gai: ai[%d].ai_family    = %d (%s)\n", i, ai->ai_family, get_family_name(ai->ai_family) );
            printf( "gai: ai[%d].ai_socktype  = %d\n", i, ai->ai_socktype );
            printf( "gai: ai[%d].ai_protocol  = %d (%s)\n", i, ai->ai_protocol, get_proto_name(ai->ai_protocol) );
            printf( "gai: ai[%d].ai_addrlen   = %d\n", i, (int)ai->ai_addrlen );

            if (ai->ai_family == AF_INET) {
                struct sockaddr_in *sa = (struct sockaddr_in *)ai->ai_addr;
                printf( "gai: ai[%d].ai_addr[IPv4].sin_family = %d (%s)\n", i, sa->sin_family, get_family_name(sa->sin_family) );
                printf( "gai: ai[%d].ai_addr[IPv4].sin_port   = %d\n", i, ntohs(sa->sin_port) );
                printf( "gai: ai[%d].ai_addr[IPv4].sin_addr   = %s\n",
                    i, inet_ntop(AF_INET, &sa->sin_addr, buf, sizeof(buf)) );
            } else if (ai->ai_family == AF_INET6) {
                struct sockaddr_in6 *sa = (struct sockaddr_in6 *)ai->ai_addr;
                printf( "gai: ai[%d].ai_addr[IPv6].sin6_family   = %d (%s)\n", i, sa->sin6_family, get_family_name(sa->sin6_family) );
                printf( "gai: ai[%d].ai_addr[IPv6].sin6_port     = %d\n", i, ntohs(sa->sin6_port) );
                printf( "gai: ai[%d].ai_addr[IPv6].sin6_flowinfo = %d\n", i, sa->sin6_flowinfo );

                printf( "gai: ai[%d].ai_addr[IPv6].sin6_addr     = %s\n",
                    i, inet_ntop(AF_INET6, &sa->sin6_addr, buf, sizeof(buf)) );

                printf( "gai: ai[%d].ai_addr[IPv6].sin6_scope_id = %d\n", i, sa->sin6_scope_id );
            } else {
                printf( "gai: ai[%d].ai_addr = %p\n", i, ai->ai_addr );
            }
            printf("\n");
        }
    } else {
        printf( "gai: failed (%d)\n", rc );
    }
    freeaddrinfo( aires );
Dummy00001
Thanks for that! I made the changes you suggested and it works =). Now to deal with the problem of interpreting the GET messages lol. Thanks for your help.
BAkz
Hint from personal experience: you can ignore everything in HTTP header up to two new lines. Implementing feature-full parser for RFC822/RFC2822 message is quite a chore - you can postpone it.
Dummy00001
Yeah I know what you mean. I am confused again =s
BAkz
A: 

Okay so now my web server is talking to the browser and I can see the GET message on the screen. But I'm not sure how to interpret it. Once I type in http"://127.0.0.1:PORT/index.html, the GET request sent to the server is

GET /index.html HTTP/1.1

Host: 127.0.0.1:1500

(some jibberish here about the browser etc)

This is where I'm stuck again. Would you say it would be better to print the above request message to a file, then read from that file and run a search for the index.html file in the folder. At the moment I am storing the request packet in a buffer:

// init line

bzero(buffer,MAX_MSG);

n = read(new_fd,buffer,MAX_MSG-1);

if (n < 0){

printf("ERROR reading from socket\n"); }

printf("Here is the message:\n%s\n",buffer);

Or is there a better way to do it without creating another txt file. Also, how would I run a search for a file in the folder? Should I make a system call and run a bash/shell script?

BAkz
This is not an answer to your question, it's a comment
George Jempty
sorry lol my bad. I should have posted in the comment section..
BAkz
No, you should have posted it as a new question, since it's completely different to the old question. (StackOverflow isn't a forum, and questions are not threads).
caf