<> <> <> <> <> <> 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 { <> <> <> <> <> <> <> <> < Destination Address and Port>> 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.