BSD sockets: Server Client Chat Program using TCP

Check latest version here.

Header File 1 for Server Program: SChat_register.h
#ifndef SCHAT_REGISTER_H
#define SCHAT_REGISTER_H
//SChat_register.h
#include "SChat_connect.h"

typedef short bool;
int* ar;//= (int*) malloc(sizeof(int));
int maxIndex;// = 0;
int top;// = -5;
bool reg_lock;// = false;

void getRegisteredList(){
 int i;
 for(i=0; i<=top; i++)
  printf("%d\t", ar[i]);
 printf("\n");
}
//call this before using any other function of this library
void init(){
 ar = (int*) calloc(1, sizeof(int));
 if(ar == NULL)
  Error("malloc error in init");
 top = -1;
 con_init();
 maxIndex = 0;
 reg_lock = false;
}

int registerMe(int fd){
printf("registerMe:In registerMe\n");
 while(reg_lock)
  printf("registerMe:reg_lock1 busy\n");
 reg_lock = true;
 printf("registerMe:reg_lock1 taken\n");

 int retIndex=-1;
 if(top == maxIndex){
  ar = realloc(ar, (maxIndex+1)*2 * sizeof(int));
  if(ar == NULL) Error("realloc error in register");
  maxIndex = (maxIndex+1)*2 - 1;
 }
 //POS FROM 0 TO top are filled on sorted order already. Use ++top and insert fd.
 int i;
 for(i=top; i>0; i--){
  if(ar[i] > fd)
   ar[i+1] = ar[i];
  else{
   retIndex = i+1;
   ar[retIndex] = fd;
   break;
  }
 }
 if(top <1){
  ar[top+1] = fd;
  retIndex = top+1;
 }
 ++top;
 AddCon_num(retIndex);
 printf("registerMe:reg_lock1 freed\n");
 reg_lock = false;
 return retIndex;
}

int getFd(int index){
 return ar[index];
}

int isRegistered(int fd){//returns -1 if not registered else returns non-negative
// test for top =0, =1, =n
 //search fd in sorted array ar using binary search
 int ans = -1;
/* int b=0, e=top;
 do{
printf("In isRegistered\n");
  int mid = (b+e)/2;
  if(ar[mid] == fd){
   ans = mid;
   break;
  }else if(ar[mid] > fd)
   e = mid-1;
  else
   b = mid+1;
 }while(b<e);*/
int i;
for(i=0; i<=top; i++){
 if(ar[i] == fd){
  ans = i;
  break;
 }
}
 return ans;
}

void unRegister(int x){//arg is index
 if(x== -1)
  return;
 int i;
 for(i=x+1; i<=top; i++){
  ar[i-1] = ar[i];
 } 
 --top;
}

void clean(int fd){
 while(reg_lock) printf("clean:reg_lock3 busy\n");
 reg_lock = true;
 printf("clean:reg_lock3 taken\n");
 int index;
 if((index = isRegistered(fd)) >= 0){
  unConnect(index);
  unRegister(index);
 }
 printf("clean:reg_lock3 freed\n");
 reg_lock = false;
}

//frees dynamic memory
void freeRegister(){
 printf("In freeRegister\n");
 freeConnect();
 free(ar);
}
#endif // SCHAT_REGISTER_H


Header File 2 for Server Program:SChat_connect.h
#ifndef SCHAT_CONNECT_H
#define SCHAT_CONNECT_H
//SChat_connect.h
#define true 1
#define false 0
#include<stdio.h>
#include<stdlib.h>
#include <string.h>
#include "SChat_register.h"
void Error(const char *msg){
    perror(msg);
    exit(1);
}

int **con_ar;
int con_num;//it num of clients connected with the server

