/*
   client server model  [server]
   enviroment : TEST_PORT .. port no. of socket
                TEST_HOST .. host name for server
*/
#include "tcp.h"
char    *uname,cmd[MAX_LINE],netcmd[MAX_LINE];
int     newsockfd;
void    prtstat();
char    netstr[]="netgrep";

int main(int argc,char *argv[]) {
     int                sockfd,ret,clilen,childpid;
     struct sockaddr_in srv_addr,cli_addr;
     char               *emsg;

     uname = argv[0];
     get_env();                    /* get host_name/port_no    */
     sprintf(cmd,"%d", port_no);
     strcpy(netcmd,TCP_INSDIR);
     strcat(netcmd,netstr);
     PRT_TRS("s:socket()\n");
     if (( sockfd = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == -1) {
        die_err(1);
     }
     PRT_TRS("e:socket()\n");
/* set addr   */
     bzero((char *) &srv_addr,SZ_ADDR);
     srv_addr.sin_family         = AF_INET;
     srv_addr.sin_addr.s_addr    = htonl(INADDR_ANY);
     srv_addr.sin_port           = htons(port_no);
     PRT_TRS("s:bind()\n");
     ret = bind(sockfd,(struct sockaddr *) &srv_addr,SZ_ADDR);
     PRT_TRS("e:bind()\n");
     if (ret == -1)  die_err(2);
     PRT_TRS("s:listen()\n");
     listen(sockfd,SZ_QUEUE);
     PRT_TRS("e:listen()\n");
     clilen = SZ_ADDR;
     printf("Server listening to port %d (pid=%d) .....\n",
             port_no,getpid());

     for (;;) {
        PRT_TRS("s:accept()\n");
        newsockfd = accept(sockfd,(struct sockaddr *)&cli_addr,&clilen);
        PRT_TRS("e:accept()\n");
        if (newsockfd < 0)  die_err(3);
        if ((childpid = fork()) <0)   die_err(4);
        else if (childpid == 0)  {	/* child process */
           pid_t  c_pid = getpid();

           prtstat();
           printf("++ DServer %d is spawned\n",c_pid);
           close(sockfd);
           str_echo(newsockfd,c_pid);
           close(newsockfd);
           printf("   DServer %d is closed socket & exit\n",c_pid);
           printf("Server %d listening to port %d ...\n",c_pid,port_no);
           fflush(stdout);
           printf("-- DServer %d is died\n",c_pid);
           exit(0);
        }
        close(newsockfd);		/* parent process */
     }
}

void prtstat() {
   if (fork() == 0) {     /* child process */
     printf("\n");
     execl(netcmd,netcmd,cmd,(char *) 0);
     exit(0);
   }
   sleep(1);
   return;
}

int str_echo(int sockfd,pid_t c_pid) {
   int   n;
   char  line[MAX_LINE];

   for (;;) {
      n = readline(sockfd,line,MAX_LINE);
      if (n == 0)   return;
      else if (n < 0)  die_err(8);
      if (writen(sockfd,line,n) != n)  die_err(9);
      printf("   DServer %d : Receive data [%s",c_pid,line);
      if (! strcmp(line,DS_CLS_WQUIT)) {
         close(sockfd);
         printf("   DServer %d : socket closed and wait (%d sec) : DS_CLS_WQUIT \n",
                c_pid,WAIT_TIME);
         prtstat();
         sleep(WAIT_TIME);
         return;
      }
      if (! strcmp(line,DS_QUIT))   return;
      if (! strcmp(line,DS_C_QUIT))   return;
      if (! strcmp(line,CQUIT_SWQUIT)) {
         printf("   DServer %d : socket not closed and wait (%d sec) : CQUIT_SWQUIT\n",
                 c_pid,WAIT_TIME);
         prtstat();
         sleep(WAIT_TIME);
         return;
      }
   }
}

int readline(int fd,char *ptr, int maxlen) {
   int   n,rc;
   char  c;

   for (n=1; n<maxlen; n++) {
      if ((rc = read(fd,&c,1)) == 1) {
         *ptr++ = c;
         if (c == '\n')   break;
      }
      else if (rc == 0) {
         if (n == 1)   return (0);
         else          break;
      }  else          return (-1);
   }
   *ptr = 0;
   return (n);
}

int writen(int fd,char *ptr,int nbytes) {
   int   nleft,nwritten;

   nleft = nbytes;
   while (nleft > 0)  {
      nwritten  = write(fd,ptr,nleft);
      if (nwritten <= 0)  return (nwritten);
      nleft    -= nwritten;
      ptr      += nwritten;
   }
   return (nbytes - nleft);
}
   
void usage() {
}

void die_err(int no) {
  perror(uname);
  exit(no);
}