Sunday 19 July 2015

Simple Proxy Server in C using Multi-threading


This articles covers a simple proxy server application for multiple clients in C. It is based on Linux based socket programming.

If you are comfortable with basics of socket programming and multithreading in c then this article is for you!

To revise basics of socket programming, please visit my earlier article. Link:


This proxy server application is as follows:
  1. Three programs will run at a time(in separate Linux terminals, of course..!) 
  • One is main server. It acts as a echo server.
  • One is proxy server. It forwards data from client to main server. And server response back to client
  • Last one is a client. 
     2.  It supports multiple clients.
     3.  There will be only one main server and one proxy server
     4.  Proxy server will accept three arguments from command line. These include server IP address   followed by server port address and then proxy's port address. Since proxy is running on a local machine. Its IP address will be 127.0.0.1 by default. No need to mention that in the command line.
     5. Client will accept two arguments. These include proxy's IP address and port.

Now you can directly jump to the code. Copy-paste it and run it for further study.

For newbies, I'm explaining how programs work in brief. The application flow is as follows:
  1. Client will accept proxy details and connect to the specified proxy through socket
  2. Proxy server will accept server details and store the details in variables
  3. Proxy server also create a socket at the mentioned proxy port and start listening for incoming client connections continuously on that port.
  4. For each successfully accepted client connection, proxy server will create a thread and pass client details(client file descriptor) and server details(ip and port) to that newly created thread. Lets call this thread as client thread.
  5. This client thread will create a socket connection and connect to the main server. Now each thread will be responsible for communication between that client and main server.
  6. While main server will accept client connections and create its own thread for each client. Lets call these threads as server threads. This will help main server to differentiate traffic between multiple clients.
  7. Here, main trick is to manage multiple client connections via proxy server. I implemented it using multithreading. 
  8. Instead of multithreading, you can use a 'select command' which can also serve the same purpose. It is used for synchronous IO multiplexing.  Following link covers the details of it with multi chat client-server application using select command:
    http://beej.us/guide/bgnet/output/html/singlepage/bgnet.html
Why multi-threading?
Answer: Codes are modular in multithreading and all accepted client-server connections are independent of each other. When client exits, that particular thread will exit. But the disadvantage of threads is that threads create complexity in the program.


So, Thats all folks! 

Now you are ready to run your own proxy server application with the help of following code. See the results and modify it as per your requirements.

I wrote comments in the codes for clarity of the logic. 

1. Copy the following code and save in a file called "mainserver.c"

 #include <sys/socket.h>  
 #include <sys/types.h>  
 #include <resolv.h>  
 #include <string.h>  
 #include <pthread.h>  
 #include<unistd.h>  
 // A thread function  
 // A thread is created for each accepted client connection  
 void *runSocket(void *vargp)  
 {  
   int c_fd =(int)vargp; // get client fd from arguments passed to the thread  
   char buffer[65535];  
   int bytes = 0;  
      while(1)  
      {  
           //receive data from client  
           memset(&buffer,'\0',sizeof(buffer));  
           bytes = read(c_fd, buffer, sizeof(buffer));  
           if(bytes <0)  
           {  
                //perror("read");  
           }  
           else if(bytes == 0)  
           {  
           }  
           else  
           {  
                //send the same data back to client  
                // similar to echo server  
                write(c_fd, buffer, sizeof(buffer));  
                //printf("client fd is : %d\n",c_fd);                    
                //printf("From client:\n");                    
                fputs(buffer,stdout);       
           }  
             fflush(stdout);  
      };       
   return NULL;  
 }  
 // main entry point  
 int main()  
 {  
      int client_fd;  
      char buffer[100];  
      int fd = 0 ;  
      struct sockaddr_in server_sd;  
 // add this line only if server exits when client exits  
 signal(SIGPIPE,SIG_IGN);  
      // create a socket  
      fd = socket(AF_INET, SOCK_STREAM, 0);  
      printf("Server started\n");  
      memset(&server_sd, 0, sizeof(server_sd));  
      // set socket variables  
      server_sd.sin_family = AF_INET;  
      server_sd.sin_port = htons(5010);  
      server_sd.sin_addr.s_addr = INADDR_ANY;  
      // bind socket to the port  
      bind(fd, (struct sockaddr*)&server_sd,sizeof(server_sd));  
      // start listening at the given port for new connection requests  
      listen(fd, SOMAXCONN);  
      // continuously accept connections in while(1) loop  
      while(1)  
      {  
           // accept any incoming connection  
           client_fd = accept(fd, (struct sockaddr*)NULL ,NULL);  
           //printf("accepted client with id: %d",client_fd);  
           // if true then client request is accpted  
           if(client_fd > 0)  
           {  
                 //multithreading variables    
                printf("proxy connected\n");     
                pthread_t tid;  
                // pass client fd as a thread parameter  
                 pthread_create(&tid, NULL, runSocket, (void *)client_fd);   
           }  
      }  
      close(client_fd);   
      return 0;  
 }  