void con_init(){
 con_ar = NULL;
 con_num = 0;
}
void printConns(){
 int i;
 for(i=0; i<con_num; i++){
  int j;
  for(j=0; j<con_num; j++){
   //printf("%d %d\n",i,j);
   printf("%d\t", con_ar[i][j]);
  }
  printf("\n");
 }
 printf("\n");
}
void AddCon_num(int ind){
 printf("In AddCon_num()\n");
 printConns();
 ++con_num;
 con_ar = (int**) realloc(con_ar, con_num*sizeof(int*));//add row at end
 if(con_ar == NULL && con_num > 0) printf("realloc returns NULL\n"), exit(1);
 con_ar[con_num-1] = NULL;//initialize last row pointer to NULL

//Extend 2D array
printf("In AddCon_num(): Row added\n");
 int i;
 for(i=0; i<con_num; i++){//for each row
  con_ar[i] = (int *) realloc(con_ar[i], con_num*sizeof(int));//add column at end
  if(con_ar[i] == NULL && con_num > 0) printf("realloc returns NULL\n"), exit(1);
 }
printf("In AddCon_num(): col added\n");

//making space for ind
 for(i=con_num-1; i>0 ; i--){//for each row
  int j;
  for(j=con_num-1; j>=ind; j--)//for each col larger than ind
   con_ar[i][j] = con_ar[i-1][j];
 }
 for(i=con_num-1; i>0 ; i--){//for each col
  int j;
  for(j=con_num-1; j>=ind; j--)//for each row larger than ind
   con_ar[j][i] = con_ar[i][j-1];
 }

//initialize ind
 for(i=0; i<con_num; i++){
  con_ar[ind][i] = 0;
  con_ar[i][ind] = 0;
 }
 printConns();
 printf("AddCon_num() ENDS\n");
}
void DeleteCon_num(int ind){
 printf("In DeleteCon_num()\n");
 printConns();
 int i; 
 for(i=ind+1; i<con_num ; i++){//for each row
  int j;
  for(j=ind+1; j<con_num; j++)//for each col
   con_ar[i-1][j-1] = con_ar[i][j];
 }
 con_num--;
 for(i=0; i<con_num; i++){
  con_ar[i] = (int *) realloc(con_ar[i], con_num*sizeof(int));//del col at end
  if(con_ar[i] == NULL  && con_num > 0) printf("realloc returns NULL\n"), exit(1);
 }
 con_ar = (int**) realloc(con_ar, con_num*sizeof(int*));//del row at end
 if(con_ar == NULL && con_num > 0) printf("realloc returns NULL\n"), exit(1);
 printConns();
}

int connectClients(int fd, int new_fd){//both fds are already registered. Returns 1 if connection accepted else returns 0
 printf("In connectClients\n");
 //if not yet connected, ask new_fd for connection
 int fd_ind = isRegistered(fd);
 int new_fd_ind = isRegistered(new_fd);
 int res = 0, n;
 if(con_ar[fd_ind][new_fd_ind] == 0){
  char buff[100]; bzero(buff,100);
  sprintf(buff, "Allow %d to chat y/n?", fd);
  n=write(new_fd, buff, strlen(buff));
  if(n<0) Error("In connectClients: ");
  bzero(buff,100);
  n=read(new_fd, buff, 99);
  if(n<0) Error("In connectClients: ");
  else if(n==0){
   close(new_fd); clean(new_fd);}
  else if(buff[0] == 'y' || buff[0] == 'Y')
   res = 1;
 }
 if(res == 1){
  con_ar[fd_ind][new_fd_ind] = 1;
  con_ar[new_fd_ind][fd_ind] = 1;
  printConns();
 }
 return res;
}

void communicate(int fd, char* msg){//sends msg to all connected to fd
 printf("In communicate\n");
 //write msg to all connections of fd
 int index = isRegistered(fd);
 if(index < 0) Error("In communicate: ");
 int i;
 for(i=0; i<con_num; i++){
 if( con_ar[i][index]==1){
  //send msg to ar[i]
  if( write(getFd(i), msg, strlen(msg)) < 0 ) Error("In communicate: ");
 }
 }
}

//
void requestConn(int fd, int fd2){//fd wants to have chat with fd2
 char msg[100];
 sprintf(msg, "SERVER: %d wants to have chat with you", fd);
 if( write(fd2, msg, strlen(msg)) < 0 ) Error("In requestConn: ");
}

//returns 0 if fd is not connected to anyone yet.
int isConnected(int fd){
 printf("In isConnected\n");
 int i, index = isRegistered(fd);
 for(i=0; i<con_num; i++){
  if(i==index) continue;
  if(con_ar[i][index] == 1) return 1;
 }
 return 0;
}

//disconnect the 2 fds
void disConnect(int fd, int fd2){
 int ind = isRegistered(fd), ind2 = isRegistered(fd2);
 con_ar[ind][ind2] = 0;
 con_ar[ind2][ind] = 0;
 printConns();
}

//disconnects fd if connected to any.
void unConnect(int x){//arg is index
 printf("In unConnect\n");
 DeleteCon_num(x);
}

