/******************************************************************************
 *    pingky - Query nodes and report problems to the problem file            *
 *									      *
 *  Version 1.0       Author: WB Norton  Merit Computer Network               *
 *  Modification History:                                                     *
 *  written 5/18/89   Bill Norton, Merit Computer Network                     *
 *  5/23/89 - Modified NetQuery.c to fork and exec ping itself for speed @wes *
 *            Called Init routine to initialize netquery routines	      *
 *  08/16/89 - Modified fileio.c to parse netprotocols and argv during read  *
 *		instead of each time through module.    @wbn1		      *
 *  09/14/89 - Checking NSS logical links, and error counters		      *
 *  10/01/89 - Added Generic Error - Just create a protocol I don't understand*
 *		and I check for the existance of Generic/<addr>.<PROTO>       *
 *		if it doesn't exists we'll print the generic protocol	      *
 ******************************************************************************/
/*
  * Copyright 1989
  * The Regents of the University of Michigan
  * All Rights Reserved
  *
  * Permission to use, copy, modify, and distribute this software and its
  * documentation for any purpose and without fee is hereby granted, provided
  * that the above copyright notice and this permission notice appear in
  * all copies of the software and derivative works or modified versions
  * thereof, and that both that copyright notice and this permission
  * notice appear in supporting documentation.
  *
  * The software is provided "as is" and the University of Michigan
  * disclaims all warranties with regard to this software, including
  * all implied warranties of merchantability and fitness.  In no event
  * shall the University of Michigan be liable for any special, direct,
  * indirect, or consequential damages or any damages whatsoever
  * resulting from loss of use, data or profits, whether in an action of
  * contract, negligence or other tortious action, arising out of or in
  * connection with the use or performance of this software.
  */
#include <time.h>
#include <stdio.h>
#include <signal.h>
#include "../ProblemManager/ProblemManager.h" /* ProblemManager Code */	
#include "../Ctools/ctools.h"		/* Misc Routines */
#include "Hostfileio.h"
#include "netquery.h"
#include "version.h"
/*#define DEBUG 1 /* */

#define NET_BROKE_DELAY 20    /* Delay in secs between cycles if things are */
                              /* Broken  - short delay */
#define NET_OK_DELAY 120  /* Delay in secs if no problems were detected last */
                          /* cycle through the hostfile                      */

char *programname;

static char *DefaultPingkyDir=".";
static char Checking_File[100];         /* What node are we Checking_File? */
static char cycletime[100];             /* How long did pingky take to cycle */
static char logfile[100];               /* Where do we log things */
static char Problem_File[100];          /* Where do we log things */
static char hostfile[100];              /* List of nodes we are Testing */

#define SLEEPING_LONG_NAP 1
#define SLEEPING_SHORT_NAP 2
#define POLLING 3

#define CHECKINGINTERVAL 60

static char CollectorState=0;
static char *Name;
/****************************************************************
 *      Init:    Initialize pingky filenames etc.               *
 *               Initialize NetQuery Layer routines             *
 ****************************************************************/
Init()
{
    init_netquery();		/* initialize net_query variables @wes */
}

EXIT()
{
char buffer[100];
extern int In_Critical_Section;

	sprintf(buffer,"%s: interrupt.......\n",programname);
	fprintf(stderr,buffer);
	Log(buffer,logfile);
        if ( In_Critical_Section ) {
                Log("programname: Interrupt during Fileio",programname,logfile);
		return;	/* I was half way writing/reading the PROBLEM.FILE!!!*/
        }
        exit( 0 );
}

#ifdef ALRM
AlarmClock()
{
char buffer[100];

	switch( CollectorState ) {
	case SLEEPING_LONG_NAP:	strcpy( buffer, "SLN - Sleeping a Long Nap"); break;
	case SLEEPING_SHORT_NAP:strcpy( buffer, "SSN  - Sleeping a Short Nap"); break;
	case POLLING:	strcpy( buffer, "POL "); 
			strcat( buffer, " Checking: ");
			strcat( buffer, Name );
			break;
	default: strcpy( buffer,"ERR "); break;
	}
	LogChecking( buffer, Checking_File );
   	signal(SIGALRM,AlarmClock);
   	alarm(CHECKINGINTERVAL);
}
#endif



