From: avalon@coombs.anu.edu.au (Darren Reed)
Newsgroups: alt.irc
Subject: stats programs...
Date: 11 Dec 92 21:18:09 GMT
Organization: Australian National University
NNTP-Posting-Host: 150.203.76.2

There has bee a lot of interest (seemingly) in stats recently...
well here is a couple of programs I wrote way back to check up on
how the net is behaving and whats happening where...both programs
run as clients and use a bit of curses to do their work.

I guess if you made them log what retrieved rather than display it,
and then ran it for a while (week at least!) you could compile some
rather interesting stats which might even be of use.

avalon

-cut here--cut here--cut here--cut here--cut here--cut here--cut here--cut here-
# This is a shell archive.  Save it in a file, remove anything before
# this line, and then unpack it by entering "sh file".  Note, it may
# create directories; files and directories will be owned by you and
# have default permissions.
#
# This archive contains:
#
#	stat/Makefile
#	stat/README
#	stat/cmdmon.c
#	stat/flowmon.c
#
echo x - stat/Makefile
sed 's/^X//' >stat/Makefile << 'END-of-stat/Makefile'
X# Makefile (C)1992 Darren Reed
X# Makefile for realtime server stats clients
X#
XLIBS=-lcurses -ltermcap
XCFLAGS=-O
XPROGS=cmdmon flowmon
X
Xall: $(PROGS)
X
Xcmdmon: cmdmon.c
X	$(CC) $@.c $(CFLAGS) -o $@ $(LIBS)
X
Xflowmon: flowmon.c
X	$(CC) $@.c $(CFLAGS) -o $@ $(LIBS)
X
Xclean:
X	/bin/rm -f core *.o $(PROGS)
END-of-stat/Makefile
echo x - stat/README
sed 's/^X//' >stat/README << 'END-of-stat/README'
X
XSimple...
X
XEdit them to set the nicks, user info and server and then get them compiled.
X
Xthen run using
X
Xcmdmon [ server [ port [ updatedelay ] ] ]
Xflowmon [ server [ port [ updatedelay ] ] ]
X
XBrief.
X------
X
Xcmdmon
X
X   Shows the changing use of the most used commands on the server in sorted
Xorder of most used to least used.
X
Xflowmon
X
X   Shows the flow of data into a server and out its links.  Can be very
Xuseful.
X
XBoth use curses to maintain the display and should show as many entries
Xas possible.
X
XThere are probably bugs somewhere too.
END-of-stat/README
echo x - stat/cmdmon.c
sed 's/^X//' >stat/cmdmon.c << 'END-of-stat/cmdmon.c'
X/*
X * cmdmon.c (C)1992 Darren Reed
X * monitor number of commands processed by a server
X *
X */
X#include <sys/types.h>
X#include <sys/time.h>
X#include <netinet/in.h>
X#include <sys/socket.h>
X#include <stdio.h>
X#include <curses.h>
X#include <netdb.h>
X/*
X * change this.
X */
Xchar signon[] ="NICK changethis\n\rUSER foobar foobar foobar foobar\n\r";
X/*
X * leave these
X */
Xchar pong[] = "PONG ping\n\r";
Xchar statsm[] ="STATS M\n\r";
X
X#define	SERVERIP	"a.server.ip.goes.here"
X#define	SERVERPORT	-1
X#define	UPDATEDELAY	60
X
Xchar	buff[512], serv[60], nick[20], msg[20], *server;
Xint	cnt, port;
X
Xmain(argc, argv)
Xint	argc;
Xchar	*argv[];
X{
X	struct sockaddr_in serv;
X	FILE	*f;
X	int	sock, sl, statsl, pl, num, fields, off = 0;
X	long	last, lastm, waittime;
X	char	*t;
X	struct	hostent *hp = NULL;
X
X	sl = strlen(signon);
X	pl = strlen(pong);
X	statsl = strlen(statsm);
X	bzero(&serv, sizeof(serv));
X	/*
X	 * ip# of server to connect to
X	 */
X	server = (argc > 1) ? argv[1] : SERVERIP;
X	port = (argc > 2 ) ? atoi(argv[2]) : SERVERPORT;
X	waittime = (argc > 3) ? atoi(argv[3]) : UPDATEDELAY;
X
X	if (!isdigit(*server))
X	    {
X		hp = gethostbyname(server);
X		if (hp)
X			bcopy(hp->h_addr_list[0], (char *)&serv.sin_addr,
X				sizeof(struct in_addr));
X		else
X		    {
X			printf("Couldnt lookup %s\n",server);
X			exit(0);
X		    }
X	    }
X	else
X		serv.sin_addr.s_addr = inet_addr(server);
X	serv.sin_port = htons(port);
X	serv.sin_family = AF_INET;
X
X	if ((sock = socket(AF_INET, SOCK_STREAM, 0))<0) {
X		perror("socket");
X		exit(-1);
X	}
X
X	if (connect(sock, (char *)&serv, sizeof(serv))==-1) {
X		perror("connect");
X		exit(-1);
X	}
X	/*if (fork())
X		exit(0);*/
X	write(sock, signon, sl);
X	write(sock, statsm, strlen(statsm)+1);
X	lastm = last = time(0);
X
X	initscr();
X	clear();
X	refresh();
X	while (1) {
X		fd_set rd;
X		struct timeval wait;
X		int len, n;
X		char *pr = NULL, *s;
X
X		wait.tv_sec = waittime;
X		wait.tv_usec = 0;
X		FD_ZERO(&rd);
X		FD_SET(sock, &rd);
X		n = select(FD_SETSIZE, &rd, 0, 0, &wait);
X
X		if (FD_ISSET(sock, &rd))
X		    {
X			if ((len=read(sock, buff+off, sizeof(buff)-1-off))<=0) {
X				s_error(s);
X				exit(-1);
X			}
X			buff[off+len] = 0;
X			pr = buff;
X			for (s = (char *)index(buff, '\n');s;
X			     pr = s, s = (char *)index(pr, '\n'))
X			    {
X				off = 0;
X				*s++ = '\0';
X				if (t = (char *)index(pr, ' '))
X					if (!isdigit(*(t+1)))
X						continue;
X				fields = sscanf(pr,":%s %d %s",
X						serv, &num, nick);
X				if (fields != 3)
X					continue;
X				if (num == 219)
X					showstats();
X				else if (num == 212)
X				    {
X					fields = sscanf(pr,":%s %d %s %s %d",
X							serv, &num, nick,
X							msg, &cnt);
X					if (fields == 5)
X						dostats();
X				    }
X			    }
X			if (pr && (off=strlen(pr)))
X				bcopy(pr, buff, off+1);
X		}
X		if (time(0)-last > 30) {
X			write(sock, pong, pl);
X			last = time(0);
X		}
X		if (time(0)-lastm > waittime) {
X			write(sock, statsm, statsl);
X			lastm = time(0);
X		}
X	}
X}
X
Xs_error(fd)
Xint	fd;
X{
X}
X
X#define MSG_PRIVATE  "PRIVMSG"
X#define MSG_WHO      "WHO"
X#define MSG_WHOIS    "WHOIS"
X#define MSG_WHOWAS   "WHOWAS"
X#define MSG_USER     "USER"
X#define MSG_NICK     "NICK"
X#define MSG_SERVER   "SERVER"
X#define MSG_LIST     "LIST"
X#define MSG_TOPIC    "TOPIC"
X#define MSG_INVITE   "INVITE"
X#define MSG_VERSION  "VERSION"
X#define MSG_QUIT     "QUIT"
X#define MSG_SQUIT    "SQUIT"
X#define MSG_KILL     "KILL"
X#define MSG_INFO     "INFO"
X#define MSG_LINKS    "LINKS"
X#define MSG_SUMMON   "SUMMON"
X#define MSG_STATS    "STATS"
X#define MSG_USERS    "USERS"
X#define MSG_RESTART  "RESTART"
X#define MSG_HELP     "HELP"
X#define MSG_WHOREPLY "WHOREPLY"
X#define MSG_ERROR    "ERROR"
X#define MSG_AWAY     "AWAY"
X#define MSG_DIE      "DIE"
X#define MSG_CONNECT  "CONNECT"
X#define MSG_PING     "PING"
X#define MSG_PONG     "PONG"
X#define MSG_OPER     "OPER"
X#define MSG_PASS     "PASS"
X#define MSG_WALLOPS  "WALLOPS"
X#define MSG_TIME     "TIME"
X#define MSG_REHASH   "REHASH"
X#define MSG_NAMES    "NAMES"
X#define MSG_NAMREPLY "NAMREPLY"
X#define MSG_ADMIN    "ADMIN"
X#define MSG_TRACE    "TRACE"
X#define MSG_LINREPLY "LINREPLY"
X#define MSG_NOTICE   "NOTICE"
X#define MSG_JOIN     "JOIN"
X#define MSG_PART     "PART"
X#define MSG_LUSERS   "LUSERS"
X#define MSG_MOTD     "MOTD"
X#define MSG_MODE     "MODE"
X#define MSG_KICK     "KICK"
X#define MSG_SERVICE  "SERVICE"
X#define MSG_USERHOST "USERHOST"
X#define MSG_ISON     "ISON"
X#define MSG_SERVICE  "SERVICE"
X#define MSG_NOTE     "NOTE"
X#define MSG_SQUERY   "SQUERY"
X#define MSG_SERVLIST "SERVLIST"
X#define MSG_SERVSET  "SERVSET"
X#define	MSG_HASH     "HASH"
X
Xtypedef struct	Message {
X  char	*cmd;
X  int	count;
X  int	lcount;
X} MType;
X
Xstruct Message msgtab[] = {
X  { MSG_PRIVATE	, 0, 0 },
X  { MSG_NICK	, 0, 0 },
X  { MSG_NOTICE	, 0, 0 },
X  { MSG_USER	, 0, 0 },
X  { MSG_JOIN	, 0, 0 },
X  { MSG_QUIT	, 0, 0 },
X  { MSG_MODE	, 0, 0 },
X  { MSG_PART	, 0, 0 },
X  { MSG_AWAY	, 0, 0 },
X  { MSG_SERVER	, 0, 0 },
X  { MSG_PONG	, 0, 0 },
X  { MSG_WHOIS	, 0, 0 },
X  { MSG_WALLOPS	, 0, 0 },
X  { MSG_TOPIC	, 0, 0 },
X  { MSG_SQUIT	, 0, 0 },
X  { MSG_OPER	, 0, 0 },
X  { MSG_WHO	, 0, 0 },
X  { MSG_USERHOST	, 0, 0 },
X  { MSG_KICK	, 0, 0 },
X  { MSG_WHOWAS	, 0, 0 },
X  { MSG_LIST	, 0, 0 },
X  { MSG_NAMES	, 0, 0 },
X  { MSG_INVITE	, 0, 0 },
X  { MSG_PING	, 0, 0 },
X  { MSG_ISON	, 0, 0 },
X  { MSG_KILL	, 0, 0 },
X  { MSG_TRACE	, 0, 0 },
X  { MSG_PASS	, 0, 0 },
X  { MSG_LUSERS	, 0, 0 },
X  { MSG_TIME	, 0, 0 },
X  { MSG_CONNECT	, 0, 0 },
X  { MSG_VERSION	, 0, 0 },
X  { MSG_STATS	, 0, 0 },
X  { MSG_LINKS	, 0, 0 },
X  { MSG_ADMIN	, 0, 0 },
X  { MSG_ERROR	, 0, 0 },
X  { MSG_USERS	, 0, 0 },
X  { MSG_REHASH	, 0, 0 },
X  { MSG_SUMMON	, 0, 0 },
X  { MSG_HELP	, 0, 0 },
X  { MSG_INFO	, 0, 0 },
X  { MSG_MOTD	, 0, 0 },
X  { MSG_NOTE	, 0, 0 },
X  { MSG_SERVICE	, 0, 0 },
X  { MSG_SERVSET	, 0, 0 },
X  { MSG_SQUERY	, 0, 0 },
X  { MSG_SERVLIST	, 0, 0 },
X  { MSG_HASH	, 0, 0 },
X  { MSG_RESTART	, 0, 0 },
X  { MSG_DIE	, 0, 0 },
X  { (char *) 0	, 0, 0 }
X};
X
Xdostats()
X{
Xregister int i;
X
Xfor (i = 0; msgtab[i].cmd; i++)
X	if (!strcasecmp(msgtab[i].cmd, msg))
X	    {
X		msgtab[i].lcount = msgtab[i].count;
X		msgtab[i].count = cnt;
X		return;
X	    }
X}
X
Xsortm(p1, p2)
Xregister MType *p1, *p2;
X{
X	return (p2->count - p1->count);
X}
Xshowstats()
X{
X	static int entries = sizeof(msgtab)/sizeof(MType);
X	int i, show;
X	long now = time(0);
X
X	show = entries;
X	if (show > LINES - 3)
X		show = LINES -3;
X
X	qsort(msgtab, sizeof(msgtab)/sizeof(MType), sizeof(MType), sortm);
X	move(0,0);
X	refresh();
X	mvcur(LINES-1,COLS-1,0,0);
X	refresh();
X	printw("%s", ctime(&now));
X	printw("Command    Count     LastCount Change %s %d\n", server,port);
X	printw("---------- --------- --------- ------\n");
X	for (i = 0; i < show; i++)
X	    {
X		printw("%-10s %9d %9d %6d\n",
X			msgtab[i].cmd, msgtab[i].count, msgtab[i].lcount,
X			msgtab[i].count - msgtab[i].lcount);
X	    }
X	refresh();
X	mvcur(LINES-1,COLS-1,0,0);
X	refresh();
X}
END-of-stat/cmdmon.c
echo x - stat/flowmon.c
sed 's/^X//' >stat/flowmon.c << 'END-of-stat/flowmon.c'
X/*
X * flownmon.c (C)1992 Darren Reed.
X * monitors data flow over irc server connections.
X * maybe of use to someone.
X */
X#include <sys/types.h>
X#include <sys/time.h>
X#include <netinet/in.h>
X#include <sys/socket.h>
X#include <stdio.h>
X#include <curses.h>
X#include <netdb.h>
X/*
X * change this.
X */
Xchar signon[] ="NICK changethis\n\rUSER foobar foobar foobar foobar\n\r";
X/*
X * leave these
X */
Xchar pong[] = "PONG ping\n\r";
Xchar statsm[] ="STATS l *\n\r";
Xchar operm[] = "OPER ---- -----\n\r";
X
X#define	SERVERIP	"a.server.ip.num.goes.here"
X#define	SERVERPORT	-1
X#define	UPDATEDELAY	10
X
Xchar	buff[8192], servn[60], nick[20], msg[20];
Xchar	*server, name[60], pbuf[512];
Xint	port, numb;
Xlong	sq, sm, sb, rm, rb, scantime;
X
Xstruct stats {
X	int	sndq, sndm, sndb, rcvm, rcvb;
X};
X
Xtypedef struct	Message {
X	char	cnam[60];
X	struct	stats	now;
X 	struct	stats	old;
X	long	update;
X} MType;
X
Xstruct Message msgtab[256];
X
Xmain(argc, argv)
Xint	argc;
Xchar	*argv[];
X{
X	struct sockaddr_in serv;
X	FILE	*f;
X	int	sock, sl, statsl, pl, fields, off = 0, len = 0;
X	int	waittime;
X	long	last, lastm;
X	struct	hostent *hp = NULL;
X
X	bzero(msgtab, sizeof(msgtab));
X	sl = strlen(signon);
X	pl = strlen(pong);
X	statsl = strlen(statsm);
X	bzero(&serv, sizeof(serv));
X	/*
X	 * ip# of server to connect to
X	 */
X	server = (argc > 1) ? argv[1] : SERVERIP;
X	port = (argc > 2 ) ? atoi(argv[2]) : SERVERPORT;
X	waittime = (argc > 3 ) ? atoi(argv[3]) : 30;
X
X	if (!isdigit(*server))
X	    {
X		hp = gethostbyname(server);
X		if (hp)
X			bcopy(hp->h_addr_list[0], (char *)&serv.sin_addr,
X				sizeof(struct in_addr));
X		else
X		    {
X			printf("couldnt lookup %s\n",server);
X			exit(0);
X		    }
X	    }
X	else
X		serv.sin_addr.s_addr = inet_addr(server);
X	printf("Connecting to %s\n", inet_ntoa(serv.sin_addr));
X	serv.sin_port = htons(port);
X	serv.sin_family = AF_INET;
X
X	if ((sock = socket(AF_INET, SOCK_STREAM, 0))<0) {
X		perror("socket");
X		exit(-1);
X	}
X
X	if (connect(sock, (char *)&serv, sizeof(serv))==-1) {
X		perror("connect");
X		exit(-1);
X	}
X	printf("Connected.\n");
X	write(sock, signon, sl);
X/*	write(sock, operm, strlen(operm));*/
X	write(sock, statsm, strlen(statsm)+1);
X	scantime = lastm = last = time(0);
X
X	initscr();
X	clear();
X	refresh();
X
X	off = 0;
X	pbuf[off] = '\0';
X
X	while (1) {
X		fd_set rd;
X		struct timeval wait;
X		int n;
X		char *pr = NULL, *s = NULL, *t = NULL;
X
X		wait.tv_sec = 10;
X		wait.tv_usec = 0;
X		FD_ZERO(&rd);
X		FD_SET(sock, &rd);
X		n = select(FD_SETSIZE, &rd, 0, 0, &wait);
X
X		if (FD_ISSET(sock, &rd))
X		    {
X			len = sizeof(buff) - 1;
X			if ((len = read(sock, buff, len)) <= 0) {
X				s_error(s);
X				exit(-1);
X			}
X			buff[len] = 0;
X			while (s = (char *)index(buff, '\n'))
X			    {
X				*s++ = '\0';
X				strncat(pbuf, buff,
X					sizeof(pbuf)- stlen(pbuf));
X				len -= (stlen(buff) + 1);
X				if (len >= 0)
X					movemem(s, buff, len+1);
X				if (t = (char *)index(pbuf, ' '))
X					if (!isdigit(*++t))
X						goto parsegoto;
X				fields = sscanf(pbuf,":%s %d %s",
X						servn, &numb, nick);
X				if (fields != 3)
X					goto parsegoto;
X				if (numb < 211 || numb > 219)
X					goto parsegoto;
X				if (numb == 219)
X					showstats();
X				else if (numb == 211)
X				    {
X					fields = sscanf(pbuf,
X						":%s %d %s %s %d %d %d %d %d",
X						servn, &numb, nick, name,
X						&sq, &sm, &sb, &rm, &rb);
X					if (fields == 9)
X						dostats();
X					else
X						goto parsegoto;
X				    }
Xparsegoto:
X				pbuf[0] = '\0';
X			    }
X			if (len > 0)
X			    {
X				movemem(buff, pbuf, len+1);
X				pbuf[len+1] = '\0';
X			    }
X			else
X			    pbuf[0] = buff[0] = '\0';
X		}
X		if (time(0)-last > waittime) {
X			write(sock, pong, pl);
X			last = time(0);
X		}
X		if (time(0)-lastm > 10) {
X			write(sock, statsm, statsl);
X			scantime = lastm = time(0);
X		}
X	}
X}
X
Xs_error(fd)
Xint	fd;
X{
X}
X
Xdostats()
X{
Xregister int i;
X
X	for (i = 0; i < 256; i++)
X		if (!strcasecmp(msgtab[i].cnam, name))
X		    {
X			bcopy(&msgtab[i].now, &msgtab[i].old,
X				sizeof(struct stats));
X			msgtab[i].now.sndq = sq;
X			msgtab[i].now.sndb = sb;
X			msgtab[i].now.sndm = sm;
X			msgtab[i].now.rcvb = rb;
X			msgtab[i].now.rcvm = rm;
X			msgtab[i].update = scantime;
X			return;
X		    }
X
X	for (i = 0; i < 256; i++)
X		if (!*msgtab[i].cnam)
X		    {
X			strcpy(msgtab[i].cnam, name);
X			msgtab[i].now.sndq = sq;
X			msgtab[i].now.sndb = sb;
X			msgtab[i].now.sndm = sm;
X			msgtab[i].now.rcvb = rb;
X			msgtab[i].now.rcvm = rm;
X				msgtab[i].update = scantime;
X			break;
X		    }
X}
X
Xremoveold()
X{
X	register	int i;
X
X	for (i = 0; i < 256; i++)
X		if (msgtab[i].update && msgtab[i].update != scantime)
X		    {
X			msgtab[i].now.rcvb = 0;
X			msgtab[i].now.sndb = 0;
X			*msgtab[i].cnam = '\0';
X		    }
X}
X
Xsortm(p1, p2)
Xregister MType *p1, *p2;
X{
X	return (p2->now.rcvb - p1->now.rcvb);
X}
Xshowstats()
X{
X	static int entries = sizeof(msgtab)/sizeof(MType);
X	int i, show;
X	long now = time(0);
X	char	*s;
X
X	if ((show = entries) > LINES - 3)
X		show = LINES - 3;
X
X	removeold();
X	qsort(msgtab, sizeof(msgtab)/sizeof(MType), sizeof(MType), sortm);
X	move(0,0);
X	refresh();
X	mvcur(LINES-1,COLS-1,0,0);
X	refresh();
X	printw("%s %d %s", server, port, ctime(&now));
X	printw("Connection                SendQ  SendM     SendB      \
X RecvM     RecvB\n");
X	printw("------------------------- ------ --------- -----------\
X --------- -----------\n");
X	for (i = 0; i < show; i++)
X	    {
X		if (!*msgtab[i].cnam)
X			clrtoeol();
X		else
X		    {
X			printw("%-25.25s %6d %9d %11d ",
X				msgtab[i].cnam,
X				msgtab[i].now.sndq,
X				msgtab[i].now.sndm - msgtab[i].old.sndm,
X				msgtab[i].now.sndb - msgtab[i].old.sndb);
X			printw("%9d %11d\n",
X				msgtab[i].now.rcvm - msgtab[i].old.rcvm,
X				msgtab[i].now.rcvb - msgtab[i].old.rcvb);
X		    }
X	    }
X	refresh();
X	mvcur(LINES-1,COLS-1,0,0);
X	refresh();
X}
X
X
Xmovemem(s,t,l)
Xregister char *s, *t;
Xregister int l;
X{
X	for (; l >= 0; l--, s++, t++) *t = *s;
X}
X
Xint	stlen(s)
Xregister char *s;
X{
X	register int i = 0;
X
X	for (; *s; s++, i++)
X		;
X	return i;
X}
END-of-stat/flowmon.c
exit