2. Copy the following code and save it in a file called 'proxy.c'


 #include <sys/socket.h>  
 #include <sys/types.h>  
 #include <resolv.h>  
 #include <string.h>  
 #include <stdlib.h>  
 #include <pthread.h>  
 #include<unistd.h>  
 #include<netdb.h> //hostent  
 #include<arpa/inet.h>  
 int hostname_to_ip(char * , char *);  
 // A structure to maintain client fd, and server ip address and port address  
 // client will establish connection to server using given IP and port   
 struct serverInfo  
 {  
      int client_fd;  
      char ip[100];  
      char port[100];  
 };  
 // A thread function  
 // A thread for each client request  
 void *runSocket(void *vargp)  
 {  
   struct serverInfo *info = (struct serverInfo *)vargp;  
   char buffer[65535];  
   int bytes =0;  
      printf("client:%d\n",info->client_fd);  
      fputs(info->ip,stdout);  
      fputs(info->port,stdout);  
      //code to connect to main server via this proxy server  
      int server_fd =0;  
      struct sockaddr_in server_sd;  
      // create a socket  
      server_fd = socket(AF_INET, SOCK_STREAM, 0);  
      if(server_fd < 0)  
      {  
           printf("server socket not created\n");  
      }  
      printf("server socket created\n");       
      memset(&server_sd, 0, sizeof(server_sd));  
      // set socket variables  
      server_sd.sin_family = AF_INET;  
      server_sd.sin_port = htons(atoi(info->port));  
      server_sd.sin_addr.s_addr = inet_addr(info->ip);  
      //connect to main server from this proxy server  
      if((connect(server_fd, (struct sockaddr *)&server_sd, sizeof(server_sd)))<0)  
      {  
           printf("server connection not established");  
      }  
      printf("server socket connected\n");  
      while(1)  
      {  
           //receive data from client  
           memset(&buffer, '\0', sizeof(buffer));  
           bytes = read(info->client_fd, buffer, sizeof(buffer));  
           if(bytes <= 0)  
           {  
           }  
           else   
           {  
                // send data to main server  
                write(server_fd, buffer, sizeof(buffer));  
                //printf("client fd is : %d\n",c_fd);                    
                printf("From client :\n");                    
                fputs(buffer,stdout);       
                  fflush(stdout);  
           }  
           //recieve response from server  
           memset(&buffer, '\0', sizeof(buffer));  
           bytes = read(server_fd, buffer, sizeof(buffer));  
           if(bytes <= 0)  
           {  
           }            
           else  
           {  
                // send response back to client  
                write(info->client_fd, buffer, sizeof(buffer));  
                printf("From server :\n");                    
                fputs(buffer,stdout);            
           }  
      };       
   return NULL;  
 }  
 // main entry point  
 int main(int argc,char *argv[])  
 {  
     pthread_t tid;  
     char port[100],ip[100];  
     char *hostname = argv[1];  
     char proxy_port[100];  
        // accept arguments from terminal  
        strcpy(ip,argv[1]); // server ip  
        strcpy(port,argv[2]);  // server port  
        strcpy(proxy_port,argv[3]); // proxy port  
        //hostname_to_ip(hostname , ip);  
        printf("server IP : %s and port %s" , ip,port);   
        printf("proxy port is %s",proxy_port);        
        printf("\n");  
      //socket variables  
      int proxy_fd =0, client_fd=0;  
      struct sockaddr_in proxy_sd;  
 // add this line only if server exits when client exits  
 signal(SIGPIPE,SIG_IGN);  
      // create a socket  
      if((proxy_fd = socket(AF_INET, SOCK_STREAM, 0)) < 0)  
      {  
          printf("\nFailed to create socket");  
      }  
      printf("Proxy created\n");  
      memset(&proxy_sd, 0, sizeof(proxy_sd));  
      // set socket variables  
      proxy_sd.sin_family = AF_INET;  
      proxy_sd.sin_port = htons(atoi(proxy_port));  
      proxy_sd.sin_addr.s_addr = INADDR_ANY;  
      // bind the socket  
      if((bind(proxy_fd, (struct sockaddr*)&proxy_sd,sizeof(proxy_sd))) < 0)  
      {  
           printf("Failed to bind a socket");  
      }  
      // start listening to the port for new connections  
      if((listen(proxy_fd, SOMAXCONN)) < 0)  
      {  
           printf("Failed to listen");  
      }  
      printf("waiting for connection..\n");  
      //accept all client connections continuously  
      while(1)  
      {  
           client_fd = accept(proxy_fd, (struct sockaddr*)NULL ,NULL);  
           printf("client no. %d connected\n",client_fd);  
           if(client_fd > 0)  
           {  
                 //multithreading variables      
                 struct serverInfo *item = malloc(sizeof(struct serverInfo));  
                 item->client_fd = client_fd;  
                 strcpy(item->ip,ip);  
                 strcpy(item->port,port);  
                 pthread_create(&tid, NULL, runSocket, (void *)item);  
                 sleep(1);  
           }  
      }  
      return 0;  
 }  
 int hostname_to_ip(char * hostname , char* ip)  
 {  
   struct hostent *he;  
   struct in_addr **addr_list;  
   int i;  
   if ( (he = gethostbyname( hostname ) ) == NULL)   
   {  
     // get the host info  
     herror("gethostbyname");  
     return 1;  
   }  
   addr_list = (struct in_addr **) he->h_addr_list;  
   for(i = 0; addr_list[i] != NULL; i++)   
   {  
     //Return the first one;  
     strcpy(ip , inet_ntoa(*addr_list[i]) );  
     return 0;  
   }  
   return 1;  
 }  