/****************************************************************
 *       pingky main:     					*
 *                    see if a node is up and tell the problem  *
 *                    manager of the results			* 
 ****************************************************************/
main(argc,argv)
int argc;
char *argv[];
{
FILE *stream;
long StartClock;
int ElapsedTime;
int i,j;
char buffer[100];
char *service,*UniqueID;  /* Temp pointers to make code more readable */
long ProblemFileLastChanged;	/* Last time PROBLEM.FILE was updated */
char *pingkydir,*getenv();
struct NodeType *Node;
extern int NumNodes;

   if ( argc != 1 ) {
	fprintf( stderr , "usage: %s \n" , argv[0] );
	exit(1);
   }

   sprintf(buffer,"ps aux | grep %s | grep -v grep | grep -v %d", argv[0], getpid() );
   if ( ! system(buffer) ) {
	fprintf(stderr,"%s ERROR: %s already running\n",argv[0],argv[0]);
	exit(1);
   }

    programname=argv[0];
    if ((pingkydir=getenv("PINGKYDIR"))==NULL) pingkydir=DefaultPingkyDir;
    strcpy(Checking_File,pingkydir); strcat(Checking_File,"/CHECKING");
    strcpy(cycletime,pingkydir); strcat(cycletime,"/pingky.cycle");
    strcpy(logfile,pingkydir); strcat(logfile,"/problemlog");
    strcpy(hostfile,pingkydir); strcat(hostfile,"/hostfile");
    strcpy(Problem_File,pingkydir); strcat(Problem_File,"/PROBLEM.FILE");

   sprintf(buffer,"Starting %s\n",Version);
   printf(buffer);
   Log(buffer,logfile);

   signal( SIGINT, EXIT );
   signal( SIGHUP, EXIT );
#ifdef ALRM
   signal(SIGALRM,AlarmClock);
   alarm( 10 ); 
#endif

   Init();

   while(1) {
      CollectorState=POLLING;
	LogChecking("POL - Rover is patrolling the Net",Checking_File);
      Node=ReadNodeFile(hostfile);       /* read hostfile */
      StartClock=time(0);
      /* For each entry in the hostfile, ping and inform Manager of results */
      for(i=0; Node[i].NodeName!=NULL; i++) {
         Name=Node[i].NodeName;
         UniqueID=Node[i].UniqueID;
	 if ( (i%20)==0 ) {
		char msg[80];
		sprintf( msg,"POL - Checking %s ....",Name);
		LogChecking( msg, Checking_File );
	 }

	 service=Node[i].Test[0].argv[0];

         if ( NetQuery(UniqueID,&Node[i].Test[0]) == ITWORKS ) {
            Problem_Manager( DELETE_PROBLEM, service, Name, UniqueID , NULL);

            for( j=1; Node[i].Test[j].argv[0] != NULL; j++) {
		service=Node[i].Test[j].argv[0];
                if ( NetQuery(UniqueID,&Node[i].Test[j]) == ITWORKS) 
		   Problem_Manager( DELETE_PROBLEM,service,Name,UniqueID, NULL);
	   	else 
                   Problem_Manager( ADD_PROBLEM,service,Name,UniqueID,NULL);
            }

 	 }
         else 					/* Node is NOT responding */
             Problem_Manager( ADD_PRIMARY_PROBLEM, service, Name, UniqueID , NULL); 
       }
       /**********************************************************************/

       ElapsedTime=time(0)-StartClock;
       if ((stream=fopen(cycletime,"w")) == NULL)
          syserr("fopen pingky.cycle");
       fprintf(stream,"%2.2d:%2.2d",ElapsedTime/60,ElapsedTime%60);
       if (fclose(stream) == -1) syserr("fclose pingky cycle");

       if (FileChanged(Problem_File, &ProblemFileLastChanged) ) {
          CollectorState=SLEEPING_SHORT_NAP;
	  LogChecking("SSN - Rover is taking a Short Nap zzz ;-)",Checking_File);
          sleep(NET_BROKE_DELAY);  /* Things are changing-sleep short */
       } else {
          CollectorState=SLEEPING_LONG_NAP;
	  LogChecking("SLN - Rover is taking a snooze zzzz |-O",Checking_File);
	  sleep(NET_OK_DELAY);  /* Give network a rest - all is OK */
       }
    }
}
