Click here to Skip to main content
14,422,938 members
Rate this:
Please Sign up or sign in to vote.
This is my code for web-server.cpp file

#include <string>
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <cerrno>
#include <cstring>
#include <netdb.h>
#include <csignal>
#include <stdio.h>
#include <stdlib.h> 
#include <fcntl.h>
#include <unistd.h>

#include "httpResponse.h"


#define BACKLOG 10
#define MESSAGE_SIZE 1000000
using namespace std;

bool writeDataToClient(int socket, const char *data, int datalen)
{
    const char *pdata = data;

    while (datalen > 0)
    {

        int numSent = send ( socket, pdata, datalen, 0 );

        if (numSent <= 0)
        {

            if (numSent == 0)
            {
                printf("The client was not written to: disconnected\n");
            }

            else
            {
                perror("The client was not written to");
            }

            return false;

        }

        pdata += numSent;

        datalen -= numSent;
    }

    return true;
}

bool writeStrToClient(int sckt, const char *str)
{
    return writeDataToClient(sckt, str, strlen(str));
}

void respond ( int n, char buffer[MESSAGE_SIZE], int *sock_clients, char* path)
{

  char mesg[MESSAGE_SIZE], *reqline[3], data_to_send[MESSAGE_SIZE] ;

	int rcvd, fd, bytes_read;

    memset(mesg, 0, MESSAGE_SIZE);

  strcpy( mesg, buffer);

	printf("%s", mesg);

  reqline[0] = strtok ( mesg, " \t\n");

	if ( strncmp ( reqline[0], "GET\0", 4) == 0 )
	{

		reqline[1] = strtok (NULL, " \t") ;
		reqline[2] = strtok (NULL, " \t\n") ;

		if ( strncmp( reqline[2], "HTTP/1.0", 8) != 0 && strncmp ( reqline[2], "HTTP/1.1", 8) != 0 )
		{
            httpResponse response(400, "");
            writeDataToClient(sock_clients[n], response.fullResponse.c_str(), response.getResponseLength());
		}
		else
		{

			if ( strncmp(reqline[1], "/\0", 2) == 0 )
			{
			   reqline[1] = (char*)"/index.html";        //Because if no file is specified, index.html will be opened by default (like it happens in APACHE...
      }

            strcpy(&path[strlen(path)], reqline[1]);

            printf("file: %s\n", path);

			if ( ( fd = open ( path, O_RDONLY) ) != -1 )    //FILE FOUND
			{
                bytes_read=read(fd, data_to_send, MESSAGE_SIZE);

                httpResponse response(200, data_to_send);

                if (!writeDataToClient(sock_clients[n], response.fullResponse.c_str(), response.getResponseLength() ) )
                {

                {
                    close(sock_clients[n]);
                }

                }

            }

			else
			{
                httpResponse response(404, "");
                writeDataToClient(sock_clients[n], response.fullResponse.c_str(), response.getResponseLength());
      }

		}

}

    	//Closing SOCKET
	shutdown ( sock_clients[n], SHUT_RDWR );         // All further send and recieve operations are DISABLED...

  close(sock_clients[n]);
    sock_clients[n]=0;

    return;
}




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 ) ;

}


int main ( int argc, char** argv )
{

  struct addrinfo hints, *serverinfo, *p ;  // struct addrinfo is kind of linked list.

  struct sockaddr_storage client_addr;

  char *path;

  int addr;

  int sock, sock_new, sock_clients[30], max_clients = 30, max_sd, sd, activity, valread ;

  fd_set readfds;

  char buffer[1025];
  int yes = 1;

  path = new char( strlen(argv[3]) );

  strcpy(path, argv[3]) ;

 printf("\n path is %s \n " , path );

  for (int i = 0; i < max_clients; i++)
    {
        sock_clients[i] = 0;
    }

  memset( &hints, 0, sizeof hints);

  hints.ai_family = AF_UNSPEC;
  hints.ai_socktype = SOCK_STREAM;
  hints.ai_flags = AI_PASSIVE;


  if( ( addr = getaddrinfo( argv[1], argv[2], &hints, &serverinfo ) ) != 0 )
  {
    fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(addr));
    return 1;
  }

  p = serverinfo;

  printf("\np->ai_addr %c " , p -> ai_addr->sa_data[0] ) ; //



  while( p != NULL)
  {

    if( ( sock = socket ( p->ai_family, p->ai_socktype, p->ai_protocol) ) == -1 )
    {
      perror("Error: socket");
      continue;
    }

    if ( setsockopt ( sock, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int) ) == -1 )
    {
      perror("Error: setsockopt");
      exit(1);
    }

    if (  ( bind ( sock, p->ai_addr, p->ai_addrlen) ) == -1 )
    {
      printf("\nhello\n") ;

      close(sock);
      perror("Error: bind");
      p = p->ai_next;  // traversing the linked list.
      continue;
    }

    break;

  }

  if ( p == NULL )  //
  {
    fprintf(stderr, "Failed to bind\n");
    exit(1);
  }

  if( listen ( sock, BACKLOG)== -1 )
  {
    perror("Error: Listen");
    exit(1);
  }

  int addrlen = sizeof(client_addr);

  cout<<"Waiting for connections.."<<endl;

  while(1)
    {
        //clear the socket set
        FD_ZERO(&readfds);

        //add master socket to set
        FD_SET(sock, &readfds);

        max_sd = sock;

        //add child sockets to set
        for (int i = 0 ; i < max_clients ; i++)
        {

            //socket descriptor
            sd = sock_clients[i];

            //if valid socket descriptor then add to read list
            if ( sd > 0 )
            {
               FD_SET( sd , &readfds);
            }

            //highest file descriptor number, need it for the select function
            if ( sd > max_sd )
            {
                max_sd = sd;
            }

        }

        //wait for an activity on one of the sockets , timeout is NULL , so wait indefinitely
        activity = select( max_sd + 1 , &readfds , NULL , NULL , NULL);

        if ( (activity < 0) && (errno!=EINTR) )
        {
            printf("select error");
        }

        //If something happened on the master socket , then its an incoming connection
        if ( FD_ISSET(sock, &readfds))
        {
            if ( (sock_new = accept(sock, (struct sockaddr *)&client_addr, (socklen_t*)&addrlen) )<0 )
            {
                perror("accept");
                exit(1);
            }

            //inform user of socket number - used in send and receive commands
            //printf("New connection , socket fd is %d , ip is : %s , port : %d \n" , new_socket , inet_ntoa(client_addr.sin_addr) , ntohs(client_addr.sin_port));

            //send new connection greeting message
            /*if( send(sock_new, message, strlen(message), 0) != strlen(message) )
            {
                perror("send");
            }*/

            puts ( "Welcome message sent successfully");

            //add new socket to array of sockets
            for (int i = 0; i < max_clients; i++)
            {
                //if position is empty
                if( sock_clients[i] == 0 )
                {
                    sock_clients[i] = sock_new;
                    printf("Adding to list of sockets as %d\n" , i);

                    break;
                }
            }
        }

        //else its some IO operation on some other socket :)
        for (int i = 0; i < max_clients; i++)
        {
            sd = sock_clients[i];

            if ( FD_ISSET( sd , &readfds) )
            {
                memset(path, 0, strlen(path));

                strcpy ( path, argv[3]);
                //Check if it was for closing , and also read the incoming message

                if ( (valread = read( sd , buffer, 1024)) == 0)
                {
                    //Somebody disconnected , get his details and print

                    getpeername(sd , (struct sockaddr*)&client_addr , (socklen_t*)&addrlen);

                    //printf("Host disconnected , ip %s , port %d \n" , inet_ntoa(client_addr.sin_addr) , ntohs(client_addr.sin_port));

                    //Close the socket and mark as 0 in list for reuse
                    close( sd );
                    sock_clients[i] = 0;
                }

                else
                {
                    //set the string terminating NULL byte on the end of the data read
                    buffer[valread] = '\0';
                    respond(i, buffer, sock_clients, path);
                }

            }

        }
      }

      return 0;


}

