/* Hang around gathering stats from C gateways for later analysis */

/*
 *------------------------------------------------------------------
 *
 * $Source: /achilles/u1/jis/gw/cgw/statd/src/RCS/statd.c,v $
 * $Revision: 1.2 $
 * $Date: 87/08/12 19:10:24 $
 * $State: Exp $
 * $Author: jon $
 * $Locker: jon $
 *
 * $Log:	statd.c,v $
 * Revision 1.2  87/08/12  19:10:24  jon
 * Doesn't abort when next itimer value is <= 0, but instead logs it and 
 * sets the timer to the poll interval.  Something fishy is going on.
 * 
 * Revision 1.1  87/06/04  17:26:26  jon
 * Initial revision
 * 
 * 
 * 
 *------------------------------------------------------------------
 */

#ifndef lint
static char *rcsid_statd_c = "$Header: statd.c,v 1.2 87/08/12 19:10:24 jon Locked $";
#endif	lint

#include <syslog.h>
#include <stdio.h>
#include <setjmp.h>
#include <signal.h>
#include "statd.h"

/* these should be grouped in a invocation data structure returned by
   read_config_info */
static gateway_info gateways[MAX_GATEWAYS];  /* dynamic allocation later */
static int gw_socket;  
long poll_interval, last_poll_time;

#define NOW (time((time_t *)NULL))
#define WHOAMI "statd"

static jmp_buf request_env;

main (argc, argv)
     int argc;
     char **argv;
{
  int timeout (), need_replies (), setup_poll ();
  struct itimerval itv;

  openlog (WHOAMI, 0, LOG_LOCAL5 /* that's us for now ... */);

  read_config_file (CONFIG_FILE, gateways);

  bind_status_socket (&gw_socket);

  itv.it_interval.tv_sec = 0;
  itv.it_interval.tv_usec = 0;
  itv.it_value.tv_usec = 0;
  last_poll_time = 0;
  signal (SIGALRM, timeout);

  while (1) {
    if (_setjmp (request_env)) {
      syslog (LOG_DEBUG, "longjmp to request_env");} 

    if (poll_interval + last_poll_time <= NOW) {
      setup_poll ();
      last_poll_time = NOW;
    }

    if (need_replies (gateways)) {
      send_status_requests (gateways, gw_socket);
      itv.it_value.tv_sec = REQUEST_INTERVAL;
      setitimer (ITIMER_REAL, &itv, (struct itimerval *)NULL);
      receive_status_replies (gateways, gw_socket);
    }
    else {
      itv.it_value.tv_sec = last_poll_time + poll_interval - NOW;
      if (itv.it_value.tv_sec <= 0) {
	syslog (LOG_ERR, 
		"Computed next poll time is in the past! (%d %d %d %d)",
		last_poll_time, poll_interval, NOW, itv.it_value.tv_sec);
	itv.it_value.tv_sec = poll_interval;
/*	abort (); */
      }
      setitimer (ITIMER_REAL, &itv, (struct itimerval *)NULL);
      sigpause (0); 
    }
  }
}

int need_replies (gw)
     gateway_info gw[];
{
  while (gw->name != NULL) {
    if (gw->need_reply) return (TRUE);
    gw++;
  }
  return (FALSE);
}

/* Will this always work given gateways are multi-homed? */

gateway_info *find_gateway_info (gws, addr)
     gateway_info gws[];
     struct sockaddr_in *addr;
{
  gateway_info *gw = gws;

  while (gw->name != NULL) {
    if (gw->sin.sin_addr.s_addr == addr->sin_addr.s_addr) return (gw);
    gw++;
  }
  return (NULL);
}

abort ()
{
  exit (1);
}

int timeout()
{
/*  _longjmp (request_env, 1); */
  return(0);
}

setup_poll ()
{
  gateway_info *gw = gateways;

  syslog (LOG_DEBUG, "Starting poll.");
  while (gw->name != NULL) {
    if (gw->log_fd >= 0) {
      if ((gw->request_packets_sent > 1) && !(gw->need_reply)) 
	syslog (LOG_INFO, "Sent %d request packets to %s.",
		gw->request_packets_sent, gw->primary_name);
      if (gw->need_reply && (gw->request_packets_sent > 0)) 
	syslog (LOG_WARNING,
		"%s did not respond last polling cycle (%d packets sent.)",
		gw->primary_name, gw->request_packets_sent);
      gw->need_reply = TRUE;
      gw->request_packets_sent = 0;
    }
    gw++;
  }
}
