DIRECTORY BasicTime USING [Now], Convert USING [RopeFromTime], IO USING [Flush, int, rope, PutChar, PutF, PutRope, STREAM], IPDefs USING [Datagram, Address], Rope USING [ROPE, Cat], TCPLogging, TCPOps USING [ConnectionState, Flip, TCPHeaderP, TCPHandle]; TCPLoggingImpl: CEDAR MONITOR IMPORTS BasicTime, Convert, IO, Rope, TCPOps EXPORTS TCPLogging = BEGIN OPEN TCPOps, TCPLogging; pktFile, logFile: PUBLIC IO.STREAM _ NIL; 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: IPDefs.Address] = { s.PutF["[%03g.%03g.%03g.%03g]", IO.int[addr[0]], IO.int[addr[1]], IO.int[addr[2]], IO.int[addr[3]]]; }; PutData: PROC [s: IO.STREAM, data: IPDefs.Datagram, fudge: BOOL] = { cruft: INT _ 0; length: INT _ data.dataLength; c: INT; tcpDataStart: INT; tcpHdrPtr: TCPHeaderP; TRUSTED { tcpHdrPtr _ LOOPHOLE[@data.data]; 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.data[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..length) DO c _ data.data[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: TCPOps.TCPHandle, data: IPDefs.Datagram, dir: Direction] = TRUSTED { tcpHdrPtr: TCPHeaderP _ LOOPHOLE[@data.data]; dirString, stateString, ctlString, time: Rope.ROPE; IF pktFile = NIL AND logFile = NIL 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.inHdr.source]; pktFile.PutF[" %g -> ", IO.int[tcpHdrPtr.sourcePort]]; PutAddr[pktFile, data.inHdr.destination]; 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[data.dataLength]]; PutData[pktFile, data, dir = fromNet]; }; IF logFile # NIL THEN { logFile.PutChar['\n]; logFile.PutF["%g ", IO.rope[time]]; PutAddr[logFile, data.inHdr.source]; logFile.PutF[" %g -> ", IO.int[tcpHdrPtr.sourcePort]]; PutAddr[logFile, data.inHdr.destination]; 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[data.dataLength]]; PutData[logFile, data, dir = fromNet]; logFile.Flush[]; }; }; PrintStateChange: PUBLIC ENTRY PROC [handle: TCPOps.TCPHandle, newState: TCPOps.ConnectionState] = { old, new, time: Rope.ROPE; IF pktFile = NIL AND logFile = NIL 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] = { 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[]; }; }; END. ˆ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. TCPLoggingImpl.mesa Last Edited by: Nichols, August 25, 1983 2:37 pm Last Edited by: Taft, January 4, 1984 12:59 pm Hal Murray May 16, 1985 3:15:02 am PDT John Larson, April 14, 1986 11:24:32 pm PST 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 Print or log state transitions. Κ‘– "cedar" style˜Icode2šœ΅™΅head™J™0J™.J™&Icode™+šΟk ˜ Kšœ œ˜Kšœœ˜Kšœœ,œ˜