3. Copy the following code and save it in a file called 'client.c'

 #include <sys/socket.h>  
 #include <sys/types.h>  
 #include <resolv.h>  
 #include <string.h>  
 // main entry point  
 int main(int argc, char* argv[])  
 {  
      //socket variables  
      char IP[200];  
      char port[200];  
      char buffer[65535];  
      int sd;  
      struct sockaddr_in client_sd;  
      printf("\nEnter proxy address:");  
      fgets(IP,sizeof("127.0.01\n")+1,stdin);  
      fputs(IP,stdout);  
      printf("\nEnter a port:");  
      fgets(port,sizeof("5000\n")+1,stdin);  
      fputs(port,stdout);  
      if((strcmp(IP,"127.0.0.1\n"))!=0 || (strcmp(port,"5000\n"))!=0)  
      {  
           printf("Invalida proxy settings. Try again...");  
      }  
      else  
      {  
           // create a socket  
           if((sd = socket(AF_INET, SOCK_STREAM, 0)) < 0)  
           {  
                printf("socket not created\n");  
           }  
           memset(&client_sd, 0, sizeof(client_sd));  
           // set socket variables  
           client_sd.sin_family = AF_INET;  
           client_sd.sin_port = htons(5000);  
           // assign any IP address to the client's socket  
           client_sd.sin_addr.s_addr = INADDR_ANY;   
           // connect to proxy server at mentioned port number  
           connect(sd, (struct sockaddr *)&client_sd, sizeof(client_sd));  
           //send and receive data contunuously  
           while(1)  
            {  
                printf("Type here:");  
                fgets(buffer, sizeof(buffer), stdin);  
                write(sd, buffer, sizeof(buffer));  
                printf("\nServer response:\n\n");  
                read(sd, buffer, sizeof(buffer));  
                fputs(buffer, stdout);  
                  //printf("\n");       
           };  
           //close(sd);  
      }  
      return 0;  
 }  

