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; 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 = { 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 = { IO.PutF[cmd.out, "Starting to send data in character mode.\n"]; msg _ SendData[blockmode: FALSE]; }; BlockTest: Commander.CommandProc = { 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 = { 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. €ArpaTCPTest.mesa Copyright (C) 1983, 1984 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, September 1, 1983 4:43 pm Last Edited by: Taft, January 22, 1984 11:28:59 am PST Last Edited by: HGM, October 6, 1984 10:51:08 pm PDT Doug Terry, March 22, 1988 3:26:02 pm PST Hal Murray May 16, 1985 3:16:56 am PDT John Larson, April 14, 1986 11:34:42 pm PST used for tests involving blocks of data being sent: SetAddress: Commander.CommandProc = { out: IO.STREAM _ cmd.out; argv: CommandTool.ArgumentVector = CommandTool.Parse[cmd ! CommandTool.Failed => {out.PutRope[errorMsg]; GO TO GiveUp}]; remoteAddresses: LIST OF Arpa.Address _ IPName.NameToAddress[argv[1]]; IF remoteAddresses=NIL THEN {out.PutRope["Name not found"]; GOTO GiveUp}; remoteAddress _ remoteAddresses.first; out.PutF["[%g.%g.%g.%g]\n", IO.int[remoteAddress[0]], IO.int[remoteAddress[1]], IO.int[remoteAddress[2]], IO.int[remoteAddress[3]]]; EXITS GiveUp => NULL; }; [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] Hack for resting reassembly via echoing to GOONHILLY-ECHO. Send big packets. Adapted from Mark Weiser: [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] Note: if checkData=TRUE then blocksize should be a multiple of 256 to be safe. Initialize block of data Create TCP connection Send data [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] the following can be adjusted to slow down the sink, perhaps to simulate a slow receiver or to test what happens when the senders window goes to zero Commander.Register["SetTCPAddress", SetAddress, "Tell which remote host to use."]; Κ 7– "cedar" style˜head™Icode2šœ―™―J™2Jšœ3Οk™6Jšœœ™4Icodešœ)™)Mšœ#™&Mšœ(™+J™š ˜ Lšœœ ˜Lšœ œ ˜Lšœ œ˜(Lšœœuœ˜…Mšœœ#˜0Lšœœœ˜/Lšœœ˜Lšœœo˜|——šΟn œœ˜Lšœœ+˜LLš˜Lšœœ˜Mšœ œ˜M˜Mšœ*˜*Mšœ)˜)Mšœ(˜(M˜Mšœ!˜!M˜M™3Mšœ œ ˜Mšœ œ Οc ˜!Lšœ œœ˜Lšœ œœ˜Lšœœ˜šž œ™%Lšœœœ ™™:LšœΟr œ œœ ™=—Lšœœœ.™FLšœœœ!œ ™ILšœ&™&Lš œœœœœ™„š™Lšœ œ™—L™—šžœ˜!Lšœœœ œ˜Lšœœœ˜Lšœœ˜Lšœ˜L˜˜šœ˜šœ˜Lšœ ˜ Lšœœ˜ L˜—šœ˜L˜ Lšœœ˜ L˜—šœ ˜ Lšœ+˜+Lšœ˜ L˜—L˜—Lš œ7œ œ1œ#œ˜ΟLšœ@˜@Lšœ&˜&LšœŸ˜1L˜šœœ˜!Lšœœœ˜4Lšœ œ˜Lšœ˜—L˜š˜šœ ˜ šœ˜L˜XLšœ)˜0———L˜—L˜—•StartOfExpansionL -- [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL]šžœ˜,LšΠckH™HLšœ œ˜Lšœ œ˜L– [PROCESS]šœ˜ L˜#L˜—šž œœ˜Lšœœ˜!Lšœœœ˜L˜šœ ˜šœ˜ Lšœ œ˜Lšœœ˜Lšœœ˜Lšœ˜—Lšœœ˜ Lšœ œœ˜Lš œ8œ-œœ œ˜™š˜Lšœ˜Lšœ œœ˜Lšœ+˜+Lšœ˜—Lšœ8œ#˜]šœ!˜'Lšœ+ œœ™Lšœ ˜L˜LLšœ˜——šœ˜%šœ ˜L˜LLšœ˜——L˜L˜Lšœ˜—L˜—M–L -- [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL]˜Mšœ™šžœ˜#Mš œœ œœœœœ™HMšœ=˜?Mšœœ˜!M˜M˜—šž œ˜$Mš œœ œœœœœ™HMšœ9˜;Mšœœ˜ M˜M˜—šžœœ œœœœœœœ˜oMšœN™NMšœ œ˜Mšœ œœ˜Mšœœ ˜!Mšœ œ˜M™Mš œœœœœ ˜'Mšœ˜šœœœ˜Mšœœœ˜Mšœ œ˜#Mšœ˜—M™Mšœbœ˜yMšœ œœ ˜)Mšœ œœ'˜GMšœŸ˜!šœ˜Lšœ>œ ˜LLšœ:œ ˜HLšœœœ ˜=L˜—šœœ œ˜Mšœ˜Mšœ˜M˜—M™ Mšœ˜šœœ)œ ˜Gšœ ˜ Mšœœ)˜0š œœœœ˜(Mšœ"˜$Mšœ˜——Mšœ˜M˜Mšœ˜—šœ ˜ Mšœœ)˜0š œœœœ˜(Mšœ"˜$Mšœ˜——Mšœ˜šœ˜Mšœ œ,œ˜A—Mšœ˜š˜Lšœ œ"˜,—M˜M˜M˜—šžœ˜Mš œœ œœœœœ™HLšœ œ˜L– [PROCESS]šœ˜ L˜!M˜M˜—Mšœ•™•Mšœœ˜Mšœ$˜$M˜šž œœ˜Lšœœ˜!Lšœ œœ˜Lšœœ˜šœŸ ˜ Lšœœ˜Lš œ6œ+œœ œ˜•š˜šœ˜ Lšœ œ˜Lšœœ˜Lšœœ˜Lšœœ˜Lšœ˜—Lšœœ˜"Lšœ œœœ˜.Lšœ&˜&šœ&œ˜.Lšœ œ˜1Lšœ˜L˜—Lšœœœœ˜BLšœ˜—Lšœœ œ˜*Mšœ˜—M˜M˜—J™RJ˜;J˜bJšœP˜PJšœN˜NJšœ_˜_Lšœ˜——…—€*