-- File: GCStats.mesa
-- Last Edit: L. Stewart December 16, 1978 8:55 PM

DIRECTORY
AltoSlaDefs: FROM "AltoSlaDefs" USING [longHop],
GCDefs: FROM "GCDefs" USING [
GCInterface, PrintErrorPup],
IODefs: FROM "IODefs" USING [
ReadChar, ReadNumber, WriteString, WriteDecimal,
Rubout, WriteLine, WriteChar, WriteNumber, CR, SP],
PupDefs: FROM "PupDefs" USING [
PupAddress, PupBuffer, PupSocket, GetFreePupBuffer, ReturnFreePupBuffer,
GetPupContentsBytes, MsToTocks, PupSocketDestroy,
PupSocketMake, SetPupContentsWords],
PupStatsDefs: FROM "PupStatsDefs" USING [
arpanetStatsReply, BcplLongInteger, FromBcplLongInteger,
ethernetStatsReply, EtherStatsEntry,
forwardingStatsReply, ForwardStatsEntry,
gateControlStatsAck, GateControlStatsEntry, gateControlStatsSend,
lineStateDown, lineStateLoopedBack, lineStateUp,
PRStatsEntry, prStatsReply,
pupStatsNak, pupStatsAck, pupStatsSend,
slaStatsReply, SlaStatsEntry, SlaStatsRoutingTableEntry],
PupTypes: FROM "PupTypes" USING [
fillInSocketID, statSoc],
StringDefs: FROM "<Mesa>StringDefs" USING [AppendLongNumber],
TimeDefs: FROM "TimeDefs" USING [CurrentDayTime];

GCStats: PROGRAM [gc: GCDefs.GCInterface]
IMPORTS GCDefs, IODefs, PupDefs, StringDefs, TimeDefs
EXPORTS GCDefs =
BEGIN OPEN gc
, IODefs, GCDefs, PupDefs, PupStatsDefs;

who: PupAddress;
statsoc: PupSocket;
statSocExists: BOOLEAN ← FALSE;

GetStats
: PUBLIC PROCEDURE =
BEGIN
net: CARDINAL ← 24;
WriteString["Statistics "L];
SELECT ReadChar[] FROM
’F, ’f =>
BEGIN
WriteLine[", Forwarding"L];
GetStatsAndPrint[177777B];
END;
’G, ’g =>
BEGIN
WriteLine[", Gateway"L];
GetGateStats[];
END;
’N, ’n =>
BEGIN
SetValue["for Network "L,@net];
GetStatsAndPrint[net];
END;
’? => WriteLine["F(orwarding), G(ateway), or N(etwork)."L];
ENDCASE => WriteLine["???"L];
EXITS
Return => NULL;
END;

GetStatsAndPrint: PROCEDURE [net: CARDINAL] =
BEGIN
i: CARDINAL ← 0;
b: PupBuffer;
IF newPartner[3] THEN
BEGIN
IF statSocExists THEN PupSocketDestroy[statsoc];
newPartner[3] ← FALSE;
who ← [remHost.net,remHost.host,PupTypes.statSoc];
statsoc ← PupSocketMake[PupTypes.fillInSocketID,who,MsToTocks[3000]];
END;

DO -- until we get the answer
i ← i+1;
b ← GetFreePupBuffer[];
b.pupID ← [7453,i];
b.pupWords[0] ← LOOPHOLE[net];
b.pupType ← pupStatsSend;
SetPupContentsWords[b,1];
statsoc.put[b];
b ← statsoc.get[];
IF b=NIL THEN
BEGIN
IF i>2 THEN
BEGIN WriteLine["No reply."]; RETURN; END
ELSE BEGIN WriteChar[’?]; LOOP; END;
END;
IF b.pupID#[7453,i] THEN
BEGIN
PrintErrorPup[b];
ReturnFreePupBuffer[b];
IF i>2 THEN
BEGIN WriteLine["I Give Up."]; RETURN; END
ELSE BEGIN WriteChar[’?]; LOOP; END;
LOOP;
END;
EXIT;
ENDLOOP;
SELECT b.pupType FROM
pupStatsNak =>
WriteLine[" ...are not available."];
pupStatsAck =>
SELECT b.pupWords[0] FROM
forwardingStatsReply => PrintForwardingStats[b];
ethernetStatsReply => PrintEtherStats[b];
arpanetStatsReply => PrintArpanetStats[b];
slaStatsReply => PrintSlaStats[b];
prStatsReply => PrintPRStats[b];
ENDCASE =>
BEGIN
WriteLine["Unknown Network Type"L];
PrintErrorPup[b];
END;
ENDCASE => PrintErrorPup[b];
ReturnFreePupBuffer[b];
END;

