/* This includes the ping functions.. or the timeout functions */
/* ----------------------------------------------------------- */

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

/* fork child to start pinging */
void startPings()
{
   int res;

   if (pinging == 0)
   {
      debug("pinging is not implemented due to previous error\n");
      return;
   }

   /* we're now connecting.. check for pings */
   debug("now forking child to start pinging..\n");

   /* (void)signal(SIGCHLD, quit); */ /* die if pinging fails */
   (void)signal(SIGCHLD, SIG_IGN);

   running = 1, newData = 0;

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

   else if (chpid == 0) 
   {
      /* 
         (kill ourselves to prevent pinging)
         exit(0); 
         child = 0;
      */

      child = 1, chpid = getpid();

      running = 0;

      (void)signal(SIGHUP, SIG_IGN);
      (void)signal(SIGCHLD, SIG_IGN);
      (void)signal(SIGUSR1, sighandler);

      while (running != 1) (void)sleep(1);
      (void)signal(SIGUSR1, gotNewData);

      checkPings();                  /* child sits and waits for pings  */
   }

   else
   {   
      char readbuf[MAXREADSIZE];

      child = 1;
      /* chpid = 0, child = 0; */

      debug("(in child) sending START PINGS to server\n");
      send_data("START PINGS\n"); /* tell server to start pinging us */

      /* FIX - add timeout */
      while(1)
      {
         memset(readbuf, 0, sizeof(readbuf));
         recv_data(readbuf, sizeof(readbuf));

         if (strncmp(readbuf, "YES PINGING", 11) == 0)
         {
#          if !defined(SUN) && !defined(BSD)
#           ifdef _POSIX_SAVED_IDS
            res = setuid(0);
#           else
            res = seteuid(0);
#           endif

            if (res == ERROR)
            {
               error("error setting [e]uid: %s\n\n", strerror(errno)); 
               quit(ERROR);
            }
#          endif

            res = kill(chpid, SIGUSR1);
            if (res == ERROR) 
               error("unable to send SIGUSR1 to ping process\n\n");

#          if !defined(SUN) && !defined(BSD)
            if (pwd != NULL)
            {
#              ifdef _POSIX_SAVED_IDS
               res = setuid(pwd->pw_uid);
#              else
               res = seteuid(pwd->pw_uid);
#              endif

               if (res == ERROR)
               {
                  error("error setting [e]uid: %s\n\n", strerror(errno)); 
                  quit(ERROR);
               }
            }
#          endif

            if (debugging == 1)
            {
               (void)putchar('\n');
               (void)write(dblogfd, "\n", 1);
            }

            debug("got server's permission to ping\n");
            break;
         }

         else if (strncmp(readbuf, "NO PINGING", 10) == 0)
         {
            debug("server is not allowing pinging.. aborting pinger\n");

            killPinger();
            child = 0, chpid = 0;

            break;
         }
      }
   }
}


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


/* check for pings and respond with pongs */
void checkPings()
{
   int count = 0;  /* prevent any overflows */

   char *dataptr, *valptr;

   char pingval[8];
   char readbuf[MAXREADSIZE];


   while(1) 
   {
      memset(pingval, 0, sizeof(pingval));
      valptr = pingval, dataptr = NULL;

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

      gotAlrm = 0;

      while(1)
      {
         memset(readbuf, 0, sizeof(readbuf));
         recv_data(readbuf, sizeof(readbuf));

         /* debug("(in getPings) data is: %s\n", readbuf); */

         if (strncmp(readbuf, "PING", 4) == 0) break;
         else if (gotAlrm == 1)
         {
            error("timed out waiting for a ping..aborting\n\n");
            quit(ERROR);
         }
      }

      dataptr = strstr(readbuf, "PING");
      dataptr += 5; /* skip "PING " */ 

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

      /* debug("ping value: %s\n", pingval); */
      send_data("PONG %s", pingval);

      debug("(in child) going to top of loop for next ping\n\n");
   }
}


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


/* kill the ping process */
void killPinger()
{
   int res;
   debug("now killing the ping process (pid %d)\n", chpid);

# if !defined(SUN) && !defined(BSD)
#  ifdef _POSIX_SAVED_IDS
   res = setuid(0);
#  else
   res = seteuid(0);
#  endif

   if (res == ERROR)
   {
      error("error setting [e]uid: %s\n\n", strerror(errno)); 
      quit(ERROR);
   }
# endif

   res = kill(chpid, SIGTERM);
   if (res == ERROR)
      error("error killing the ping process: %s\n\n", strerror(errno));

   if (pwd != NULL)
   {
#    if !defined(SUN) && !defined(BSD)
#     ifdef _POSIX_SAVED_IDS
      res = setuid(pwd->pw_uid);
#     else
      res = seteuid(pwd->pw_uid);
#     endif

      if (res == ERROR)
      {
         error("error setting [e]uid: %s\n\n", strerror(errno)); 
         quit(ERROR);
      }
#    endif
   }

   child = chpid = 0;
}

