-- File: OISCPTesterSink.mesa -- Last edit: BLyon, January 16, 1981 5:42 PM -- Last edit: HGM, January 27, 1981 9:03 PM DIRECTORY FormSW USING [ AllocateItemDescriptor, BooleanItem, ClientItemsProcType, CommandItem, NumberItem, line0, line1, ProcType, StringItem], Inline USING [BITAND, BITSHIFT], MsgSW USING [Post], NetworkStream USING [ Close, CreateListener, defaultWaitTime, DeleteListener, FindAddresses, Listen, ListenerHandle, CloseReply, closeSST, CloseStatus, ConnectionSuspended], OISCP USING [OiscpPackageDestroy, OiscpPackageMake], Process USING [Yield, Detach], Put USING [Char, CR, Decimal, Line, Octal, Text], Router USING [FindMyHostID, FindDestinationRelativeNetID], SpecialSystem USING [ HostNumber, NetworkAddress, NetworkNumber, nullNetworkNumber, SocketNumber], Storage USING [FreeString, FreeNodeNil, Node, String], Stream, String USING [AppendChar, AppendNumber, AppendString], System USING [], Tool USING [Create, MakeFileSW, MakeFormSW, MakeMsgSW, MakeSWsProc], ToolWindow USING [TransitionProcType], Window USING [Handle, Place]; OISCPTesterSink: PROGRAM IMPORTS FormSW, Inline, MsgSW, NetworkStream, OISCP, Process, Put, Router, Storage, Stream, String, Tool EXPORTS System = BEGIN NetworkAddress: PUBLIC TYPE = SpecialSystem.NetworkAddress; -- global variable declarations pleaseStop, networkStreamRunning: BOOLEAN ← FALSE; handle, msgSW, fileSW, formSW: Window.Handle ← NIL; localSocket: SpecialSystem.SocketNumber ← [400B]; useLoopCount: BOOLEAN ← TRUE; loopCount: CARDINAL ← 100; machineIDString: STRING ← NIL; -- UserProc needed routines Init: PROCEDURE = BEGIN handle ← Tool.Create[ name: "OISCP Tester Sink of September 23, 1980"L, makeSWsProc: DoUserProcSpecificSetup, clientTransition: Transition, initialState: inactive]; END; DoUserProcSpecificSetup: Tool.MakeSWsProc = BEGIN IF handle = NIL THEN ERROR; msgSW ← Tool.MakeMsgSW[window: handle, lines: 1]; formSW ← Tool.MakeFormSW[window: handle, formProc: MakeParameterArray]; fileSW ← Tool.MakeFileSW[window: handle, name: "OISCPTesterSink.log"]; END; -- in this tool tiny and active are the same state. Transition: ToolWindow.TransitionProcType = BEGIN IF old = inactive AND new # inactive THEN BEGIN primaryNetID: SpecialSystem.NetworkNumber; myHostID: SpecialSystem.HostNumber; OISCP.OiscpPackageMake[]; primaryNetID ← Router.FindDestinationRelativeNetID[ SpecialSystem.nullNetworkNumber]; myHostID ← Router.FindMyHostID[]; -- set the machine id string machineIDString ← Storage.String[6*SIZE[NetworkAddress] + 2]; machineIDString.length ← 0; AppendSuperLongToString[ machineIDString, @primaryNetID, SIZE[SpecialSystem.NetworkNumber]]; String.AppendChar[machineIDString, '#]; AppendSuperLongToString[ machineIDString, @myHostID, SIZE[SpecialSystem.HostNumber]]; String.AppendChar[machineIDString, '#]; loopCount ← 100; END ELSE IF new = inactive AND old # inactive THEN BEGIN Storage.FreeString[machineIDString]; OISCP.OiscpPackageDestroy[]; END; END; AppendSuperLongToString: PUBLIC PROCEDURE [ s: STRING, num: POINTER, length: CARDINAL] = BEGIN number: POINTER TO ARRAY [0..0) OF CARDINAL = LOOPHOLE[num]; myCopy: POINTER TO ARRAY [0..0) OF CARDINAL; i: CARDINAL; AppendSuperLong: PROCEDURE [recurring: BOOLEAN] = BEGIN finished: BOOLEAN ← recurring; lastRem, rem: CARDINAL ← 0; i: CARDINAL; FOR i IN [0..length) DO IF myCopy[i] # 0 THEN finished ← FALSE; rem ← Inline.BITAND[myCopy[i], 7B]; myCopy[i] ← Inline.BITSHIFT[lastRem, 13] + Inline.BITSHIFT[myCopy[i], -3]; lastRem ← rem; ENDLOOP; IF finished THEN RETURN; AppendSuperLong[TRUE]; String.AppendNumber[s, rem, 8]; END; -- AppendSuperLong myCopy ← Storage.Node[length]; FOR i IN [0..length) DO myCopy[i] ← number[i]; ENDLOOP; AppendSuperLong[FALSE]; myCopy ← Storage.FreeNodeNil[myCopy]; END; -- AppendSuperLongToString MakeParameterArray: FormSW.ClientItemsProcType = BEGIN sinkTestReceivePlace: Window.Place = [x: 2, y: FormSW.line0]; sinkTestSendPlace: Window.Place = [x: 25*7, y: FormSW.line0]; stopPlace: Window.Place = [x: 50*7, y: FormSW.line0]; useCountPlace: Window.Place = [x: 2, y: FormSW.line1]; countPlace: Window.Place = [x: 9*7, y: FormSW.line1]; machineIDPlace: Window.Place = [x: 25*7, y: FormSW.line1]; localSocketPlace: Window.Place = [x: 50*7, y: FormSW.line1]; nParams: CARDINAL = 7; i: INTEGER ← -1; freeDesc ← TRUE; -- ???? items ← FormSW.AllocateItemDescriptor[nParams]; items[i ← i + 1] ← FormSW.CommandItem[ tag: "SinkTestReceive"L, place: sinkTestReceivePlace, proc: ListenerTestSinkCmd]; items[i ← i + 1] ← FormSW.CommandItem[ tag: "SinkTestSend"L, place: sinkTestSendPlace, proc: ListenerTestSendCmd]; items[i ← i + 1] ← FormSW.CommandItem[ tag: "STOP"L, place: stopPlace, proc: Stop]; items[i ← i + 1] ← FormSW.BooleanItem[ tag: "UseCount"L, place: useCountPlace, switch: @useLoopCount]; items[i ← i + 1] ← FormSW.NumberItem[ tag: "LoopCount"L, place: countPlace, value: @loopCount, radix: decimal, notNegative: TRUE, signed: FALSE, default: 100]; items[i ← i + 1] ← FormSW.StringItem[ tag: "NetAddr"L, place: machineIDPlace, string: @machineIDString, readOnly: TRUE, drawBox: TRUE]; items[i ← i + 1] ← FormSW.NumberItem[ tag: "LocalSocket"L, place: localSocketPlace, value: @localSocket, radix: octal, notNegative: TRUE, signed: FALSE, default: 400B]; IF i # nParams - 1 THEN ERROR; END; -- utility tools specific routines GetLoopCount: PROCEDURE RETURNS [useCount: BOOLEAN, count: CARDINAL] = BEGIN RETURN[useLoopCount, loopCount]; END; FindLocalSocketID: PROCEDURE RETURNS [localSocketID: SpecialSystem.SocketNumber] = BEGIN RETURN[localSocket]; END; PrintPoop: PROCEDURE [who: STRING, loopCountUsed: BOOLEAN] = BEGIN Put.CR[fileSW]; Put.Line[fileSW, who]; Put.Text[fileSW, "LoopCount: "L]; IF loopCountUsed THEN IF useLoopCount THEN Put.Decimal[fileSW, loopCount] ELSE Put.Text[fileSW, "infinite"L] ELSE Put.Text[fileSW, "Not Used"L]; Put.Text[fileSW, " LocalSocket: "L]; Put.Octal[fileSW, LOOPHOLE[localSocket, UNSPECIFIED]]; Put.CR[fileSW]; END; -- tool command routines Stop: FormSW.ProcType = BEGIN pleaseStop ← TRUE; Process.Yield[]; END; ListenerTestSinkCmd: PUBLIC FormSW.ProcType = BEGIN primaryNetID: SpecialSystem.NetworkNumber ← Router.FindDestinationRelativeNetID[SpecialSystem.nullNetworkNumber]; myHostID: SpecialSystem.HostNumber ← Router.FindMyHostID[]; localSocketID: SpecialSystem.SocketNumber ← FindLocalSocketID[]; localAddr: NetworkAddress ← [primaryNetID, myHostID, localSocketID]; IF networkStreamRunning THEN BEGIN MsgSW.Post[msgSW, "A test is already running. Use STOP to abort it."]; RETURN; END; PrintPoop["SinkTestReceive", FALSE]; networkStreamRunning ← TRUE; pleaseStop ← FALSE; Process.Detach[FORK ListenerTestSink[localAddr]]; MsgSW.Post[msgSW, "SinkTestReceive successfully started"L]; Process.Yield[]; END; ListenerTestSink: PROCEDURE [localAddr: NetworkAddress] = BEGIN attnFork: PROCESS; listenerH: NetworkStream.ListenerHandle ← NetworkStream.CreateListener[ localAddr]; stH: Stream.Handle; DO stH ← NetworkStream.Listen[ listenerH, NetworkStream.defaultWaitTime, NetworkStream.defaultWaitTime]; IF stH # NIL THEN BEGIN connectionMsg: STRING ← Storage.String[80]; remoteGuy: NetworkAddress ← NetworkStream.FindAddresses[stH].remote; String.AppendString[ connectionMsg, "SinkTestReceive Connection established with "L]; AppendSuperLongToString[ connectionMsg, @remoteGuy.net, SIZE[SpecialSystem.NetworkNumber]]; String.AppendChar[connectionMsg, '#]; AppendSuperLongToString[ connectionMsg, @remoteGuy.host, SIZE[SpecialSystem.HostNumber]]; String.AppendChar[connectionMsg, '#]; AppendSuperLongToString[ connectionMsg, @remoteGuy.socket, SIZE[SpecialSystem.SocketNumber]]; MsgSW.Post[msgSW, connectionMsg]; Put.Line[fileSW, connectionMsg]; Storage.FreeString[connectionMsg]; attnFork ← FORK AttentionListener[stH]; StreamTestSinkAgent[stH]; JOIN attnFork; Stream.Delete[stH]; IF pleaseStop THEN EXIT ELSE LOOP; END ELSE BEGIN IF pleaseStop THEN BEGIN msg: STRING ← "SinkTestReceive: No requests for service within the default time."L; MsgSW.Post[msgSW, msg]; Put.Line[fileSW, msg]; EXIT; END ELSE BEGIN Put.Char[fileSW, 't]; LOOP; END; END; ENDLOOP; NetworkStream.DeleteListener[listenerH]; networkStreamRunning ← FALSE; END; StreamTestSinkAgent: PROCEDURE [stH: Stream.Handle] = BEGIN c: CHARACTER; msg: STRING; counter: CARDINAL ← 0; dataByte: Stream.Byte ← 1; dataSpace: PACKED ARRAY [0..542) OF Stream.Byte; bl: Stream.Block ← [@dataSpace, 0, 542]; options: Stream.InputOptions ← [TRUE, FALSE, FALSE, TRUE, FALSE]; i: CARDINAL; bytesTransferred: CARDINAL; why: Stream.CompletionCode; inSST: Stream.SubSequenceType; closeStatus: NetworkStream.CloseStatus; suspended: BOOLEAN ← FALSE; Stream.SetInputOptions[stH, options]; [bytesTransferred, why, inSST] ← Stream.GetBlock[stH, bl]; FOR i IN [0..bytesTransferred) DO IF (dataSpace[i] # 1) AND (dataSpace[i] # 100) THEN BEGIN Put.Text[fileSW, "SinkTestReceive error: "L]; Put.Decimal[fileSW, i]; Put.Text[fileSW, ", "L]; END; ENDLOOP; Put.Char[fileSW, '!]; DO c ← '!; IF ((counter ← counter + 1) MOD 4) = 0 THEN Process.Yield[]; [bytesTransferred, why, inSST] ← Stream.GetBlock[ stH, bl ! Stream.SSTChange => BEGIN IF sst = NetworkStream.closeSST THEN EXIT; Put.Char[fileSW, 'c]; RESUME ; END; NetworkStream.ConnectionSuspended => BEGIN msg ← "SinkTestReceive: Connection suspended"L; suspended ← TRUE; EXIT; END; Stream.TimeOut => BEGIN msg ← "SinkTestReceive: GetBlock timed out."; suspended ← TRUE; EXIT; END]; FOR i IN [0..bytesTransferred) DO IF (dataSpace[i] # 1) AND (dataSpace[i] # 100) THEN BEGIN Put.Text[fileSW, "SinkTestReceive error: "L]; Put.Decimal[fileSW, i]; Put.Text[fileSW, ", "]; END; ENDLOOP; Put.Char[fileSW, '!]; ENDLOOP; IF ~suspended THEN BEGIN -- conform to closing protocol -- first get any remaining bytes [bytesTransferred, why, inSST] ← Stream.GetBlock[stH, bl ! ANY => NULL]; closeStatus ← NetworkStream.CloseReply[stH]; msg ← IF closeStatus = good THEN "SinkTestReceive: stream connection cleanly closed."L ELSE "SinkTestReceive: stream connection closed with some doubt."L; END; Put.Line[fileSW, msg]; MsgSW.Post[msgSW, msg]; END; -- This simple attention listener waits for 4 attentions as we never send any more AttentionListener: PROCEDURE [stH: Stream.Handle] = BEGIN i: INTEGER ← 0; attnByte: Stream.Byte ← 0; FOR i IN [0..4) DO attnByte ← Stream.WaitForAttention[stH ! Stream.TimeOut => RETRY]; Put.Text[fileSW, "attn: "]; Put.Decimal[fileSW, attnByte]; Put.CR[fileSW]; ENDLOOP; END; ListenerTestSendCmd: PUBLIC FormSW.ProcType = BEGIN primaryNetID: SpecialSystem.NetworkNumber ← Router.FindDestinationRelativeNetID[SpecialSystem.nullNetworkNumber]; myHostID: SpecialSystem.HostNumber ← Router.FindMyHostID[]; localSocketID: SpecialSystem.SocketNumber ← FindLocalSocketID[]; localAddr: NetworkAddress ← [primaryNetID, myHostID, localSocketID]; IF networkStreamRunning THEN BEGIN MsgSW.Post[msgSW, "A test is already running. Use STOP to abort it."]; RETURN; END; PrintPoop["SinkTestSend", TRUE]; networkStreamRunning ← TRUE; pleaseStop ← FALSE; Process.Detach[FORK ListenerTestSend[localAddr]]; MsgSW.Post[msgSW, "SinkTestSend successfully started"L]; Process.Yield[]; END; ListenerTestSend: PROCEDURE [localAddr: NetworkAddress] = BEGIN listenerH: NetworkStream.ListenerHandle ← NetworkStream.CreateListener[ localAddr]; stH: Stream.Handle; DO stH ← NetworkStream.Listen[ listenerH, NetworkStream.defaultWaitTime, NetworkStream.defaultWaitTime]; IF stH # NIL THEN BEGIN connectionMsg: STRING ← Storage.String[80]; remoteGuy: NetworkAddress ← NetworkStream.FindAddresses[stH].remote; String.AppendString[ connectionMsg, "SinkTestSend Connection established with "L]; AppendSuperLongToString[ connectionMsg, @remoteGuy.net, SIZE[SpecialSystem.NetworkNumber]]; String.AppendChar[connectionMsg, '#]; AppendSuperLongToString[ connectionMsg, @remoteGuy.host, SIZE[SpecialSystem.HostNumber]]; String.AppendChar[connectionMsg, '#]; AppendSuperLongToString[ connectionMsg, @remoteGuy.socket, SIZE[SpecialSystem.SocketNumber]]; MsgSW.Post[msgSW, connectionMsg]; Put.Line[fileSW, connectionMsg]; Storage.FreeString[connectionMsg]; NetworkStreamSendTest[stH]; Stream.Delete[stH]; IF pleaseStop THEN EXIT ELSE LOOP; END ELSE BEGIN IF pleaseStop THEN BEGIN msg: STRING ← "SinkTestSend: No requests for service within the default time."L; MsgSW.Post[msgSW, msg]; Put.Line[fileSW, msg]; EXIT; END ELSE BEGIN Put.Char[fileSW, 't]; LOOP; END; END; ENDLOOP; NetworkStream.DeleteListener[listenerH]; networkStreamRunning ← FALSE; END; NetworkStreamSendTest: PROCEDURE [streamH: Stream.Handle] = BEGIN msg: STRING; maxPush: CARDINAL; useMaxPush: BOOLEAN; suspended: BOOLEAN ← FALSE; counter: CARDINAL ← 0; putDataSpace: PACKED ARRAY [0..542) OF Stream.Byte; bl: Stream.Block ← [@putDataSpace, 0, 542]; closeStatus: NetworkStream.CloseStatus; i: CARDINAL; outSST: Stream.SubSequenceType ← 0; dataByte: Stream.Byte ← 1; attnByte: Stream.Byte ← 100; [useMaxPush, maxPush] ← GetLoopCount[]; FOR i IN [0..542) DO putDataSpace[i] ← dataByte; ENDLOOP; BEGIN ENABLE NetworkStream.ConnectionSuspended => BEGIN suspended ← TRUE; msg ← "NetworkTester.TestSend: Connection suspended."; GOTO close; END; UNTIL pleaseStop OR (counter >= maxPush AND useMaxPush) DO Stream.PutByte[streamH, dataByte]; Stream.PutByte[streamH, dataByte]; Stream.SendNow[streamH]; outSST ← 1; Stream.SetSST[streamH, outSST]; outSST ← 2; Stream.SetSST[streamH, outSST]; Stream.SendNow[streamH]; bl ← [@putDataSpace, 0, 200]; Stream.PutBlock[streamH, bl, FALSE]; bl ← [@putDataSpace, 0, 201]; Stream.PutBlock[streamH, bl, FALSE]; bl ← [@putDataSpace, 0, 542]; Stream.PutBlock[streamH, bl, TRUE]; outSST ← 0; Stream.SetSST[streamH, outSST]; IF ((counter ← counter + 1) MOD 4) = 0 THEN Process.Yield[]; Put.Char[fileSW, '!]; ENDLOOP; THROUGH [0..4) DO Stream.SendAttention[streamH, attnByte]; Put.Char[fileSW, 'a]; ENDLOOP; EXITS close => NULL; END; -- ENABLE IF ~suspended THEN BEGIN -- close the communication stream closeStatus ← NetworkStream.Close[streamH]; IF closeStatus = good THEN msg ← "SinkTestSend: stream connection cleanly closed."L ELSE msg ← "SinkTestSend: stream connection closed with some doubt."L; END; Put.Line[fileSW, msg]; MsgSW.Post[msgSW, msg]; END; -- Mainline code Init[]; -- this gets string out of global frame END...