<> <> <> <> <> <> <> <> <<>> DIRECTORY Arpa USING [Address], ArpaExtras USING [MyAddress], Commander USING [CommandProc, Register], IO USING [Close, EndOf, EndOfStream, Error, Flush, GetChar, GetLineRope, int, PutBlock, PutChar, PutF, PutFR, PutRope, rope, STREAM], Process USING [Detach, Milliseconds, PauseMsec], Rope USING [Cat, Find, FromChar, Length, ROPE], UserCredentials USING [Get], ArpaTCP USING [AbortTCPStream, CreateTCPStream, Error, ErrorFromStream, neverTimeout, Reason, Timeout, WaitForListenerOpen]; ArpaTCPTest: CEDAR PROGRAM IMPORTS ArpaExtras, Commander, IO, Process, Rope, UserCredentials, ArpaTCP = BEGIN fingerSocket: INT = 79; sinkSocket: INT = 531; me: Arpa.Address _ ArpaExtras.MyAddress[]; cslSun: Arpa.Address _ [13, 1, 100, 206]; parcvax: Arpa.Address _ [13, 2, 16, 8]; remoteAddress: Arpa.Address _ me; <> totalsize: INT _ 100000; blocksize: INT _ 8192; -- 256*32 checkData: BOOLEAN _ TRUE; running: BOOL _ TRUE; server: PROCESS; <> <> <> < {out.PutRope[errorMsg]; GO TO GiveUp}];>> <> <> <> <> <> < NULL;>> <<};>> Finger: Commander.CommandProc = { out: IO.STREAM _ cmd.out; fingerStream: IO.STREAM; c: CHAR; cr: ArpaTCP.Reason _ neverOpen; { ENABLE { ArpaTCP.Timeout => { out.PutRope["[No response.]\n"]; GO TO GiveUp; }; ArpaTCP.Error => { cr _ reason; GO TO GiveUp; }; IO.Error => { cr _ ArpaTCP.ErrorFromStream[fingerStream]; GOTO GiveUp; }; }; fingerStream _ ArpaTCP.CreateTCPStream[[matchLocalPort~FALSE, localPort~0, matchForeignAddr~TRUE, foreignAddress~remoteAddress, matchForeignPort~TRUE, foreignPort~fingerSocket, active~TRUE, timeout~120000]]; ArpaTCP.WaitForListenerOpen[fingerStream, ArpaTCP.neverTimeout]; fingerStream.PutRope[cmd.commandLine]; fingerStream.PutChar['\l]; -- send the LF as well fingerStream.Flush[]; WHILE NOT fingerStream.EndOf[] DO c _ fingerStream.GetChar[ ! IO.EndOfStream => EXIT]; IF c # '\l THEN out.PutChar[c]; ENDLOOP; fingerStream.Close[]; EXITS GiveUp => SELECT cr FROM remoteAbort => out.PutRope["[Remote host refused to point the finger at its users.]\n"]; ENDCASE => ArpaTCP.AbortTCPStream[fingerStream]; }; }; StartFingerServer: Commander.CommandProc = { <<[cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL]>> running _ TRUE; server _ FORK FingerServer[]; TRUSTED{Process.Detach[server]}; msg _ "TCP finger server started."; }; FingerServer: PROC = { ENABLE ArpaTCP.Timeout => RESUME; fingerStream: IO.STREAM; WHILE running DO ENABLE BEGIN IO.Error => RETRY; ArpaTCP.Timeout => RETRY; ArpaTCP.Error => RETRY; END; char: CHAR; rope: Rope.ROPE _ NIL; fingerStream _ ArpaTCP.CreateTCPStream[[matchLocalPort: TRUE, localPort: fingerSocket, matchForeignAddr: FALSE, matchForeignPort: FALSE, active: FALSE]]; DO char _ fingerStream.GetChar[]; IF char = '\l THEN EXIT; rope _ Rope.Cat[rope, Rope.FromChar[char]]; ENDLOOP; fingerStream.PutF["User %g logged in on a Dorado.\n\l", IO.rope[UserCredentials.Get[].name]]; IF Rope.Find[rope, "Verbose"] # -1 THEN <> THROUGH [0..20) DO fingerStream.PutF[" 123456789 123456789 123456789 123456789 123456789\n\l"]; ENDLOOP; IF Rope.Find[rope, "Super"] # -1 THEN THROUGH [0..200) DO fingerStream.PutF[" 123456789 123456789 123456789 123456789 123456789\n\l"]; ENDLOOP; fingerStream.Flush[]; fingerStream.Close[]; ENDLOOP; }; <> CharTest: Commander.CommandProc = { <<[cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL]>> IO.PutF[cmd.out, "Starting to send data in character mode.\n"]; msg _ SendData[blockmode: FALSE]; }; BlockTest: Commander.CommandProc = { <<[cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL]>> IO.PutF[cmd.out, "Starting to send data in block mode.\n"]; msg _ SendData[blockmode: TRUE]; }; SendData: PROC[blockmode: BOOLEAN _ TRUE, waitForResult: BOOLEAN _ FALSE] RETURNS [result: Rope.ROPE _ NIL] = { <> stillToDo: INT; tcpStream: IO.STREAM; headerForm: Rope.ROPE = "t%09g "; header: Rope.ROPE; <> block: REF TEXT _ NEW[TEXT[blocksize]]; block.length _ blocksize; FOR i: INT IN [0..blocksize) DO byte: BYTE _ i MOD 256; TRUSTED{block[i] _ LOOPHOLE[byte];} ENDLOOP; <> tcpStream _ ArpaTCP.CreateTCPStream[[foreignAddress~remoteAddress, foreignPort~sinkSocket, active~TRUE, timeout~200000]]; header _ IO.PutFR[headerForm, IO.int[0]]; header _ IO.PutFR[headerForm, IO.int[totalsize + Rope.Length[header]]]; { -- nested block to catch errors ENABLE { ArpaTCP.Timeout => {result _ "ArpaTCP.Timeout on TCP stream"; GOTO GiveUp}; ArpaTCP.Error => {result _ "ArpaTCP.Error on TCP stream"; GOTO GiveUp}; IO.Error => {result _ "IO.Error on TCP stream"; GOTO GiveUp}; }; IF NOT checkData THEN { IO.PutF[tcpStream, header]; IO.Flush[tcpStream]; }; <> stillToDo _ totalsize; FOR left: INT _ totalsize-blocksize, left - blocksize UNTIL left < 0 DO IF blockmode THEN IO.PutBlock[tcpStream, block, 0, blocksize] ELSE FOR count: INT IN [0..blocksize) DO IO.PutChar[tcpStream, block[count]]; ENDLOOP; IO.Flush[tcpStream]; stillToDo _ left; ENDLOOP; IF blockmode THEN IO.PutBlock[tcpStream, block, 0, stillToDo] ELSE FOR count: INT IN [0..stillToDo) DO IO.PutChar[tcpStream, block[count]]; ENDLOOP; IO.Flush[tcpStream]; IF waitForResult THEN result _ IO.GetLineRope[tcpStream ! ArpaTCP.Timeout => CONTINUE]; IO.Close[tcpStream]; EXITS GiveUp => ArpaTCP.AbortTCPStream[tcpStream]; }; }; Sink: Commander.CommandProc = { <<[cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL]>> server _ FORK SinkServer[]; TRUSTED{Process.Detach[server]}; msg _ "TCP sink server started."; }; <> charsBetweenPauses: INT _ 500; msToPause: Process.Milliseconds _ 0; SinkServer: PROC = { ENABLE ArpaTCP.Timeout => RESUME; sinkStream: IO.STREAM; charsSincePause: INT _ 0; DO -- forever byteExpected: CHAR _ 0C; sinkStream _ ArpaTCP.CreateTCPStream[[matchLocalPort: TRUE, localPort: sinkSocket, matchForeignAddr: FALSE, matchForeignPort: FALSE, active: FALSE]]; DO ENABLE BEGIN IO.Error => EXIT; IO.EndOfStream => EXIT; ArpaTCP.Timeout => EXIT; ArpaTCP.Error => EXIT; END; char: CHAR _ sinkStream.GetChar[]; IF checkData AND char#byteExpected THEN ERROR; charsSincePause _ charsSincePause + 1; IF charsSincePause > charsBetweenPauses THEN { IF msToPause#0 THEN Process.PauseMsec[msToPause]; charsSincePause _ 0; }; byteExpected _ IF byteExpected=377C THEN 0C ELSE byteExpected + 1; ENDLOOP; sinkStream.Close[ ! IO.Error => CONTINUE]; ENDLOOP; }; <> Commander.Register["TCPFinger", Finger, "Who is on host."]; Commander.Register["TCPFingerServer", StartFingerServer, "Start TCP finger server on this host."]; Commander.Register["TCPBlockSend", BlockTest, "Tests the 'ArpaTCP' interface."]; Commander.Register["TCPCharSend", CharTest, "Tests the 'ArpaTCP' interface."]; Commander.Register["TCPSink", Sink, "Start TCP server that eats whatever data is sent to it."]; END.