/*
 * print PPP statistics:
 * 	pppstats [-i interval] [-v] [-r] [-c] [interface]
 *
 *   -i <update interval in seconds>
 *   -v Verbose mode for default display
 *   -r Show compression ratio in default display
 *   -c Show Compression statistics instead of default display
 *
 *
 * History:
 *		Felipe A. Rodriguez, modified for GateKeeper.App  8/29/95
 *					far@ix.netcom.com
 *
 *      perkins@cps.msu.edu: Added compression statistics and alternate 
 *                display. 11/94
 *
 *	Brad Parker (brad@cayman.com) 6/92
 *
 * from the original "slstats" by Van Jaconson
 *
 * Copyright (c) 1989 Regents of the University of California.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms are permitted
 * provided that the above copyright notice and this paragraph are
 * duplicated in all such forms and that any documentation,
 * advertising materials, and other materials related to such
 * distribution and use acknowledge that the software was developed
 * by the University of California, Berkeley.  The name of the
 * University may not be used to endorse or promote products derived
 * from this software without specific prior written permission.
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 *	Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:
 *	- Initial distribution.
 */

//#ifndef lint
//static char rcsid[] = "$Id: pppstats.c,v 1.10 1995/06/30 01:58:25 paulus Exp //$";
//#endif

#include <ctype.h>
#include <errno.h>
#include <nlist.h>
#include <stdio.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/param.h>
#include <sys/types.h>
#include <sys/ioctl.h>

#include <./ppp/net/ppp_defs.h>

#ifdef __svr4__
#include <sys/stropts.h>
#include <net/pppio.h>		/* SVR4, Solaris 2, etc. */

#else
#include <sys/socket.h>
#include <net/if.h>

#ifndef STREAMS
#include <./ppp/net/if_ppp.h>		/* BSD, Linux, NeXT, etc. */

#else				/* SunOS 4, AIX 4, OSF/1, etc. */
#define PPP_STATS	1	/* should be defined iff it is in ppp_if.c */
#include <sys/stream.h>
#include <net/ppp_str.h>
#endif
#endif

int	vflag, rflag, cflag;
unsigned interval = 5;
int	unit;
int s = 0;			/* socket file descriptor */
int	signalled;		/* set if alarm goes off "early" */

extern	char *malloc();

				// GateKeeper.app NeXTStep modifications 8/29/95

	struct ppp_stats cur, old, tot;
  	struct ppp_comp_stats ccs, ocs, lastCTot;
  	volatile int line = 0;

#define BUFFERSIZE 2048
#import <objc/Object.h>								// recognize type id
#import "CommandScroll.h"
#import <bsd/memory.h>
#import <bsd/libc.h>
#import <appkit/Application.h>
#import <defaults/defaults.h>
#import "pppstats.h"

    static char outputBuffer[BUFFERSIZE];
    id pppstatsView;

void get_ppp_stats(struct ppp_stats *curp);
void get_ppp_cstats(struct ppp_comp_stats *csp);
void displayDataPoint();							// display a line of output
void displayHeader();


#define V(offset) (line % 20 ? cur.offset - old.offset:cur.offset - tot.offset)
#define W(offset) (line % 20 ? ccs.offset - ocs.offset: ccs.offset)

#define CRATE(comp, inc, unc)	((unc) == 0? 0.0: \
				 1.0 - (double)((comp) + (inc)) / (unc))

//*****************************************************************************
//
// 		open IP datagram socket 
//
//*****************************************************************************

void openSocket(id aView)
{
	if(s > 0)
		close(s);
	if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) 
		perror("couldn't create IP socket");
    memset(&old, 0, sizeof(old));				// set mem to 0
    memset(&ocs, 0, sizeof(ocs));
    memset(&ccs, 0, sizeof(ccs));
	memset(&cur, 0, sizeof(cur));
	pppstatsView = aView;						// view to display pppstats in
  	line = 0;
}
//*****************************************************************************
//
// Print a running summary of interface statistics.
// Repeat display every interval seconds, showing statistics
// collected over that interval.  Assumes that interval is non-zero.
// First line printed at top of screen is always cumulative.
//
//	GateKeeper mod returns whether interface was inactive since last measure
//
//*****************************************************************************

struct pppIO * intpr(void)
{
	get_ppp_stats(&cur);
										// if we totaled on this measurement
	if ((line % 20) == 0) 				// cycle, load actual traffic
		{								// measurement for this cycle
		if(line != 0)					// show total for previous 20 lines
			{
			displayHeader();
			displayDataPoint();			// unless this is first line
			}
		tot = cur;						// save a total every 20 lines
		line++;
		pppIOstat.inPkts = V(p.ppp_ibytes);
		pppIOstat.outPkts = V(p.ppp_obytes);
		if(line != 1)
			displayDataPoint();			// if we totaled, also show meas for
		}								// this period
	else
		{
		if(line == 1)					// special case display of header
			displayHeader();
		displayDataPoint();
		pppIOstat.inPkts = V(p.ppp_ibytes);		
		pppIOstat.outPkts = V(p.ppp_obytes);	
		line++;
		}
	old = cur;