How to run the programs?

I'm posting snapshots of my program. Please follow steps in sequence:

1. Compile and run main server





2. Compile and run proxy server






3. Compile and run client










Please note that

  1. -lpthread is a command used to compile the code if multi-threading is used. So, commands to compile proxy.c and mainserver.c are little different from client.c
  2. And client.c file accepts 5000 as a port address for proxy server. It is hard coded in the file. you can either comment that line or write other valid port address if you need it that way.



Friday 10 July 2015

Echo Server Using TCP and UDP protocol in C

This article contains programs illustrating echo server application in C using socket programming.

This echo server prints the messages received by it on the screen as well as sent those messages back to the sender. And sender will print the messages on its screen before sending to echo server and after receving from echo server.


For beginners in socket programming, I explained basics of it before presenting code. Those who are already aware can directly jump to code section.

Socket programming is a popular style of programming in networking domain. Two computers communicate each other using socket programming. And this communication is independant of programming language used for implementing it. And this is the main reason behind it's popularity. So, a program written in Java can communicate with a program written in C using sockets. 

These sockets provide an interface for programming at the transport layer. Transport layer uses TCP and/or UDPprotocols for communication. Now, we can formally answer the Question:

What is socket programming?
It is a communication mechanism between two computers using protocols like TCP or UDP.

But, what is a socket??!
socket is an end point of communication across a computer network.

So, socket programming can be visualized as a telephone line from telephone operator to many different users with sockets acting as a separate telephone numbers for every user.

Every socket will have an address. And this address is comprised of two parts. One is IP address and other is port number. This address is nothing but like a telephone number with a particular extension to connect directly to a particular user.

Now, we need two machines for communication and a program through which they will communicate with other. 

Section A: This covers echo server using TCP protocol in C.

Steps to run the programs:

1. Copy this code and save it in a file with name as 'echo_server.c'

 #include <sys/socket.h>  
 #include <netinet/in.h>  
 #include <arpa/inet.h>  
 #include <stdio.h>  
 #include <stdlib.h>  
 #include <unistd.h>  
 #include <errno.h>  
 #include <string.h>  
 #include <sys/types.h>  
 int main(void)  
 {  
  int clientfd = 0,connfd = 0;  
  int n = 0;  
  struct sockaddr_in serv_addr;  
  char buffer[1024];   
  clientfd = socket(AF_INET, SOCK_STREAM, 0);  
  printf("socket retrieve success\n");  
  memset(&serv_addr, '0', sizeof(serv_addr));  
  memset(buffer, '0', sizeof(buffer));  
  serv_addr.sin_family = AF_INET;    
  serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);   
  serv_addr.sin_port = htons(5000);    
  bind(clientfd, (struct sockaddr*)&serv_addr,sizeof(serv_addr));  
  if(listen(clientfd, 10) == -1){  
    printf("Failed to listen\n");  
    return -1;  
  }  
  connfd = accept(clientfd, (struct sockaddr*)NULL ,NULL);  
  while(1)  
   {  
    read(connfd, buffer, sizeof(buffer));  
    write(connfd, buffer, sizeof(buffer));  
    fputs(buffer,stdout);            
   }  
  close(connfd);   
  return 0;  
 }  