GetGateStats: PROCEDURE =
BEGIN
i: CARDINAL ← 0;
b: PupBuffer;
gse: POINTER TO GateControlStatsEntry;
DO -- until we get the answer
i ← i+1;
b ← GetFreePupBuffer[];
b.pupID ← [27182,i];
b.pupType ← gateControlStatsSend;
SetPupContentsWords[b,0];
gcSoc.put[b];
b ← gcSoc.get[];
IF b=NIL THEN
BEGIN
IF i>2 THEN BEGIN WriteLine["No reply."]; RETURN; END
ELSE LOOP;
END;
IF b.pupID#[27182,i]
OR b.pupType#gateControlStatsAck
OR GetPupContentsBytes[b]#2*SIZE[GateControlStatsEntry] THEN
BEGIN
PrintErrorPup[b];
ReturnFreePupBuffer[b];
IF i>2 THEN BEGIN WriteLine["I Give Up."]; RETURN; END
ELSE LOOP;
END;
EXIT;
ENDLOOP;
gse ← LOOPHOLE[@b.pupWords];
WriteChar[CR];
PrintUpTime[FromBcplLongInteger[LOOPHOLE[gse.startTime,BcplLongInteger]]];
WriteChar[CR];
WriteLine["Server Requests: "L];
WriteString["Echo: "L]; LD[gse.echo];
WriteString[", Time: "L]; LD[gse.time];
WriteString[", Name: "L]; LD[gse.name];
WriteString[", Gateway Info: "L]; LD[gse.route];
WriteString[", Boot: "L]; LD[gse.boot];
WriteChar[CR];
WriteString["Directories sent: "L]; LD[gse.directoriesSent];
WriteString[", Directory version = "L]; D[gse.directoryVersion];
WriteString[", FreePBIs: "L]; D[gse.freeBuffers];
WriteChar[CR];
END;

PrintUpTime: PROCEDURE [pt: LONG INTEGER] =
BEGIN
sec: LONG INTEGER ← LOOPHOLE[TimeDefs.CurrentDayTime[],LONG INTEGER]-pt;
min: LONG INTEGER;
hours: LONG INTEGER;
WriteString["Gateway up: "L];
hours ← sec/3600;
sec ← sec-hours*3600;
min ← sec/60;
sec ← sec-min*60;
LD[hours]; WriteChar[’:];
LD[min]; WriteChar[’:];
LD[sec]; WriteChar[CR];
END;

SetValue: PROCEDURE [s: STRING, v: POINTER] =
BEGIN
WriteString[s];
v↑ ← ReadNumber[v↑,8 ! Rubout => GOTO Reject];
WriteChar[CR];
EXITS Reject => WriteLine["xxx"L];
END;