	return &pppIOstat;						 
}										
//*****************************************************************************
//
// 		display a data point 
//
//*****************************************************************************

void displayDataPoint()
{
	sprintf(outputBuffer, "%8d %6d %6d %6d %6d",
				V(p.ppp_ibytes),
				V(p.ppp_ipackets), V(vj.vjs_compressedin),
				V(vj.vjs_uncompressedin), V(vj.vjs_errorin));
	if(pppstatsView)
		[pppstatsView appendStringUseFixedFont:outputBuffer];
	sprintf(outputBuffer, "  | %8d %6d %6d %6d %6d", V(p.ppp_obytes),
		   		V(p.ppp_opackets), V(vj.vjs_compressed),
		   		V(vj.vjs_packets) - V(vj.vjs_compressed),
		  		 V(p.ppp_opackets) - V(vj.vjs_packets));
	if(pppstatsView)
		[pppstatsView appendStringUseFixedFont:outputBuffer];
	if(pppstatsView)
		[pppstatsView appendStringUseFixedFont:"\n"];
}
//*****************************************************************************
//
// 		display header 
//
//*****************************************************************************

void displayHeader()
{
	if(pppstatsView)
		[pppstatsView appendStringUseFixedFont:"\n"];
	sprintf(outputBuffer,"%8.8s %6.6s %6.6s %6.6s %6.6s",
			"in", "pack", "comp", "uncomp", "err");
	if(pppstatsView)
		[pppstatsView appendStringUseFixedFont:outputBuffer];
	sprintf(outputBuffer,"  | %8.8s %6.6s %6.6s %6.6s %6.6s",
			"out", "pack", "comp", "uncomp", "ip");
	if(pppstatsView)
		[pppstatsView appendStringUseFixedFont:outputBuffer];
	if(pppstatsView)
		[pppstatsView appendStringUseFixedFont:"\n"];
}

#ifndef __svr4__
void get_ppp_stats(curp)
    struct ppp_stats *curp;
{
    struct ifpppstatsreq req;

#ifdef _linux_
    req.stats_ptr = &req.stats;
#undef ifr_name
#define ifr_name ifr__name
#endif

    sprintf(req.ifr_name, "ppp%d", unit);
    if (ioctl(s, SIOCGPPPSTATS, &req) < 0) {
	if (errno == ENOTTY)
	    fprintf(stderr, "pppstats: kernel support missing\n");
	else
	    perror("ioctl(SIOCGPPPSTATS)");
//	exit(1);
    }
    *curp = req.stats;
}

void get_ppp_cstats(csp)
    struct ppp_comp_stats *csp;
{
    struct ifpppcstatsreq creq;

#ifdef _linux_
    creq.stats_ptr = &creq.stats;
#undef  ifr_name
#define ifr_name ifr__name
#endif

    sprintf(creq.ifr_name, "ppp%d", unit);
    if (ioctl(s, SIOCGPPPCSTATS, &creq) < 0) {
	if (errno == ENOTTY) {
	    fprintf(stderr, "pppstats: no kernel compression support\n");
	    if (cflag)
		exit(1);
	    rflag = 0;
	} else {
	    perror("ioctl(SIOCGPPPCSTATS)");
	    exit(1);
	}
    }
    *csp = creq.stats;
}
#else	/* __svr4__ */
get_ppp_stats(curp)
    struct ppp_stats *curp;
{
    if (strioctl(s, PPPIO_GETSTAT, curp, 0, sizeof(*curp)) < 0) {
	if (errno == EINVAL)
	    fprintf(stderr, "pppstats: kernel support missing\n");
	else
	    perror("pppstats: Couldn't get statistics");
	exit(1);
    }
}

get_ppp_cstats(csp)
    struct ppp_comp_stats *csp;
{
    if (strioctl(s, PPPIO_GETCSTAT, csp, 0, sizeof(*csp)) < 0) {
	if (errno == ENOTTY) {
	    fprintf(stderr, "pppstats: no kernel compression support\n");
	    if (cflag)
		exit(1);
	    rflag = 0;
	} else {
	    perror("pppstats: Couldn't get compression statistics");
	    exit(1);
	}
    }
}

int
strioctl(fd, cmd, ptr, ilen, olen)
    int fd, cmd, ilen, olen;
    char *ptr;
{
    struct strioctl str;

    str.ic_cmd = cmd;
    str.ic_timout = 0;
    str.ic_len = ilen;
    str.ic_dp = ptr;
    if (ioctl(fd, I_STR, &str) == -1)
	return -1;
    if (str.ic_len != olen)
	fprintf(stderr, "strioctl: expected %d bytes, got %d for cmd %x\n",
	       olen, str.ic_len, cmd);
    return 0;
}
#endif /* __svr4__ */

