#include "headers.h" /* has all the important stuff */

/* this file has function to implement pings.. for timeouts */

/* for child and start pinging */
void startPings()
{
   int res;

   debug("starting the ping/pong timeout procedure..\n\n");
   debug("before forking, curPid = %d\n", curPid);

   curPid++;
   clients[curClient].pinging = 1;

   res = fork();
   if (res == ERROR)
   {
      error("error forking: %s\n\n", strerror(errno));
      quit(ERROR);
   } 

   else if (res == 0)
   { 
      if (curPid >= MAXNUMKIDS)
      {
         error("too many processes for the client..\n\n");

         res = seteuid(0); 
         if (res == ERROR) 
         {
            error("error with seteuid: %s\n\n", strerror(errno));
            quit(ERROR);
         }

         res = kill(getppid(), SIGTERM);
         if (res == ERROR) 
            error("error killing parent pid %d: %s\n\n", 
                  getppid(), strerror(errno));

         res = seteuid(pwd->pw_uid);
         if (res == ERROR) 
         {
            error("error with seteuid: %s\n\n", strerror(errno));
            quit(ERROR);
         }

         quit(ERROR);
      }

      clients[curClient].free    = ERROR; /* we're used */
      clients[curClient].running = 1; 

      clients[curClient].newData = 0; /* no new data yet */

      clients[curClient].pidstats[curPid].pid  = getpid(); 
      clients[curClient].pidstats[curPid].ppid = getppid();

      child = 1;

      /* check for new data.. according to the parent */
      signal(SIGUSR1, gotNewData); 
      sendPings(); /* child loops endlessly with pings */
   }

   else
   {
      if (curPid >= MAXNUMKIDS) 
      {
         error("too many children for client %04d.. aborting\n\n",
               clients[curClient].ID);

         res = wait((int *)NULL);
         if (res == ERROR)
         {
            error("error wait()'ing for child: %s\n\n", 
                  strerror(errno));

            quit(ERROR);
         } 

         else curPid--; /* the child will take care of this */
      }

      clients[curClient].pidstats[curPid].pid = res;
      clients[curClient].running = 1;

      child = 1;
      signal(SIGUSR2, startUp); /* used when parent can continue */
   }
}


/* ------------------------------------------ */


/* send pings to client */
void sendPings()
{
   int count = 0;   /* prevent overflows */

   int res;     /* results from various functions */
   int pingval; /* random value sent as ping to client */

   char *pongptr, *dataptr;

   char pongstr[8];
   char readbuf[MAXREADSIZE];

   checkValid();

   debug("(in sendPings) ready to ping..\n\n");

   while(1)
   {
      int sleeptime = MAXTIMEOUT;

      while(1)
      {
         int ret;
         ret = sleep(sleeptime);

         if ((ret != 0) && (clients[curClient].newData != 1))
            sleeptime = ret;

         else break;
      }

      pingval = ((int)random() % 9999) + 1;
      send_data((clients[curClient]).sockfd, "PING %d", pingval);

      memset(pongstr, 0, sizeof(pongstr));
      pongptr = pongstr;

      signal(SIGALRM, pingTimeout);
      (void)alarm(MAXTIMEOUT);

      while(1)
      {
         recv_data((clients[curClient]).sockfd, readbuf, 
                   sizeof(readbuf)-1, 1);

         debug("(in sendPings) data = %s\n", readbuf);

         if (strstr(readbuf, "PONG") != NULL)
         {
            (void)alarm(0);
            break;
         }
      }

      dataptr = strstr(readbuf, "PONG");
      if (dataptr == NULL)
      {
         error("unexpected error.. PONG not in data\n\n");
         quit(ERROR);
      }

      dataptr += 5; /* skip "PONG " */

      count = 0;
      while ((*dataptr) && (*dataptr != ' ') &&
             (isprint(*dataptr) != 0) && (count < (int)sizeof(pongstr)))
      {
         *pongptr++ = *dataptr++;
         count++;
      }

      if (pingval == atoi(pongstr)) continue;
      else
      {
         signal(SIGPIPE, SIG_IGN);

         send_data((clients[curClient]).sockfd, "ERROR: %s\n", PINGERROR);
         (void)sleep(MAXPAUSE); /* give them time to react */

         res = seteuid(0); 
         if (res == ERROR) 
         {
            error("error with seteuid: %s\n\n", strerror(errno));
            quit(ERROR);
         }

         res = kill(getppid(), SIGTERM);
         if (res == ERROR) 
            error("error killing parent process (pid %d): %s\n\n",
                  getppid(), strerror(errno));

         res = seteuid(pwd->pw_uid);
         if (res == ERROR) 
         {
            error("error with seteuid: %s\n\n", strerror(errno));
            quit(ERROR);
         }

         quit(ERROR);
      }
   }
}
