#include "headers.h"

/* this file has the signal handlers for timeouts, gen. signals, etc. */

/* FIX - MUST BE REENTRANT.. OR "SAFE"..                 */
/*     - this probably includes functions it calls too.. */

/* called for things such as SIGINT, SIGTERM, etc. */
RETSIGTYPE sighandler(int signum)
{
   int res;    /* results of various functions */
   int status; /* used with waitpid()          */

   register int i;
 
   if (signum == SIGUSR1)
   {
      stopped = 0;
      return;
   }

   else if (signum == SIGPIPE)
   {
      error("SIGPIPE received, killing myself...\n\n");
      longjmp(doquit, ERROR);
   }

   else if (signum == SIGCHLD)
   {
      /* FIX - NOT SAFE.. BLOCK SIGNALS */
      signal(SIGCHLD, sighandler); /* restart it */
      
      for (i = 0; i < MAXCONNS; i++)
      {
         if (clients[i].free == 1) continue;

         errno = 0;
         res = waitpid((clients[i]).pidstats[0].pid, &status, WNOHANG);

         if (res == 0) continue;
         else if ((res == ERROR) || (WIFEXITED(status)))
         {
            if (errno <= 0)
            {
               if (clients[i].pidstats[0].pid > 0)
               {
                  debug("child (pid %d) has exited..\n\n",
                        clients[i].pidstats[0].pid);

                  memset(&clients[i], 0, sizeof(struct client));

                  (clients[i]).free = 1;
                  (clients[i]).ID = ERROR;
                  (clients[i]).pidstats[0].pid = ERROR;
                  (clients[i]).pidstats[1].pid = ERROR;

                  nofree = 0;

                  /* continue; */
                  break;
               }
            }

            else
            {
               if (errno != ECHILD)
                  error("waitpid() result: %s\n\n", strerror(errno));

               if (clients[i].pidstats[0].pid > 0)
               {
                  debug("child (pid %d) has exited..\n\n",
                        clients[i].pidstats[0].pid);

                  memset(&clients[i], 0, sizeof(struct client));

                  (clients[i]).free = 1;

                  (clients[i]).ID = ERROR;
                  (clients[i]).pidstats[0].pid = ERROR;
                  (clients[i]).pidstats[1].pid = ERROR;

                  nofree = 0;

                  /* continue; */
                  break;
               }
            }
         }
      }
   }

   else 
   {
      error("received a signal to abort in sighandler.. signal was %d\n\n",
            signum);

      /* FIX - NOT SAFE */
      longjmp(doquit, ABORT);
   }
}


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


/* called when we time out waiting for ID */
RETSIGTYPE IDtimeout(int signum)
{
   error("timedout while waiting for ID\n\n");
   timeout = 1;
}


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


/* called when we time out auth'ing ID */
RETSIGTYPE authIDtimeout(int signum)
{
   error("timeout while authenticating ID\n\n");
   timeout = 1;
}


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


/* called when we time out waiting for an instruction */
RETSIGTYPE InsTimeout(int signum)
{
   error("timeout while waiting for an instruction.. exiting\n\n");
   longjmp(doquit, ERROR);
}


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


/* when we time out waiting for or sending "OKAY */
RETSIGTYPE okayTimeout(int sig)
{
   error("timed out waiting or sending OKAY\n\n");
   timeout = 1;
}


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


/* called when we timeout waiting for pong */
RETSIGTYPE pingTimeout(int signum)
{
   error("timed out waiting for ping response.. exiting\n\n");
   longjmp(doquit, ERROR);
}


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


/* sighandler when we get OK from child to restart */
RETSIGTYPE startUp(int signum)
{
   if (debugging == 1)
   {
      char *error = "got SIGUSR2 from child (free to continue)\n";
      (void)write(STDOUT, error, strlen(error));
   }

   clients[curClient].running = 1; /* set us back running */
   return;
}


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


/* sighandler when we are notified of new data from parent */
RETSIGTYPE gotNewData(int signum)
{
   if (debugging == 1)
   {
      char *error = "got SIGUSR1 from parent (new data available)\n";
      (void)write(STDOUT, error, strlen(error));
   }

   signal(SIGUSR1, gotNewData); /* this has to always be up */
   clients[curClient].newData = 1; /* set us back running */

   return;
}