//frees dynamic memory
void freeConnect(){
 printf("In freeConnect\n");
 int i;
 for(i=0; i< con_num; i++)
  free(con_ar[i]);
}

#endif // SCHAT_CONNECT_H

Server Program: SChat.c
//Server Program
#include <unistd.h>
#include <sys/types.h> 
#include <sys/socket.h>
#include <netinet/in.h>
#include "SChat_register.h"

#define BACKLOG 1023

int createServerSocket(int port){
 int listenfd;
 struct sockaddr_in servaddr;
//STEP1 socket function  
 if((listenfd=socket(AF_INET, SOCK_STREAM, 0)) < 0)
  Error("ERROR WITH socket function");
 
//STEP2 address structure
 bzero((char *) &servaddr, sizeof(servaddr));
 servaddr.sin_family=AF_INET;
 servaddr.sin_port=htons(port);
 servaddr.sin_addr.s_addr=INADDR_ANY;
 
//STEP3 bind function
 if(bind(listenfd, (struct sockaddr*)&servaddr, sizeof(servaddr)) < 0)
  Error("ERROR WITH bind function");
 
//STEP4 listen function
 listen(listenfd, BACKLOG);
 
 return listenfd;
}

int serve(int fd){
printf("\nIn serve\n");
 int regisIndex = isRegistered(fd);
printf("Registered fds: ");
getRegisteredList();
 char buff[100], temp[100];
 int status=0, rd=0, wr=0;
 bzero(buff,100);
 rd = read(fd, buff, 99);
 if(rd == 0){
  clean(fd);
  printf("Closing connection");
  return status;
 }
 if(rd < 0){
  //Error("read error in serve: ");
  clean(fd);
  return status;
 }
 if(regisIndex == -1){//if not registered
printf("Gonna register now\n");
  sscanf(buff, "%s", temp);
  if(strcmp((temp), "register") != 0){
   printf("Closing connection");
   return status;
  }
  //clean(fd);
  registerMe(fd);
printf("Registered\n");
  sprintf(buff, "You are now registered with registration id = %d\n", fd);
  wr = write(fd, buff, strlen(buff));
  if(wr < 0)
   Error("write error in serve: ");
  return status=1;
 }else{//if registered
printf("Already registered\n");
  sscanf(buff, "%s", temp);
  int disconn_req = strcmp(temp, "disconnect");
  int conn_req = (isConnected(fd) == 0)?strcmp(temp, "connect"):1;//if not already connected, return 1
  if(conn_req == 0){//connect request
   int new_fd;
   sscanf(buff, "%s %d", temp, &new_fd);
   if(isRegistered(new_fd) < 0 ){//if new_fd NOT registered
    sprintf(buff, "No connection exists registered with id = %d\n", new_fd);
   }else if(isConnected(new_fd) == 1){//new_fd is already connected
    requestConn(fd, new_fd);
    sprintf(buff, "%d is already connected with someone. Your request to chat is sent to %d.\n", new_fd, new_fd);
   }else if(connectClients(fd, new_fd) == 1){//if connection accepted by new_fd
    sprintf(buff, "%d now connected with %d\n", fd, new_fd);
   }else{//if connection refused by new_fd
    sprintf(buff, "Connection refused by %d\n", new_fd);
   }
   wr = write(fd, buff, strlen(buff));
   if(wr < 0) Error("write error in serve: ");
   return status=1;
  }else if(isConnected(fd) == 0){//if not connected to anyone yet
   sprintf(buff, "Please connect to chat\n", fd);
   wr = write(fd, buff, strlen(buff));
   if(wr < 0) Error("write error in serve: ");
   return status=1;
  }else if(disconn_req == 0){//if disconn request
   int new_fd;
   sscanf(buff, "%s %d", temp, &new_fd);
   if(isRegistered(new_fd) < 0 ){//if new_fd NOT registered
    sprintf(buff, "No connection exists registered with id = %d\n", new_fd);
   }else{//if there is a connection
    disConnect(fd ,new_fd);
    sprintf(buff, "You and %d are now DISCONNECTED OR there was no connection.\n", new_fd);
   }
   wr = write(fd, buff, strlen(buff));
   if(wr < 0) Error("write error in serve: ");
   return status=1;
  }else{//if already connected, send msg
   communicate(fd, buff);
  }
 }
}

