
/*
 *------------------------------------------------------------------
 *
 * $Source: /u1/jis/gw/cgw/statd/src/RCS/gw_status_utils.c,v $
 * $Revision: 1.4 $
 * $Date: 89/11/06 19:23:43 $
 * $State: Exp $
 * $Author: jon $
 * $Locker: jon $
 *
 * $Log:	gw_status_utils.c,v $
 * Revision 1.4  89/11/06  19:23:43  jon
 * increase buffer size (e19gw is too big)
 * 
 * Revision 1.3  89/03/11  23:09:11  jon
 * lint (or hc) is your friend
 * 
 * Revision 1.2  87/07/15  17:34:33  jon
 * Logs gateway restarts to LOG_NOTICE.
 * 
 * Revision 1.1  87/06/04  17:26:47  jon
 * Initial revision
 * 
 * 
 * 
 *------------------------------------------------------------------
 */

#ifndef lint
static char *rcsid_statd_c = "$Header: gw_status_utils.c,v 1.4 89/11/06 19:23:43 jon Locked $";
#endif	lint

#include <stdio.h>
#include <sys/errno.h>
#include <syslog.h>

#include "statd.h"
#include "types.h"
#include "status.h"
#include "param.h"

ext int errno;
ext long poll_interval;

char *errno_description ()
{
  ext int sys_nerr;
  ext char *sys_errlist[];
  static char str[10];

  if (errno <= sys_nerr)
    return (sys_errlist[errno]);
  else {
    sprintf (str, "%d", errno);
    return (str);
  }
}

int bind_status_socket (gw_socket)
     int *gw_socket;
{
  struct sockaddr_in sin;

  *gw_socket = socket(AF_INET, SOCK_DGRAM, 0);
  if (*gw_socket < 0) {
    syslog (LOG_ERR, "%s creating socket.", errno_description ());
    return (-1);
  }

  bzero((char *)&sin, sizeof (sin));
  sin.sin_family = AF_INET;
  sin.sin_port = GWSTAT_PORT;
  if (bind(*gw_socket, &sin, sizeof (sin)) < 0) {
    syslog (LOG_ERR, "%s. Binding socket.", errno_description ());
    return (-1);
  }
  return(0);
}

send_status_requests (gw, gw_socket)
     gateway_info gw[];
     int gw_socket;
{
  int cc;
  char sendbuf[4];

  while (gw->name != NULL) {
    if (gw->need_reply && (gw->request_packets_sent < MAX_REQUESTS) &&
	(gw->log_fd >= 0)) {
      cc = sendto (gw_socket, sendbuf, sizeof(sendbuf), 0, 
		   &(gw->sin), sizeof (gw->sin));
      if (cc < 0)
	syslog (LOG_ERR, "%s when sending to %s (%s)", errno_description (),
		gw->primary_name, inet_ntoa (gw->sin.sin_addr));
      else {
	syslog (LOG_DEBUG, "Sent status request to %s (%s)",
		gw->primary_name, inet_ntoa (gw->sin.sin_addr));
	if (++(gw->request_packets_sent) == MAX_REQUESTS) {
	  syslog (LOG_DEBUG, "Gateway %s (%s) not responding", 
		  gw->primary_name, inet_ntoa (gw->sin.sin_addr));
	}
      }
    }
    gw++;
  }
}

  
receive_status_replies (gw, gw_socket)
     gateway_info gw[];
     int gw_socket;
{
    char		recvbuf[2048];
    int cc;
    struct sockaddr_in	from_socket;
    int			from_ssize = sizeof(from_socket);
    gateway_info        *the_gw, *find_gateway_info();
    gw_status_header    header;

    strcpy (header.version, GW_STAT_HEADER_VERSION);
    bzero (&(header.mbz[0]), sizeof (header.mbz));

    while (1) {
      cc = recvfrom (gw_socket, recvbuf, sizeof (recvbuf), 0, &from_socket, from_ssize);
      if (cc < 0) {
	if (errno != EINTR)
	  syslog (LOG_ERR, "%s during receive.", errno_description ());
	break;
      }

      the_gw = find_gateway_info (gw, &from_socket);
      if (the_gw) {
	syslog (LOG_DEBUG, "Received %d bytes from %s", 
		cc, the_gw->primary_name);
	if (the_gw->need_reply == FALSE) {
	  syslog (LOG_NOTICE, "Received duplicate packet from %s.",
		  the_gw->primary_name);
	  continue;
	}
	the_gw->need_reply = FALSE;
	gettimeofday(&(the_gw->last_time), 0);
	bcopy (&(the_gw->last_time), &(header.time_received), sizeof (struct timeval));

	if (compute_length (&recvbuf[0], &(header.length_of_data), 
			    the_gw->primary_name)) continue; /* bad packet */

	if (write (the_gw->log_fd, &header, 
		   sizeof (header)) != sizeof (header)) {
	  syslog (LOG_ERR, "%s while writing header for %s.", 
		  errno_description (), the_gw->name);
	  continue;
	}
	if (write (the_gw->log_fd, &(recvbuf[0]), cc) != cc) {
	  syslog (LOG_ERR, "%s while writing status record for %s.", 
		  errno_description (), the_gw->name);
	  continue;
	}
      }
      else
	syslog (LOG_WARNING, "Received %d bytes from unknown host (%s)",
		cc, inet_ntoa (from_socket.sin_addr));
    }
  }

int compute_length (statbuf, length, name)
     char *statbuf;
     int *length;
     char *name; /* for error messages */
{
  netinfo *netip;
  statpkt *status = (statpkt *) statbuf;
  int i;

  /* version sanity check and length computation */
  if (status->version != STAT_VERSION) {
    syslog (LOG_ERR, "Unknown status record version (%d) from %s.\n",
	    status->version, name);
    return (-1);
  }

  if (status->uptime < poll_interval) 
    syslog (LOG_NOTICE, "%s has been restarted.", name);

  *length = sizeof (statpkt);
  for (i = 0, netip = (netinfo *) (status + 1); i < status->nnets; i++) {
    if ((netip->type < 0) || (netip->type >= T_MAX)) {
      syslog (LOG_ERR, "Bad netinfo structure (type %d) froom %s.\n",
	      netip->type, name);
      return (-1);
    }
    *length += sizeof (netinfo) + netip->devlen;
    netip = (netinfo *) ((byte *) (netip + 1) + netip->devlen);
  }
  return(0);
}
  
