#if !defined(lint) && !defined(__INSIGHT__)
static char sos__rcsid[] = "stdioping.c,v 1.2 1995/05/18 20:27:41 seth Exp";
static char sos__copyright[] = "Copyright (c) 1994, 1995 SOS Corporation";
static char sos__contact[] = "SOS Corporation <manager@soscorp.com> +1 800 SOS UNIX";
#endif /* not lint */

/*
 * ++Copyright Released Product++
 *
 * Copyright (c) 1994, 1995 Sources of Supply Corporation ("SOS").
 * All rights reserved.
 *
 * The SOS Released Product License Agreement specifies the terms and
 * conditions for redistribution.  You may find the License Agreement
 * in the file LICENSE.
 *
 * SOS Corporation
 * 461 5th Ave.; 16th floor
 * New York, NY 10017
 *
 * +1 800 SOS UNIX
 * <sos-info@soscorp.com>
 *
 * --Copyright Released Product--
 */

/*
 * Measure response time and connectivity via STDIO
 *
 */

#include "sos.h"

unsigned int success, sent;
struct timeval max = { 0, 0 };
struct timeval min = { INT_MAX, INT_MAX };
struct timeval timesum = { 0, 0 };
int maxcount = INT_MAX;
int schedeof = 0;

#define USEC(val) ((val)->tv_sec*1000000+(val)->tv_usec)
#define MSEC(val) ((val)->tv_sec*1000+(val)->tv_usec/1000)

char inbuf[64], outbuf[64];
char *prog;
char *host = "stdio";
int infd = 0;
int outfd = 1;

void sendpacket();
static void tvadd();
static void tvsub();
void tcpeof();
void sigint();

main(int argc, char *argv[])
{
  int tmpvar;
  int getopterr = 0;
  int port = 7;
  extern char *optarg;
  extern int optind;
  struct timeval current = { 0, 0 };
  struct timeval diff = { 0, 0 };

  prog = argv[0];

  while ((tmpvar = getopt(argc,argv, "c:")) != -1)
    switch(tmpvar)
      {
      case 'c':
	maxcount = atoi(optarg);
	break;
      case '?':
	getopterr++;
      }

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

  signal(SIGALRM,sendpacket);
  signal(SIGINT,sigint);

  sendpacket();
  while (1)
    {
      int width = infd+1;
      fd_set readset;

      FD_SET(infd,&readset);

      if (select(width, &readset, NULL, NULL, NULL) < 0)
	{
	  if (errno = EINTR)
	    continue;
	  fprintf(stderr,"%s: select error: %s\n",prog,strerror(errno));
	  exit(1);
	}

      if (FD_ISSET(infd, &readset))
	{
	  int bytesin = 0;
	  int ret = 0;

	  while (bytesin < sizeof(inbuf))
	    {
	      if ((ret = read(infd, inbuf+bytesin, sizeof(inbuf)-bytesin)) < 1)
		{
		  if (errno = EINTR)
		    continue;
		  fprintf(stderr,"%s: read: %s\n",prog,strerror(errno));
		  exit(3);
		}
	      bytesin += ret;
	    }
	  gettimeofday(&current,NULL);
	  tvsub(&diff, &current, (struct timeval *)inbuf);

	  if (timercmp(&diff, &max, >))
	    {
	      max.tv_sec = diff.tv_sec;
	      max.tv_usec = diff.tv_usec;
	    }

	  if (timercmp(&diff, &min, <))
	    {
	      min.tv_sec = diff.tv_sec;
	      min.tv_usec = diff.tv_usec;
	    }

	  tvadd(&timesum,&timesum,&diff);
	  success++;

	  fprintf(stderr,"%d bytes from %s: seq=%d time=%d ms\n",sizeof(inbuf),host,*((int *)(inbuf+sizeof(struct timeval))), MSEC(&diff));
	}
    }

  tcpeof();
}

void tcpeof()
{
  unsigned int avgmsec;

  fprintf(stderr,"------%s STDIOPING Statistics------\n",host);
  fprintf(stderr,"%d packets transmitted, %d packets received, %d%% packet loss\n",sent,success,(sent-success)*100/sent);
  avgmsec = MSEC(&timesum) / success;
  fprintf(stderr,"round-trip (ms) min/avg/max = %d/%d/%d\n",MSEC(&min),avgmsec,MSEC(&max));
  exit(0);
}

void sendpacket()
{
  int bytesout = 0;
  int ret;

  if (schedeof || sent >= maxcount)
    tcpeof();

  gettimeofday((struct timeval *)outbuf, NULL);
  *((int *)(outbuf + sizeof(struct timeval))) = sent++;

  while (bytesout < sizeof(outbuf))
    {
      if ((ret = write(outfd,outbuf+bytesout,sizeof(outbuf)-bytesout)) < 1)
	{
	  fprintf(stderr,"%s: read: %s\n",prog,strerror(errno));
	  exit(3);
	}
      bytesout += ret;
    }

  alarm(1);
}

static void
tvadd(tsum, t0, t1)
struct timeval *tsum, *t0, *t1;
{
    
  tsum->tv_sec = t0->tv_sec + t1->tv_sec;
  tsum->tv_usec = t0->tv_usec + t1->tv_usec;
  if (tsum->tv_usec > 1000000)
    tsum->tv_sec++, tsum->tv_usec -= 1000000;
}

static void
tvsub(tdiff, t1, t0)
struct timeval *tdiff, *t1, *t0;
{

  tdiff->tv_sec = t1->tv_sec - t0->tv_sec;
  tdiff->tv_usec = t1->tv_usec - t0->tv_usec;
  if (tdiff->tv_usec < 0)
    tdiff->tv_sec--, tdiff->tv_usec += 1000000;
}

void
sigint()
{
  schedeof = 1;
}