PrintPRStats: PROCEDURE [b: PupBuffer] =
BEGIN
i: CARDINAL;
p: POINTER TO PRStatsEntry;
WriteLine["Packet Radio Statistics"];
p ← LOOPHOLE[@b.pupWords[1]];
WriteString[" "];
WriteLine[" Pkts Alives One-F Two-F Three-F Words"L];
WriteString["Sent: "];
LD10[p.packetsSent];
LD10[p.imAliveSent];
LD10[p.oneFragPupSent];
LD10[p.twoFragPupSent];
LD10[p.threeFragPupSent];
LD10[p.wordsSent];
WriteChar[CR];
WriteString["Rcvd: "];
LD10[p.packetsReceived];
LD10[p.imAliveReceived];
LD10[p.oneFragPupRcvd];
LD10[p.twoFragPupRcvd];
LD10[p.threeFragPupRcvd];
LD10[p.wordsReceived];
WriteChar[CR]; WriteChar[CR];
LD10[p.topsSent]; WriteString[" TOPs Sent "];
LD10[p.inputFilter]; WriteString[" Input Fltr"];
LD10[p.outputPacketsDiscarded]; WriteString[" Out Disc "];
WriteChar[CR];
LD10[p.assemblyTimeout]; WriteString[" Assy T-O "];
LD10[p.assemblyOverflow]; WriteString[" Assy ovflw"];
LD10[p.transferTimeout]; WriteString[" Xfer T-O "];
WriteChar[CR];
LD10[p.oldPackets]; WriteString[" Old Pkts "];
LD10[p.skippedPackets]; WriteString[" Skipped "];
LD10[p.sequencerResets]; WriteString[" Seq Resets"];
WriteChar[CR];
WriteString["PR Host Status:"];
FOR i IN [0..p.maxHosts) DO
WriteString[IF p.hostsUp[i] THEN " Up" ELSE " Down"];
ENDLOOP;
WriteChar[CR];
END;

PrintArpanetStats: PROCEDURE [b: PupBuffer] =
BEGIN
WriteLine["Arpanet statistics format unknown"];
PrintErrorPup[b];
END;

PrintEtherStats: PROCEDURE [b: PupBuffer] =
BEGIN
i: CARDINAL;
p: POINTER TO EtherStatsEntry;
WriteLine["Ethernet statistics"];
IF GetPupContentsBytes[b]#2*(1+SIZE[EtherStatsEntry]) THEN
BEGIN
WriteLine["Garbage Stats Packet!"];
PrintErrorPup[b];
RETURN;
END;
p ← LOOPHOLE[@b.pupWords[1]];
D10[p.packetsSent]; WriteLine[" Packets Sent"];
D10[p.badSendSatus]; WriteLine[" Bad Send Status"];
D10[p.inUnderOut]; WriteLine[" In Under Out"];
D10[p.packetsRecv]; WriteLine[" Packets Received"];
D10[p.badRecvStatus]; WriteLine[" Bad Receive Status"];
D10[p.inputOff]; WriteLine[" Input Off"];
WriteLine["Load Table"];
FOR i IN [0..16] DO
WriteChar[SP];WriteDecimal[p.loadTable[i]];
ENDLOOP;
WriteChar[CR];
END;

PrintSlaStats: PROCEDURE [b: PupBuffer] =
BEGIN OPEN IODefs, PupStatsDefs;
activeLines, host, maxLines, line: CARDINAL;
rte: POINTER TO SlaStatsRoutingTableEntry;
sse: POINTER TO SlaStatsEntry;
sizeOfRT: CARDINAL;
maxLines ← b.pupWords[1];
sizeOfRT ← maxLines*SIZE[SlaStatsRoutingTableEntry];
activeLines ← b.pupWords[2+sizeOfRT]+1;
IF GetPupContentsBytes[b]#2*(3+sizeOfRT+activeLines*SIZE[SlaStatsEntry]) THEN
BEGIN
WriteLine["Garbage Stats Packet!"];
PrintErrorPup[b];
RETURN;
END;
sse ← LOOPHOLE[@b.pupWords[3+sizeOfRT]];
WriteLine["SLA Line Statistics:"L];
WriteLine[" ----Packets---- ----Bytes------ ------Errors-------"L];
WriteLine["Line Sent Received Sent Received Sync CRC Control State"L];
FOR line IN [0..activeLines) DO
O3[line];
LD10[FromBcplLongInteger[sse.packetsSent]];
LD10[FromBcplLongInteger[sse.packetsRecv]];
LD10[FromBcplLongInteger[sse.bytesSent]];
LD10[FromBcplLongInteger[sse.bytesRecv]];
D6[sse.syncErrors];
D6[sse.badCrc];
D6[sse.controlError];
WriteString[" "L];
SELECT sse.state FROM
lineStateUp => WriteLine["Up"L];
lineStateDown => WriteLine["Down"L];
lineStateLoopedBack => WriteLine["Looped back"L];
ENDCASE => WriteLine[" ??"L];
sse ← sse + SIZE[SlaStatsEntry];
ENDLOOP;
WriteChar[CR];
WriteLine["Routing Table:"L];
WriteLine["Host Line Hops"L];
rte ← LOOPHOLE[@b.pupWords[2]];
FOR host IN [1..maxLines] DO
IF rte.hops#AltoSlaDefs.longHop THEN
BEGIN
O3[host]; O5[rte.line]; D5[rte.hops]; WriteChar[CR];
END;
rte ← rte + SIZE[SlaStatsRoutingTableEntry];
ENDLOOP;
END;