2. Copy this code and save it in a file with name as 'echo_client.c'

 #include <sys/socket.h>  
 #include <sys/types.h>  
 #include <netinet/in.h>  
 #include <netdb.h>  
 #include <stdio.h>  
 #include <string.h>  
 #include <stdlib.h>  
 #include <unistd.h>  
 #include <errno.h>  
 #include <arpa/inet.h>  
 #define BLOCK_SIZE 1024  
 int main(void)  
 {  
  int serverfd = 0,n = 0;  
  struct sockaddr_in serv_addr;  
  char buffer[BLOCK_SIZE];  
  int revCnt = 0;  
  memset(buffer, '0' ,sizeof(buffer));  
  if((serverfd = socket(AF_INET, SOCK_STREAM, 0))< 0)  
   {  
    printf("\n Error : Could not create socket \n");  
    return 1;  
   }  
  serv_addr.sin_family = AF_INET;  
  serv_addr.sin_port = htons(5000);  
  serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");  
  if(connect(serverfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr))<0)  
   {  
    printf("\n Error : Connect Failed \n");  
    return 1;  
   }  
  do  
  {  
      fgets(buffer, sizeof(buffer), stdin);  
      write(serverfd, buffer, sizeof(buffer));  
      //memset(buffer,'0',sizeof(buffer));  
      read(serverfd, buffer, sizeof(buffer));  
      fputs(buffer, stdout);  
      fflush(stdin);  
        printf("\n");  
   }while(strcmp(buffer,"bye\n")!=0);  
   return 0;  
 }  

3. Compile these two programs in two seperate terminals in a linux based machine. Following are the commands. These commands will create object file with the name provided. In this case 'server' and 'client' are object files.

 gcc echo_server.c -o server  
 gcc echo_client.c -o client  


Here, each terminal will act as a machine. And now these two terminals communicate with each other using sockets. These terminals are nothing but two processes in a operating system. So, socket programming is known for inter process communication.

4. Next, run the programs using following commands in each of the terminals:

 ./server  
 ./client  



Section B: This covers echo server using UDP protocol

1. Copy and save code in a file 'udp_server.c'
 #include <sys/socket.h>  
 #include <sys/types.h>  
 #include <resolv.h>  
 #include <string.h>  
 #define BUFSIZE 200  
 int main()  
 {  
      int sd = 0;  
      char buffer[BUFSIZE];  
      int recvlen = 0;  
      struct sockaddr_in server_socket;  
      struct sockaddr_in rem_socket;  
      socklen_t addrlen = sizeof(rem_socket);  
      sd = socket(AF_INET, SOCK_DGRAM, 0);  
     printf("socket created\n");  
      memset(&server_socket, 0, sizeof(server_socket));  
      server_socket.sin_family = AF_INET;  
      server_socket.sin_port = htons(5000);  
      server_socket.sin_addr.s_addr = INADDR_ANY;  
      bind(sd, (struct sockaddr*)&server_socket,sizeof(server_socket));  
       do  
      {  
           recvlen = recvfrom(sd, buffer, BUFSIZE, 0, (struct sockaddr *)&rem_socket, &addrlen);  
           if (recvlen > 0)   
           {   
                buffer[recvlen] = 0;  
                fputs(buffer,stdout);  
           }  
           sendto(sd, buffer, sizeof(buffer), 0, (struct sockaddr *)&rem_socket, addrlen);  
      }while(strcmp(buffer,"bye\n")!=0);  
      close(sd);  
      return 0;  
 }  

