ArpaTCPLoggingImpl.mesa
Copyright (C) 1983, 1984, 1985 by Xerox Corporation. All rights reserved. The following program was created in 1983 but has not been published within the meaning of the copyright law, is furnished under license, and may not be used, copied and/or disclosed except in accordance with the terms of said license.
Last Edited by: Nichols, August 25, 1983 2:37 pm
Last Edited by: Taft, January 4, 1984 12:59 pm
Doug Terry, October 16, 1987 3:41:05 pm PDT
Hal Murray May 16, 1985 3:15:02 am PDT
John Larson, February 29, 1988 0:12:25 am PST
DIRECTORY
Arpa USING [Address, nullAddress],
ArpaIP USING [Buffers, GetUserBytes],
ArpaBuf USING [Hdr],
BasicTime USING [Now],
Convert USING [RopeFromTime],
ConvertExtras USING [RopeFromArpaAddress],
IO USING [Flush, int, rope, PutChar, PutF, PutRope, STREAM],
Rope USING [ROPE, Cat],
ArpaTCPLogging,
ArpaTCPOps USING [tcpHdrByteLength, ConnectionState, Flip, TCPHeaderP, TCPHandle];
ArpaTCPLoggingImpl: CEDAR MONITOR
IMPORTS ArpaIP, BasicTime, Convert, ConvertExtras, IO, Rope, ArpaTCPOps
EXPORTS ArpaTCPLogging =
BEGIN OPEN ArpaTCPOps, ArpaTCPLogging;
pktFile, logFile: PUBLIC IO.STREAMNIL;
allAddresses: Arpa.Address = [255,255,255,255];
addrToWatch: PUBLIC Arpa.Address ← allAddresses;
pktBytesPrinted: INT ← 200;
StateToRope: PROC [state: ConnectionState] RETURNS [stateRope: Rope.ROPE] = {
SELECT state FROM
closed => stateRope ← "CLS";
listen => stateRope ← "LSN";
synSent => stateRope ← "SSN";
synRcvd => stateRope ← "SRD";
established => stateRope ← "EST";
finWait1 => stateRope ← "FW1";
finWait2 => stateRope ← "FW2";
closeWait => stateRope ← "CWT";
closing => stateRope ← "CLG";
lastAck => stateRope ← "LAK";
timeWait => stateRope ← "TWT"
ENDCASE; };
PutAddr: PROC [s: IO.STREAM, addr: Arpa.Address] = {
s.PutF["[%03g.%03g.%03g.%03g]",
IO.int[addr.a], IO.int[addr.b], IO.int[addr.c], IO.int[addr.d]]; };
PutData: PROC [s: IO.STREAM, data: ArpaIP.Buffers, fudge: BOOL] = {
cruft: INT ← 0;
length: INT ← ArpaIP.GetUserBytes[data].bodyBytes;
c: INT;
tcpDataStart: INT;
tcpHdrPtr: TCPHeaderP;
IF length <= ArpaTCPOps.tcpHdrByteLength THEN RETURN;
TRUSTED {
tcpHdrPtr ← LOOPHOLE[@data.body];
tcpDataStart ← tcpHdrPtr.dataWordOffset*4;
IF fudge THEN { -- Recv case ??
IF tcpHdrPtr.dataWordOffset # 5 THEN { -- TCP Options
end: INT = tcpHdrPtr.dataWordOffset*4;
s.PutRope["Options: "];
FOR i: INT IN [4*5..end) DO
c ← data.body.bytes[tcpDataStart+i];
s.PutF["%b ", IO.int[c]];
ENDLOOP;
s.PutChar['\n]; };
length ← length - tcpHdrPtr.dataWordOffset*4; }; };
IF length = 0 THEN RETURN;
FOR i: INT IN [0..MIN[length,pktBytesPrinted]) DO
c ← data.body.bytes[tcpDataStart+i];
IF c IN [40b..176b] THEN
s.PutChar['\000 + c]
ELSE {
cruft ← cruft + 1;
IF cruft > 10 THEN { s.PutRope["(more)"]; EXIT; };
s.PutF["<%b>", IO.int[c]]; };
ENDLOOP;
s.PutChar['\n]; };
PrintTCPPacket: PUBLIC ENTRY PROC [handle: ArpaTCPOps.TCPHandle, data: ArpaIP.Buffers, dir: Direction] = TRUSTED {
Print or log TCP packets. The following information is printed for each packet:
state of Connection
Received, Sent or Retransmitted (R, S or X)
Control Flags (Urgent, Ack, Push, Reset, SYN, FIN)
Sequence number mod 100000
Ack number mod 100000
Window
length (number of bytes of TCP header and data)
source Address and Port -> Destination Address and Port
ENABLE UNWIND => NULL;
tcpHdrPtr: TCPHeaderP ← LOOPHOLE[@data.body];
ipHdr: ArpaBuf.Hdr ← LOOPHOLE[data.hdr1];
dirString, stateString, ctlString, time: Rope.ROPE;
IF pktFile = NIL AND logFile = NIL THEN RETURN;
IF ipHdr.protocol # tcp THEN RETURN;
IF addrToWatch = Arpa.nullAddress THEN RETURN;
IF addrToWatch # allAddresses AND addrToWatch # data.hdr1.dest AND addrToWatch # data.hdr1.source THEN RETURN;
time ← Convert.RopeFromTime[
from: BasicTime.Now[], start: hours, end: seconds, useAMPM: FALSE, includeZone: FALSE];
SELECT dir FROM
fromNet => dirString ← "R";
toNet => dirString ← "S";
rexmitToNet => dirString ← "X"
ENDCASE;
IF handle = NIL THEN
stateString ← "CLS"
ELSE
stateString ← StateToRope[handle.state];
ctlString ← "";
IF tcpHdrPtr.urg THEN ctlString ← ctlString.Cat["U"];
IF tcpHdrPtr.ack THEN ctlString ← ctlString.Cat["A"];
IF tcpHdrPtr.psh THEN ctlString ← ctlString.Cat["P"];
IF tcpHdrPtr.rst THEN ctlString ← ctlString.Cat["R"];
IF tcpHdrPtr.syn THEN ctlString ← ctlString.Cat["S"];
IF tcpHdrPtr.fin THEN ctlString ← ctlString.Cat["F"];
IF pktFile # NIL THEN {
pktFile.PutChar['\n];
PutAddr[pktFile, data.hdr1.source];
pktFile.PutF[" %g -> ", IO.int[tcpHdrPtr.sourcePort]];
PutAddr[pktFile, data.hdr1.dest];
pktFile.PutF[" %g\n", IO.int[tcpHdrPtr.dstnPort]];
pktFile.PutF[" %g %g %6g ", IO.rope[stateString], IO.rope[dirString], IO.rope[ctlString]];
pktFile.PutF["%7g %7g %7g %7g\n", IO.int[Flip[tcpHdrPtr.seqNumber] MOD 100000], IO.int[Flip[tcpHdrPtr.ackNumber] MOD 100000], IO.int[tcpHdrPtr.window], IO.int[ArpaIP.GetUserBytes[data].bodyBytes]];
PutData[pktFile, data, dir = fromNet]; };
IF logFile # NIL THEN {
logFile.PutChar['\n];
logFile.PutF["%g ", IO.rope[time]];
PutAddr[logFile, data.hdr1.source];
logFile.PutF[" %g -> ", IO.int[tcpHdrPtr.sourcePort]];
PutAddr[logFile, data.hdr1.dest];
logFile.PutF[" %g\n", IO.int[tcpHdrPtr.dstnPort]];
logFile.PutF[" %g %g %6g ", IO.rope[stateString], IO.rope[dirString], IO.rope[ctlString]];
logFile.PutF["%7g %7g %7g %7g\n", IO.int[Flip[tcpHdrPtr.seqNumber] MOD 100000], IO.int[Flip[tcpHdrPtr.ackNumber] MOD 100000], IO.int[tcpHdrPtr.window], IO.int[ArpaIP.GetUserBytes[data].bodyBytes]];
PutData[logFile, data, dir = fromNet];
logFile.Flush[]; }; };
PrintStateChange: PUBLIC ENTRY PROC [handle: ArpaTCPOps.TCPHandle, newState: ArpaTCPOps.ConnectionState] = {
Print or log state transitions.
ENABLE UNWIND => NULL;
old, new, time: Rope.ROPE;
IF pktFile = NIL AND logFile = NIL THEN RETURN;
IF addrToWatch = Arpa.nullAddress THEN RETURN;
IF addrToWatch # allAddresses AND addrToWatch # handle.foreignAddr THEN RETURN;
time ← Convert.RopeFromTime[
from: BasicTime.Now[], start: hours, end: seconds, useAMPM: FALSE, includeZone: FALSE];
old ← StateToRope[handle.state];
new ← StateToRope[newState];
IF pktFile # NIL THEN {
pktFile.PutChar['\n];
pktFile.PutF["[ME] %g <-> ", IO.int[handle.localPort]];
PutAddr[pktFile, handle.foreignAddr];
pktFile.PutF[" %g", IO.int[handle.foreignPort]];
pktFile.PutF[" %g -> %g\n", IO.rope[old], IO.rope[new]]; };
IF logFile # NIL THEN {
logFile.PutF["\n%g ", IO.rope[time]];
logFile.PutF["[ME] %g <-> ", IO.int[handle.localPort]];
PutAddr[logFile, handle.foreignAddr];
logFile.PutF[" %g", IO.int[handle.foreignPort]];
logFile.PutF[" %g -> %g\n", IO.rope[old], IO.rope[new]];
logFile.Flush[]; }; };
PrintMessage: PUBLIC ENTRY PROC [r: Rope.ROPE] = {
ENABLE UNWIND => NULL;
IF pktFile = NIL AND logFile = NIL THEN RETURN;
IF pktFile # NIL THEN pktFile.PutF["%g\n", IO.rope[r]];
IF logFile # NIL THEN { logFile.PutF["%g\n", IO.rope[r]]; logFile.Flush[]; }; };
PrintMessageWithSrc: PUBLIC ENTRY PROC [r: Rope.ROPE, sourceAddr: Arpa.Address] = {
ENABLE UNWIND => NULL;
IF pktFile = NIL AND logFile = NIL THEN RETURN;
IF addrToWatch = Arpa.nullAddress THEN RETURN;
IF addrToWatch # allAddresses AND addrToWatch # sourceAddr THEN RETURN;
IF pktFile # NIL THEN pktFile.PutF["%g, source: %g\n", IO.rope[r], IO.rope[ConvertExtras.RopeFromArpaAddress[sourceAddr]]];
IF logFile # NIL THEN { logFile.PutF["%g, source: %g\n", IO.rope[r], IO.rope[ConvertExtras.RopeFromArpaAddress[sourceAddr]]]; logFile.Flush[]; };
};
END.