/**
 * Name  : Edison Chindrawaly
 * File  : Palindrome_server.cc
 * Class : CSCI 3780 Spring of 2001
 * Desc  : This file is part of Palindrome checker's problem.
 *         It servers as server which processes the list of words
 *         that client submits and determine whether it is palindrome
 *         or not. If it is palindrome, it will return 1 else return 0
 *         It uses client/server model with TCP as the protocol.
 */

#include "MyHeader.h"
#define BACKLOG 5

int checkPalindrome(char*);
char* eraseWhite(char*);
int askServerPort();
void startProcess(int);
int sendAll(int s, char *buffer, int *length);
 
/**
 * sigchld_handler's method is to handle signal send by child
 * this method is taken from Beej's guide to networking with the url
 * of http://www.ecst.csuchico.edu/~beej/guide/net/html
 * @param  int s (s = descriptor)
 * return  none
 */
void sigchld_handler(int s)
{                              
  wait(NULL);                  
}

void main(int argc, char **argv)
{
 int portNumber = askServerPort();
 startProcess(portNumber);
 exit(1);
}

/**
 * askServerPort's method is to ask the user for
 * the host port number.
 * @param  none
 * @return the port number of the host
 */
int askServerPort()
{
 int temp;
 cout<<"Enter your server port: "<<flush;
 cin>>temp;
 return temp;
}

/**
 * startProcess's method is to start the connection and start
 * processing the a list of words that the client sends.
 * @param  int numPort
 * @return none
 */
void startProcess(int numPort)
{
 int sockfd, fdConnect, clientSize;
 struct sockaddr_in clientAdd, servAdd;
 struct sigaction sa;
 int yes = 1;
 int pal = 0;
 char palindrome;
 char* connectMsg = "you are connected to server.\n";
// fd_set readfds;
// FD_ZERO(&readfds);
// FD_SET(STDIN, &readfds);
 sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// FD_SET(sockfd,&readfds);
 
 if(setsockopt(sockfd,SOL_SOCKET,SO_REUSEADDR,&yes,sizeof(int))==-1)
 {
   perror("setsockopt error");
   exit(1);
 }


 bzero(&servAdd, sizeof(servAdd));
 servAdd.sin_family = AF_INET;
 servAdd.sin_port = htons(numPort);
 servAdd.sin_addr.s_addr = htonl(INADDR_ANY);

 if(bind(sockfd,(struct sockaddr *)&servAdd,sizeof(struct sockaddr))==-1)
 {
   perror("bind error");
   exit(1);
 }

 if(listen(sockfd, BACKLOG) == -1)
 {
   perror("listen error");
   exit(1);
 }

 sa.sa_handler = sigchld_handler;
 sigemptyset(&sa.sa_mask);
 sa.sa_flags = SA_RESTART;

 if(sigaction(SIGCHLD, &sa, NULL) == -1)
 {
   perror("sigaction error");
   exit(1);
 }

 bool flag=false;

 do
 {
   clientSize = sizeof(struct sockaddr_in);
   if((fdConnect=accept(sockfd,(struct sockaddr *)&clientAdd,
   (socklen_t *)&clientSize)) == -1)
   {
     perror("accept error");
     continue;
   }
//   FD_SET(fdConnect, &readfds);
//   select(sockfd+1, &readfds, NULL,NULL,NULL);
   cout<<"server: got connection from "<<inet_ntoa(clientAdd.sin_addr)<<endl;
   char buffer[MAXSIZE]; 
   if(!fork())
   { // child process
     close(sockfd);
     if(send(fdConnect,connectMsg,strlen(connectMsg),0)==-1)
     {
       perror("send error");
       exit(0);
     }
     int numbyte=recv(fdConnect,buffer,MAXSIZE,0);
     buffer[numbyte] = '\0';
     pal=checkPalindrome(buffer);
     if(pal == 0)
       palindrome = '0';
     else
       palindrome = '1';
     send(fdConnect,&palindrome,sizeof(palindrome),0);
     close(fdConnect);
     exit(0);
   }
/*   if(FD_ISSET(STDIN, &readfds))
   {
     cout<<"A key is press\n";
     flag=true;
   } */
   close(fdConnect); // parent closes connection

 } while(flag == false);  // end of while loop

}

/**
 * sendAll's method is taken from Beej's networking guide.
 * The URL: http://www.ecst.csuchico.edu/~beej/net/html/advanced.html
 * This method would send a complete message. Not a partial bits.
 * @param  int s: the  socket descriptor
 *         char * buffer: the string to be send
 *         int *length: the length of the string
 * @return int n (return -1 on failure. Otherwise return 0)
 */
int sendAll(int s, char *buffer, int *length)
{
  int total = 0;
  int bytesleft = *length;
  int numGets;
 
  while(total < *length)
  {
    numGets = send(s, buffer+total, bytesleft, 0);
    if(numGets == -1) break;
    total += numGets;
    bytesleft -= numGets;
  }
  *length = total;
  return numGets==-1? -1:0;
}

/**
 * checkPalindrome's method is to check the given string
 * whether it is palindrome sentence or not. If it is
 * Palindrome, it will return 1 else it will return 0.
 * @param  char* inStr
 * @return int 1 (if it is palindrome) else 0
 */
int checkPalindrome(char* inStr)
{
 char* outStr = strdup(eraseWhite(inStr));
 int length = strlen(outStr);
 int condition = 0;

 for(int i = 0; i < length; i++)
   if(i != length)
     outStr[i] = (char)tolower(outStr[i]);
   else
     outStr[i] = '\0';

 char* newStr = new char;
 int j = length;
 for(int i=0; i < length; i++)
   newStr[i] = outStr[--j];
 newStr[length] = '\0';

//if palindrome is found, return condition=1
 if(strcmp(newStr,outStr) == 0)
   condition = 1; 

 delete newStr;
 delete outStr;
 return condition;
}

/**
 * eraseWhite's method is to erase all the blank space
 * in the given string. The leading, trailing, and in between
 * space will be erase.
 * @param char* source
 * @return char* result1
 */
char* eraseWhite(char* source)
{
  if(!source)
    return NULL;
  int lenStr = strlen(source);
  int count = 0;
  char result[lenStr];
  for(int i=0;i<lenStr;i++)
    if(source[i] !=' ')
      result[count++]=source[i];
  result[count]='\0';
  char* result1 = strdup(result);
  return result1;
}
 

1