2. Copy and save code in a file 'udp_client.c'
 #include <sys/socket.h>  
 #include <sys/types.h>  
 #include <resolv.h>  
 #include <string.h>  
 #define BUFSIZE 200  
 int main(void)  
 {  
      char buffer[200];  
      int sd = 0;  
      struct sockaddr_in client_socket;  
      struct sockaddr_in rem_socket;  
      socklen_t addrlen = sizeof(rem_socket);  
      int recvlen = 0;  
      if((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0)  
      {  
           printf("socket not created\n");  
      }  
      printf("socket created\n");  
      memset(&client_socket, 0, sizeof(client_socket));  
      client_socket.sin_family = AF_INET;  
      client_socket.sin_port = htons(5000);  
      client_socket.sin_addr.s_addr = inet_addr("127.0.0.1");   
      do  
      {       
           memset(buffer, '0', sizeof(buffer));            
           fgets(buffer,sizeof(buffer),stdin);  
           if (sendto(sd, buffer, sizeof(buffer), 0, (struct sockaddr *)&client_socket, sizeof(client_socket)) < 0)   
           {  
                 printf("sendto failed");   
                return 0;   
           }  
           //fputs(buffer,stdout);  
           recvlen = recvfrom(sd, buffer, BUFSIZE, 0, (struct sockaddr *)&rem_socket, &addrlen);  
           if (recvlen > 0)   
           {   
                buffer[recvlen] = 0;  
                fputs(buffer,stdout);  
           }  
      }while(strcmp(buffer,"bye\n")!=0);  
      close(sd);  
      return 0;  
 }  

3. Compile these two files in two separate terminals. Commands are as follows:
 gcc udp_server.c -o udp_server  
 gcc udp_client.c -o udp_client  

4. Run the programs as follows:
 ./udp_server  
 ./udp_client  



Congrats..!! You have successfully ran your first echo server using TCP as well as UDP protocol in C!!
Messages you type in the 'client' terminal will get printed in 'server' terminal and also these will be sent back by 'server' to 'client' and get printed in 'client' terminal.

Section C: How these programs work


Server machine implements following steps:
1. Create a socket.
2. Assign family, type and port number to the created socket.
3. Bind the socket.
4. Once request from a client comes at the port number mentioned in step 2 then accept it.
5. Receive the messages. Print it to the screen and sent it back to the corresponding client until message saying 'bye' is received.

The difference between TCP server and UDP server is that step no. 4 is absent in UDP server. why?
TCP is a connection oriented protocol. So a connection is always ensured before
communication between client and server in a TCP which is done by above step no. 4. While UDP is a connectionless protocol. It means that connection is not established between server and client before sending packets.
Type of communication i.e. TCP or UDP is specified in step no. 2 i.e. type is SOCK_STREAM in TCP while it is SOCK_DGRAM in UDP.

For e.g. In UDP, we wrote:
 sd = socket(AF_INET, SOCK_DGRAM, 0)  
while creating a socket.

Client machine implements following steps:
1. Create a socket.
2. Assign family, type and port number to the created socket.

3. Connect the client's socket to server socket.
4. Send and receive messages till client types 'bye'

Since, UDP is connectionless protocol, step no. 3 is absent in UDP client code. While it is must in TCP client code.

Another difference between TCP and UDP socket programming is the functions used for sending and receiving packets(in this case, messages).

In TCP,
 read(sd, buffer, sizeof(buffer));  

While, in UDP,
 recvlen = recvfrom(sd, buffer, BUFSIZE, 0, (struct sockaddr *)&rem_socket, &addrlen);  

command used for reading.

We specify a socket address to receive packets in UDP since connection is not specified in advance.

In TCP,
 write(sd, buffer, sizeof(buffer));  

While in UDP,
 sendto(sd, buffer, sizeof(buffer), 0, (struct sockaddr *)&rem_socket, addrlen);  

In UDP, reply is sent via the socket received in read command. In this way, even if connection is not maintained, server can still reply to client's packets.