PrintForwardingStats: PROCEDURE [b: PupBuffer] =
BEGIN
s, d, o, i, ts: CARDINAL;
numNets, numfse: CARDINAL;
fse: POINTER TO ForwardStatsEntry;
WriteLine["Packets Forwarded:"L];
WriteChar[CR];
WriteLine["from to"L];
WriteChar[CR];
WriteString[" Discard"L];
numNets ← b.pupWords[1];
numfse ← (GetPupContentsBytes[b]-2*(numNets+2))/(2*SIZE[ForwardStatsEntry]);
FOR o IN [0..numNets) DO
WriteString[" "L];
O4[b.pupWords[2+o]];
ENDLOOP;
WriteChar[CR];
FOR o IN [1..numNets] DO
s ← b.pupWords[1+o];
O4[s];
FOR i IN [0..numNets] DO
IF i=0 THEN d ← 0 ELSE d ← b.pupWords[1+i];
FOR ts IN [0..numfse) DO
fse ← LOOPHOLE[@b.pupWords[numNets+2]+(ts*SIZE[ForwardStatsEntry])];
IF s=LOOPHOLE[fse.sourceNet] AND d=LOOPHOLE[fse.destNet] THEN GOTO Found;
REPEAT
Found => LD10[FromBcplLongInteger[fse.count]];
FINISHED => WriteString[" - "L];
ENDLOOP;
ENDLOOP;
WriteChar[CR];
ENDLOOP;
END;

O3: PROCEDURE [n: CARDINAL] =
BEGIN
IODefs.WriteNumber[n,[8,FALSE,TRUE,3]];
END;

O4: PROCEDURE [n: CARDINAL] =
BEGIN
IODefs.WriteNumber[n,[8,FALSE,TRUE,4]];
END;

O5: PROCEDURE [n: CARDINAL] =
BEGIN
IODefs.WriteNumber[n,[8,FALSE,TRUE,5]];
END;

D: PROCEDURE [n: CARDINAL] =
BEGIN
IODefs.WriteNumber[n,[10,FALSE,TRUE,0]];
END;

D5: PROCEDURE [n: CARDINAL] =
BEGIN
IODefs.WriteNumber[n,[10,FALSE,TRUE,5]];
END;

D6: PROCEDURE [n: CARDINAL] =
BEGIN
IODefs.WriteNumber[n,[10,FALSE,TRUE,6]];
END;

D10: PROCEDURE [n: CARDINAL] =
BEGIN
IODefs.WriteNumber[n,[10,FALSE,TRUE,10]];
END;

LD10: PROCEDURE [num: LONG INTEGER] =
BEGIN
s: STRING = [20];
StringDefs.AppendLongNumber[s,num,10];
THROUGH [s.length..10) DO WriteChar[’ ]; ENDLOOP;
WriteString[s];
END;

LD: PROCEDURE [n: LONG INTEGER] =
BEGIN
s: STRING = [20];
StringDefs.AppendLongNumber[s,n,10];
WriteString[s];
END;

END. -- GCStats