int main(int argc, char** argv){
 int port, listenfd, nfds, temp_fd;
 fd_set temp_fds, rfds;
 struct sockaddr_in cli_addr;

 if(argc != 2 || (port=atoi(argv[1])) < 1024)//test 1. 2.abbc 3.9041abc 4.+abc 5.-abc 6.1024 7.9041
  Error("ERROR WITH ARGS- Usage: ./a.out <portNumber 1024+ >");

 listenfd = createServerSocket(port);

 nfds = getdtablesize();
 FD_ZERO(&temp_fds);
 FD_SET(listenfd, &temp_fds);
 init();
 while(1){
  memcpy(&rfds, &temp_fds, sizeof(rfds));
  if(select(nfds, &rfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0) < 0) Error("select");
  if(FD_ISSET(listenfd, &rfds))
  {
   int connfd, alen = sizeof(cli_addr);
   connfd = accept(listenfd, (struct sockaddr *)&cli_addr, &alen);
   if(connfd < 0)    error("accept ");
   FD_SET(connfd, &temp_fds);
   nfds = (connfd>nfds)?connfd:nfds;
  }
  for(temp_fd=0; temp_fd <= nfds; ++temp_fd)
  if(temp_fd != listenfd && FD_ISSET(temp_fd, &rfds))
  if(serve(temp_fd) == 0)
  {
   (void) close(temp_fd);
   FD_CLR(temp_fd, &temp_fds);
  }
 }
 close(listenfd);
 freeRegister();
 return 0;
}
Client Program: CChat.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h> 

void error(const char *msg)
{
    perror(msg);
    exit(0);
}

int main(int argc, char *argv[])
{
    int sockfd, n, max_fd;
    fd_set rd_set, wr_set, temp_rd_set;
    struct sockaddr_in serv_addr;
    struct hostent *server;
    char exit_str[5] = "exit";
    char buffer[256];
    if (argc < 3) {
       fprintf(stderr,"usage %s hostname port\n", argv[0]);
       exit(0);
    }

//STEP1 socket function
    sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if (sockfd < 0) 
        error("ERROR opening socket");
    server = gethostbyname(argv[1]);
    if (server == NULL) {
        fprintf(stderr,"ERROR, no such host\n");
        exit(0);
    }
 
//STEP2 prepare address structure
    bzero((char *) &serv_addr, sizeof(serv_addr));
    serv_addr.sin_family = AF_INET;
    bcopy((char *)server->h_addr, 
         (char *)&serv_addr.sin_addr.s_addr,
         server->h_length);
    serv_addr.sin_port = htons(atoi(argv[2]));

//STEP3 connect function: request to server for connection
    if (connect(sockfd,(struct sockaddr *) &serv_addr,sizeof(serv_addr)) < 0) 
        error("ERROR connecting");
    
    max_fd = (sockfd>fileno(stdin))?sockfd:fileno(stdin);
    //FD_ZERO(&wr_set); 
    FD_ZERO(&rd_set);
//    FD_SET(sockfd, &wr_set);
    FD_SET(sockfd, &temp_rd_set);
    FD_SET(fileno(stdin), &temp_rd_set);
//STEP4 read and write to server.
    while(1){
 memcpy(&rd_set, &temp_rd_set, sizeof(rd_set));
 if(select( max_fd+1, &rd_set, (fd_set *)NULL, (fd_set *)NULL, (struct timeval*)NULL)<0) error("in select: ");
 if(FD_ISSET(sockfd, &rd_set)){
  //printf("CLIENT: sockfd is readable.\n");
  bzero(buffer,256);
  n = read(sockfd,buffer,255);//read from server and save it in array buffer
  if (n < 0) error("ERROR reading from socket");
  printf("%s\n",buffer);//write to stdout the buffer's contents
 }
 if(FD_ISSET(fileno(stdin), &rd_set)){
  //printf("CLIENT: stdin is readable.\n");
  bzero(buffer,256);
  fgets(buffer,255,stdin);//read from client stdin
  if(bcmp(exit_str, buffer, 4)==0){ close(sockfd); return 0; }    
  n = write(sockfd,buffer,strlen(buffer));//write to server
  if (n < 0) error("ERROR writing to socket");
 }
    }
    close(sockfd);
    return 0;
}
Cheers. Please leave a comment for any bug or issue!

1 comment:

  1. Can you show to how execute the program? as i tried but the client is not getting registred

    ReplyDelete