-- File: EchoServer.mesa, Last Edit: January 30, 1981 3:16 PM -- Please don't forget to update the herald too..... DIRECTORY Ascii USING [CR], InlineDefs USING [MesaToBcplLongNumber], Process USING [Yield], Event USING [Item, Reason, AddNotifier], FormSW USING [ AllocateItemDescriptor, newLine, ClientItemsProcType, ProcType, FindItem, Display, CommandItem, BooleanItem], MsgSW USING [AppendString], Tool USING [Create, MakeSWsProc, MakeMsgSW, MakeFormSW, AddThisSW], ToolWindow USING [TransitionProcType, DisplayProcType, CreateSubwindow], Window USING [Handle, Box, DisplayData, DisplayInvert, DisplayWhite], EchoServerDefs USING [ echoStatsRequest, echoStatsReply, EchoStatsEntry, echoVersion], StatsDefs USING [StatIncr, StatBump, StatGetCounter], PupDefs USING [ PupBuffer, ReturnFreePupBuffer, PupPackageMake, PupPackageDestroy, PupRouterSendThis, ReturnPup, SwapPupSourceAndDest, GetPupContentsBytes, PupSocket, PupSocketMake, PupSocketDestroy, PupSocketKick, veryLongWait], PupTypes USING [echoSoc, fillInPupAddress]; EchoServer: PROGRAM IMPORTS InlineDefs, Process, Event, FormSW, MsgSW, Tool, ToolWindow, Window, StatsDefs, PupDefs EXPORTS EchoServerDefs = BEGIN OPEN PupDefs; useCount, hits: CARDINAL ← 0; pleaseStop, running, verbose: BOOLEAN ← FALSE; echoFork: PROCESS; echoSocket: PupSocket; showSomething: PROCEDURE [CHARACTER] ← DummyEchoHook; tool, msg, form, boxes: Window.Handle ← NIL; eventItem: Event.Item ← [eventMask: 177777B, eventProc: Broom]; EchoServerOn: PUBLIC PROCEDURE = BEGIN IF (useCount ← useCount + 1) = 1 THEN BEGIN running ← TRUE; Starter[]; END; UpdatePicture[]; END; Starter: PROCEDURE = BEGIN pleaseStop ← FALSE; PupDefs.PupPackageMake[]; echoSocket ← PupSocketMake[ PupTypes.echoSoc, PupTypes.fillInPupAddress, veryLongWait]; echoFork ← FORK Echoer[]; END; EchoServerOff: PUBLIC PROCEDURE = BEGIN IF useCount # 0 AND (useCount ← useCount - 1) = 0 THEN BEGIN running ← FALSE; Stopper[]; END; UpdatePicture[]; END; Stopper: PROCEDURE = BEGIN pleaseStop ← TRUE; PupSocketKick[echoSocket]; JOIN echoFork[]; PupSocketDestroy[echoSocket]; PupDefs.PupPackageDestroy[]; END; UpdatePicture: PROCEDURE = BEGIN IF running THEN SetupBoxes[] ELSE SetDownBoxes[]; IF form = NIL THEN RETURN; FormSW.FindItem[form, startIX].flags.invisible ← running; FormSW.FindItem[form, stopIX].flags.invisible ← ~running; FormSW.Display[form]; END; Echoer: PROCEDURE = BEGIN b: PupBuffer; UNTIL pleaseStop DO IF (b ← echoSocket.get[]) # NIL THEN BEGIN SELECT b.pupType FROM echoMe => BEGIN b.pupType ← iAmEcho; SwapPupSourceAndDest[b]; PupRouterSendThis[b]; StatsDefs.StatIncr[pupsEchoed]; StatsDefs.StatBump[pupBytesEchoed, GetPupContentsBytes[b]]; showSomething['!]; END; EchoServerDefs.echoStatsRequest => BEGIN OPEN EchoServerDefs; ese: LONG POINTER TO EchoStatsEntry ← LOOPHOLE[@b.pupWords]; ese↑ ← [version: echoVersion, pupsEchoed: InlineDefs.MesaToBcplLongNumber[ StatsDefs.StatGetCounter[pupsEchoed]]]; ReturnPup[b, EchoServerDefs.echoStatsReply, 2*SIZE[EchoStatsEntry]]; END; ENDCASE => ReturnFreePupBuffer[b]; END; Process.Yield[]; -- avoid hogging machine ENDLOOP; END; DummyEchoHook: PUBLIC PROCEDURE [c: CHARACTER] = {}; RealEchoHook: PUBLIC PROCEDURE [c: CHARACTER] = BEGIN s: STRING = [2]; IF boxes # NIL THEN FlipBoxes[]; IF msg = NIL OR ~verbose THEN RETURN; s[0] ← c; s.length ← 1; IF ((hits ← hits + 1) MOD 50) = 0 THEN {s[1] ← Ascii.CR; s.length ← 2; }; MsgSW.AppendString[msg, s]; END; indicator: {off, left, right} ← off; indicatorBox: Window.Box = [[25, 10], [16, 16]]; DisplayBoxes: ToolWindow.DisplayProcType = BEGIN pattern: ARRAY [0..1] OF ARRAY [0..8) OF WORD; left: WORD = 177400B; right: WORD = 000377B; SELECT indicator FROM left => pattern ← [ALL[left], ALL[right]]; right => pattern ← [ALL[right], ALL[left]]; off => pattern ← [ALL[0], ALL[0]]; ENDCASE; Window.DisplayData[window, indicatorBox, @pattern, 1] END; SetupBoxes: PROCEDURE = BEGIN indicator ← left; IF boxes # NIL THEN DisplayBoxes[boxes]; END; FlipBoxes: PROCEDURE = BEGIN SELECT indicator FROM left => indicator ← right; off, right => indicator ← left; ENDCASE; IF boxes # NIL THEN Window.DisplayInvert[boxes, indicatorBox]; END; SetDownBoxes: PROCEDURE = BEGIN indicator ← off; IF boxes # NIL THEN Window.DisplayWhite[boxes, indicatorBox]; END; MakeBoxesSW: PROCEDURE [window: Window.Handle] = BEGIN boxes ← ToolWindow.CreateSubwindow[parent: window, display: DisplayBoxes]; boxes.box.dims.h ← 36; Tool.AddThisSW[window: window, sw: boxes, swType: vanilla]; END; Start: FormSW.ProcType = BEGIN EchoServerOn[]; END; Stop: FormSW.ProcType = BEGIN EchoServerOff[]; END; MakeSWs: Tool.MakeSWsProc = BEGIN msg ← Tool.MakeMsgSW[window: window, lines: 3]; form ← Tool.MakeFormSW[window: window, formProc: MakeForm]; MakeBoxesSW[window]; END; startIX: CARDINAL = 0; stopIX: CARDINAL = 1; MakeForm: FormSW.ClientItemsProcType = BEGIN nParams: CARDINAL = 3; items ← FormSW.AllocateItemDescriptor[nParams]; items[0] ← FormSW.CommandItem[ tag: "Start"L, proc: Start, place: FormSW.newLine, invisible: running]; items[1] ← FormSW.CommandItem[ tag: "Stop"L, proc: Stop, place: FormSW.newLine, invisible: ~running]; items[2] ← FormSW.BooleanItem[tag: "Verbose"L, switch: @verbose]; RETURN[items, TRUE]; END; ClientTransition: ToolWindow.TransitionProcType = BEGIN IF new = inactive THEN msg ← form ← boxes ← NIL; showSomething ← IF new = active THEN RealEchoHook ELSE DummyEchoHook; END; Broom: PROCEDURE [why: Event.Reason] = BEGIN SELECT why FROM makeImage, makeCheck => IF running THEN Stopper[]; startImage, restartCheck, continueCheck => IF running THEN Starter[]; ENDCASE => NULL; END; -- initialization tool ← Tool.Create[ name: "Echo Server of January 30, 1981"L, makeSWsProc: MakeSWs, clientTransition: ClientTransition, initialState: inactive]; Event.AddNotifier[@eventItem]; EchoServerOn[]; -- This may be undesirable END.