What I have tried:

I am trying to implement HTTP client server using socket programming in C.
When I run my web server the bind() function is unable to assign the request address. I don't know why.

I am trying to implement GET request method of http.

To run the client and server on linux terminal I do the following : 
g++ -o abc.exe httpRequest.cpp web-client.cpp

g++ -o def.exe httpResponse.cpp web-server.cpp

./abc.exe http://www.google.com/earth/index.html

./def.exe www.google.com 80 /earth/index.html

I want to know what is going wrong in my program. 

Any help is appreciated. Thanks.
Posted
Updated 5-Mar-19 9:24am
v3
Comments
jeron1 4-Mar-19 17:54pm
   
Is there a particular error code that you are getting?
Member 13995616 4-Mar-19 18:06pm
   
I get the error : Error: bind: Cannot assign the request address
jeron1 4-Mar-19 18:10pm
   
What's the errno?
Member 13995616 5-Mar-19 7:03am
   
After modifying my code I get the error number as 99 that is EADDRNOTAVAIL
How can I resolve this ?

1 solution

Rate this:
Please Sign up or sign in to vote.

Solution 1

Try adjust the code around the call to bind to something like this :
fprintf( stdout, "attempting bind to %08X\n", pi->ai_addr );
int rv = bind( sock, p->ai_addr, p->ai_addrlen );
if( rv != 0 )
{
  close(sock);

  auto ev = WSAGetLastError();    // or however else you can get the last error
  fprintf( stderr, "Error: bind failed - error code %X\n", ev );

  p = p->ai_next;  // traversing the linked list.
  continue;
}

fprintf( stdout, "bind succeeded to %08X\n", pi->ai_addr );
break;
This will tell you what address you are trying to bind the socket to (in hex format) and will display the error code you receive. That is, if WSAGetLastError() is valid for you. I don't know. It may not be in a non-Windows OS. If it isn't then find the appropriate function you can call to get the error code. The bottom line is you need to see what is going on. Right now you are just guessing and hoping someone else can guess correctly for you. I think it best to display as much information as possible so you can figure it out for yourself.

Good luck.
   
v2
Comments
CPallini 5-Mar-19 3:11am
   
Are you sure the OP is using Windows?
Member 13995616 5-Mar-19 7:02am
   
I am working on Linux and after modifying the code I get the errno as 99 that is EADDRNOTAVAIL.
jeron1 5-Mar-19 10:03am
   
Is that port already in use, by something else?
Rick York 5-Mar-19 10:36am
   
Make sure you have formed the address correctly. Here is the code I use to set up a small-scale server.
    SOCKET listenTCP = socket( AF_INET, SOCK_STREAM, IPPROTO_TCP );
    sockaddr_in socketAddress = { 0 };
    socketAddr.sin_family = AF_INET;
    socketAddr.sin_port   = htons( port );
    socketAddr.sin_addr.s_addr = INADDR_ANY;
    if( address )
        socketAddr.sin_addr.s_addr = inet_addr( address );
    if( ::bind( listenTCP, (PSOCKADDR)&socketAddress, sizeof( socketAddress ) ) )
    {
        fprintf( stderr, "Error - bind failed : %s", WSAGetErrorMsg() );
        return 1;
    }
and then it calls listen.
Member 13995616 6-Mar-19 21:11pm
   
thank you, this worked.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)




CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100